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