source: webkit/trunk/Source/WebCore/css/parser/CSSParserImpl.cpp

Last change on this file was 294007, checked in by Brent Fulgham, 3 years ago

Remove abandoned CSSDeferredParser implementation and feature flag
https://bugs.webkit.org/show_bug.cgi?id=240244

Reviewed by Antti Koivisto.

This patch rolls out the abandoned CSSDeferredParser implementation added in Bug 165743.

Source/WebCore:

  • Sources.txt:
  • WebCore.xcodeproj/project.pbxproj:
  • css/CSSKeyframesRule.cpp:

(WebCore::StyleRuleKeyframes::keyframes const):
(WebCore::StyleRuleKeyframes::wrapperAppendKeyframe):
(WebCore::StyleRuleKeyframes::wrapperRemoveKeyframe):
(WebCore::StyleRuleKeyframes::findKeyframeIndex const):
(WebCore::StyleRuleKeyframes::parseDeferredRulesIfNeeded const): Deleted.

  • css/CSSKeyframesRule.h:
  • css/StyleProperties.cpp:

(WebCore::MutableStyleProperties::MutableStyleProperties):
(WebCore::StyleProperties::PropertyReference::cssText const):
(WebCore::DeferredStyleProperties::create): Deleted.
(WebCore::DeferredStyleProperties::DeferredStyleProperties): Deleted.
(WebCore::DeferredStyleProperties::parseDeferredProperties): Deleted.

  • css/StyleProperties.h:

(WebCore::StylePropertiesBase::deref const):
(isType):

  • css/StyleRule.cpp:

(WebCore::StyleRule::properties const):
(WebCore::StyleRuleGroup::childRules const):
(WebCore::StyleRuleGroup::wrapperInsertRule):
(WebCore::StyleRuleGroup::wrapperRemoveRule):
(WebCore::DeferredStyleGroupRuleList::DeferredStyleGroupRuleList): Deleted.
(WebCore::DeferredStyleGroupRuleList::parseDeferredRules): Deleted.
(WebCore::DeferredStyleGroupRuleList::parseDeferredKeyframes): Deleted.
(WebCore::StyleRuleGroup::parseDeferredRulesIfNeeded const): Deleted.

  • css/StyleRule.h:

(WebCore::StyleRule::propertiesWithoutDeferredParsing const): Deleted.
(WebCore::StyleRuleGroup::childRulesWithoutDeferredParsing const): Deleted.

  • css/StyleSheetContents.cpp:

(WebCore::StyleSheetContents::parseAuthorStyleSheet):
(WebCore::StyleSheetContents::parseString):
(WebCore::traverseRulesInVector):
(WebCore::StyleSheetContents::traverseSubresources const):

  • css/parser/CSSDeferredParser.cpp: Removed.
  • css/parser/CSSDeferredParser.h: Removed.
  • css/parser/CSSParser.cpp:

(WebCore::CSSParser::parseSheet):

  • css/parser/CSSParser.h:
  • css/parser/CSSParserContext.cpp:

(WebCore::operator==):
(WebCore::add):

  • css/parser/CSSParserContext.h:
  • css/parser/CSSParserImpl.cpp:

(WebCore::CSSParserImpl::CSSParserImpl):
(WebCore::CSSParserImpl::parseStyleSheet):
(WebCore::CSSParserImpl::consumeMediaRule):
(WebCore::CSSParserImpl::consumeSupportsRule):
(WebCore::CSSParserImpl::consumeKeyframesRule):
(WebCore::CSSParserImpl::consumeLayerRule):
(WebCore::CSSParserImpl::consumeContainerRule):
(WebCore::CSSParserImpl::consumeStyleRule):
(WebCore::CSSParserImpl::createDeferredStyleProperties): Deleted.
(WebCore::CSSParserImpl::parseDeferredDeclaration): Deleted.
(WebCore::CSSParserImpl::parseDeferredRuleList): Deleted.
(WebCore::CSSParserImpl::parseDeferredKeyframeList): Deleted.
(WebCore::CSSParserImpl::adoptTokenizerEscapedStrings): Deleted.

  • css/parser/CSSParserImpl.h:

(WebCore::CSSParserImpl::tokenizer const):
(WebCore::CSSParserImpl::deferredParser const): Deleted.

  • style/ElementRuleCollector.cpp:

(WebCore::Style::ElementRuleCollector::collectMatchingRulesForList):

  • style/StyleInvalidator.cpp:

(WebCore::Style::shouldDirtyAllStyle):

  • testing/Internals.cpp:

(WebCore::deferredStyleRulesCountForList): Deleted.
(WebCore::Internals::deferredStyleRulesCount): Deleted.
(WebCore::deferredGroupRulesCountForList): Deleted.
(WebCore::Internals::deferredGroupRulesCount): Deleted.
(WebCore::deferredKeyframesRulesCountForList): Deleted.
(WebCore::Internals::deferredKeyframesRulesCount): Deleted.

  • testing/Internals.h:
  • testing/Internals.idl:

Source/WebKit:

  • UIProcess/API/C/WKPreferences.cpp:

(WKPreferencesSetDeferredCSSParserEnabled): Deleted.
(WKPreferencesGetDeferredCSSParserEnabled): Deleted.

  • UIProcess/API/C/WKPreferencesRefPrivate.h:

Source/WTF:

  • Scripts/Preferences/WebPreferences.yaml:

