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