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