LayoutTests:

  • fast/css/deferred-parsing/dynamic-external-style-expected.txt: Removed.
  • fast/css/deferred-parsing/dynamic-external-style.html: Removed.
  • fast/css/deferred-parsing/dynamic-style-in-document-expected.txt: Removed.
  • fast/css/deferred-parsing/dynamic-style-in-document.html: Removed.
  • fast/css/deferred-parsing/hover-test-expected.txt: Removed.
  • fast/css/deferred-parsing/hover-test.html: Removed.
  • fast/css/deferred-parsing/keyframes-rule-expected.txt: Removed.
  • fast/css/deferred-parsing/keyframes-rule.html: Removed.
  • fast/css/deferred-parsing/media-print-expected.txt: Removed.
  • fast/css/deferred-parsing/media-print.html: Removed.
  • fast/css/deferred-parsing/nth-of-type-expected.txt: Removed.
  • fast/css/deferred-parsing/nth-of-type.html: Removed.
  • fast/css/deferred-parsing/resources/basic-sheet.css: Removed.
  • fast/css/deferred-parsing/simple-external-style-expected.txt: Removed.
  • fast/css/deferred-parsing/simple-external-style.html: Removed.
  • fast/css/deferred-parsing/simple-style-in-document-expected.txt: Removed.
  • fast/css/deferred-parsing/simple-style-in-document.html: Removed.
  • fast/css/deferred-parsing/supports-rule-expected.txt: Removed.
  • fast/css/deferred-parsing/supports-rule.html: Removed.
  • platform/ios-wk2/TestExpectations:
  • platform/ios/TestExpectations:
