fcf2352a80629048f16b6205935d8f7ef1226d48
[WebKit-https.git] / Source / WebCore / css / parser / CSSParserImpl.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 "CSSParserImpl.h"
32
33 #include "CSSAtRuleID.h"
34 #include "CSSCustomPropertyValue.h"
35 #include "CSSDeferredParser.h"
36 #include "CSSKeyframeRule.h"
37 #include "CSSKeyframesRule.h"
38 #include "CSSParserObserver.h"
39 #include "CSSParserObserverWrapper.h"
40 #include "CSSParserSelector.h"
41 #include "CSSPropertyParser.h"
42 #include "CSSSelectorParser.h"
43 #include "CSSStyleSheet.h"
44 #include "CSSSupportsParser.h"
45 #include "CSSTokenizer.h"
46 #include "CSSVariableParser.h"
47 #include "Document.h"
48 #include "Element.h"
49 #include "MediaQueryParser.h"
50 #include "StyleProperties.h"
51 #include "StyleRuleImport.h"
52 #include "StyleSheetContents.h"
53
54 #include <bitset>
55 #include <memory>
56
57 namespace WebCore {
58
59 CSSParserImpl::CSSParserImpl(const CSSParserContext& context, StyleSheetContents* styleSheet)
60     : m_context(context)
61     , m_styleSheet(styleSheet)
62 {
63     
64 }
65
66 CSSParserImpl::CSSParserImpl(CSSDeferredParser& deferredParser)
67     : m_context(deferredParser.context())
68     , m_styleSheet(deferredParser.styleSheet())
69     , m_deferredParser(&deferredParser)
70 {
71 }
72
73 CSSParserImpl::CSSParserImpl(const CSSParserContext& context, const String& string, StyleSheetContents* styleSheet, CSSParserObserverWrapper* wrapper, CSSParser::RuleParsing ruleParsing)
74     : m_context(context)
75     , m_styleSheet(styleSheet)
76     , m_observerWrapper(wrapper)
77 {
78     m_tokenizer = wrapper ? std::make_unique<CSSTokenizer>(string, *wrapper) : std::make_unique<CSSTokenizer>(string);
79     if (context.deferredCSSParserEnabled && !wrapper && styleSheet && ruleParsing == CSSParser::RuleParsing::Deferred)
80         m_deferredParser = CSSDeferredParser::create(context, string, *styleSheet);
81 }
82
83 CSSParser::ParseResult CSSParserImpl::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, const CSSParserContext& context)
84 {
85     CSSParserImpl parser(context, string);
86     StyleRule::Type ruleType = StyleRule::Style;
87 #if ENABLE(CSS_DEVICE_ADAPTATION)
88     if (declaration->cssParserMode() == CSSViewportRuleMode)
89         ruleType = StyleRule::Viewport;
90 #endif
91     parser.consumeDeclarationValue(parser.tokenizer()->tokenRange(), propertyID, important, ruleType);
92     if (parser.m_parsedProperties.isEmpty())
93         return CSSParser::ParseResult::Error;
94     return declaration->addParsedProperties(parser.m_parsedProperties) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
95 }
96
97 CSSParser::ParseResult CSSParserImpl::parseCustomPropertyValue(MutableStyleProperties* declaration, const AtomicString& propertyName, const String& string, bool important, const CSSParserContext& context)
98 {
99     CSSParserImpl parser(context, string);
100     parser.consumeCustomPropertyValue(parser.tokenizer()->tokenRange(), propertyName, important);
101     if (parser.m_parsedProperties.isEmpty())
102         return CSSParser::ParseResult::Error;
103     return declaration->addParsedProperties(parser.m_parsedProperties) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
104 }
105
106 static inline void filterProperties(bool important, const ParsedPropertyVector& input, ParsedPropertyVector& output, size_t& unusedEntries, std::bitset<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenCustomProperties)
107 {
108     // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
109     for (size_t i = input.size(); i--; ) {
110         const CSSProperty& property = input[i];
111         if (property.isImportant() != important)
112             continue;
113         const unsigned propertyIDIndex = property.id() - firstCSSProperty;
114         
115         if (property.id() == CSSPropertyCustom) {
116             auto& name = downcast<CSSCustomPropertyValue>(*property.value()).name();
117             if (!seenCustomProperties.add(name).isNewEntry)
118                 continue;
119             output[--unusedEntries] = property;
120             continue;
121         }
122         
123         // FIXME-NEWPARSER: We won't support @apply yet.
124         /*else if (property.id() == CSSPropertyApplyAtRule) {
125          // FIXME: Do we need to do anything here?
126          } */
127         
128         if (seenProperties.test(propertyIDIndex))
129             continue;
130         seenProperties.set(propertyIDIndex);
131
132         output[--unusedEntries] = property;
133     }
134 }
135
136 Ref<DeferredStyleProperties> CSSParserImpl::createDeferredStyleProperties(const CSSParserTokenRange& propertyRange)
137 {
138     ASSERT(m_deferredParser);
139     return DeferredStyleProperties::create(propertyRange, *m_deferredParser);
140 }
141
142 static Ref<ImmutableStyleProperties> createStyleProperties(ParsedPropertyVector& parsedProperties, CSSParserMode mode)
143 {
144     std::bitset<numCSSProperties> seenProperties;
145     size_t unusedEntries = parsedProperties.size();
146     ParsedPropertyVector results(unusedEntries);
147     HashSet<AtomicString> seenCustomProperties;
148
149     filterProperties(true, parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
150     filterProperties(false, parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
151
152     Ref<ImmutableStyleProperties> result = ImmutableStyleProperties::create(results.data() + unusedEntries, results.size() - unusedEntries, mode);
153     parsedProperties.clear();
154     return result;
155 }
156
157 Ref<ImmutableStyleProperties> CSSParserImpl::parseInlineStyleDeclaration(const String& string, Element* element)
158 {
159     CSSParserContext context(element->document());
160     context.mode = strictToCSSParserMode(element->isHTMLElement() && !element->document().inQuirksMode());
161
162     CSSParserImpl parser(context, string);
163     parser.consumeDeclarationList(parser.tokenizer()->tokenRange(), StyleRule::Style);
164     return createStyleProperties(parser.m_parsedProperties, context.mode);
165 }
166
167 Ref<ImmutableStyleProperties> CSSParserImpl::parseDeferredDeclaration(CSSParserTokenRange tokenRange, const CSSParserContext& context, StyleSheetContents* styleSheet)
168 {
169     if (!styleSheet) {
170         ParsedPropertyVector properties;
171         return createStyleProperties(properties, context.mode);
172     }
173     CSSParserImpl parser(context, styleSheet);
174     parser.consumeDeclarationList(tokenRange, StyleRule::Style);
175     return createStyleProperties(parser.m_parsedProperties, context.mode);
176 }
177     
178 void CSSParserImpl::parseDeferredRuleList(CSSParserTokenRange tokenRange, CSSDeferredParser& deferredParser, Vector<RefPtr<StyleRuleBase>>& childRules)
179 {
180     if (!deferredParser.styleSheet())
181         return;
182     CSSParserImpl parser(deferredParser);
183     parser.consumeRuleList(tokenRange, RegularRuleList, [&childRules](const RefPtr<StyleRuleBase>& rule) {
184         childRules.append(rule);
185     });
186 }
187
188 void CSSParserImpl::parseDeferredKeyframeList(CSSParserTokenRange tokenRange, CSSDeferredParser& deferredParser, StyleRuleKeyframes& keyframeRule)
189 {
190     if (!deferredParser.styleSheet())
191         return;
192     CSSParserImpl parser(deferredParser);
193     parser.consumeRuleList(tokenRange, KeyframesRuleList, [&keyframeRule](const RefPtr<StyleRuleBase>& keyframe) {
194         keyframeRule.parserAppendKeyframe(downcast<const StyleKeyframe>(keyframe.get()));
195     });
196 }
197
198 bool CSSParserImpl::parseDeclarationList(MutableStyleProperties* declaration, const String& string, const CSSParserContext& context)
199 {
200     CSSParserImpl parser(context, string);
201     StyleRule::Type ruleType = StyleRule::Style;
202 #if ENABLE(CSS_DEVICE_ADAPTATION)
203     if (declaration->cssParserMode() == CSSViewportRuleMode)
204         ruleType = StyleRule::Viewport;
205 #endif
206     parser.consumeDeclarationList(parser.tokenizer()->tokenRange(), ruleType);
207     if (parser.m_parsedProperties.isEmpty())
208         return false;
209
210     std::bitset<numCSSProperties> seenProperties;
211     size_t unusedEntries = parser.m_parsedProperties.size();
212     ParsedPropertyVector results(unusedEntries);
213     HashSet<AtomicString> seenCustomProperties;
214     filterProperties(true, parser.m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
215     filterProperties(false, parser.m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
216     if (unusedEntries)
217         results.remove(0, unusedEntries);
218     return declaration->addParsedProperties(results);
219 }
220
221 RefPtr<StyleRuleBase> CSSParserImpl::parseRule(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, AllowedRulesType allowedRules)
222 {
223     CSSParserImpl parser(context, string, styleSheet);
224     CSSParserTokenRange range = parser.tokenizer()->tokenRange();
225     range.consumeWhitespace();
226     if (range.atEnd())
227         return nullptr; // Parse error, empty rule
228     RefPtr<StyleRuleBase> rule;
229     if (range.peek().type() == AtKeywordToken)
230         rule = parser.consumeAtRule(range, allowedRules);
231     else
232         rule = parser.consumeQualifiedRule(range, allowedRules);
233     if (!rule)
234         return nullptr; // Parse error, failed to consume rule
235     range.consumeWhitespace();
236     if (!rule || !range.atEnd())
237         return nullptr; // Parse error, trailing garbage
238     return rule;
239 }
240
241 void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, CSSParser::RuleParsing ruleParsing)
242 {
243     CSSParserImpl parser(context, string, styleSheet, nullptr, ruleParsing);
244     bool firstRuleValid = parser.consumeRuleList(parser.tokenizer()->tokenRange(), TopLevelRuleList, [&styleSheet](RefPtr<StyleRuleBase> rule) {
245         if (rule->isCharsetRule())
246             return;
247         styleSheet->parserAppendRule(rule.releaseNonNull());
248     });
249     styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid);
250     parser.adoptTokenizerEscapedStrings();
251 }
252
253 void CSSParserImpl::adoptTokenizerEscapedStrings()
254 {
255     if (!m_deferredParser || !m_tokenizer)
256         return;
257     m_deferredParser->adoptTokenizerEscapedStrings(m_tokenizer->escapedStringsForAdoption());
258 }
259
260 CSSSelectorList CSSParserImpl::parsePageSelector(CSSParserTokenRange range, StyleSheetContents* styleSheet)
261 {
262     // We only support a small subset of the css-page spec.
263     range.consumeWhitespace();
264     AtomicString typeSelector;
265     if (range.peek().type() == IdentToken)
266         typeSelector = range.consume().value().toAtomicString();
267
268     AtomicString pseudo;
269     if (range.peek().type() == ColonToken) {
270         range.consume();
271         if (range.peek().type() != IdentToken)
272             return CSSSelectorList();
273         pseudo = range.consume().value().toAtomicString();
274     }
275
276     range.consumeWhitespace();
277     if (!range.atEnd())
278         return CSSSelectorList(); // Parse error; extra tokens in @page selector
279
280     std::unique_ptr<CSSParserSelector> selector;
281     if (!typeSelector.isNull() && pseudo.isNull())
282         selector = std::unique_ptr<CSSParserSelector>(new CSSParserSelector(QualifiedName(nullAtom, typeSelector, styleSheet->defaultNamespace())));
283     else {
284         selector = std::unique_ptr<CSSParserSelector>(new CSSParserSelector);
285         if (!pseudo.isNull()) {
286             selector = std::unique_ptr<CSSParserSelector>(CSSParserSelector::parsePagePseudoSelector(pseudo));
287             if (!selector || selector->match() != CSSSelector::PagePseudoClass)
288                 return CSSSelectorList();
289         }
290         if (!typeSelector.isNull())
291             selector->prependTagSelector(QualifiedName(nullAtom, typeSelector, styleSheet->defaultNamespace()));
292     }
293
294     selector->setForPage();
295     Vector<std::unique_ptr<CSSParserSelector>> selectorVector;
296     selectorVector.append(WTFMove(selector));
297     CSSSelectorList selectorList;
298     selectorList.adoptSelectorVector(selectorVector);
299     return selectorList;
300 }
301
302 std::unique_ptr<Vector<double>> CSSParserImpl::parseKeyframeKeyList(const String& keyList)
303 {
304     return consumeKeyframeKeyList(CSSTokenizer(keyList).tokenRange());
305 }
306
307 bool CSSParserImpl::supportsDeclaration(CSSParserTokenRange& range)
308 {
309     ASSERT(m_parsedProperties.isEmpty());
310     consumeDeclaration(range, StyleRule::Style);
311     bool result = !m_parsedProperties.isEmpty();
312     m_parsedProperties.clear();
313     return result;
314 }
315
316 void CSSParserImpl::parseDeclarationListForInspector(const String& declaration, const CSSParserContext& context, CSSParserObserver& observer)
317 {
318     CSSParserObserverWrapper wrapper(observer);
319     CSSParserImpl parser(context, declaration, nullptr, &wrapper);
320     observer.startRuleHeader(StyleRule::Style, 0);
321     observer.endRuleHeader(1);
322     parser.consumeDeclarationList(parser.tokenizer()->tokenRange(), StyleRule::Style);
323 }
324
325 void CSSParserImpl::parseStyleSheetForInspector(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, CSSParserObserver& observer)
326 {
327     CSSParserObserverWrapper wrapper(observer);
328     CSSParserImpl parser(context, string, styleSheet, &wrapper);
329     bool firstRuleValid = parser.consumeRuleList(parser.tokenizer()->tokenRange(), TopLevelRuleList, [&styleSheet](RefPtr<StyleRuleBase> rule) {
330         if (rule->isCharsetRule())
331             return;
332         styleSheet->parserAppendRule(rule.releaseNonNull());
333     });
334     styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid);
335 }
336
337 static CSSParserImpl::AllowedRulesType computeNewAllowedRules(CSSParserImpl::AllowedRulesType allowedRules, StyleRuleBase* rule)
338 {
339     if (!rule || allowedRules == CSSParserImpl::KeyframeRules || allowedRules == CSSParserImpl::NoRules)
340         return allowedRules;
341     ASSERT(allowedRules <= CSSParserImpl::RegularRules);
342     if (rule->isCharsetRule() || rule->isImportRule())
343         return CSSParserImpl::AllowImportRules;
344     if (rule->isNamespaceRule())
345         return CSSParserImpl::AllowNamespaceRules;
346     return CSSParserImpl::RegularRules;
347 }
348
349 template<typename T>
350 bool CSSParserImpl::consumeRuleList(CSSParserTokenRange range, RuleListType ruleListType, const T callback)
351 {
352     AllowedRulesType allowedRules = RegularRules;
353     switch (ruleListType) {
354     case TopLevelRuleList:
355         allowedRules = AllowCharsetRules;
356         break;
357     case RegularRuleList:
358         allowedRules = RegularRules;
359         break;
360     case KeyframesRuleList:
361         allowedRules = KeyframeRules;
362         break;
363     default:
364         ASSERT_NOT_REACHED();
365     }
366
367     bool seenRule = false;
368     bool firstRuleValid = false;
369     while (!range.atEnd()) {
370         RefPtr<StyleRuleBase> rule;
371         switch (range.peek().type()) {
372         case WhitespaceToken:
373             range.consumeWhitespace();
374             continue;
375         case AtKeywordToken:
376             rule = consumeAtRule(range, allowedRules);
377             break;
378         case CDOToken:
379         case CDCToken:
380             if (ruleListType == TopLevelRuleList) {
381                 range.consume();
382                 continue;
383             }
384             FALLTHROUGH;
385         default:
386             rule = consumeQualifiedRule(range, allowedRules);
387             break;
388         }
389         if (!seenRule) {
390             seenRule = true;
391             firstRuleValid = rule;
392         }
393         if (rule) {
394             allowedRules = computeNewAllowedRules(allowedRules, rule.get());
395             callback(rule);
396         }
397     }
398
399     return firstRuleValid;
400 }
401
402 RefPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserTokenRange& range, AllowedRulesType allowedRules)
403 {
404     ASSERT(range.peek().type() == AtKeywordToken);
405     const StringView name = range.consumeIncludingWhitespace().value();
406     const CSSParserToken* preludeStart = &range.peek();
407     while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek().type() != SemicolonToken)
408         range.consumeComponentValue();
409
410     CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek());
411     CSSAtRuleID id = cssAtRuleID(name);
412     
413     if (range.atEnd() || range.peek().type() == SemicolonToken) {
414         range.consume();
415         if (allowedRules == AllowCharsetRules && id == CSSAtRuleCharset)
416             return consumeCharsetRule(prelude);
417         if (allowedRules <= AllowImportRules && id == CSSAtRuleImport)
418             return consumeImportRule(prelude);
419         if (allowedRules <= AllowNamespaceRules && id == CSSAtRuleNamespace)
420             return consumeNamespaceRule(prelude);
421         // FIXME-NEWPARSER: Support "apply"
422         /*if (allowedRules == ApplyRules && id == CSSAtRuleApply) {
423             consumeApplyRule(prelude);
424             return nullptr; // consumeApplyRule just updates m_parsedProperties
425         }*/
426         return nullptr; // Parse error, unrecognised at-rule without block
427     }
428
429     CSSParserTokenRange block = range.consumeBlock();
430     if (allowedRules == KeyframeRules)
431         return nullptr; // Parse error, no at-rules supported inside @keyframes
432     if (allowedRules == NoRules || allowedRules == ApplyRules)
433         return nullptr; // Parse error, no at-rules with blocks supported inside declaration lists
434
435     ASSERT(allowedRules <= RegularRules);
436
437     switch (id) {
438     case CSSAtRuleMedia:
439         return consumeMediaRule(prelude, block);
440     case CSSAtRuleSupports:
441         return consumeSupportsRule(prelude, block);
442 #if ENABLE(CSS_DEVICE_ADAPTATION)
443     case CSSAtRuleViewport:
444         return consumeViewportRule(prelude, block);
445 #endif
446     case CSSAtRuleFontFace:
447         return consumeFontFaceRule(prelude, block);
448     case CSSAtRuleWebkitKeyframes:
449         return consumeKeyframesRule(true, prelude, block);
450     case CSSAtRuleKeyframes:
451         return consumeKeyframesRule(false, prelude, block);
452     case CSSAtRulePage:
453         return consumePageRule(prelude, block);
454 #if ENABLE(CSS_REGIONS)
455     case CSSAtRuleWebkitRegion:
456         return consumeRegionRule(prelude, block);
457 #endif
458     default:
459         return nullptr; // Parse error, unrecognised at-rule with block
460     }
461 }
462
463 RefPtr<StyleRuleBase> CSSParserImpl::consumeQualifiedRule(CSSParserTokenRange& range, AllowedRulesType allowedRules)
464 {
465     const CSSParserToken* preludeStart = &range.peek();
466     while (!range.atEnd() && range.peek().type() != LeftBraceToken)
467         range.consumeComponentValue();
468
469     if (range.atEnd())
470         return nullptr; // Parse error, EOF instead of qualified rule block
471
472     CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek());
473     CSSParserTokenRange block = range.consumeBlockCheckingForEditability(m_styleSheet.get());
474
475     if (allowedRules <= RegularRules)
476         return consumeStyleRule(prelude, block);
477     if (allowedRules == KeyframeRules)
478         return consumeKeyframeStyleRule(prelude, block);
479
480     ASSERT_NOT_REACHED();
481     return nullptr;
482 }
483
484 // This may still consume tokens if it fails
485 static AtomicString consumeStringOrURI(CSSParserTokenRange& range)
486 {
487     const CSSParserToken& token = range.peek();
488
489     if (token.type() == StringToken || token.type() == UrlToken)
490         return range.consumeIncludingWhitespace().value().toAtomicString();
491
492     if (token.type() != FunctionToken || !equalIgnoringASCIICase(token.value(), "url"))
493         return AtomicString();
494
495     CSSParserTokenRange contents = range.consumeBlock();
496     const CSSParserToken& uri = contents.consumeIncludingWhitespace();
497     if (uri.type() == BadStringToken || !contents.atEnd())
498         return AtomicString();
499     return uri.value().toAtomicString();
500 }
501
502 RefPtr<StyleRuleCharset> CSSParserImpl::consumeCharsetRule(CSSParserTokenRange prelude)
503 {
504     const CSSParserToken& string = prelude.consumeIncludingWhitespace();
505     if (string.type() != StringToken || !prelude.atEnd())
506         return nullptr; // Parse error, expected a single string
507     return StyleRuleCharset::create();
508 }
509
510 RefPtr<StyleRuleImport> CSSParserImpl::consumeImportRule(CSSParserTokenRange prelude)
511 {
512     AtomicString uri(consumeStringOrURI(prelude));
513     if (uri.isNull())
514         return nullptr; // Parse error, expected string or URI
515
516     if (m_observerWrapper) {
517         unsigned endOffset = m_observerWrapper->endOffset(prelude);
518         m_observerWrapper->observer().startRuleHeader(StyleRule::Import, m_observerWrapper->startOffset(prelude));
519         m_observerWrapper->observer().endRuleHeader(endOffset);
520         m_observerWrapper->observer().startRuleBody(endOffset);
521         m_observerWrapper->observer().endRuleBody(endOffset);
522     }
523
524     return StyleRuleImport::create(uri, MediaQueryParser::parseMediaQuerySet(prelude).releaseNonNull());
525 }
526
527 RefPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(CSSParserTokenRange prelude)
528 {
529     AtomicString namespacePrefix;
530     if (prelude.peek().type() == IdentToken)
531         namespacePrefix = prelude.consumeIncludingWhitespace().value().toAtomicString();
532
533     AtomicString uri(consumeStringOrURI(prelude));
534     if (uri.isNull() || !prelude.atEnd())
535         return nullptr; // Parse error, expected string or URI
536
537     return StyleRuleNamespace::create(namespacePrefix, uri);
538 }
539
540 RefPtr<StyleRuleMedia> CSSParserImpl::consumeMediaRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
541 {
542     if (m_deferredParser)
543         return StyleRuleMedia::create(MediaQueryParser::parseMediaQuerySet(prelude).releaseNonNull(),  std::make_unique<DeferredStyleGroupRuleList>(block, *m_deferredParser));
544
545     Vector<RefPtr<StyleRuleBase>> rules;
546
547     if (m_observerWrapper) {
548         m_observerWrapper->observer().startRuleHeader(StyleRule::Media, m_observerWrapper->startOffset(prelude));
549         m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
550         m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
551     }
552
553     consumeRuleList(block, RegularRuleList, [&rules](RefPtr<StyleRuleBase> rule) {
554         rules.append(rule);
555     });
556
557     if (m_observerWrapper)
558         m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
559
560     return StyleRuleMedia::create(MediaQueryParser::parseMediaQuerySet(prelude).releaseNonNull(), rules);
561 }
562
563 RefPtr<StyleRuleSupports> CSSParserImpl::consumeSupportsRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
564 {
565     CSSSupportsParser::SupportsResult supported = CSSSupportsParser::supportsCondition(prelude, *this);
566     if (supported == CSSSupportsParser::Invalid)
567         return nullptr; // Parse error, invalid @supports condition
568
569     if (m_deferredParser)
570         return StyleRuleSupports::create(prelude.serialize().stripWhiteSpace(), supported, std::make_unique<DeferredStyleGroupRuleList>(block, *m_deferredParser));
571
572     if (m_observerWrapper) {
573         m_observerWrapper->observer().startRuleHeader(StyleRule::Supports, m_observerWrapper->startOffset(prelude));
574         m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
575         m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
576     }
577
578     Vector<RefPtr<StyleRuleBase>> rules;
579     consumeRuleList(block, RegularRuleList, [&rules](RefPtr<StyleRuleBase> rule) {
580         rules.append(rule);
581     });
582
583     if (m_observerWrapper)
584         m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
585
586     return StyleRuleSupports::create(prelude.serialize().stripWhiteSpace(), supported, rules);
587 }
588
589 #if ENABLE(CSS_DEVICE_ADAPTATION)
590 RefPtr<StyleRuleViewport> CSSParserImpl::consumeViewportRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
591 {
592     if (!prelude.atEnd())
593         return nullptr; // Parser error; @viewport prelude should be empty
594
595     if (m_observerWrapper) {
596         unsigned endOffset = m_observerWrapper->endOffset(prelude);
597         m_observerWrapper->observer().startRuleHeader(StyleRule::Viewport, m_observerWrapper->startOffset(prelude));
598         m_observerWrapper->observer().endRuleHeader(endOffset);
599         m_observerWrapper->observer().startRuleBody(endOffset);
600         m_observerWrapper->observer().endRuleBody(endOffset);
601     }
602
603     consumeDeclarationList(block, StyleRule::Viewport);
604     return StyleRuleViewport::create(createStyleProperties(m_parsedProperties, CSSViewportRuleMode));
605 }
606 #endif
607
608 RefPtr<StyleRuleFontFace> CSSParserImpl::consumeFontFaceRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
609 {
610     if (!prelude.atEnd())
611         return nullptr; // Parse error; @font-face prelude should be empty
612
613     if (m_observerWrapper) {
614         unsigned endOffset = m_observerWrapper->endOffset(prelude);
615         m_observerWrapper->observer().startRuleHeader(StyleRule::FontFace, m_observerWrapper->startOffset(prelude));
616         m_observerWrapper->observer().endRuleHeader(endOffset);
617         m_observerWrapper->observer().startRuleBody(endOffset);
618         m_observerWrapper->observer().endRuleBody(endOffset);
619     }
620
621     consumeDeclarationList(block, StyleRule::FontFace);
622     return StyleRuleFontFace::create(createStyleProperties(m_parsedProperties, m_context.mode));
623 }
624
625 RefPtr<StyleRuleKeyframes> CSSParserImpl::consumeKeyframesRule(bool webkitPrefixed, CSSParserTokenRange prelude, CSSParserTokenRange block)
626 {
627     CSSParserTokenRange rangeCopy = prelude; // For inspector callbacks
628     const CSSParserToken& nameToken = prelude.consumeIncludingWhitespace();
629     if (!prelude.atEnd())
630         return nullptr; // Parse error; expected single non-whitespace token in @keyframes header
631
632     String name;
633     if (nameToken.type() == IdentToken) {
634         name = nameToken.value().toString();
635     } else if (nameToken.type() == StringToken && webkitPrefixed)
636         name = nameToken.value().toString();
637     else
638         return nullptr; // Parse error; expected ident token in @keyframes header
639
640     if (m_deferredParser)
641         return StyleRuleKeyframes::create(name, std::make_unique<DeferredStyleGroupRuleList>(block, *m_deferredParser));
642
643     if (m_observerWrapper) {
644         m_observerWrapper->observer().startRuleHeader(StyleRule::Keyframes, m_observerWrapper->startOffset(rangeCopy));
645         m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
646         m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
647         m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
648     }
649
650     RefPtr<StyleRuleKeyframes> keyframeRule = StyleRuleKeyframes::create(name);
651     consumeRuleList(block, KeyframesRuleList, [keyframeRule](const RefPtr<StyleRuleBase>& keyframe) {
652         keyframeRule->parserAppendKeyframe(downcast<const StyleKeyframe>(keyframe.get()));
653     });
654
655     // FIXME-NEWPARSER: Find out why this is done. Behavior difference when prefixed?
656     // keyframeRule->setVendorPrefixed(webkitPrefixed);
657     return keyframeRule;
658 }
659
660 RefPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
661 {
662     CSSSelectorList selectorList = parsePageSelector(prelude, m_styleSheet.get());
663     if (!selectorList.isValid())
664         return nullptr; // Parse error, invalid @page selector
665
666     if (m_observerWrapper) {
667         unsigned endOffset = m_observerWrapper->endOffset(prelude);
668         m_observerWrapper->observer().startRuleHeader(StyleRule::Page, m_observerWrapper->startOffset(prelude));
669         m_observerWrapper->observer().endRuleHeader(endOffset);
670     }
671
672     consumeDeclarationList(block, StyleRule::Style);
673     
674     RefPtr<StyleRulePage> page = StyleRulePage::create(createStyleProperties(m_parsedProperties, m_context.mode));
675     page->wrapperAdoptSelectorList(selectorList);
676     return page;
677 }
678
679 #if ENABLE(CSS_REGIONS)
680 RefPtr<StyleRuleRegion> CSSParserImpl::consumeRegionRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
681 {
682     CSSSelectorList selectorList = CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet.get());
683     if (!selectorList.isValid())
684         return nullptr; // Parse error, invalid selector list
685
686     if (m_observerWrapper) {
687         m_observerWrapper->observer().startRuleHeader(StyleRule::Region, m_observerWrapper->startOffset(prelude));
688         m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
689         m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
690     }
691     
692     Vector<RefPtr<StyleRuleBase>> rules;
693     consumeRuleList(block, RegularRuleList, [&rules](RefPtr<StyleRuleBase> rule) {
694         rules.append(rule);
695     });
696     
697     if (m_observerWrapper)
698         m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
699     
700     return StyleRuleRegion::create(selectorList, rules);
701
702 }
703 #endif
704
705 // FIXME-NEWPARSER: Support "apply"
706 /*void CSSParserImpl::consumeApplyRule(CSSParserTokenRange prelude)
707 {
708     const CSSParserToken& ident = prelude.consumeIncludingWhitespace();
709     if (!prelude.atEnd() || !CSSVariableParser::isValidVariableName(ident))
710         return; // Parse error, expected a single custom property name
711     m_parsedProperties.append(CSSProperty(
712         CSSPropertyApplyAtRule,
713         *CSSCustomIdentValue::create(ident.value().toString())));
714 }
715 */
716     
717 RefPtr<StyleKeyframe> CSSParserImpl::consumeKeyframeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
718 {
719     std::unique_ptr<Vector<double>> keyList = consumeKeyframeKeyList(prelude);
720     if (!keyList)
721         return nullptr;
722
723     if (m_observerWrapper) {
724         m_observerWrapper->observer().startRuleHeader(StyleRule::Keyframe, m_observerWrapper->startOffset(prelude));
725         m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
726     }
727
728     consumeDeclarationList(block, StyleRule::Keyframe);
729     return StyleKeyframe::create(WTFMove(keyList), createStyleProperties(m_parsedProperties, m_context.mode));
730 }
731
732 static void observeSelectors(CSSParserObserverWrapper& wrapper, CSSParserTokenRange selectors)
733 {
734     // This is easier than hooking into the CSSSelectorParser
735     selectors.consumeWhitespace();
736     CSSParserTokenRange originalRange = selectors;
737     wrapper.observer().startRuleHeader(StyleRule::Style, wrapper.startOffset(originalRange));
738
739     while (!selectors.atEnd()) {
740         const CSSParserToken* selectorStart = &selectors.peek();
741         while (!selectors.atEnd() && selectors.peek().type() != CommaToken)
742             selectors.consumeComponentValue();
743         CSSParserTokenRange selector = selectors.makeSubRange(selectorStart, &selectors.peek());
744         selectors.consumeIncludingWhitespace();
745
746         wrapper.observer().observeSelector(wrapper.startOffset(selector), wrapper.endOffset(selector));
747     }
748
749     wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange));
750 }
751
752 RefPtr<StyleRule> CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
753 {
754     CSSSelectorList selectorList = CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet.get());
755     if (!selectorList.isValid())
756         return nullptr; // Parse error, invalid selector list
757
758     RefPtr<StyleRule> rule;
759     if (m_observerWrapper)
760         observeSelectors(*m_observerWrapper, prelude);
761     
762     if (m_deferredParser) {
763         // If a rule is empty (i.e., only whitespace), don't bother using
764         // deferred parsing. This allows the empty rule optimization in ElementRuleCollector
765         // to continue to work. Note we don't have to consider CommentTokens, since those
766         // are stripped out.
767         CSSParserTokenRange blockCopy = block;
768         blockCopy.consumeWhitespace();
769         if (!blockCopy.atEnd()) {
770             rule = StyleRule::create(createDeferredStyleProperties(block));
771             rule->wrapperAdoptSelectorList(selectorList);
772             return rule;
773         }
774     }
775
776     consumeDeclarationList(block, StyleRule::Style);
777     rule = StyleRule::create(createStyleProperties(m_parsedProperties, m_context.mode));
778     rule->wrapperAdoptSelectorList(selectorList);
779     return rule;
780 }
781
782 void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRule::Type ruleType)
783 {
784     ASSERT(m_parsedProperties.isEmpty());
785
786     bool useObserver = m_observerWrapper && (ruleType == StyleRule::Style || ruleType == StyleRule::Keyframe);
787     if (useObserver) {
788         m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(range));
789         m_observerWrapper->skipCommentsBefore(range, true);
790     }
791
792     while (!range.atEnd()) {
793         switch (range.peek().type()) {
794         case WhitespaceToken:
795         case SemicolonToken:
796             range.consume();
797             break;
798         case IdentToken: {
799             const CSSParserToken* declarationStart = &range.peek();
800
801             if (useObserver)
802                 m_observerWrapper->yieldCommentsBefore(range);
803
804             while (!range.atEnd() && range.peek().type() != SemicolonToken)
805                 range.consumeComponentValue();
806
807             consumeDeclaration(range.makeSubRange(declarationStart, &range.peek()), ruleType);
808
809             if (useObserver)
810                 m_observerWrapper->skipCommentsBefore(range, false);
811             break;
812         }
813         case AtKeywordToken: {
814             // FIXME-NEWPARSER: Support apply
815             AllowedRulesType allowedRules = /* ruleType == StyleRule::Style && RuntimeEnabledFeatures::cssApplyAtRulesEnabled() ? ApplyRules :*/ NoRules;
816             RefPtr<StyleRuleBase> rule = consumeAtRule(range, allowedRules);
817             ASSERT_UNUSED(rule, !rule);
818             break;
819         }
820         default: // Parse error, unexpected token in declaration list
821             while (!range.atEnd() && range.peek().type() != SemicolonToken)
822                 range.consumeComponentValue();
823             break;
824         }
825     }
826
827     // Yield remaining comments
828     if (useObserver) {
829         m_observerWrapper->yieldCommentsBefore(range);
830         m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(range));
831     }
832 }
833
834 void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRule::Type ruleType)
835 {
836     CSSParserTokenRange rangeCopy = range; // For inspector callbacks
837
838     ASSERT(range.peek().type() == IdentToken);
839     const CSSParserToken& token = range.consumeIncludingWhitespace();
840     CSSPropertyID propertyID = token.parseAsCSSPropertyID();
841     if (range.consume().type() != ColonToken)
842         return; // Parse error
843
844     bool important = false;
845     const CSSParserToken* declarationValueEnd = range.end();
846     const CSSParserToken* last = range.end() - 1;
847     while (last->type() == WhitespaceToken)
848         --last;
849     if (last->type() == IdentToken && equalIgnoringASCIICase(last->value(), "important")) {
850         --last;
851         while (last->type() == WhitespaceToken)
852             --last;
853         if (last->type() == DelimiterToken && last->delimiter() == '!') {
854             important = true;
855             declarationValueEnd = last;
856         }
857     }
858
859     size_t propertiesCount = m_parsedProperties.size();
860     if (propertyID == CSSPropertyInvalid && CSSVariableParser::isValidVariableName(token)) {
861         AtomicString variableName = token.value().toAtomicString();
862         consumeCustomPropertyValue(range.makeSubRange(&range.peek(), declarationValueEnd), variableName, important);
863     }
864
865     if (important && (ruleType == StyleRule::FontFace || ruleType == StyleRule::Keyframe))
866         return;
867
868     if (propertyID != CSSPropertyInvalid)
869         consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), propertyID, important, ruleType);
870
871     if (m_observerWrapper && (ruleType == StyleRule::Style || ruleType == StyleRule::Keyframe)) {
872         m_observerWrapper->observer().observeProperty(
873             m_observerWrapper->startOffset(rangeCopy), m_observerWrapper->endOffset(rangeCopy),
874             important, m_parsedProperties.size() != propertiesCount);
875     }
876 }
877
878 void CSSParserImpl::consumeCustomPropertyValue(CSSParserTokenRange range, const AtomicString& variableName, bool important)
879 {
880     if (RefPtr<CSSCustomPropertyValue> value = CSSVariableParser::parseDeclarationValue(variableName, range))
881         m_parsedProperties.append(CSSProperty(CSSPropertyCustom, WTFMove(value), important));
882 }
883
884 void CSSParserImpl::consumeDeclarationValue(CSSParserTokenRange range, CSSPropertyID propertyID, bool important, StyleRule::Type ruleType)
885 {
886     CSSPropertyParser::parseValue(propertyID, important, range, m_context, m_styleSheet.get(), m_parsedProperties, ruleType);
887 }
888
889 std::unique_ptr<Vector<double>> CSSParserImpl::consumeKeyframeKeyList(CSSParserTokenRange range)
890 {
891     std::unique_ptr<Vector<double>> result = std::unique_ptr<Vector<double>>(new Vector<double>);
892     while (true) {
893         range.consumeWhitespace();
894         const CSSParserToken& token = range.consumeIncludingWhitespace();
895         if (token.type() == PercentageToken && token.numericValue() >= 0 && token.numericValue() <= 100)
896             result->append(token.numericValue() / 100);
897         else if (token.type() == IdentToken && equalIgnoringASCIICase(token.value(), "from"))
898             result->append(0);
899         else if (token.type() == IdentToken && equalIgnoringASCIICase(token.value(), "to"))
900             result->append(1);
901         else
902             return nullptr; // Parser error, invalid value in keyframe selector
903         if (range.atEnd())
904             return result;
905         if (range.consume().type() != CommaToken)
906             return nullptr; // Parser error
907     }
908 }
909
910 } // namespace WebCore