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