09e76ff671022cd12191b26a70cb3ce682d5d1c2
[WebKit-https.git] / Source / WebCore / css / parser / CSSSelectorParser.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Copyright (C) 2016 Apple Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //    * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //    * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //    * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "config.h"
31 #include "CSSSelectorParser.h"
32
33 #include "CSSParserIdioms.h"
34 #include "CSSParserMode.h"
35 #include "CSSSelectorList.h"
36 #include "StyleSheetContents.h"
37 #include <memory>
38
39 namespace WebCore {
40
41 CSSSelectorList CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParserContext& context, StyleSheetContents* styleSheet)
42 {
43     CSSSelectorParser parser(context, styleSheet);
44     range.consumeWhitespace();
45     CSSSelectorList result = parser.consumeComplexSelectorList(range);
46     if (!range.atEnd())
47         return CSSSelectorList();
48     return result;
49 }
50
51 CSSSelectorParser::CSSSelectorParser(const CSSParserContext& context, StyleSheetContents* styleSheet)
52     : m_context(context)
53     , m_styleSheet(styleSheet)
54 {
55 }
56
57 CSSSelectorList CSSSelectorParser::consumeComplexSelectorList(CSSParserTokenRange& range)
58 {
59     Vector<std::unique_ptr<CSSParserSelector>> selectorList;
60     std::unique_ptr<CSSParserSelector> selector = consumeComplexSelector(range);
61     if (!selector)
62         return CSSSelectorList();
63     selectorList.append(WTFMove(selector));
64     while (!range.atEnd() && range.peek().type() == CommaToken) {
65         range.consumeIncludingWhitespace();
66         selector = consumeComplexSelector(range);
67         if (!selector)
68             return CSSSelectorList();
69         selectorList.append(WTFMove(selector));
70     }
71
72     CSSSelectorList list;
73     if (m_failedParsing)
74         return list;
75     list.adoptSelectorVector(selectorList);
76     return list;
77 }
78
79 CSSSelectorList CSSSelectorParser::consumeCompoundSelectorList(CSSParserTokenRange& range)
80 {
81     Vector<std::unique_ptr<CSSParserSelector>> selectorList;
82     std::unique_ptr<CSSParserSelector> selector = consumeCompoundSelector(range);
83     range.consumeWhitespace();
84     if (!selector)
85         return CSSSelectorList();
86     selectorList.append(WTFMove(selector));
87     while (!range.atEnd() && range.peek().type() == CommaToken) {
88         range.consumeIncludingWhitespace();
89         selector = consumeCompoundSelector(range);
90         range.consumeWhitespace();
91         if (!selector)
92             return CSSSelectorList();
93         selectorList.append(WTFMove(selector));
94     }
95
96     CSSSelectorList list;
97     if (m_failedParsing)
98         return list;
99     list.adoptSelectorVector(selectorList);
100     return list;
101 }
102
103 static bool consumeLangArgumentList(std::unique_ptr<Vector<AtomicString>>& argumentList, CSSParserTokenRange& range)
104 {
105     const CSSParserToken& ident = range.consumeIncludingWhitespace();
106     if (ident.type() != IdentToken && ident.type() != StringToken)
107         return false;
108     StringView string = ident.value();
109     if (string.startsWith("--"))
110         return false;
111     argumentList->append(string.toAtomicString());
112     while (!range.atEnd() && range.peek().type() == CommaToken) {
113         range.consumeIncludingWhitespace();
114         const CSSParserToken& ident = range.consumeIncludingWhitespace();
115         if (ident.type() != IdentToken && ident.type() != StringToken)
116             return false;
117         StringView string = ident.value();
118         if (string.startsWith("--"))
119             return false;
120         argumentList->append(string.toAtomicString());
121     }
122     return range.atEnd();
123 }
124
125 namespace {
126
127 enum CompoundSelectorFlags {
128     HasPseudoElementForRightmostCompound = 1 << 0,
129     HasContentPseudoElement = 1 << 1
130 };
131
132 unsigned extractCompoundFlags(const CSSParserSelector& simpleSelector, CSSParserMode parserMode)
133 {
134     if (simpleSelector.match() != CSSSelector::PseudoElement)
135         return 0;
136     // FIXME-NEWPARSER: These don't exist for us, so may need to revisit.
137     // if (simpleSelector.pseudoElementType() == CSSSelector::PseudoContent)
138     //    return HasContentPseudoElement;
139     // if (simpleSelector.pseudoElementType() == CSSSelector::PseudoShadow)
140     //    return 0;
141
142     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=161747
143     // The UASheetMode check is a work-around to allow this selector in mediaControls(New).css:
144     // input[type="range" i]::-webkit-media-slider-container > div {
145     if (parserMode == UASheetMode && simpleSelector.pseudoElementType() == CSSSelector::PseudoElementWebKitCustom)
146         return 0;
147     return HasPseudoElementForRightmostCompound;
148 }
149
150 } // namespace
151
152 static bool isDescendantCombinator(CSSSelector::RelationType relation)
153 {
154 #if ENABLE(CSS_SELECTORS_LEVEL4)
155     return relation == CSSSelector::DescendantSpace || relation == CSSSelector::DescendantDoubleChild;
156 #else
157     return relation == CSSSelector::DescendantSpace;
158 #endif
159 }
160 std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeComplexSelector(CSSParserTokenRange& range)
161 {
162     std::unique_ptr<CSSParserSelector> selector = consumeCompoundSelector(range);
163     if (!selector)
164         return nullptr;
165
166     unsigned previousCompoundFlags = 0;
167
168     for (CSSParserSelector* simple = selector.get(); simple && !previousCompoundFlags; simple = simple->tagHistory())
169         previousCompoundFlags |= extractCompoundFlags(*simple, m_context.mode);
170
171     while (auto combinator = consumeCombinator(range)) {
172         std::unique_ptr<CSSParserSelector> nextSelector = consumeCompoundSelector(range);
173         if (!nextSelector)
174             return isDescendantCombinator(combinator) ? WTFMove(selector) : nullptr;
175         if (previousCompoundFlags & HasPseudoElementForRightmostCompound)
176             return nullptr;
177         CSSParserSelector* end = nextSelector.get();
178         unsigned compoundFlags = extractCompoundFlags(*end, m_context.mode);
179         while (end->tagHistory()) {
180             end = end->tagHistory();
181             compoundFlags |= extractCompoundFlags(*end, m_context.mode);
182         }
183         end->setRelation(combinator);
184         // FIXME-NEWPARSER: Shadow stuff that we don't have.
185         // if (previousCompoundFlags & HasContentPseudoElement)
186         //    end->setRelationIsAffectedByPseudoContent();
187         previousCompoundFlags = compoundFlags;
188         end->setTagHistory(WTFMove(selector));
189
190         selector = WTFMove(nextSelector);
191     }
192
193     return selector;
194 }
195
196 namespace {
197
198 bool isScrollbarPseudoClass(CSSSelector::PseudoClassType pseudo)
199 {
200     switch (pseudo) {
201     case CSSSelector::PseudoClassEnabled:
202     case CSSSelector::PseudoClassDisabled:
203     case CSSSelector::PseudoClassHover:
204     case CSSSelector::PseudoClassActive:
205     case CSSSelector::PseudoClassHorizontal:
206     case CSSSelector::PseudoClassVertical:
207     case CSSSelector::PseudoClassDecrement:
208     case CSSSelector::PseudoClassIncrement:
209     case CSSSelector::PseudoClassStart:
210     case CSSSelector::PseudoClassEnd:
211     case CSSSelector::PseudoClassDoubleButton:
212     case CSSSelector::PseudoClassSingleButton:
213     case CSSSelector::PseudoClassNoButton:
214     case CSSSelector::PseudoClassCornerPresent:
215     case CSSSelector::PseudoClassWindowInactive:
216         return true;
217     default:
218         return false;
219     }
220 }
221
222 bool isUserActionPseudoClass(CSSSelector::PseudoClassType pseudo)
223 {
224     switch (pseudo) {
225     case CSSSelector::PseudoClassHover:
226     case CSSSelector::PseudoClassFocus:
227     case CSSSelector::PseudoClassActive:
228         return true;
229     default:
230         return false;
231     }
232 }
233
234 bool isPseudoClassValidAfterPseudoElement(CSSSelector::PseudoClassType pseudoClass, CSSSelector::PseudoElementType compoundPseudoElement)
235 {
236     switch (compoundPseudoElement) {
237     case CSSSelector::PseudoElementResizer:
238     case CSSSelector::PseudoElementScrollbar:
239     case CSSSelector::PseudoElementScrollbarCorner:
240     case CSSSelector::PseudoElementScrollbarButton:
241     case CSSSelector::PseudoElementScrollbarThumb:
242     case CSSSelector::PseudoElementScrollbarTrack:
243     case CSSSelector::PseudoElementScrollbarTrackPiece:
244         return isScrollbarPseudoClass(pseudoClass);
245     case CSSSelector::PseudoElementSelection:
246         return pseudoClass == CSSSelector::PseudoClassWindowInactive;
247     case CSSSelector::PseudoElementWebKitCustom:
248     case CSSSelector::PseudoElementWebKitCustomLegacyPrefixed:
249         return isUserActionPseudoClass(pseudoClass);
250     default:
251         return false;
252     }
253 }
254
255 bool isSimpleSelectorValidAfterPseudoElement(const CSSParserSelector& simpleSelector, CSSSelector::PseudoElementType compoundPseudoElement)
256 {
257     if (compoundPseudoElement == CSSSelector::PseudoElementUnknown)
258         return true;
259     // FIXME-NEWPARSER: This doesn't exist for us.
260     // if (compoundPseudoElement == CSSSelector::PseudoElementContent)
261     //    return simpleSelector.match() != CSSSelector::PseudoElement;
262     if (simpleSelector.match() != CSSSelector::PseudoClass)
263         return false;
264     CSSSelector::PseudoClassType pseudo = simpleSelector.pseudoClassType();
265     if (pseudo == CSSSelector::PseudoClassNot) {
266         ASSERT(simpleSelector.selectorList());
267         ASSERT(simpleSelector.selectorList()->first());
268         ASSERT(!simpleSelector.selectorList()->first()->tagHistory());
269         pseudo = simpleSelector.selectorList()->first()->pseudoClassType();
270     }
271     return isPseudoClassValidAfterPseudoElement(pseudo, compoundPseudoElement);
272 }
273
274 } // namespace
275
276 std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector(CSSParserTokenRange& range)
277 {
278     std::unique_ptr<CSSParserSelector> compoundSelector;
279
280     AtomicString namespacePrefix;
281     AtomicString elementName;
282     CSSSelector::PseudoElementType compoundPseudoElement = CSSSelector::PseudoElementUnknown;
283     if (!consumeName(range, elementName, namespacePrefix)) {
284         compoundSelector = consumeSimpleSelector(range);
285         if (!compoundSelector)
286             return nullptr;
287         if (compoundSelector->match() == CSSSelector::PseudoElement)
288             compoundPseudoElement = compoundSelector->pseudoElementType();
289     }
290
291     while (std::unique_ptr<CSSParserSelector> simpleSelector = consumeSimpleSelector(range)) {
292         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=161747
293         // The UASheetMode check is a work-around to allow this selector in mediaControls(New).css:
294         // video::-webkit-media-text-track-region-container.scrolling
295         if (m_context.mode != UASheetMode && !isSimpleSelectorValidAfterPseudoElement(*simpleSelector.get(), compoundPseudoElement)) {
296             m_failedParsing = true;
297             return nullptr;
298         }
299         if (simpleSelector->match() == CSSSelector::PseudoElement)
300             compoundPseudoElement = simpleSelector->pseudoElementType();
301
302         if (compoundSelector)
303             compoundSelector = addSimpleSelectorToCompound(WTFMove(compoundSelector), WTFMove(simpleSelector));
304         else
305             compoundSelector = WTFMove(simpleSelector);
306     }
307
308     if (!compoundSelector) {
309         AtomicString namespaceURI = determineNamespace(namespacePrefix);
310         if (namespaceURI.isNull()) {
311             m_failedParsing = true;
312             return nullptr;
313         }
314         if (namespaceURI == defaultNamespace())
315             namespacePrefix = nullAtom;
316         
317         CSSParserSelector* rawSelector = new CSSParserSelector(QualifiedName(namespacePrefix, elementName, namespaceURI));
318         std::unique_ptr<CSSParserSelector> selector = std::unique_ptr<CSSParserSelector>(rawSelector);
319         return selector;
320     }
321     prependTypeSelectorIfNeeded(namespacePrefix, elementName, compoundSelector.get());
322     return splitCompoundAtImplicitShadowCrossingCombinator(WTFMove(compoundSelector));
323 }
324
325 std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeSimpleSelector(CSSParserTokenRange& range)
326 {
327     const CSSParserToken& token = range.peek();
328     std::unique_ptr<CSSParserSelector> selector;
329     if (token.type() == HashToken)
330         selector = consumeId(range);
331     else if (token.type() == DelimiterToken && token.delimiter() == '.')
332         selector = consumeClass(range);
333     else if (token.type() == LeftBracketToken)
334         selector = consumeAttribute(range);
335     else if (token.type() == ColonToken)
336         selector = consumePseudo(range);
337     else
338         return nullptr;
339     if (!selector)
340         m_failedParsing = true;
341     return selector;
342 }
343
344 bool CSSSelectorParser::consumeName(CSSParserTokenRange& range, AtomicString& name, AtomicString& namespacePrefix)
345 {
346     name = nullAtom;
347     namespacePrefix = nullAtom;
348
349     const CSSParserToken& firstToken = range.peek();
350     if (firstToken.type() == IdentToken) {
351         name = firstToken.value().toAtomicString();
352         range.consume();
353     } else if (firstToken.type() == DelimiterToken && firstToken.delimiter() == '*') {
354         name = starAtom;
355         range.consume();
356     } else if (firstToken.type() == DelimiterToken && firstToken.delimiter() == '|') {
357         // This is an empty namespace, which'll get assigned this value below
358         name = emptyAtom;
359     } else
360         return false;
361
362     if (range.peek().type() != DelimiterToken || range.peek().delimiter() != '|')
363         return true;
364     range.consume();
365
366     namespacePrefix = name;
367     const CSSParserToken& nameToken = range.consume();
368     if (nameToken.type() == IdentToken) {
369         name = nameToken.value().toAtomicString();
370     } else if (nameToken.type() == DelimiterToken && nameToken.delimiter() == '*')
371         name = starAtom;
372     else {
373         name = nullAtom;
374         namespacePrefix = nullAtom;
375         return false;
376     }
377
378     return true;
379 }
380
381 std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeId(CSSParserTokenRange& range)
382 {
383     ASSERT(range.peek().type() == HashToken);
384     if (range.peek().getHashTokenType() != HashTokenId)
385         return nullptr;
386     std::unique_ptr<CSSParserSelector> selector = std::unique_ptr<CSSParserSelector>(new CSSParserSelector());
387     selector->setMatch(CSSSelector::Id);
388     
389     // FIXME-NEWPARSER: Avoid having to do this, but the old parser does and we need
390     // to be compatible for now.
391     CSSParserToken token = range.consume();
392     if (m_context.mode == HTMLQuirksMode)
393         token.convertToASCIILowercaseInPlace();
394     selector->setValue(token.value().toAtomicString());
395
396     return selector;
397 }
398
399 std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeClass(CSSParserTokenRange& range)
400 {
401     ASSERT(range.peek().type() == DelimiterToken);
402     ASSERT(range.peek().delimiter() == '.');
403     range.consume();
404     if (range.peek().type() != IdentToken)
405         return nullptr;
406     std::unique_ptr<CSSParserSelector> selector = std::unique_ptr<CSSParserSelector>(new CSSParserSelector());
407     selector->setMatch(CSSSelector::Class);
408     
409     // FIXME-NEWPARSER: Avoid having to do this, but the old parser does and we need
410     // to be compatible for now.
411     CSSParserToken token = range.consume();
412     if (m_context.mode == HTMLQuirksMode)
413         token.convertToASCIILowercaseInPlace();
414     selector->setValue(token.value().toAtomicString());
415
416     return selector;
417 }
418
419 std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeAttribute(CSSParserTokenRange& range)
420 {
421     ASSERT(range.peek().type() == LeftBracketToken);
422     CSSParserTokenRange block = range.consumeBlock();
423     if (block.end() == range.end())
424         return nullptr; // No ] was found. Be strict about this.
425
426     block.consumeWhitespace();
427
428     AtomicString namespacePrefix;
429     AtomicString attributeName;
430     if (!consumeName(block, attributeName, namespacePrefix))
431         return nullptr;
432     block.consumeWhitespace();
433
434     AtomicString namespaceURI = determineNamespace(namespacePrefix);
435     if (namespaceURI.isNull())
436         return nullptr;
437
438     QualifiedName qualifiedName = namespacePrefix.isNull()
439         ? QualifiedName(nullAtom, attributeName, nullAtom)
440         : QualifiedName(namespacePrefix, attributeName, namespaceURI);
441
442     std::unique_ptr<CSSParserSelector> selector = std::unique_ptr<CSSParserSelector>(new CSSParserSelector());
443
444     if (block.atEnd()) {
445         selector->setAttribute(qualifiedName, m_context.isHTMLDocument, CSSSelector::CaseSensitive);
446         selector->setMatch(CSSSelector::Set);
447         return selector;
448     }
449
450     selector->setMatch(consumeAttributeMatch(block));
451
452     const CSSParserToken& attributeValue = block.consumeIncludingWhitespace();
453     if (attributeValue.type() != IdentToken && attributeValue.type() != StringToken)
454         return nullptr;
455     selector->setValue(attributeValue.value().toAtomicString());
456     
457     selector->setAttribute(qualifiedName, m_context.isHTMLDocument, consumeAttributeFlags(block));
458
459     if (!block.atEnd())
460         return nullptr;
461     return selector;
462 }
463
464 static bool isOnlyPseudoClassFunction(CSSSelector::PseudoClassType pseudoClassType)
465 {
466     switch (pseudoClassType) {
467     case CSSSelector::PseudoClassNot:
468     case CSSSelector::PseudoClassMatches:
469     case CSSSelector::PseudoClassNthChild:
470     case CSSSelector::PseudoClassNthLastChild:
471     case CSSSelector::PseudoClassNthOfType:
472     case CSSSelector::PseudoClassNthLastOfType:
473     case CSSSelector::PseudoClassLang:
474     case CSSSelector::PseudoClassAny:
475 #if ENABLE_CSS_SELECTORS_LEVEL4
476     case CSSSelector::PseudoClassDir:
477     case CSSSelector::PseudoClassRole:
478 #endif
479         return true;
480     default:
481         break;
482     }
483     return false;
484 }
485     
486 static bool isOnlyPseudoElementFunction(CSSSelector::PseudoElementType pseudoElementType)
487 {
488     // Note that we omit cue since it can be both an ident or a function.
489     switch (pseudoElementType) {
490     case CSSSelector::PseudoElementSlotted:
491         return true;
492     default:
493         break;
494     }
495     return false;
496 }
497
498 std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumePseudo(CSSParserTokenRange& range)
499 {
500     ASSERT(range.peek().type() == ColonToken);
501     range.consume();
502
503     int colons = 1;
504     if (range.peek().type() == ColonToken) {
505         range.consume();
506         colons++;
507     }
508
509     const CSSParserToken& token = range.peek();
510     if (token.type() != IdentToken && token.type() != FunctionToken)
511         return nullptr;
512
513     std::unique_ptr<CSSParserSelector> selector;
514     
515     // FIXME-NEWPARSER: Would like to eliminate this.
516     const_cast<CSSParserToken&>(token).convertToASCIILowercaseInPlace();
517     
518     StringView value = token.value();
519     
520     // FIXME-NEWPARSER: We can't change the pseudoclass/element maps that the old parser
521     // uses without breaking it; this hack allows function selectors to work. When the new
522     // parser turns on, we can patch the map and remove this code.
523     String newValue;
524     if (token.type() == FunctionToken && colons == 1) {
525         String tokenString = value.toString();
526         if (!tokenString.startsWithIgnoringASCIICase("host")) {
527             newValue = value.toString() + "(";
528             value = newValue;
529         }
530     }
531
532     if (colons == 1)
533         selector = std::unique_ptr<CSSParserSelector>(CSSParserSelector::parsePseudoClassSelectorFromStringView(value));
534     else {
535         selector = std::unique_ptr<CSSParserSelector>(CSSParserSelector::parsePseudoElementSelectorFromStringView(value));
536 #if ENABLE(VIDEO_TRACK)
537         if (selector && selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementWebKitCustom) {
538             // FIXME-NEWPARSER: The old parser treats cue as two pseudo-element types, because it
539             // is unable to handle a dual pseudo-element (one that can be both an ident or a
540             // function) without splitting them up.
541             //
542             // This means that "cue" is being parsed as PseudoElementWebkitCustom when used as an
543             // identifier, and it's being parsed as PseudoElementCue when used as a function.
544             //
545             // We have to mimic this behavior until the old parser is gone, at which point we can
546             // make all code use PseudoElementCue.
547             if (token.type() == FunctionToken && value.startsWithIgnoringASCIICase("cue"))
548                 selector->setPseudoElementType(CSSSelector::PseudoElementCue);
549         }
550 #endif
551     }
552
553     if (!selector || (selector->match() == CSSSelector::PseudoElement && m_disallowPseudoElements))
554         return nullptr;
555
556     if (token.type() == IdentToken) {
557         range.consume();
558         if ((selector->match() == CSSSelector::PseudoElement && (selector->pseudoElementType() == CSSSelector::PseudoElementUnknown || isOnlyPseudoElementFunction(selector->pseudoElementType())))
559             || (selector->match() == CSSSelector::PseudoClass && (selector->pseudoClassType() == CSSSelector::PseudoClassUnknown || isOnlyPseudoClassFunction(selector->pseudoClassType()))))
560             return nullptr;
561         return selector;
562     }
563
564     CSSParserTokenRange block = range.consumeBlock();
565     block.consumeWhitespace();
566     if (token.type() != FunctionToken)
567         return nullptr;
568     
569     const auto& argumentStart = block.peek();
570     
571     if (selector->match() == CSSSelector::PseudoClass) {
572         switch (selector->pseudoClassType()) {
573         case CSSSelector::PseudoClassNot: {
574             DisallowPseudoElementsScope scope(this);
575             std::unique_ptr<CSSSelectorList> selectorList = std::unique_ptr<CSSSelectorList>(new CSSSelectorList());
576             *selectorList = consumeComplexSelectorList(block);
577             if (!selectorList->componentCount() || !block.atEnd())
578                 return nullptr;
579             selector->setSelectorList(WTFMove(selectorList));
580             return selector;
581         }
582         case CSSSelector::PseudoClassNthChild:
583         case CSSSelector::PseudoClassNthLastChild:
584         case CSSSelector::PseudoClassNthOfType:
585         case CSSSelector::PseudoClassNthLastOfType: {
586             std::pair<int, int> ab;
587             if (!consumeANPlusB(block, ab))
588                 return nullptr;
589             block.consumeWhitespace();
590             const auto& argumentEnd = block.peek();
591             auto rangeOfANPlusB = block.makeSubRange(&argumentStart, &argumentEnd);
592             auto argument = rangeOfANPlusB.serialize();
593             selector->setArgument(argument.stripWhiteSpace());
594             if (!block.atEnd()) {
595                 if (block.peek().type() != IdentToken)
596                     return nullptr;
597                 const CSSParserToken& ident = block.consume();
598                 if (!equalIgnoringASCIICase(ident.value(), "of"))
599                     return nullptr;
600                 if (block.peek().type() != WhitespaceToken)
601                     return nullptr;
602                 DisallowPseudoElementsScope scope(this);
603                 block.consumeWhitespace();
604                 std::unique_ptr<CSSSelectorList> selectorList = std::unique_ptr<CSSSelectorList>(new CSSSelectorList());
605                 *selectorList = consumeComplexSelectorList(block);
606                 if (!selectorList->componentCount() || !block.atEnd())
607                     return nullptr;
608                 selector->setSelectorList(WTFMove(selectorList));
609             }
610             selector->setNth(ab.first, ab.second);
611             return selector;
612         }
613         case CSSSelector::PseudoClassLang: {
614             // FIXME: CSS Selectors Level 4 allows :lang(*-foo)
615             auto argumentList = std::make_unique<Vector<AtomicString>>();
616             if (!consumeLangArgumentList(argumentList, block))
617                 return nullptr;
618             selector->setLangArgumentList(WTFMove(argumentList));
619             return selector;
620         }
621         case CSSSelector::PseudoClassMatches: {
622             std::unique_ptr<CSSSelectorList> selectorList = std::unique_ptr<CSSSelectorList>(new CSSSelectorList());
623             *selectorList = consumeComplexSelectorList(block);
624             if (!selectorList->componentCount() || !block.atEnd())
625                 return nullptr;
626             selector->setSelectorList(WTFMove(selectorList));
627             return selector;
628         }
629         case CSSSelector::PseudoClassAny:
630         case CSSSelector::PseudoClassHost: {
631             std::unique_ptr<CSSSelectorList> selectorList = std::unique_ptr<CSSSelectorList>(new CSSSelectorList());
632             *selectorList = consumeCompoundSelectorList(block);
633             if (!selectorList->componentCount() || !block.atEnd())
634                 return nullptr;
635             selector->setSelectorList(WTFMove(selectorList));
636             return selector;
637         }
638 #if ENABLE_CSS_SELECTORS_LEVEL4
639         case CSSSelector::PseudoClassDir:
640         case CSSSelector::PseudoClassRole: {
641             const CSSParserToken& ident = block.consumeIncludingWhitespace();
642             if (ident.type() != IdentToken || !block.atEnd())
643                 return nullptr;
644             selector->setArgument(ident.value().toAtomicString());
645             return selector;
646         }
647 #endif
648         default:
649             break;
650         }
651
652     }
653     
654     if (selector->match() == CSSSelector::PseudoElement) {
655         switch (selector->pseudoElementType()) {
656 #if ENABLE(VIDEO_TRACK)
657         case CSSSelector::PseudoElementCue: {
658             DisallowPseudoElementsScope scope(this);
659             std::unique_ptr<CSSSelectorList> selectorList = std::unique_ptr<CSSSelectorList>(new CSSSelectorList());
660             *selectorList = consumeCompoundSelectorList(block);
661             if (!selectorList->isValid() || !block.atEnd())
662                 return nullptr;
663             selector->setSelectorList(WTFMove(selectorList));
664             return selector;
665         }
666 #endif
667         case CSSSelector::PseudoElementSlotted: {
668             DisallowPseudoElementsScope scope(this);
669
670             std::unique_ptr<CSSParserSelector> innerSelector = consumeCompoundSelector(block);
671             block.consumeWhitespace();
672             if (!innerSelector || !block.atEnd())
673                 return nullptr;
674             Vector<std::unique_ptr<CSSParserSelector>> selectorVector;
675             selectorVector.append(WTFMove(innerSelector));
676             selector->adoptSelectorVector(selectorVector);
677             return selector;
678         }
679         default:
680             break;
681         }
682     }
683
684     return nullptr;
685 }
686
687 CSSSelector::RelationType CSSSelectorParser::consumeCombinator(CSSParserTokenRange& range)
688 {
689     auto fallbackResult = CSSSelector::Subselector;
690     while (range.peek().type() == WhitespaceToken) {
691         range.consume();
692         fallbackResult = CSSSelector::DescendantSpace;
693     }
694
695     if (range.peek().type() != DelimiterToken)
696         return fallbackResult;
697
698     UChar delimiter = range.peek().delimiter();
699
700     if (delimiter == '+' || delimiter == '~' || delimiter == '>') {
701         if (delimiter == '+') {
702             range.consumeIncludingWhitespace();
703             return CSSSelector::DirectAdjacent;
704         }
705         
706         if (delimiter == '~') {
707             range.consumeIncludingWhitespace();
708             return CSSSelector::IndirectAdjacent;
709         }
710         
711 #if ENABLE_CSS_SELECTORS_LEVEL4
712         range.consume();
713         if (range.peek().type() == DelimiterToken && range.peek().delimiter() == '>') {
714             range.consumeIncludingWhitespace();
715             return CSSSelector::DescendantDoubleChild;
716         }
717         range.consumeWhitespace();
718 #else
719         range.consumeIncludingWhitespace();
720 #endif
721         return CSSSelector::Child;
722     }
723
724     return fallbackResult;
725 }
726
727 CSSSelector::Match CSSSelectorParser::consumeAttributeMatch(CSSParserTokenRange& range)
728 {
729     const CSSParserToken& token = range.consumeIncludingWhitespace();
730     switch (token.type()) {
731     case IncludeMatchToken:
732         return CSSSelector::List;
733     case DashMatchToken:
734         return CSSSelector::Hyphen;
735     case PrefixMatchToken:
736         return CSSSelector::Begin;
737     case SuffixMatchToken:
738         return CSSSelector::End;
739     case SubstringMatchToken:
740         return CSSSelector::Contain;
741     case DelimiterToken:
742         if (token.delimiter() == '=')
743             return CSSSelector::Exact;
744         FALLTHROUGH;
745     default:
746         m_failedParsing = true;
747         return CSSSelector::Exact;
748     }
749 }
750
751 CSSSelector::AttributeMatchType CSSSelectorParser::consumeAttributeFlags(CSSParserTokenRange& range)
752 {
753     if (range.peek().type() != IdentToken)
754         return CSSSelector::CaseSensitive;
755     const CSSParserToken& flag = range.consumeIncludingWhitespace();
756     if (equalIgnoringASCIICase(flag.value(), "i"))
757         return CSSSelector::CaseInsensitive;
758     m_failedParsing = true;
759     return CSSSelector::CaseSensitive;
760 }
761
762 bool CSSSelectorParser::consumeANPlusB(CSSParserTokenRange& range, std::pair<int, int>& result)
763 {
764     const CSSParserToken& token = range.consume();
765     if (token.type() == NumberToken && token.numericValueType() == IntegerValueType) {
766         result = std::make_pair(0, static_cast<int>(token.numericValue()));
767         return true;
768     }
769     if (token.type() == IdentToken) {
770         if (equalIgnoringASCIICase(token.value(), "odd")) {
771             result = std::make_pair(2, 1);
772             return true;
773         }
774         if (equalIgnoringASCIICase(token.value(), "even")) {
775             result = std::make_pair(2, 0);
776             return true;
777         }
778     }
779
780     // The 'n' will end up as part of an ident or dimension. For a valid <an+b>,
781     // this will store a string of the form 'n', 'n-', or 'n-123'.
782     String nString;
783
784     if (token.type() == DelimiterToken && token.delimiter() == '+' && range.peek().type() == IdentToken) {
785         result.first = 1;
786         nString = range.consume().value().toString();
787     } else if (token.type() == DimensionToken && token.numericValueType() == IntegerValueType) {
788         result.first = token.numericValue();
789         nString = token.value().toString();
790     } else if (token.type() == IdentToken) {
791         if (token.value()[0] == '-') {
792             result.first = -1;
793             nString = token.value().toString().substring(1);
794         } else {
795             result.first = 1;
796             nString = token.value().toString();
797         }
798     }
799
800     range.consumeWhitespace();
801
802     if (nString.isEmpty() || !isASCIIAlphaCaselessEqual(nString[0], 'n'))
803         return false;
804     if (nString.length() > 1 && nString[1] != '-')
805         return false;
806
807     if (nString.length() > 2) {
808         bool valid;
809         result.second = nString.substring(1).toIntStrict(&valid);
810         return valid;
811     }
812
813     NumericSign sign = nString.length() == 1 ? NoSign : MinusSign;
814     if (sign == NoSign && range.peek().type() == DelimiterToken) {
815         char delimiterSign = range.consumeIncludingWhitespace().delimiter();
816         if (delimiterSign == '+')
817             sign = PlusSign;
818         else if (delimiterSign == '-')
819             sign = MinusSign;
820         else
821             return false;
822     }
823
824     if (sign == NoSign && range.peek().type() != NumberToken) {
825         result.second = 0;
826         return true;
827     }
828
829     const CSSParserToken& b = range.consume();
830     if (b.type() != NumberToken || b.numericValueType() != IntegerValueType)
831         return false;
832     if ((b.numericSign() == NoSign) == (sign == NoSign))
833         return false;
834     result.second = b.numericValue();
835     if (sign == MinusSign)
836         result.second = -result.second;
837     return true;
838 }
839
840 const AtomicString& CSSSelectorParser::defaultNamespace() const
841 {
842     if (!m_styleSheet)
843         return starAtom;
844     return m_styleSheet->defaultNamespace();
845 }
846
847 const AtomicString& CSSSelectorParser::determineNamespace(const AtomicString& prefix)
848 {
849     if (prefix.isNull())
850         return defaultNamespace();
851     if (prefix.isEmpty())
852         return emptyAtom; // No namespace. If an element/attribute has a namespace, we won't match it.
853     if (prefix == starAtom)
854         return starAtom; // We'll match any namespace.
855     if (!m_styleSheet)
856         return nullAtom; // Cannot resolve prefix to namespace without a stylesheet, syntax error.
857     return m_styleSheet->namespaceURIFromPrefix(prefix);
858 }
859
860 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector)
861 {
862     bool isShadowDOM = compoundSelector->needsImplicitShadowCombinatorForMatching();
863     
864     if (elementName.isNull() && defaultNamespace() == starAtom && !isShadowDOM)
865         return;
866
867     AtomicString determinedElementName = elementName.isNull() ? starAtom : elementName;
868     AtomicString namespaceURI = determineNamespace(namespacePrefix);
869     if (namespaceURI.isNull()) {
870         m_failedParsing = true;
871         return;
872     }
873     AtomicString determinedPrefix = namespacePrefix;
874     if (namespaceURI == defaultNamespace())
875         determinedPrefix = nullAtom;
876     QualifiedName tag = QualifiedName(determinedPrefix, determinedElementName, namespaceURI);
877
878     // *:host never matches, so we can't discard the *,
879     // otherwise we can't tell the difference between *:host and just :host.
880     //
881     // Also, selectors where we use a ShadowPseudo combinator between the
882     // element and the pseudo element for matching (custom pseudo elements,
883     // ::cue), we need a universal selector to set the combinator
884     // (relation) on in the cases where there are no simple selectors preceding
885     // the pseudo element.
886     bool explicitForHost = compoundSelector->isHostPseudoSelector() && !elementName.isNull();
887     if (tag != anyQName() || explicitForHost || isShadowDOM)
888         compoundSelector->prependTagSelector(tag, determinedPrefix == nullAtom && determinedElementName == starAtom && !explicitForHost);
889 }
890
891 std::unique_ptr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(std::unique_ptr<CSSParserSelector> compoundSelector, std::unique_ptr<CSSParserSelector> simpleSelector)
892 {
893     compoundSelector->appendTagHistory(CSSSelector::Subselector, WTFMove(simpleSelector));
894     return compoundSelector;
895 }
896
897 std::unique_ptr<CSSParserSelector> CSSSelectorParser::splitCompoundAtImplicitShadowCrossingCombinator(std::unique_ptr<CSSParserSelector> compoundSelector)
898 {
899     // The tagHistory is a linked list that stores combinator separated compound selectors
900     // from right-to-left. Yet, within a single compound selector, stores the simple selectors
901     // from left-to-right.
902     //
903     // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each element in the
904     // list stored with an associated relation (combinator or Subselector).
905     //
906     // ::cue, ::shadow, and custom pseudo elements have an implicit ShadowPseudo combinator
907     // to their left, which really makes for a new compound selector, yet it's consumed by
908     // the selector parser as a single compound selector.
909     //
910     // Example: input#x::-webkit-clear-button -> [ ::-webkit-clear-button, input, #x ]
911     //
912     // Likewise, ::slotted() pseudo element has an implicit ShadowSlot combinator to its left
913     // for finding matching slot element in other TreeScope.
914     //
915     // Example: slot[name=foo]::slotted(div) -> [ ::slotted(div), slot, [name=foo] ]
916     CSSParserSelector* splitAfter = compoundSelector.get();
917
918     while (splitAfter->tagHistory() && !splitAfter->tagHistory()->needsImplicitShadowCombinatorForMatching())
919         splitAfter = splitAfter->tagHistory();
920
921     if (!splitAfter || !splitAfter->tagHistory())
922         return compoundSelector;
923
924     std::unique_ptr<CSSParserSelector> secondCompound = splitAfter->releaseTagHistory();
925     secondCompound->appendTagHistory(CSSSelector::ShadowDescendant, WTFMove(compoundSelector));
926     return secondCompound;
927 }
928
929 } // namespace WebCore