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

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

Issue 1099963003: Support type selector for camel-cased SVG elements in HTML. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fix performance regression. tagMatches() became too big to be inlined on Linux. Created 5 years, 8 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 | Annotate | Revision Log
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 "config.h" 5 #include "config.h"
6 #include "core/css/parser/CSSSelectorParser.h" 6 #include "core/css/parser/CSSSelectorParser.h"
7 7
8 #include "core/css/CSSLocalNameToLowerMaps.h"
8 #include "core/css/CSSSelectorList.h" 9 #include "core/css/CSSSelectorList.h"
9 #include "core/css/StyleSheetContents.h" 10 #include "core/css/StyleSheetContents.h"
10 #include "core/frame/UseCounter.h" 11 #include "core/frame/UseCounter.h"
11 #include "platform/RuntimeEnabledFeatures.h" 12 #include "platform/RuntimeEnabledFeatures.h"
12 13
13 namespace blink { 14 namespace blink {
14 15
15 void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParser Context& context, const AtomicString& defaultNamespace, StyleSheetContents* styl eSheet, CSSSelectorList& output) 16 void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParser Context& context, const AtomicString& defaultNamespace, StyleSheetContents* styl eSheet, CSSSelectorList& output)
16 { 17 {
17 CSSSelectorParser parser(context, defaultNamespace, styleSheet); 18 CSSSelectorParser parser(context, defaultNamespace, styleSheet);
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 return selector.release(); 100 return selector.release();
100 } 101 }
101 102
102 PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector(CSSPars erTokenRange& range) 103 PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector(CSSPars erTokenRange& range)
103 { 104 {
104 OwnPtr<CSSParserSelector> compoundSelector; 105 OwnPtr<CSSParserSelector> compoundSelector;
105 106
106 AtomicString namespacePrefix; 107 AtomicString namespacePrefix;
107 AtomicString elementName; 108 AtomicString elementName;
108 bool hasNamespace; 109 bool hasNamespace;
110 TagSelectorCase tagSelectorCase = TagLowerCase;
109 if (!consumeName(range, elementName, namespacePrefix, hasNamespace)) { 111 if (!consumeName(range, elementName, namespacePrefix, hasNamespace)) {
110 compoundSelector = consumeSimpleSelector(range); 112 compoundSelector = consumeSimpleSelector(range);
111 if (!compoundSelector) 113 if (!compoundSelector)
112 return nullptr; 114 return nullptr;
113 } 115 }
114 if (m_context.isHTMLDocument()) 116 if (m_context.isHTMLDocument() && !elementName.isNull()) {
115 elementName = elementName.lower(); 117 if (CSSLocalNameToLowerMaps::elementToLower(elementName).isNull())
118 elementName = elementName.lower();
119 else
120 tagSelectorCase = TagCamelCase;
121 }
116 122
117 while (OwnPtr<CSSParserSelector> simpleSelector = consumeSimpleSelector(rang e)) { 123 while (OwnPtr<CSSParserSelector> simpleSelector = consumeSimpleSelector(rang e)) {
118 if (compoundSelector) 124 if (compoundSelector)
119 compoundSelector = addSimpleSelectorToCompound(compoundSelector.rele ase(), simpleSelector.release()); 125 compoundSelector = addSimpleSelectorToCompound(compoundSelector.rele ase(), simpleSelector.release());
120 else 126 else
121 compoundSelector = simpleSelector.release(); 127 compoundSelector = simpleSelector.release();
122 } 128 }
123 129
124 if (!compoundSelector) { 130 if (!compoundSelector) {
125 if (hasNamespace) 131 if (hasNamespace)
126 return CSSParserSelector::create(determineNameInNamespace(namespaceP refix, elementName)); 132 return CSSParserSelector::create(determineNameInNamespace(namespaceP refix, elementName), false, tagSelectorCase);
127 return CSSParserSelector::create(QualifiedName(nullAtom, elementName, m_ defaultNamespace)); 133 return CSSParserSelector::create(QualifiedName(nullAtom, elementName, m_ defaultNamespace), false, tagSelectorCase);
128 } 134 }
129 prependTypeSelectorIfNeeded(namespacePrefix, elementName, compoundSelector.g et()); 135 prependTypeSelectorIfNeeded(namespacePrefix, elementName, compoundSelector.g et(), tagSelectorCase);
130 return compoundSelector.release(); 136 return compoundSelector.release();
131 } 137 }
132 138
133 PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeSimpleSelector(CSSParser TokenRange& range) 139 PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeSimpleSelector(CSSParser TokenRange& range)
134 { 140 {
135 const CSSParserToken& token = range.peek(); 141 const CSSParserToken& token = range.peek();
136 OwnPtr<CSSParserSelector> selector; 142 OwnPtr<CSSParserSelector> selector;
137 if (token.type() == HashToken) 143 if (token.type() == HashToken)
138 selector = consumeId(range); 144 selector = consumeId(range);
139 else if (token.type() == DelimiterToken && token.delimiter() == '.') 145 else if (token.type() == DelimiterToken && token.delimiter() == '.')
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 return true; 517 return true;
512 } 518 }
513 519
514 QualifiedName CSSSelectorParser::determineNameInNamespace(const AtomicString& pr efix, const AtomicString& localName) 520 QualifiedName CSSSelectorParser::determineNameInNamespace(const AtomicString& pr efix, const AtomicString& localName)
515 { 521 {
516 if (!m_styleSheet) 522 if (!m_styleSheet)
517 return QualifiedName(prefix, localName, m_defaultNamespace); 523 return QualifiedName(prefix, localName, m_defaultNamespace);
518 return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(pre fix)); 524 return QualifiedName(prefix, localName, m_styleSheet->determineNamespace(pre fix));
519 } 525 }
520 526
521 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) 527 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector, T agSelectorCase tagSelectorCase)
522 { 528 {
523 if (elementName.isNull() && m_defaultNamespace == starAtom && !compoundSelec tor->crossesTreeScopes()) 529 if (elementName.isNull() && m_defaultNamespace == starAtom && !compoundSelec tor->crossesTreeScopes())
524 return; 530 return;
525 531
526 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme ntName; 532 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme ntName;
527 AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleShe et ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace; 533 AtomicString determinedNamespace = namespacePrefix != nullAtom && m_styleShe et ? m_styleSheet->determineNamespace(namespacePrefix) : m_defaultNamespace;
528 QualifiedName tag(namespacePrefix, determinedElementName, determinedNamespac e); 534 QualifiedName tag(namespacePrefix, determinedElementName, determinedNamespac e);
529 535
530 if (compoundSelector->crossesTreeScopes()) 536 if (compoundSelector->crossesTreeScopes())
531 return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, compo undSelector, elementName.isNull()); 537 return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, compo undSelector, elementName.isNull(), tagSelectorCase);
532 538
533 if (compoundSelector->isContentPseudoElement()) 539 if (compoundSelector->isContentPseudoElement())
534 return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, comp oundSelector, elementName.isNull()); 540 return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, comp oundSelector, elementName.isNull(), tagSelectorCase);
535 541
536 // *:host never matches, so we can't discard the * otherwise we can't tell t he 542 // *:host never matches, so we can't discard the * otherwise we can't tell t he
537 // difference between *:host and just :host. 543 // difference between *:host and just :host.
538 if (tag == anyQName() && !compoundSelector->hasHostPseudoSelector()) 544 if (tag == anyQName() && !compoundSelector->hasHostPseudoSelector())
539 return; 545 return;
540 compoundSelector->prependTagSelector(tag, elementName.isNull()); 546 compoundSelector->prependTagSelector(tag, elementName.isNull(), tagSelectorC ase);
541 } 547 }
542 548
543 void CSSSelectorParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(c onst QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit) 549 void CSSSelectorParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(c onst QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit, TagS electorCase tagSelectorCase)
544 { 550 {
545 CSSParserSelector* lastShadowPseudo = specifiers; 551 CSSParserSelector* lastShadowPseudo = specifiers;
546 CSSParserSelector* history = specifiers; 552 CSSParserSelector* history = specifiers;
547 while (history->tagHistory()) { 553 while (history->tagHistory()) {
548 history = history->tagHistory(); 554 history = history->tagHistory();
549 if (history->crossesTreeScopes() || history->hasShadowPseudo()) 555 if (history->crossesTreeScopes() || history->hasShadowPseudo())
550 lastShadowPseudo = history; 556 lastShadowPseudo = history;
551 } 557 }
552 558
553 if (lastShadowPseudo->tagHistory()) { 559 if (lastShadowPseudo->tagHistory()) {
554 if (tag != anyQName()) 560 if (tag != anyQName())
555 lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsImplici t); 561 lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsImplici t, tagSelectorCase);
556 return; 562 return;
557 } 563 }
558 564
559 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo c ombinator has to be used. 565 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo c ombinator has to be used.
560 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*'). 566 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
561 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta g); 567 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta g, false /* isImplicit */, tagSelectorCase);
562 lastShadowPseudo->setTagHistory(elementNameSelector.release()); 568 lastShadowPseudo->setTagHistory(elementNameSelector.release());
563 lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo); 569 lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
564 } 570 }
565 571
566 void CSSSelectorParser::rewriteSpecifiersWithElementNameForContentPseudoElement( const QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit) 572 void CSSSelectorParser::rewriteSpecifiersWithElementNameForContentPseudoElement( const QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit, Tag SelectorCase tagSelectorCase)
567 { 573 {
568 CSSParserSelector* last = specifiers; 574 CSSParserSelector* last = specifiers;
569 CSSParserSelector* history = specifiers; 575 CSSParserSelector* history = specifiers;
570 while (history->tagHistory()) { 576 while (history->tagHistory()) {
571 history = history->tagHistory(); 577 history = history->tagHistory();
572 if (history->isContentPseudoElement() || history->relationIsAffectedByPs eudoContent()) 578 if (history->isContentPseudoElement() || history->relationIsAffectedByPs eudoContent())
573 last = history; 579 last = history;
574 } 580 }
575 581
576 if (last->tagHistory()) { 582 if (last->tagHistory()) {
577 if (tag != anyQName()) 583 if (tag != anyQName())
578 last->tagHistory()->prependTagSelector(tag, tagIsImplicit); 584 last->tagHistory()->prependTagSelector(tag, tagIsImplicit, tagSelect orCase);
579 return; 585 return;
580 } 586 }
581 587
582 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo c ombinator has to be used. 588 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo c ombinator has to be used.
583 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*'). 589 // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
584 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta g); 590 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta g, false /* isImplicit */, tagSelectorCase);
585 last->setTagHistory(elementNameSelector.release()); 591 last->setTagHistory(elementNameSelector.release());
586 } 592 }
587 593
588 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl eSelector) 594 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl eSelector)
589 { 595 {
590 // The tagHistory is a linked list that stores combinator separated compound selectors 596 // The tagHistory is a linked list that stores combinator separated compound selectors
591 // from right-to-left. Yet, within a single compound selector, stores the si mple selectors 597 // from right-to-left. Yet, within a single compound selector, stores the si mple selectors
592 // from left-to-right. 598 // from left-to-right.
593 // 599 //
594 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele ment in the 600 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele ment in the
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
675 context.useCounter()->count(feature); 681 context.useCounter()->count(feature);
676 if (current->relation() == CSSSelector::ShadowDeep) 682 if (current->relation() == CSSSelector::ShadowDeep)
677 context.useCounter()->count(UseCounter::CSSDeepCombinator); 683 context.useCounter()->count(UseCounter::CSSDeepCombinator);
678 if (current->selectorList()) 684 if (current->selectorList())
679 recordSelectorStats(context, *current->selectorList()); 685 recordSelectorStats(context, *current->selectorList());
680 } 686 }
681 } 687 }
682 } 688 }
683 689
684 } // namespace blink 690 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698