File size: 41.0 KB
Line 
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Copyright (C) 2016-2022 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 "CSSCounterStyleRule.h"
35#include "CSSCustomPropertyValue.h"
36#include "CSSFontFamily.h"
37#include "CSSFontPaletteValuesOverrideColorsValue.h"
38#include "CSSKeyframeRule.h"
39#include "CSSKeyframesRule.h"
40#include "CSSParserObserver.h"
41#include "CSSParserObserverWrapper.h"
42#include "CSSParserSelector.h"
43#include "CSSPropertyParser.h"
44#include "CSSSelectorParser.h"
45#include "CSSStyleSheet.h"
46#include "CSSSupportsParser.h"
47#include "CSSTokenizer.h"
48#include "CSSVariableParser.h"
49#include "ContainerQueryParser.h"
50#include "Document.h"
51#include "Element.h"
52#include "FontPaletteValues.h"
53#include "MediaList.h"
54#include "MediaQueryParser.h"
55#include "MediaQueryParserContext.h"
56#include "StyleProperties.h"
57#include "StyleRuleImport.h"
58#include "StyleSheetContents.h"
59
60#include <bitset>
61#include <memory>
62
63namespace WebCore {
64
65CSSParserImpl::CSSParserImpl(const CSSParserContext& context, StyleSheetContents* styleSheet)
66 : m_context(context)
67 , m_styleSheet(styleSheet)
68{
69
70}
71
72CSSParserImpl::CSSParserImpl(const CSSParserContext& context, const String& string, StyleSheetContents* styleSheet, CSSParserObserverWrapper* wrapper)
73 : m_context(context)
74 , m_styleSheet(styleSheet)
75 , m_tokenizer(wrapper ? CSSTokenizer::tryCreate(string, *wrapper) : CSSTokenizer::tryCreate(string))
76 , m_observerWrapper(wrapper)
77{
78}
79
80CSSParser::ParseResult CSSParserImpl::parseValue(MutableStyleProperties* declaration, CSSPropertyID propertyID, const String& string, bool important, const CSSParserContext& context)
81{
82 CSSParserImpl parser(context, string);
83 auto ruleType = context.enclosingRuleType.value_or(StyleRuleType::Style);
84 parser.consumeDeclarationValue(parser.tokenizer()->tokenRange(), propertyID, important, ruleType);
85 if (parser.m_parsedProperties.isEmpty())
86 return CSSParser::ParseResult::Error;
87 return declaration->addParsedProperties(parser.m_parsedProperties) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
88}
89
90CSSParser::ParseResult CSSParserImpl::parseCustomPropertyValue(MutableStyleProperties* declaration, const AtomString& propertyName, const String& string, bool important, const CSSParserContext& context)
91{
92 CSSParserImpl parser(context, string);
93 parser.consumeCustomPropertyValue(parser.tokenizer()->tokenRange(), propertyName, important);
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
99static inline void filterProperties(bool important, const ParsedPropertyVector& input, ParsedPropertyVector& output, size_t& unusedEntries, std::bitset<numCSSProperties>& seenProperties, HashSet<AtomString>& seenCustomProperties)
100{
101 // Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
102 for (size_t i = input.size(); i--; ) {
103 const CSSProperty& property = input[i];
104 if (property.isImportant() != important)
105 continue;
106 const unsigned propertyIDIndex = property.id() - firstCSSProperty;
107
108 if (property.id() == CSSPropertyCustom) {
109 auto& name = downcast<CSSCustomPropertyValue>(*property.value()).name();
110 if (!seenCustomProperties.add(name).isNewEntry)
111 continue;
112 output[--unusedEntries] = property;
113 continue;
114 }
115
116 auto seenPropertyBit = seenProperties[propertyIDIndex];
117 if (seenPropertyBit)
118 continue;
119 seenPropertyBit = true;
120
121 output[--unusedEntries] = property;
122 }
123}
124
125static Ref<ImmutableStyleProperties> createStyleProperties(ParsedPropertyVector& parsedProperties, CSSParserMode mode)
126{
127 std::bitset<numCSSProperties> seenProperties;
128 size_t unusedEntries = parsedProperties.size();
129 ParsedPropertyVector results(unusedEntries);
130 HashSet<AtomString> seenCustomProperties;
131
132 filterProperties(true, parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
133 filterProperties(false, parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
134
135 Ref<ImmutableStyleProperties> result = ImmutableStyleProperties::create(results.data() + unusedEntries, results.size() - unusedEntries, mode);
136 parsedProperties.clear();
137 return result;
138}
139
140Ref<ImmutableStyleProperties> CSSParserImpl::parseInlineStyleDeclaration(const String& string, const Element* element)
141{
142 CSSParserContext context(element->document());
143 context.mode = strictToCSSParserMode(element->isHTMLElement() && !element->document().inQuirksMode());
144
145 CSSParserImpl parser(context, string);
146 parser.consumeDeclarationList(parser.tokenizer()->tokenRange(), StyleRuleType::Style);
147 return createStyleProperties(parser.m_parsedProperties, context.mode);
148}
149
150bool CSSParserImpl::parseDeclarationList(MutableStyleProperties* declaration, const String& string, const CSSParserContext& context)
151{
152 CSSParserImpl parser(context, string);
153 auto ruleType = context.enclosingRuleType.value_or(StyleRuleType::Style);
154 parser.consumeDeclarationList(parser.tokenizer()->tokenRange(), ruleType);
155 if (parser.m_parsedProperties.isEmpty())
156 return false;
157
158 std::bitset<numCSSProperties> seenProperties;
159 size_t unusedEntries = parser.m_parsedProperties.size();
160 ParsedPropertyVector results(unusedEntries);
161 HashSet<AtomString> seenCustomProperties;
162 filterProperties(true, parser.m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
163 filterProperties(false, parser.m_parsedProperties, results, unusedEntries, seenProperties, seenCustomProperties);
164 if (unusedEntries)
165 results.remove(0, unusedEntries);
166 return declaration->addParsedProperties(results);
167}
168
169RefPtr<StyleRuleBase> CSSParserImpl::parseRule(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, AllowedRulesType allowedRules)
170{
171 CSSParserImpl parser(context, string, styleSheet);
172 CSSParserTokenRange range = parser.tokenizer()->tokenRange();
173 range.consumeWhitespace();
174 if (range.atEnd())
175 return nullptr; // Parse error, empty rule
176 RefPtr<StyleRuleBase> rule;
177 if (range.peek().type() == AtKeywordToken)
178 rule = parser.consumeAtRule(range, allowedRules);
179 else
180 rule = parser.consumeQualifiedRule(range, allowedRules);
181 if (!rule)
182 return nullptr; // Parse error, failed to consume rule
183 range.consumeWhitespace();
184 if (!rule || !range.atEnd())
185 return nullptr; // Parse error, trailing garbage
186 return rule;
187}
188
189void CSSParserImpl::parseStyleSheet(const String& string, const CSSParserContext& context, StyleSheetContents& styleSheet)
190{
191 CSSParserImpl parser(context, string, &styleSheet, nullptr);
192 bool firstRuleValid = parser.consumeRuleList(parser.tokenizer()->tokenRange(), TopLevelRuleList, [&styleSheet](RefPtr<StyleRuleBase> rule) {
193 if (rule->isCharsetRule())
194 return;
195 styleSheet.parserAppendRule(rule.releaseNonNull());
196 });
197 styleSheet.setHasSyntacticallyValidCSSHeader(firstRuleValid);
198 styleSheet.shrinkToFit();
199}
200
201CSSSelectorList CSSParserImpl::parsePageSelector(CSSParserTokenRange range, StyleSheetContents* styleSheet)
202{
203 // We only support a small subset of the css-page spec.
204 range.consumeWhitespace();
205 AtomString typeSelector;
206 if (range.peek().type() == IdentToken)
207 typeSelector = range.consume().value().toAtomString();
208
209 StringView pseudo;
210 if (range.peek().type() == ColonToken) {
211 range.consume();
212 if (range.peek().type() != IdentToken)
213 return CSSSelectorList();
214 pseudo = range.consume().value();
215 }
216
217 range.consumeWhitespace();
218 if (!range.atEnd())
219 return CSSSelectorList(); // Parse error; extra tokens in @page selector
220
221 std::unique_ptr<CSSParserSelector> selector;
222 if (!typeSelector.isNull() && pseudo.isNull())
223 selector = makeUnique<CSSParserSelector>(QualifiedName(nullAtom(), typeSelector, styleSheet->defaultNamespace()));
224 else {
225 selector = makeUnique<CSSParserSelector>();
226 if (!pseudo.isNull()) {
227 selector = std::unique_ptr<CSSParserSelector>(CSSParserSelector::parsePagePseudoSelector(pseudo));
228 if (!selector || selector->match() != CSSSelector::PagePseudoClass)
229 return CSSSelectorList();
230 }
231 if (!typeSelector.isNull())
232 selector->prependTagSelector(QualifiedName(nullAtom(), typeSelector, styleSheet->defaultNamespace()));
233 }
234
235 selector->setForPage();
236 return CSSSelectorList { Vector<std::unique_ptr<CSSParserSelector>>::from(WTFMove(selector)) };
237}
238
239Vector<double> CSSParserImpl::parseKeyframeKeyList(const String& keyList)
240{
241 return consumeKeyframeKeyList(CSSTokenizer(keyList).tokenRange());
242}
243
244bool CSSParserImpl::supportsDeclaration(CSSParserTokenRange& range)
245{
246 ASSERT(m_parsedProperties.isEmpty());
247 consumeDeclaration(range, StyleRuleType::Style);
248 bool result = !m_parsedProperties.isEmpty();
249 m_parsedProperties.clear();
250 return result;
251}
252
253void CSSParserImpl::parseDeclarationListForInspector(const String& declaration, const CSSParserContext& context, CSSParserObserver& observer)
254{
255 CSSParserObserverWrapper wrapper(observer);
256 CSSParserImpl parser(context, declaration, nullptr, &wrapper);
257 observer.startRuleHeader(StyleRuleType::Style, 0);
258 observer.endRuleHeader(1);
259 parser.consumeDeclarationList(parser.tokenizer()->tokenRange(), StyleRuleType::Style);
260}
261
262void CSSParserImpl::parseStyleSheetForInspector(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, CSSParserObserver& observer)
263{
264 CSSParserObserverWrapper wrapper(observer);
265 CSSParserImpl parser(context, string, styleSheet, &wrapper);
266 bool firstRuleValid = parser.consumeRuleList(parser.tokenizer()->tokenRange(), TopLevelRuleList, [&styleSheet](RefPtr<StyleRuleBase> rule) {
267 if (rule->isCharsetRule())
268 return;
269 styleSheet->parserAppendRule(rule.releaseNonNull());
270 });
271 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid);
272}
273
274static CSSParserImpl::AllowedRulesType computeNewAllowedRules(CSSParserImpl::AllowedRulesType allowedRules, StyleRuleBase* rule)
275{
276 if (!rule || allowedRules == CSSParserImpl::KeyframeRules || allowedRules == CSSParserImpl::CounterStyleRules || allowedRules == CSSParserImpl::NoRules)
277 return allowedRules;
278
279 ASSERT(allowedRules <= CSSParserImpl::RegularRules);
280 if (rule->isCharsetRule())
281 return CSSParserImpl::AllowLayerStatementRules;
282 if (allowedRules <= CSSParserImpl::AllowLayerStatementRules && rule->isLayerRule() && downcast<StyleRuleLayer>(*rule).isStatement())
283 return CSSParserImpl::AllowLayerStatementRules;
284 if (rule->isImportRule())
285 return CSSParserImpl::AllowImportRules;
286 if (rule->isNamespaceRule())
287 return CSSParserImpl::AllowNamespaceRules;
288 return CSSParserImpl::RegularRules;
289}
290
291template<typename T>
292bool CSSParserImpl::consumeRuleList(CSSParserTokenRange range, RuleListType ruleListType, const T callback)
293{
294 AllowedRulesType allowedRules = RegularRules;
295 switch (ruleListType) {
296 case TopLevelRuleList:
297 allowedRules = AllowCharsetRules;
298 break;
299 case RegularRuleList:
300 allowedRules = RegularRules;
301 break;
302 case KeyframesRuleList:
303 allowedRules = KeyframeRules;
304 break;
305 default:
306 ASSERT_NOT_REACHED();
307 }
308
309 bool seenRule = false;
310 bool firstRuleValid = false;
311 while (!range.atEnd()) {
312 RefPtr<StyleRuleBase> rule;
313 switch (range.peek().type()) {
314 case WhitespaceToken:
315 range.consumeWhitespace();
316 continue;
317 case AtKeywordToken:
318 rule = consumeAtRule(range, allowedRules);
319 break;
320 case CDOToken:
321 case CDCToken:
322 if (ruleListType == TopLevelRuleList) {
323 range.consume();
324 continue;
325 }
326 FALLTHROUGH;
327 default:
328 rule = consumeQualifiedRule(range, allowedRules);
329 break;
330 }
331 if (!seenRule) {
332 seenRule = true;
333 firstRuleValid = rule;
334 }
335 if (rule) {
336 allowedRules = computeNewAllowedRules(allowedRules, rule.get());
337 callback(rule);
338 }
339 }
340
341 return firstRuleValid;
342}
343
344RefPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserTokenRange& range, AllowedRulesType allowedRules)
345{
346 ASSERT(range.peek().type() == AtKeywordToken);
347 const StringView name = range.consumeIncludingWhitespace().value();
348 const CSSParserToken* preludeStart = &range.peek();
349 while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek().type() != SemicolonToken)
350 range.consumeComponentValue();
351
352 CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek());
353 CSSAtRuleID id = cssAtRuleID(name);
354
355 if (range.atEnd() || range.peek().type() == SemicolonToken) {
356 range.consume();
357 if (allowedRules == AllowCharsetRules && id == CSSAtRuleCharset)
358 return consumeCharsetRule(prelude);
359 if (allowedRules <= AllowImportRules && id == CSSAtRuleImport)
360 return consumeImportRule(prelude);
361 if (allowedRules <= AllowNamespaceRules && id == CSSAtRuleNamespace)
362 return consumeNamespaceRule(prelude);
363 if (allowedRules <= RegularRules && id == CSSAtRuleLayer)
364 return consumeLayerRule(prelude, { });
365 return nullptr; // Parse error, unrecognised at-rule without block
366 }
367
368 CSSParserTokenRange block = range.consumeBlock();
369 if (allowedRules == KeyframeRules)
370 return nullptr; // Parse error, no at-rules supported inside @keyframes
371 if (allowedRules == NoRules)
372 return nullptr;
373
374 ASSERT(allowedRules <= RegularRules);
375
376 switch (id) {
377 case CSSAtRuleMedia:
378 return consumeMediaRule(prelude, block);
379 case CSSAtRuleSupports:
380 return consumeSupportsRule(prelude, block);
381 case CSSAtRuleFontFace:
382 return consumeFontFaceRule(prelude, block);
383 case CSSAtRuleFontPaletteValues:
384 return consumeFontPaletteValuesRule(prelude, block);
385 case CSSAtRuleWebkitKeyframes:
386 return consumeKeyframesRule(true, prelude, block);
387 case CSSAtRuleKeyframes:
388 return consumeKeyframesRule(false, prelude, block);
389 case CSSAtRulePage:
390 return consumePageRule(prelude, block);
391 case CSSAtRuleCounterStyle:
392 return consumeCounterStyleRule(prelude, block);
393 case CSSAtRuleLayer:
394 return consumeLayerRule(prelude, block);
395 case CSSAtRuleContainer:
396 return consumeContainerRule(prelude, block);
397 default:
398 return nullptr; // Parse error, unrecognised at-rule with block
399 }
400}
401
402RefPtr<StyleRuleBase> CSSParserImpl::consumeQualifiedRule(CSSParserTokenRange& range, AllowedRulesType allowedRules)
403{
404 const CSSParserToken* preludeStart = &range.peek();
405 while (!range.atEnd() && range.peek().type() != LeftBraceToken)
406 range.consumeComponentValue();
407
408 if (range.atEnd())
409 return nullptr; // Parse error, EOF instead of qualified rule block
410
411 CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek());
412 CSSParserTokenRange block = range.consumeBlockCheckingForEditability(m_styleSheet.get());
413
414 if (allowedRules <= RegularRules)
415 return consumeStyleRule(prelude, block);
416 if (allowedRules == KeyframeRules)
417 return consumeKeyframeStyleRule(prelude, block);
418
419 ASSERT_NOT_REACHED();
420 return nullptr;
421}
422
423// This may still consume tokens if it fails
424static AtomString consumeStringOrURI(CSSParserTokenRange& range)
425{
426 const CSSParserToken& token = range.peek();
427
428 if (token.type() == StringToken || token.type() == UrlToken)
429 return range.consumeIncludingWhitespace().value().toAtomString();
430
431 if (token.type() != FunctionToken || !equalLettersIgnoringASCIICase(token.value(), "url"_s))
432 return AtomString();
433
434 CSSParserTokenRange contents = range.consumeBlock();
435 const CSSParserToken& uri = contents.consumeIncludingWhitespace();
436 if (uri.type() == BadStringToken || !contents.atEnd())
437 return AtomString();
438 return uri.value().toAtomString();
439}
440
441RefPtr<StyleRuleCharset> CSSParserImpl::consumeCharsetRule(CSSParserTokenRange prelude)
442{
443 const CSSParserToken& string = prelude.consumeIncludingWhitespace();
444 if (string.type() != StringToken || !prelude.atEnd())
445 return nullptr; // Parse error, expected a single string
446 return StyleRuleCharset::create();
447}
448
449enum class AllowAnonymous { Yes, No };
450static std::optional<CascadeLayerName> consumeCascadeLayerName(CSSParserTokenRange& range, AllowAnonymous allowAnonymous)
451{
452 CascadeLayerName name;
453 if (range.atEnd()) {
454 if (allowAnonymous == AllowAnonymous::Yes)
455 return name;
456 return { };
457 }
458
459 while (true) {
460 auto nameToken = range.consume();
461 if (nameToken.type() != IdentToken)
462 return { };
463
464 name.append(nameToken.value().toAtomString());
465
466 if (range.peek().type() != DelimiterToken || range.peek().delimiter() != '.')
467 break;
468 range.consume();
469 }
470
471 range.consumeWhitespace();
472 return name;
473}
474
475RefPtr<StyleRuleImport> CSSParserImpl::consumeImportRule(CSSParserTokenRange prelude)
476{
477 AtomString uri(consumeStringOrURI(prelude));
478 if (uri.isNull())
479 return nullptr; // Parse error, expected string or URI
480
481 if (m_observerWrapper) {
482 unsigned endOffset = m_observerWrapper->endOffset(prelude);
483 m_observerWrapper->observer().startRuleHeader(StyleRuleType::Import, m_observerWrapper->startOffset(prelude));
484 m_observerWrapper->observer().endRuleHeader(endOffset);
485 m_observerWrapper->observer().startRuleBody(endOffset);
486 m_observerWrapper->observer().endRuleBody(endOffset);
487 }
488
489 prelude.consumeWhitespace();
490
491 auto consumeCascadeLayer = [&]() -> std::optional<CascadeLayerName> {
492 if (!m_context.cascadeLayersEnabled)
493 return { };
494
495 auto& token = prelude.peek();
496 if (token.type() == FunctionToken && equalLettersIgnoringASCIICase(token.value(), "layer"_s)) {
497 auto savedPreludeForFailure = prelude;
498 auto contents = CSSPropertyParserHelpers::consumeFunction(prelude);
499 auto layerName = consumeCascadeLayerName(contents, AllowAnonymous::No);
500 if (!layerName || !contents.atEnd()) {
501 prelude = savedPreludeForFailure;
502 return { };
503 }
504 return layerName;
505 }
506 if (token.type() == IdentToken && equalLettersIgnoringASCIICase(token.value(), "layer"_s)) {
507 prelude.consumeIncludingWhitespace();
508 return CascadeLayerName { };
509 }
510 return { };
511 };
512
513 auto cascadeLayerName = consumeCascadeLayer();
514 auto mediaQuerySet = MediaQueryParser::parseMediaQuerySet(prelude, MediaQueryParserContext(m_context));
515
516 return StyleRuleImport::create(uri, mediaQuerySet.releaseNonNull(), WTFMove(cascadeLayerName));
517}
518
519RefPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(CSSParserTokenRange prelude)
520{
521 AtomString namespacePrefix;
522 if (prelude.peek().type() == IdentToken)
523 namespacePrefix = prelude.consumeIncludingWhitespace().value().toAtomString();
524
525 AtomString uri(consumeStringOrURI(prelude));
526 if (uri.isNull() || !prelude.atEnd())
527 return nullptr; // Parse error, expected string or URI
528
529 return StyleRuleNamespace::create(namespacePrefix, uri);
530}
531
532RefPtr<StyleRuleMedia> CSSParserImpl::consumeMediaRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
533{
534 Vector<RefPtr<StyleRuleBase>> rules;
535
536 if (m_observerWrapper) {
537 m_observerWrapper->observer().startRuleHeader(StyleRuleType::Media, m_observerWrapper->startOffset(prelude));
538 m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
539 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
540 }
541
542 consumeRuleList(block, RegularRuleList, [&rules](RefPtr<StyleRuleBase> rule) {
543 rules.append(rule);
544 });
545 rules.shrinkToFit();
546
547 if (m_observerWrapper)
548 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
549
550 return StyleRuleMedia::create(MediaQueryParser::parseMediaQuerySet(prelude, { m_context }).releaseNonNull(), WTFMove(rules));
551}
552
553RefPtr<StyleRuleSupports> CSSParserImpl::consumeSupportsRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
554{
555 auto supported = CSSSupportsParser::supportsCondition(prelude, *this, CSSSupportsParser::ForAtRule);
556 if (supported == CSSSupportsParser::Invalid)
557 return nullptr; // Parse error, invalid @supports condition
558
559 if (m_observerWrapper) {
560 m_observerWrapper->observer().startRuleHeader(StyleRuleType::Supports, m_observerWrapper->startOffset(prelude));
561 m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
562 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
563 }
564
565 Vector<RefPtr<StyleRuleBase>> rules;
566 consumeRuleList(block, RegularRuleList, [&rules](RefPtr<StyleRuleBase> rule) {
567 rules.append(rule);
568 });
569 rules.shrinkToFit();
570
571 if (m_observerWrapper)
572 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
573
574 return StyleRuleSupports::create(prelude.serialize().stripWhiteSpace(), supported, WTFMove(rules));
575}
576
577RefPtr<StyleRuleFontFace> CSSParserImpl::consumeFontFaceRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
578{
579 if (!prelude.atEnd())
580 return nullptr; // Parse error; @font-face prelude should be empty
581
582 if (m_observerWrapper) {
583 unsigned endOffset = m_observerWrapper->endOffset(prelude);
584 m_observerWrapper->observer().startRuleHeader(StyleRuleType::FontFace, m_observerWrapper->startOffset(prelude));
585 m_observerWrapper->observer().endRuleHeader(endOffset);
586 m_observerWrapper->observer().startRuleBody(endOffset);
587 m_observerWrapper->observer().endRuleBody(endOffset);
588 }
589
590 consumeDeclarationList(block, StyleRuleType::FontFace);
591 return StyleRuleFontFace::create(createStyleProperties(m_parsedProperties, m_context.mode));
592}
593
594RefPtr<StyleRuleFontPaletteValues> CSSParserImpl::consumeFontPaletteValuesRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
595{
596 auto name = CSSPropertyParserHelpers::consumeDashedIdent(prelude);
597 if (!name || !prelude.atEnd())
598 return nullptr; // Parse error; expected custom ident in @font-palette-values header
599
600 if (m_observerWrapper) {
601 unsigned endOffset = m_observerWrapper->endOffset(prelude);
602 m_observerWrapper->observer().startRuleHeader(StyleRuleType::FontPaletteValues, m_observerWrapper->startOffset(prelude));
603 m_observerWrapper->observer().endRuleHeader(endOffset);
604 m_observerWrapper->observer().startRuleBody(endOffset);
605 m_observerWrapper->observer().endRuleBody(endOffset);
606 }
607
608 consumeDeclarationList(block, StyleRuleType::FontPaletteValues);
609 auto properties = createStyleProperties(m_parsedProperties, m_context.mode);
610
611 AtomString fontFamily;
612 if (auto fontFamilyValue = properties->getPropertyCSSValue(CSSPropertyFontFamily))
613 fontFamily = AtomString { downcast<CSSPrimitiveValue>(*fontFamilyValue).fontFamily().familyName };
614
615 std::optional<FontPaletteIndex> basePalette;
616 if (auto basePaletteValue = properties->getPropertyCSSValue(CSSPropertyBasePalette)) {
617 const auto& primitiveValue = downcast<CSSPrimitiveValue>(*basePaletteValue);
618 if (primitiveValue.isInteger())
619 basePalette = FontPaletteIndex(primitiveValue.value<unsigned>());
620 else if (primitiveValue.valueID() == CSSValueLight)
621 basePalette = FontPaletteIndex(FontPaletteIndex::Type::Light);
622 else if (primitiveValue.valueID() == CSSValueDark)
623 basePalette = FontPaletteIndex(FontPaletteIndex::Type::Dark);
624 }
625
626 Vector<FontPaletteValues::OverriddenColor> overrideColors;
627 if (auto overrideColorsValue = properties->getPropertyCSSValue(CSSPropertyOverrideColors)) {
628 const auto& list = downcast<CSSValueList>(*overrideColorsValue);
629 for (const auto& item : list) {
630 const auto& pair = downcast<CSSFontPaletteValuesOverrideColorsValue>(item.get());
631 if (!pair.key().isInteger())
632 continue;
633 unsigned key = pair.key().value<unsigned>();
634 Color color = pair.color().isRGBColor() ? pair.color().color() : StyleColor::colorFromKeyword(pair.color().valueID(), { });
635 overrideColors.append(std::make_pair(key, color));
636 }
637 }
638
639 return StyleRuleFontPaletteValues::create(AtomString { name->stringValue() }, AtomString { fontFamily }, WTFMove(basePalette), WTFMove(overrideColors));
640}
641
642RefPtr<StyleRuleKeyframes> CSSParserImpl::consumeKeyframesRule(bool webkitPrefixed, CSSParserTokenRange prelude, CSSParserTokenRange block)
643{
644 CSSParserTokenRange rangeCopy = prelude; // For inspector callbacks
645 const CSSParserToken& nameToken = prelude.consumeIncludingWhitespace();
646 if (!prelude.atEnd())
647 return nullptr; // Parse error; expected single non-whitespace token in @keyframes header
648
649 AtomString name;
650 if (nameToken.type() == IdentToken) {
651 name = nameToken.value().toAtomString();
652 } else if (nameToken.type() == StringToken && webkitPrefixed)
653 name = nameToken.value().toAtomString();
654 else
655 return nullptr; // Parse error; expected ident token in @keyframes header
656
657 if (m_observerWrapper) {
658 m_observerWrapper->observer().startRuleHeader(StyleRuleType::Keyframes, m_observerWrapper->startOffset(rangeCopy));
659 m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
660 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
661 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
662 }
663
664 RefPtr<StyleRuleKeyframes> keyframeRule = StyleRuleKeyframes::create(name);
665 consumeRuleList(block, KeyframesRuleList, [keyframeRule](const RefPtr<StyleRuleBase>& keyframe) {
666 keyframeRule->parserAppendKeyframe(downcast<const StyleRuleKeyframe>(keyframe.get()));
667 });
668
669 // FIXME-NEWPARSER: Find out why this is done. Behavior difference when prefixed?
670 // keyframeRule->setVendorPrefixed(webkitPrefixed);
671
672 keyframeRule->shrinkToFit();
673 return keyframeRule;
674}
675
676RefPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
677{
678 CSSSelectorList selectorList = parsePageSelector(prelude, m_styleSheet.get());
679 if (selectorList.isEmpty())
680 return nullptr; // Parse error, invalid @page selector
681
682 if (m_observerWrapper) {
683 unsigned endOffset = m_observerWrapper->endOffset(prelude);
684 m_observerWrapper->observer().startRuleHeader(StyleRuleType::Page, m_observerWrapper->startOffset(prelude));
685 m_observerWrapper->observer().endRuleHeader(endOffset);
686 }
687
688 consumeDeclarationList(block, StyleRuleType::Style);
689
690 return StyleRulePage::create(createStyleProperties(m_parsedProperties, m_context.mode), WTFMove(selectorList));
691}
692
693RefPtr<StyleRuleCounterStyle> CSSParserImpl::consumeCounterStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
694{
695 if (!m_context.counterStyleAtRulesEnabled)
696 return nullptr;
697
698 auto rangeCopy = prelude; // For inspector callbacks
699 auto name = CSSPropertyParserHelpers::consumeCounterStyleNameInPrelude(rangeCopy);
700 if (name.isNull())
701 return nullptr;
702
703 if (m_observerWrapper) {
704 m_observerWrapper->observer().startRuleHeader(StyleRuleType::CounterStyle, m_observerWrapper->startOffset(rangeCopy));
705 m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
706 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
707 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
708 }
709
710 consumeDeclarationList(block, StyleRuleType::CounterStyle);
711 return StyleRuleCounterStyle::create(name, createStyleProperties(m_parsedProperties, m_context.mode));
712}
713
714RefPtr<StyleRuleLayer> CSSParserImpl::consumeLayerRule(CSSParserTokenRange prelude, std::optional<CSSParserTokenRange> block)
715{
716 if (!m_context.cascadeLayersEnabled)
717 return nullptr;
718
719 auto preludeCopy = prelude;
720
721 if (!block) {
722 // List syntax.
723 Vector<CascadeLayerName> nameList;
724 while (true) {
725 auto name = consumeCascadeLayerName(prelude, AllowAnonymous::No);
726 if (!name)
727 return nullptr;
728 nameList.append(*name);
729
730 if (prelude.atEnd())
731 break;
732
733 auto commaToken = prelude.consumeIncludingWhitespace();
734 if (commaToken.type() != CommaToken)
735 return { };
736 }
737
738 if (m_observerWrapper) {
739 unsigned endOffset = m_observerWrapper->endOffset(preludeCopy);
740 m_observerWrapper->observer().startRuleHeader(StyleRuleType::LayerStatement, m_observerWrapper->startOffset(preludeCopy));
741 m_observerWrapper->observer().endRuleHeader(endOffset);
742 m_observerWrapper->observer().startRuleBody(endOffset);
743 m_observerWrapper->observer().endRuleBody(endOffset);
744 }
745
746 return StyleRuleLayer::createStatement(WTFMove(nameList));
747 }
748
749 auto name = consumeCascadeLayerName(prelude, AllowAnonymous::Yes);
750 if (!name)
751 return nullptr;
752
753 // No comma separated list when using the block syntax.
754 if (!prelude.atEnd())
755 return nullptr;
756
757 if (m_observerWrapper) {
758 m_observerWrapper->observer().startRuleHeader(StyleRuleType::LayerBlock, m_observerWrapper->startOffset(preludeCopy));
759 m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(preludeCopy));
760 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(*block));
761 }
762
763 Vector<RefPtr<StyleRuleBase>> rules;
764 consumeRuleList(*block, RegularRuleList, [&](RefPtr<StyleRuleBase> rule) {
765 rules.append(rule);
766 });
767 rules.shrinkToFit();
768
769 if (m_observerWrapper)
770 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(*block));
771
772 return StyleRuleLayer::createBlock(WTFMove(*name), WTFMove(rules));
773}
774
775RefPtr<StyleRuleContainer> CSSParserImpl::consumeContainerRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
776{
777 if (!m_context.containerQueriesEnabled)
778 return nullptr;
779
780 if (prelude.atEnd())
781 return nullptr;
782
783 auto query = ContainerQueryParser::consumeFilteredContainerQuery(prelude, m_context);
784 if (!query)
785 return nullptr;
786
787 prelude.consumeWhitespace();
788 if (!prelude.atEnd())
789 return nullptr;
790
791 Vector<RefPtr<StyleRuleBase>> rules;
792
793 if (m_observerWrapper) {
794 m_observerWrapper->observer().startRuleHeader(StyleRuleType::Container, m_observerWrapper->startOffset(prelude));
795 m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
796 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block));
797 }
798
799 consumeRuleList(block, RegularRuleList, [&rules](RefPtr<StyleRuleBase> rule) {
800 rules.append(rule);
801 });
802 rules.shrinkToFit();
803
804 if (m_observerWrapper)
805 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block));
806
807 return StyleRuleContainer::create(WTFMove(*query), WTFMove(rules));
808}
809
810RefPtr<StyleRuleKeyframe> CSSParserImpl::consumeKeyframeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
811{
812 auto keyList = consumeKeyframeKeyList(prelude);
813 if (keyList.isEmpty())
814 return nullptr;
815
816 if (m_observerWrapper) {
817 m_observerWrapper->observer().startRuleHeader(StyleRuleType::Keyframe, m_observerWrapper->startOffset(prelude));
818 m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude));
819 }
820
821 consumeDeclarationList(block, StyleRuleType::Keyframe);
822 return StyleRuleKeyframe::create(WTFMove(keyList), createStyleProperties(m_parsedProperties, m_context.mode));
823}
824
825static void observeSelectors(CSSParserObserverWrapper& wrapper, CSSParserTokenRange selectors)
826{
827 // This is easier than hooking into the CSSSelectorParser
828 selectors.consumeWhitespace();
829 CSSParserTokenRange originalRange = selectors;
830 wrapper.observer().startRuleHeader(StyleRuleType::Style, wrapper.startOffset(originalRange));
831
832 while (!selectors.atEnd()) {
833 const CSSParserToken* selectorStart = &selectors.peek();
834 while (!selectors.atEnd() && selectors.peek().type() != CommaToken)
835 selectors.consumeComponentValue();
836 CSSParserTokenRange selector = selectors.makeSubRange(selectorStart, &selectors.peek());
837 selectors.consumeIncludingWhitespace();
838
839 wrapper.observer().observeSelector(wrapper.startOffset(selector), wrapper.endOffset(selector));
840 }
841
842 wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange));
843}
844
845RefPtr<StyleRule> CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, CSSParserTokenRange block)
846{
847 auto selectorList = parseCSSSelector(prelude, m_context, m_styleSheet.get());
848 if (!selectorList)
849 return nullptr; // Parse error, invalid selector list
850
851 if (m_observerWrapper)
852 observeSelectors(*m_observerWrapper, prelude);
853
854 consumeDeclarationList(block, StyleRuleType::Style);
855 return StyleRule::create(createStyleProperties(m_parsedProperties, m_context.mode), m_context.hasDocumentSecurityOrigin, WTFMove(*selectorList));
856}
857
858void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRuleType ruleType)
859{
860 ASSERT(m_parsedProperties.isEmpty());
861
862 bool useObserver = m_observerWrapper && (ruleType == StyleRuleType::Style || ruleType == StyleRuleType::Keyframe || ruleType == StyleRuleType::CounterStyle);
863 if (useObserver) {
864 m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(range));
865 m_observerWrapper->skipCommentsBefore(range, true);
866 }
867
868 while (!range.atEnd()) {
869 switch (range.peek().type()) {
870 case WhitespaceToken:
871 case SemicolonToken:
872 range.consume();
873 break;
874 case IdentToken: {
875 const CSSParserToken* declarationStart = &range.peek();
876
877 if (useObserver)
878 m_observerWrapper->yieldCommentsBefore(range);
879
880 while (!range.atEnd() && range.peek().type() != SemicolonToken)
881 range.consumeComponentValue();
882
883 consumeDeclaration(range.makeSubRange(declarationStart, &range.peek()), ruleType);
884
885 if (useObserver)
886 m_observerWrapper->skipCommentsBefore(range, false);
887 break;
888 }
889 case AtKeywordToken: {
890 RefPtr<StyleRuleBase> rule = consumeAtRule(range, NoRules);
891 ASSERT_UNUSED(rule, !rule);
892 break;
893 }
894 default: // Parse error, unexpected token in declaration list
895 while (!range.atEnd() && range.peek().type() != SemicolonToken)
896 range.consumeComponentValue();
897 break;
898 }
899 }
900
901 // Yield remaining comments
902 if (useObserver) {
903 m_observerWrapper->yieldCommentsBefore(range);
904 m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(range));
905 }
906}
907
908static void removeTrailingWhitespace(const CSSParserTokenRange& range, const CSSParserToken*& position)
909{
910 while (position != range.begin() && position[-1].type() == WhitespaceToken)
911 --position;
912}
913
914// https://drafts.csswg.org/css-syntax/#consume-declaration
915void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRuleType ruleType)
916{
917 CSSParserTokenRange rangeCopy = range; // For inspector callbacks
918
919 ASSERT(range.peek().type() == IdentToken);
920 auto& token = range.consumeIncludingWhitespace();
921 auto propertyID = token.parseAsCSSPropertyID();
922 if (range.consume().type() != ColonToken)
923 return; // Parse error
924 range.consumeWhitespace();
925
926 auto declarationValueEnd = range.end();
927 bool important = false;
928 if (!range.atEnd()) {
929 auto end = range.end();
930 removeTrailingWhitespace(range, end);
931 declarationValueEnd = end;
932 if (end[-1].type() == IdentToken && equalLettersIgnoringASCIICase(end[-1].value(), "important"_s)) {
933 --end;
934 removeTrailingWhitespace(range, end);
935 if (end[-1].type() == DelimiterToken && end[-1].delimiter() == '!') {
936 important = true;
937 --end;
938 removeTrailingWhitespace(range, end);
939 declarationValueEnd = end;
940 }
941 }
942 }
943
944 size_t propertiesCount = m_parsedProperties.size();
945
946 if (m_context.isPropertyRuntimeDisabled(propertyID) || isInternalCSSProperty(propertyID))
947 propertyID = CSSPropertyInvalid;
948
949 if (propertyID == CSSPropertyInvalid && CSSVariableParser::isValidVariableName(token)) {
950 AtomString variableName = token.value().toAtomString();
951 consumeCustomPropertyValue(range.makeSubRange(&range.peek(), declarationValueEnd), variableName, important);
952 }
953
954 if (important && (ruleType == StyleRuleType::FontFace || ruleType == StyleRuleType::Keyframe || ruleType == StyleRuleType::CounterStyle || ruleType == StyleRuleType::FontPaletteValues))
955 return;
956
957 if (propertyID != CSSPropertyInvalid)
958 consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), propertyID, important, ruleType);
959
960 if (m_observerWrapper && (ruleType == StyleRuleType::Style || ruleType == StyleRuleType::Keyframe)) {
961 m_observerWrapper->observer().observeProperty(
962 m_observerWrapper->startOffset(rangeCopy), m_observerWrapper->endOffset(rangeCopy),
963 important, m_parsedProperties.size() != propertiesCount);
964 }
965}
966
967void CSSParserImpl::consumeCustomPropertyValue(CSSParserTokenRange range, const AtomString& variableName, bool important)
968{
969 if (range.atEnd())
970 m_parsedProperties.append(CSSProperty(CSSPropertyCustom, CSSCustomPropertyValue::createEmpty(variableName), important));
971 else if (auto value = CSSVariableParser::parseDeclarationValue(variableName, range, m_context))
972 m_parsedProperties.append(CSSProperty(CSSPropertyCustom, WTFMove(value), important));
973}
974
975void CSSParserImpl::consumeDeclarationValue(CSSParserTokenRange range, CSSPropertyID propertyID, bool important, StyleRuleType ruleType)
976{
977 CSSPropertyParser::parseValue(propertyID, important, range, m_context, m_parsedProperties, ruleType);
978}
979
980Vector<double> CSSParserImpl::consumeKeyframeKeyList(CSSParserTokenRange range)
981{
982 Vector<double> result;
983 while (true) {
984 range.consumeWhitespace();
985 const CSSParserToken& token = range.consumeIncludingWhitespace();
986 if (token.type() == PercentageToken && token.numericValue() >= 0 && token.numericValue() <= 100)
987 result.append(token.numericValue() / 100);
988 else if (token.type() == IdentToken && equalLettersIgnoringASCIICase(token.value(), "from"_s))
989 result.append(0);
990 else if (token.type() == IdentToken && equalLettersIgnoringASCIICase(token.value(), "to"_s))
991 result.append(1);
992 else
993 return { }; // Parser error, invalid value in keyframe selector
994
995 if (range.atEnd()) {
996 result.shrinkToFit();
997 return result;
998 }
999
1000 if (range.consume().type() != CommaToken)
1001 return { }; // Parser error
1002 }
1003}
1004
1005} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.