OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/css/parser/CSSParserImpl.h" | 5 #include "core/css/parser/CSSParserImpl.h" |
6 | 6 |
7 #include "core/css/CSSCustomIdentValue.h" | 7 #include "core/css/CSSCustomIdentValue.h" |
8 #include "core/css/CSSCustomPropertyDeclaration.h" | 8 #include "core/css/CSSCustomPropertyDeclaration.h" |
9 #include "core/css/CSSKeyframesRule.h" | 9 #include "core/css/CSSKeyframesRule.h" |
10 #include "core/css/CSSStyleSheet.h" | 10 #include "core/css/CSSStyleSheet.h" |
11 #include "core/css/PropertyRegistry.h" | 11 #include "core/css/PropertyRegistry.h" |
12 #include "core/css/StyleRuleImport.h" | 12 #include "core/css/StyleRuleImport.h" |
13 #include "core/css/StyleRuleKeyframe.h" | 13 #include "core/css/StyleRuleKeyframe.h" |
14 #include "core/css/StyleRuleNamespace.h" | 14 #include "core/css/StyleRuleNamespace.h" |
15 #include "core/css/StyleSheetContents.h" | 15 #include "core/css/StyleSheetContents.h" |
16 #include "core/css/parser/CSSAtRuleID.h" | 16 #include "core/css/parser/CSSAtRuleID.h" |
17 #include "core/css/parser/CSSLazyParsingState.h" | 17 #include "core/css/parser/CSSLazyParsingState.h" |
18 #include "core/css/parser/CSSLazyPropertyParserImpl.h" | 18 #include "core/css/parser/CSSLazyPropertyParserImpl.h" |
19 #include "core/css/parser/CSSParserObserver.h" | 19 #include "core/css/parser/CSSParserObserver.h" |
20 #include "core/css/parser/CSSParserObserverWrapper.h" | |
21 #include "core/css/parser/CSSParserSelector.h" | 20 #include "core/css/parser/CSSParserSelector.h" |
22 #include "core/css/parser/CSSPropertyParser.h" | 21 #include "core/css/parser/CSSPropertyParser.h" |
23 #include "core/css/parser/CSSSelectorParser.h" | 22 #include "core/css/parser/CSSSelectorParser.h" |
24 #include "core/css/parser/CSSSupportsParser.h" | 23 #include "core/css/parser/CSSSupportsParser.h" |
25 #include "core/css/parser/CSSTokenizer.h" | 24 #include "core/css/parser/CSSTokenizer.h" |
26 #include "core/css/parser/CSSVariableParser.h" | 25 #include "core/css/parser/CSSVariableParser.h" |
27 #include "core/css/parser/MediaQueryParser.h" | 26 #include "core/css/parser/MediaQueryParser.h" |
28 #include "core/dom/Document.h" | 27 #include "core/dom/Document.h" |
29 #include "core/dom/Element.h" | 28 #include "core/dom/Element.h" |
30 #include "core/frame/Deprecation.h" | 29 #include "core/frame/Deprecation.h" |
31 #include "core/frame/UseCounter.h" | 30 #include "core/frame/UseCounter.h" |
32 #include "platform/instrumentation/tracing/TraceEvent.h" | 31 #include "platform/instrumentation/tracing/TraceEvent.h" |
33 #include "wtf/PtrUtil.h" | 32 #include "wtf/PtrUtil.h" |
34 #include <bitset> | 33 #include <bitset> |
35 #include <memory> | 34 #include <memory> |
36 | 35 |
37 namespace blink { | 36 namespace blink { |
38 | 37 |
39 CSSParserImpl::CSSParserImpl(const CSSParserContext& context, | 38 CSSParserImpl::CSSParserImpl(const CSSParserContext& context, |
40 StyleSheetContents* styleSheet) | 39 StyleSheetContents* styleSheet) |
41 : m_context(context), | 40 : m_context(context), m_styleSheet(styleSheet) {} |
42 m_styleSheet(styleSheet), | |
43 m_observerWrapper(nullptr) {} | |
44 | 41 |
45 MutableStylePropertySet::SetResult CSSParserImpl::parseValue( | 42 MutableStylePropertySet::SetResult CSSParserImpl::parseValue( |
46 MutableStylePropertySet* declaration, | 43 MutableStylePropertySet* declaration, |
47 CSSPropertyID unresolvedProperty, | 44 CSSPropertyID unresolvedProperty, |
48 const String& string, | 45 const String& string, |
49 bool important, | 46 bool important, |
50 const CSSParserContext& context) { | 47 const CSSParserContext& context) { |
51 CSSParserImpl parser(context); | 48 CSSParserImpl parser(context); |
52 StyleRule::RuleType ruleType = StyleRule::Style; | 49 StyleRule::RuleType ruleType = StyleRule::Style; |
53 if (declaration->cssParserMode() == CSSViewportRuleMode) | 50 if (declaration->cssParserMode() == CSSViewportRuleMode) |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 const String& string, | 150 const String& string, |
154 Element* element) { | 151 Element* element) { |
155 Document& document = element->document(); | 152 Document& document = element->document(); |
156 CSSParserContext context = | 153 CSSParserContext context = |
157 CSSParserContext(document.elementSheet().contents()->parserContext(), | 154 CSSParserContext(document.elementSheet().contents()->parserContext(), |
158 UseCounter::getFrom(&document)); | 155 UseCounter::getFrom(&document)); |
159 CSSParserMode mode = element->isHTMLElement() && !document.inQuirksMode() | 156 CSSParserMode mode = element->isHTMLElement() && !document.inQuirksMode() |
160 ? HTMLStandardMode | 157 ? HTMLStandardMode |
161 : HTMLQuirksMode; | 158 : HTMLQuirksMode; |
162 context.setMode(mode); | 159 context.setMode(mode); |
| 160 CSSTokenizer tokenizer(string); |
| 161 CSSParserTokenStream stream(tokenizer); |
163 CSSParserImpl parser(context, document.elementSheet().contents()); | 162 CSSParserImpl parser(context, document.elementSheet().contents()); |
164 CSSTokenizer tokenizer(string); | 163 parser.consumeDeclarationList(stream, StyleRule::Style); |
165 parser.consumeDeclarationList(tokenizer.tokenRange(), StyleRule::Style); | |
166 return createStylePropertySet(parser.m_parsedProperties, mode); | 164 return createStylePropertySet(parser.m_parsedProperties, mode); |
167 } | 165 } |
168 | 166 |
169 bool CSSParserImpl::parseDeclarationList(MutableStylePropertySet* declaration, | 167 bool CSSParserImpl::parseDeclarationList(MutableStylePropertySet* declaration, |
170 const String& string, | 168 const String& string, |
171 const CSSParserContext& context) { | 169 const CSSParserContext& context) { |
172 CSSParserImpl parser(context); | 170 CSSParserImpl parser(context); |
173 StyleRule::RuleType ruleType = StyleRule::Style; | 171 StyleRule::RuleType ruleType = StyleRule::Style; |
174 if (declaration->cssParserMode() == CSSViewportRuleMode) | 172 if (declaration->cssParserMode() == CSSViewportRuleMode) |
175 ruleType = StyleRule::Viewport; | 173 ruleType = StyleRule::Viewport; |
176 CSSTokenizer tokenizer(string); | 174 CSSTokenizer tokenizer(string); |
177 parser.consumeDeclarationList(tokenizer.tokenRange(), ruleType); | 175 CSSParserTokenStream stream(tokenizer); |
| 176 parser.consumeDeclarationList(stream, ruleType); |
178 if (parser.m_parsedProperties.isEmpty()) | 177 if (parser.m_parsedProperties.isEmpty()) |
179 return false; | 178 return false; |
180 | 179 |
181 std::bitset<numCSSProperties> seenProperties; | 180 std::bitset<numCSSProperties> seenProperties; |
182 size_t unusedEntries = parser.m_parsedProperties.size(); | 181 size_t unusedEntries = parser.m_parsedProperties.size(); |
183 HeapVector<CSSProperty, 256> results(unusedEntries); | 182 HeapVector<CSSProperty, 256> results(unusedEntries); |
184 HashSet<AtomicString> seenCustomProperties; | 183 HashSet<AtomicString> seenCustomProperties; |
185 filterProperties(true, parser.m_parsedProperties, results, unusedEntries, | 184 filterProperties(true, parser.m_parsedProperties, results, unusedEntries, |
186 seenProperties, seenCustomProperties); | 185 seenProperties, seenCustomProperties); |
187 filterProperties(false, parser.m_parsedProperties, results, unusedEntries, | 186 filterProperties(false, parser.m_parsedProperties, results, unusedEntries, |
188 seenProperties, seenCustomProperties); | 187 seenProperties, seenCustomProperties); |
189 if (unusedEntries) | 188 if (unusedEntries) |
190 results.remove(0, unusedEntries); | 189 results.remove(0, unusedEntries); |
191 return declaration->addParsedProperties(results); | 190 return declaration->addParsedProperties(results); |
192 } | 191 } |
193 | 192 |
194 StyleRuleBase* CSSParserImpl::parseRule(const String& string, | 193 StyleRuleBase* CSSParserImpl::parseRule(const String& string, |
195 const CSSParserContext& context, | 194 const CSSParserContext& context, |
196 StyleSheetContents* styleSheet, | 195 StyleSheetContents* styleSheet, |
197 AllowedRulesType allowedRules) { | 196 AllowedRulesType allowedRules) { |
198 CSSParserImpl parser(context, styleSheet); | 197 CSSParserImpl parser(context, styleSheet); |
199 CSSTokenizer tokenizer(string); | 198 CSSTokenizer tokenizer(string); |
200 CSSParserTokenRange range = tokenizer.tokenRange(); | 199 CSSParserTokenStream stream(tokenizer); |
201 range.consumeWhitespace(); | 200 stream.skipWhitespaceAndComments(); |
202 if (range.atEnd()) | 201 if (stream.atEnd()) |
203 return nullptr; // Parse error, empty rule | 202 return nullptr; // Parse error, empty rule |
204 StyleRuleBase* rule; | 203 StyleRuleBase* rule; |
205 if (range.peek().type() == AtKeywordToken) | 204 if (stream.peek().type() == AtKeywordToken) |
206 rule = parser.consumeAtRule(range, allowedRules); | 205 rule = parser.consumeAtRule(stream, allowedRules); |
207 else | 206 else |
208 rule = parser.consumeQualifiedRule(range, allowedRules); | 207 rule = parser.consumeQualifiedRule(stream, allowedRules); |
209 if (!rule) | 208 if (!rule) |
210 return nullptr; // Parse error, failed to consume rule | 209 return nullptr; // Parse error, failed to consume rule |
211 range.consumeWhitespace(); | 210 stream.skipWhitespaceAndComments(); |
212 if (!rule || !range.atEnd()) | 211 if (!rule || !stream.atEnd()) |
213 return nullptr; // Parse error, trailing garbage | 212 return nullptr; // Parse error, trailing garbage |
214 return rule; | 213 return rule; |
215 } | 214 } |
216 | 215 |
217 void CSSParserImpl::parseStyleSheet(const String& string, | 216 void CSSParserImpl::parseStyleSheet(const String& string, |
218 const CSSParserContext& context, | 217 const CSSParserContext& context, |
219 StyleSheetContents* styleSheet, | 218 StyleSheetContents* styleSheet, |
220 bool deferPropertyParsing) { | 219 bool deferPropertyParsing) { |
221 TRACE_EVENT_BEGIN2("blink,blink_style", "CSSParserImpl::parseStyleSheet", | 220 TRACE_EVENT_BEGIN2("blink,blink_style", "CSSParserImpl::parseStyleSheet", |
222 "baseUrl", context.baseURL().getString().utf8(), "mode", | 221 "baseUrl", context.baseURL().getString().utf8(), "mode", |
223 context.mode()); | 222 context.mode()); |
224 | |
225 TRACE_EVENT_BEGIN0("blink,blink_style", | |
226 "CSSParserImpl::parseStyleSheet.tokenize"); | |
227 CSSTokenizer tokenizer(string); | 223 CSSTokenizer tokenizer(string); |
228 TRACE_EVENT_END0("blink,blink_style", | 224 CSSParserTokenStream stream(tokenizer); |
229 "CSSParserImpl::parseStyleSheet.tokenize"); | |
230 | |
231 TRACE_EVENT_BEGIN0("blink,blink_style", | |
232 "CSSParserImpl::parseStyleSheet.parse"); | |
233 CSSParserImpl parser(context, styleSheet); | 225 CSSParserImpl parser(context, styleSheet); |
234 if (deferPropertyParsing) { | 226 if (deferPropertyParsing) { |
235 parser.m_lazyState = new CSSLazyParsingState( | 227 parser.m_lazyState = |
236 context, tokenizer.takeEscapedStrings(), string, parser.m_styleSheet); | 228 new CSSLazyParsingState(context, string, parser.m_styleSheet); |
237 } | 229 } |
238 bool firstRuleValid = | 230 bool firstRuleValid = parser.consumeRuleList( |
239 parser.consumeRuleList(tokenizer.tokenRange(), TopLevelRuleList, | 231 stream, TopLevelRuleList, [&styleSheet](StyleRuleBase* rule) { |
240 [&styleSheet](StyleRuleBase* rule) { | 232 if (rule->isCharsetRule()) |
241 if (rule->isCharsetRule()) | 233 return; |
242 return; | 234 styleSheet->parserAppendRule(rule); |
243 styleSheet->parserAppendRule(rule); | 235 }); |
244 }); | |
245 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); | 236 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); |
246 TRACE_EVENT_END0("blink,blink_style", "CSSParserImpl::parseStyleSheet.parse"); | 237 TRACE_EVENT_END1("blink,blink_style", "CSSParserImpl::parseStyleSheet", |
247 | 238 "length", string.length()); |
248 TRACE_EVENT_END2("blink,blink_style", "CSSParserImpl::parseStyleSheet", | |
249 "tokenCount", tokenizer.tokenCount(), "length", | |
250 string.length()); | |
251 } | 239 } |
252 | 240 |
253 CSSSelectorList CSSParserImpl::parsePageSelector( | 241 CSSSelectorList CSSParserImpl::parsePageSelector( |
254 CSSParserTokenRange range, | 242 CSSParserTokenRange range, |
255 StyleSheetContents* styleSheet) { | 243 StyleSheetContents* styleSheet) { |
256 // We only support a small subset of the css-page spec. | 244 // We only support a small subset of the css-page spec. |
257 range.consumeWhitespace(); | 245 range.consumeWhitespace(); |
258 AtomicString typeSelector; | 246 AtomicString typeSelector; |
259 if (range.peek().type() == IdentToken) | 247 if (range.peek().type() == IdentToken) |
260 typeSelector = range.consume().value().toAtomicString(); | 248 typeSelector = range.consume().value().toAtomicString(); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 ImmutableStylePropertySet* CSSParserImpl::parseCustomPropertySet( | 288 ImmutableStylePropertySet* CSSParserImpl::parseCustomPropertySet( |
301 CSSParserTokenRange range) { | 289 CSSParserTokenRange range) { |
302 range.consumeWhitespace(); | 290 range.consumeWhitespace(); |
303 if (range.peek().type() != LeftBraceToken) | 291 if (range.peek().type() != LeftBraceToken) |
304 return nullptr; | 292 return nullptr; |
305 CSSParserTokenRange block = range.consumeBlock(); | 293 CSSParserTokenRange block = range.consumeBlock(); |
306 range.consumeWhitespace(); | 294 range.consumeWhitespace(); |
307 if (!range.atEnd()) | 295 if (!range.atEnd()) |
308 return nullptr; | 296 return nullptr; |
309 CSSParserImpl parser(strictCSSParserContext()); | 297 CSSParserImpl parser(strictCSSParserContext()); |
310 parser.consumeDeclarationList(block, StyleRule::Style); | 298 parser.consumeDeclarationListForAtApply(block); |
311 | |
312 // Drop nested @apply rules. Seems nicer to do this here instead of making | |
313 // a different StyleRule type | |
314 for (size_t i = parser.m_parsedProperties.size(); i--;) { | |
315 if (parser.m_parsedProperties[i].id() == CSSPropertyApplyAtRule) | |
316 parser.m_parsedProperties.remove(i); | |
317 } | |
318 | |
319 return createStylePropertySet(parser.m_parsedProperties, HTMLStandardMode); | 299 return createStylePropertySet(parser.m_parsedProperties, HTMLStandardMode); |
320 } | 300 } |
321 | 301 |
322 std::unique_ptr<Vector<double>> CSSParserImpl::parseKeyframeKeyList( | 302 std::unique_ptr<Vector<double>> CSSParserImpl::parseKeyframeKeyList( |
323 const String& keyList) { | 303 const String& keyList) { |
324 return consumeKeyframeKeyList(CSSTokenizer(keyList).tokenRange()); | 304 return consumeKeyframeKeyList(CSSTokenizer(keyList).tokenRange()); |
325 } | 305 } |
326 | 306 |
327 bool CSSParserImpl::supportsDeclaration(CSSParserTokenRange& range) { | 307 bool CSSParserImpl::supportsDeclaration(CSSParserTokenRange& range) { |
328 ASSERT(m_parsedProperties.isEmpty()); | 308 ASSERT(m_parsedProperties.isEmpty()); |
329 consumeDeclaration(range, StyleRule::Style); | 309 consumeDeclaration(range, StyleRule::Style, 0, 0); |
330 bool result = !m_parsedProperties.isEmpty(); | 310 bool result = !m_parsedProperties.isEmpty(); |
331 m_parsedProperties.clear(); | 311 m_parsedProperties.clear(); |
332 return result; | 312 return result; |
333 } | 313 } |
334 | 314 |
335 void CSSParserImpl::parseDeclarationListForInspector( | 315 void CSSParserImpl::parseDeclarationListForInspector( |
336 const String& declaration, | 316 const String& declaration, |
337 const CSSParserContext& context, | 317 const CSSParserContext& context, |
338 CSSParserObserver& observer) { | 318 CSSParserObserver& observer) { |
339 CSSParserImpl parser(context); | |
340 CSSParserObserverWrapper wrapper(observer); | |
341 parser.m_observerWrapper = &wrapper; | |
342 CSSTokenizer tokenizer(declaration, wrapper); | |
343 observer.startRuleHeader(StyleRule::Style, 0); | 319 observer.startRuleHeader(StyleRule::Style, 0); |
344 observer.endRuleHeader(1); | 320 observer.endRuleHeader(1); |
345 parser.consumeDeclarationList(tokenizer.tokenRange(), StyleRule::Style); | 321 |
| 322 CSSParserImpl parser(context); |
| 323 parser.m_observer = &observer; |
| 324 CSSTokenizer tokenizer(declaration); |
| 325 CSSParserTokenStream stream(tokenizer); |
| 326 parser.consumeDeclarationList(stream, StyleRule::Style); |
346 } | 327 } |
347 | 328 |
348 void CSSParserImpl::parseStyleSheetForInspector(const String& string, | 329 void CSSParserImpl::parseStyleSheetForInspector(const String& string, |
349 const CSSParserContext& context, | 330 const CSSParserContext& context, |
350 StyleSheetContents* styleSheet, | 331 StyleSheetContents* styleSheet, |
351 CSSParserObserver& observer) { | 332 CSSParserObserver& observer) { |
| 333 CSSTokenizer tokenizer(string); |
| 334 CSSParserTokenStream stream(tokenizer); |
352 CSSParserImpl parser(context, styleSheet); | 335 CSSParserImpl parser(context, styleSheet); |
353 CSSParserObserverWrapper wrapper(observer); | 336 parser.m_observer = &observer; |
354 parser.m_observerWrapper = &wrapper; | 337 bool firstRuleValid = parser.consumeRuleList( |
355 CSSTokenizer tokenizer(string, wrapper); | 338 stream, TopLevelRuleList, [&styleSheet](StyleRuleBase* rule) { |
356 bool firstRuleValid = | 339 if (rule->isCharsetRule()) |
357 parser.consumeRuleList(tokenizer.tokenRange(), TopLevelRuleList, | 340 return; |
358 [&styleSheet](StyleRuleBase* rule) { | 341 styleSheet->parserAppendRule(rule); |
359 if (rule->isCharsetRule()) | 342 }); |
360 return; | |
361 styleSheet->parserAppendRule(rule); | |
362 }); | |
363 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); | 343 styleSheet->setHasSyntacticallyValidCSSHeader(firstRuleValid); |
364 } | 344 } |
365 | 345 |
366 StylePropertySet* CSSParserImpl::parseDeclarationListForLazyStyle( | 346 StylePropertySet* CSSParserImpl::parseDeclarationListForLazyStyle( |
367 CSSParserTokenRange block, | 347 const String& string, |
| 348 size_t startOffset, |
368 const CSSParserContext& context) { | 349 const CSSParserContext& context) { |
| 350 CSSTokenizer tokenizer(string, startOffset); |
| 351 CSSParserTokenStream stream(tokenizer); |
| 352 stream.peek(); |
| 353 // We can't start the stream inside the block as the } wouldn't end the |
| 354 // stream. |
| 355 CSSParserTokenStream block(stream, CSSParserTokenStream::MakeSubStream); |
369 CSSParserImpl parser(context); | 356 CSSParserImpl parser(context); |
370 parser.consumeDeclarationList(std::move(block), StyleRule::Style); | 357 parser.consumeDeclarationList(block, StyleRule::Style); |
371 return createStylePropertySet(parser.m_parsedProperties, context.mode()); | 358 return createStylePropertySet(parser.m_parsedProperties, context.mode()); |
372 } | 359 } |
373 | 360 |
374 static CSSParserImpl::AllowedRulesType computeNewAllowedRules( | 361 static CSSParserImpl::AllowedRulesType computeNewAllowedRules( |
375 CSSParserImpl::AllowedRulesType allowedRules, | 362 CSSParserImpl::AllowedRulesType allowedRules, |
376 StyleRuleBase* rule) { | 363 StyleRuleBase* rule) { |
377 if (!rule || allowedRules == CSSParserImpl::KeyframeRules || | 364 if (!rule || allowedRules == CSSParserImpl::KeyframeRules || |
378 allowedRules == CSSParserImpl::NoRules) | 365 allowedRules == CSSParserImpl::NoRules) |
379 return allowedRules; | 366 return allowedRules; |
380 ASSERT(allowedRules <= CSSParserImpl::RegularRules); | 367 ASSERT(allowedRules <= CSSParserImpl::RegularRules); |
381 if (rule->isCharsetRule() || rule->isImportRule()) | 368 if (rule->isCharsetRule() || rule->isImportRule()) |
382 return CSSParserImpl::AllowImportRules; | 369 return CSSParserImpl::AllowImportRules; |
383 if (rule->isNamespaceRule()) | 370 if (rule->isNamespaceRule()) |
384 return CSSParserImpl::AllowNamespaceRules; | 371 return CSSParserImpl::AllowNamespaceRules; |
385 return CSSParserImpl::RegularRules; | 372 return CSSParserImpl::RegularRules; |
386 } | 373 } |
387 | 374 |
388 template <typename T> | 375 template <typename T> |
389 bool CSSParserImpl::consumeRuleList(CSSParserTokenRange range, | 376 bool CSSParserImpl::consumeRuleList(CSSParserTokenStream& stream, |
390 RuleListType ruleListType, | 377 RuleListType ruleListType, |
391 const T callback) { | 378 const T callback) { |
392 AllowedRulesType allowedRules = RegularRules; | 379 AllowedRulesType allowedRules = RegularRules; |
393 switch (ruleListType) { | 380 switch (ruleListType) { |
394 case TopLevelRuleList: | 381 case TopLevelRuleList: |
395 allowedRules = AllowCharsetRules; | 382 allowedRules = AllowCharsetRules; |
396 break; | 383 break; |
397 case RegularRuleList: | 384 case RegularRuleList: |
398 allowedRules = RegularRules; | 385 allowedRules = RegularRules; |
399 break; | 386 break; |
400 case KeyframesRuleList: | 387 case KeyframesRuleList: |
401 allowedRules = KeyframeRules; | 388 allowedRules = KeyframeRules; |
402 break; | 389 break; |
403 default: | 390 default: |
404 ASSERT_NOT_REACHED(); | 391 ASSERT_NOT_REACHED(); |
405 } | 392 } |
406 | 393 |
407 bool seenRule = false; | 394 bool seenRule = false; |
408 bool firstRuleValid = false; | 395 bool firstRuleValid = false; |
409 while (!range.atEnd()) { | 396 while (true) { |
410 StyleRuleBase* rule; | 397 StyleRuleBase* rule; |
411 switch (range.peek().type()) { | 398 size_t qualifiedRuleStartOffset = stream.offsetAfterComments(); |
| 399 if (stream.atEnd()) |
| 400 break; |
| 401 switch (stream.peek().type()) { |
412 case WhitespaceToken: | 402 case WhitespaceToken: |
413 range.consumeWhitespace(); | 403 stream.consume(); |
414 continue; | 404 continue; |
415 case AtKeywordToken: | 405 case AtKeywordToken: |
416 rule = consumeAtRule(range, allowedRules); | 406 rule = consumeAtRule(stream, allowedRules); |
| 407 stream.clean(); |
417 break; | 408 break; |
418 case CDOToken: | 409 case CDOToken: |
419 case CDCToken: | 410 case CDCToken: |
420 if (ruleListType == TopLevelRuleList) { | 411 if (ruleListType == TopLevelRuleList) { |
421 range.consume(); | 412 stream.consume(); |
422 continue; | 413 continue; |
423 } | 414 } |
424 // fallthrough | 415 // fallthrough |
425 default: | 416 default: |
426 rule = consumeQualifiedRule(range, allowedRules); | 417 rule = consumeQualifiedRule(stream, allowedRules, |
| 418 qualifiedRuleStartOffset); |
| 419 stream.clean(); |
427 break; | 420 break; |
428 } | 421 } |
429 if (!seenRule) { | 422 if (!seenRule) { |
430 seenRule = true; | 423 seenRule = true; |
431 firstRuleValid = rule; | 424 firstRuleValid = rule; |
432 } | 425 } |
433 if (rule) { | 426 if (rule) { |
434 allowedRules = computeNewAllowedRules(allowedRules, rule); | 427 allowedRules = computeNewAllowedRules(allowedRules, rule); |
435 callback(rule); | 428 callback(rule); |
436 } | 429 } |
437 } | 430 } |
438 | 431 |
439 return firstRuleValid; | 432 return firstRuleValid; |
440 } | 433 } |
441 | 434 |
442 StyleRuleBase* CSSParserImpl::consumeAtRule(CSSParserTokenRange& range, | 435 StyleRuleBase* CSSParserImpl::consumeAtRule(CSSParserTokenStream& stream, |
443 AllowedRulesType allowedRules) { | 436 AllowedRulesType allowedRules) { |
444 ASSERT(range.peek().type() == AtKeywordToken); | 437 DCHECK_EQ(stream.peek().type(), AtKeywordToken); |
445 const StringView name = range.consumeIncludingWhitespace().value(); | 438 const StringView name = stream.peek().value(); |
446 const CSSParserToken* preludeStart = &range.peek(); | 439 stream.consume(); |
447 while (!range.atEnd() && range.peek().type() != LeftBraceToken && | 440 stream.skipWhitespaceAndComments(); |
448 range.peek().type() != SemicolonToken) | 441 size_t preludeStartOffset = stream.offset(); |
449 range.consumeComponentValue(); | 442 size_t preludeStart = stream.index(); |
| 443 stream.consumeUntilAtEndOrPeekedTypeIs<LeftBraceToken, SemicolonToken>(); |
450 | 444 |
451 CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek()); | 445 CSSParserTokenRange prelude = stream.makeSubRangeFrom(preludeStart); |
452 CSSAtRuleID id = cssAtRuleID(name); | 446 CSSAtRuleID id = cssAtRuleID(name); |
453 if (id != CSSAtRuleInvalid && m_context.useCounter()) | 447 if (id != CSSAtRuleInvalid && m_context.useCounter()) |
454 countAtRule(m_context.useCounter(), id); | 448 countAtRule(m_context.useCounter(), id); |
455 | 449 |
456 if (range.atEnd() || range.peek().type() == SemicolonToken) { | 450 if (stream.atEnd() || stream.peek().type() == SemicolonToken) { |
457 range.consume(); | 451 size_t preludeEndOffset = stream.previousOffset(); |
| 452 if (!stream.atEnd()) |
| 453 stream.consume(); |
458 if (allowedRules == AllowCharsetRules && id == CSSAtRuleCharset) | 454 if (allowedRules == AllowCharsetRules && id == CSSAtRuleCharset) |
459 return consumeCharsetRule(prelude); | 455 return consumeCharsetRule(prelude); |
460 if (allowedRules <= AllowImportRules && id == CSSAtRuleImport) | 456 if (allowedRules <= AllowImportRules && id == CSSAtRuleImport) |
461 return consumeImportRule(prelude); | 457 return consumeImportRule(prelude, preludeStartOffset, preludeEndOffset); |
462 if (allowedRules <= AllowNamespaceRules && id == CSSAtRuleNamespace) | 458 if (allowedRules <= AllowNamespaceRules && id == CSSAtRuleNamespace) |
463 return consumeNamespaceRule(prelude); | 459 return consumeNamespaceRule(prelude); |
464 if (allowedRules == ApplyRules && id == CSSAtRuleApply) { | 460 if (allowedRules == ApplyRules && id == CSSAtRuleApply) { |
465 consumeApplyRule(prelude); | 461 consumeApplyRule(prelude); |
466 return nullptr; // consumeApplyRule just updates m_parsedProperties | 462 return nullptr; // consumeApplyRule just updates m_parsedProperties |
467 } | 463 } |
468 return nullptr; // Parse error, unrecognised at-rule without block | 464 return nullptr; // Parse error, unrecognised at-rule without block |
469 } | 465 } |
470 | 466 |
471 CSSParserTokenRange block = range.consumeBlock(); | 467 CSSParserTokenStream block(stream, CSSParserTokenStream::MakeSubStream); |
472 if (allowedRules == KeyframeRules) | 468 if (allowedRules == KeyframeRules) |
473 return nullptr; // Parse error, no at-rules supported inside @keyframes | 469 return nullptr; // Parse error, no at-rules supported inside @keyframes |
474 if (allowedRules == NoRules || allowedRules == ApplyRules) | 470 if (allowedRules == NoRules || allowedRules == ApplyRules) |
475 return nullptr; // Parse error, no at-rules with blocks supported inside | 471 return nullptr; // Parse error, no at-rules with blocks supported inside |
476 // declaration lists | 472 // declaration lists |
477 | 473 |
478 ASSERT(allowedRules <= RegularRules); | 474 ASSERT(allowedRules <= RegularRules); |
479 | 475 |
480 switch (id) { | 476 switch (id) { |
481 case CSSAtRuleMedia: | 477 case CSSAtRuleMedia: |
482 return consumeMediaRule(prelude, block); | 478 return consumeMediaRule(prelude, block, preludeStartOffset); |
483 case CSSAtRuleSupports: | 479 case CSSAtRuleSupports: |
484 return consumeSupportsRule(prelude, block); | 480 return consumeSupportsRule(prelude, block, preludeStartOffset); |
485 case CSSAtRuleViewport: | 481 case CSSAtRuleViewport: |
486 return consumeViewportRule(prelude, block); | 482 return consumeViewportRule(prelude, block, preludeStartOffset); |
487 case CSSAtRuleFontFace: | 483 case CSSAtRuleFontFace: |
488 return consumeFontFaceRule(prelude, block); | 484 return consumeFontFaceRule(prelude, block, preludeStartOffset); |
489 case CSSAtRuleWebkitKeyframes: | 485 case CSSAtRuleWebkitKeyframes: |
490 return consumeKeyframesRule(true, prelude, block); | 486 return consumeKeyframesRule(true, prelude, block, preludeStartOffset); |
491 case CSSAtRuleKeyframes: | 487 case CSSAtRuleKeyframes: |
492 return consumeKeyframesRule(false, prelude, block); | 488 return consumeKeyframesRule(false, prelude, block, preludeStartOffset); |
493 case CSSAtRulePage: | 489 case CSSAtRulePage: |
494 return consumePageRule(prelude, block); | 490 return consumePageRule(prelude, block, preludeStartOffset); |
495 default: | 491 default: |
496 return nullptr; // Parse error, unrecognised at-rule with block | 492 return nullptr; // Parse error, unrecognised at-rule with block |
497 } | 493 } |
498 } | 494 } |
499 | 495 |
500 StyleRuleBase* CSSParserImpl::consumeQualifiedRule( | 496 StyleRuleBase* CSSParserImpl::consumeQualifiedRule( |
501 CSSParserTokenRange& range, | 497 CSSParserTokenStream& stream, |
502 AllowedRulesType allowedRules) { | 498 AllowedRulesType allowedRules, |
503 const CSSParserToken* preludeStart = &range.peek(); | 499 size_t startOffset) { |
504 while (!range.atEnd() && range.peek().type() != LeftBraceToken) | 500 if (allowedRules <= RegularRules) |
505 range.consumeComponentValue(); | 501 return consumeStyleRule(stream, startOffset); |
506 | 502 |
507 if (range.atEnd()) | 503 size_t preludeStart = stream.index(); |
| 504 stream.consumeUntilAtEndOrPeekedTypeIs<LeftBraceToken>(); |
| 505 |
| 506 if (stream.atEnd()) |
508 return nullptr; // Parse error, EOF instead of qualified rule block | 507 return nullptr; // Parse error, EOF instead of qualified rule block |
509 | 508 |
510 CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek()); | 509 CSSParserTokenRange prelude = stream.makeSubRangeFrom(preludeStart); |
511 CSSParserTokenRange block = range.consumeBlock(); | 510 CSSParserTokenStream block(stream, CSSParserTokenStream::MakeSubStream); |
512 | 511 DCHECK(allowedRules == KeyframeRules); |
513 if (allowedRules <= RegularRules) | 512 return consumeKeyframeStyleRule(prelude, block, startOffset); |
514 return consumeStyleRule(prelude, block); | |
515 if (allowedRules == KeyframeRules) | |
516 return consumeKeyframeStyleRule(prelude, block); | |
517 | |
518 ASSERT_NOT_REACHED(); | |
519 return nullptr; | |
520 } | 513 } |
521 | 514 |
522 // This may still consume tokens if it fails | 515 // This may still consume tokens if it fails |
523 static AtomicString consumeStringOrURI(CSSParserTokenRange& range) { | 516 static AtomicString consumeStringOrURI(CSSParserTokenRange& range) { |
524 const CSSParserToken& token = range.peek(); | 517 const CSSParserToken& token = range.peek(); |
525 | 518 |
526 if (token.type() == StringToken || token.type() == UrlToken) | 519 if (token.type() == StringToken || token.type() == UrlToken) |
527 return range.consumeIncludingWhitespace().value().toAtomicString(); | 520 return range.consumeIncludingWhitespace().value().toAtomicString(); |
528 | 521 |
529 if (token.type() != FunctionToken || | 522 if (token.type() != FunctionToken || |
530 !equalIgnoringASCIICase(token.value(), "url")) | 523 !equalIgnoringASCIICase(token.value(), "url")) |
531 return AtomicString(); | 524 return AtomicString(); |
532 | 525 |
533 CSSParserTokenRange contents = range.consumeBlock(); | 526 CSSParserTokenRange contents = range.consumeBlock(); |
534 const CSSParserToken& uri = contents.consumeIncludingWhitespace(); | 527 const CSSParserToken& uri = contents.consumeIncludingWhitespace(); |
535 if (uri.type() == BadStringToken || !contents.atEnd()) | 528 if (uri.type() == BadStringToken || !contents.atEnd()) |
536 return AtomicString(); | 529 return AtomicString(); |
537 DCHECK_EQ(uri.type(), StringToken); | 530 DCHECK_EQ(uri.type(), StringToken); |
538 return uri.value().toAtomicString(); | 531 return uri.value().toAtomicString(); |
539 } | 532 } |
540 | 533 |
541 StyleRuleCharset* CSSParserImpl::consumeCharsetRule( | 534 StyleRuleCharset* CSSParserImpl::consumeCharsetRule( |
542 CSSParserTokenRange prelude) { | 535 CSSParserTokenRange prelude) { |
543 const CSSParserToken& string = prelude.consumeIncludingWhitespace(); | 536 const CSSParserToken& string = prelude.consumeIncludingWhitespace(); |
544 if (string.type() != StringToken || !prelude.atEnd()) | 537 if (string.type() != StringToken || !prelude.atEnd()) |
545 return nullptr; // Parse error, expected a single string | 538 return nullptr; // Parse error, expected a single string |
546 return StyleRuleCharset::create(); | 539 return StyleRuleCharset::create(); |
547 } | 540 } |
548 | 541 |
549 StyleRuleImport* CSSParserImpl::consumeImportRule(CSSParserTokenRange prelude) { | 542 StyleRuleImport* CSSParserImpl::consumeImportRule(CSSParserTokenRange prelude, |
| 543 size_t startOffset, |
| 544 size_t endOffset) { |
550 AtomicString uri(consumeStringOrURI(prelude)); | 545 AtomicString uri(consumeStringOrURI(prelude)); |
551 if (uri.isNull()) | 546 if (uri.isNull()) |
552 return nullptr; // Parse error, expected string or URI | 547 return nullptr; // Parse error, expected string or URI |
553 | 548 |
554 if (m_observerWrapper) { | 549 if (m_observer) { |
555 unsigned endOffset = m_observerWrapper->endOffset(prelude); | 550 m_observer->startRuleHeader(StyleRule::Import, startOffset); |
556 m_observerWrapper->observer().startRuleHeader( | 551 m_observer->endRuleHeader(endOffset); |
557 StyleRule::Import, m_observerWrapper->startOffset(prelude)); | 552 m_observer->startRuleBody(endOffset); |
558 m_observerWrapper->observer().endRuleHeader(endOffset); | 553 m_observer->endRuleBody(endOffset); |
559 m_observerWrapper->observer().startRuleBody(endOffset); | |
560 m_observerWrapper->observer().endRuleBody(endOffset); | |
561 } | 554 } |
562 | 555 |
563 return StyleRuleImport::create(uri, | 556 return StyleRuleImport::create(uri, |
564 MediaQueryParser::parseMediaQuerySet(prelude)); | 557 MediaQueryParser::parseMediaQuerySet(prelude)); |
565 } | 558 } |
566 | 559 |
567 StyleRuleNamespace* CSSParserImpl::consumeNamespaceRule( | 560 StyleRuleNamespace* CSSParserImpl::consumeNamespaceRule( |
568 CSSParserTokenRange prelude) { | 561 CSSParserTokenRange prelude) { |
569 AtomicString namespacePrefix; | 562 AtomicString namespacePrefix; |
570 if (prelude.peek().type() == IdentToken) | 563 if (prelude.peek().type() == IdentToken) |
571 namespacePrefix = | 564 namespacePrefix = |
572 prelude.consumeIncludingWhitespace().value().toAtomicString(); | 565 prelude.consumeIncludingWhitespace().value().toAtomicString(); |
573 | 566 |
574 AtomicString uri(consumeStringOrURI(prelude)); | 567 AtomicString uri(consumeStringOrURI(prelude)); |
575 if (uri.isNull() || !prelude.atEnd()) | 568 if (uri.isNull() || !prelude.atEnd()) |
576 return nullptr; // Parse error, expected string or URI | 569 return nullptr; // Parse error, expected string or URI |
577 | 570 |
578 return StyleRuleNamespace::create(namespacePrefix, uri); | 571 return StyleRuleNamespace::create(namespacePrefix, uri); |
579 } | 572 } |
580 | 573 |
581 StyleRuleMedia* CSSParserImpl::consumeMediaRule(CSSParserTokenRange prelude, | 574 StyleRuleMedia* CSSParserImpl::consumeMediaRule(CSSParserTokenRange prelude, |
582 CSSParserTokenRange block) { | 575 CSSParserTokenStream& block, |
| 576 size_t preludeStartOffset) { |
583 HeapVector<Member<StyleRuleBase>> rules; | 577 HeapVector<Member<StyleRuleBase>> rules; |
584 | 578 |
585 if (m_observerWrapper) { | 579 if (m_observer) { |
586 m_observerWrapper->observer().startRuleHeader( | 580 m_observer->startRuleHeader(StyleRule::Media, preludeStartOffset); |
587 StyleRule::Media, m_observerWrapper->startOffset(prelude)); | 581 m_observer->endRuleHeader(block.offset() - 1); |
588 m_observerWrapper->observer().endRuleHeader( | 582 m_observer->startRuleBody(block.offset() - 1); |
589 m_observerWrapper->endOffset(prelude)); | |
590 m_observerWrapper->observer().startRuleBody( | |
591 m_observerWrapper->previousTokenStartOffset(block)); | |
592 } | 583 } |
593 | 584 |
594 if (m_styleSheet) | 585 if (m_styleSheet) |
595 m_styleSheet->setHasMediaQueries(); | 586 m_styleSheet->setHasMediaQueries(); |
596 | 587 |
597 consumeRuleList(block, RegularRuleList, | 588 consumeRuleList(block, RegularRuleList, |
598 [&rules](StyleRuleBase* rule) { rules.push_back(rule); }); | 589 [&rules](StyleRuleBase* rule) { rules.push_back(rule); }); |
599 | 590 |
600 if (m_observerWrapper) | 591 if (m_observer) |
601 m_observerWrapper->observer().endRuleBody( | 592 m_observer->endRuleBody(block.offset()); |
602 m_observerWrapper->endOffset(block)); | |
603 | 593 |
604 return StyleRuleMedia::create(MediaQueryParser::parseMediaQuerySet(prelude), | 594 return StyleRuleMedia::create(MediaQueryParser::parseMediaQuerySet(prelude), |
605 rules); | 595 rules); |
606 } | 596 } |
607 | 597 |
608 StyleRuleSupports* CSSParserImpl::consumeSupportsRule( | 598 StyleRuleSupports* CSSParserImpl::consumeSupportsRule( |
609 CSSParserTokenRange prelude, | 599 CSSParserTokenRange prelude, |
610 CSSParserTokenRange block) { | 600 CSSParserTokenStream& block, |
| 601 size_t preludeStartOffset) { |
611 CSSSupportsParser::SupportsResult supported = | 602 CSSSupportsParser::SupportsResult supported = |
612 CSSSupportsParser::supportsCondition(prelude, *this); | 603 CSSSupportsParser::supportsCondition(prelude, *this); |
613 if (supported == CSSSupportsParser::Invalid) | 604 if (supported == CSSSupportsParser::Invalid) |
614 return nullptr; // Parse error, invalid @supports condition | 605 return nullptr; // Parse error, invalid @supports condition |
615 | 606 |
616 if (m_observerWrapper) { | 607 if (m_observer) { |
617 m_observerWrapper->observer().startRuleHeader( | 608 m_observer->startRuleHeader(StyleRule::Supports, preludeStartOffset); |
618 StyleRule::Supports, m_observerWrapper->startOffset(prelude)); | 609 m_observer->endRuleHeader(block.offset() - 1); |
619 m_observerWrapper->observer().endRuleHeader( | 610 m_observer->startRuleBody(block.offset() - 1); |
620 m_observerWrapper->endOffset(prelude)); | |
621 m_observerWrapper->observer().startRuleBody( | |
622 m_observerWrapper->previousTokenStartOffset(block)); | |
623 } | 611 } |
624 | 612 |
625 HeapVector<Member<StyleRuleBase>> rules; | 613 HeapVector<Member<StyleRuleBase>> rules; |
626 consumeRuleList(block, RegularRuleList, | 614 consumeRuleList(block, RegularRuleList, |
627 [&rules](StyleRuleBase* rule) { rules.push_back(rule); }); | 615 [&rules](StyleRuleBase* rule) { rules.push_back(rule); }); |
628 | 616 |
629 if (m_observerWrapper) | 617 if (m_observer) |
630 m_observerWrapper->observer().endRuleBody( | 618 m_observer->endRuleBody(block.offset()); |
631 m_observerWrapper->endOffset(block)); | |
632 | 619 |
633 return StyleRuleSupports::create(prelude.serialize().stripWhiteSpace(), | 620 return StyleRuleSupports::create(prelude.serialize().stripWhiteSpace(), |
634 supported, rules); | 621 supported, rules); |
635 } | 622 } |
636 | 623 |
637 StyleRuleViewport* CSSParserImpl::consumeViewportRule( | 624 StyleRuleViewport* CSSParserImpl::consumeViewportRule( |
638 CSSParserTokenRange prelude, | 625 CSSParserTokenRange prelude, |
639 CSSParserTokenRange block) { | 626 CSSParserTokenStream& block, |
| 627 size_t preludeStartOffset) { |
640 // Allow @viewport rules from UA stylesheets even if the feature is disabled. | 628 // Allow @viewport rules from UA stylesheets even if the feature is disabled. |
641 if (!RuntimeEnabledFeatures::cssViewportEnabled() && | 629 if (!RuntimeEnabledFeatures::cssViewportEnabled() && |
642 !isUASheetBehavior(m_context.mode())) | 630 !isUASheetBehavior(m_context.mode())) |
643 return nullptr; | 631 return nullptr; |
644 | 632 |
645 if (!prelude.atEnd()) | 633 if (!prelude.atEnd()) |
646 return nullptr; // Parser error; @viewport prelude should be empty | 634 return nullptr; // Parser error; @viewport prelude should be empty |
647 | 635 |
648 if (m_observerWrapper) { | 636 if (m_observer) { |
649 unsigned endOffset = m_observerWrapper->endOffset(prelude); | 637 m_observer->startRuleHeader(StyleRule::Viewport, preludeStartOffset); |
650 m_observerWrapper->observer().startRuleHeader( | 638 m_observer->endRuleHeader(block.offset() - 1); |
651 StyleRule::Viewport, m_observerWrapper->startOffset(prelude)); | 639 m_observer->startRuleBody(block.offset() - 1); |
652 m_observerWrapper->observer().endRuleHeader(endOffset); | 640 m_observer->endRuleBody(block.offset() - 1); |
653 m_observerWrapper->observer().startRuleBody(endOffset); | |
654 m_observerWrapper->observer().endRuleBody(endOffset); | |
655 } | 641 } |
656 | 642 |
657 if (m_styleSheet) | 643 if (m_styleSheet) |
658 m_styleSheet->setHasViewportRule(); | 644 m_styleSheet->setHasViewportRule(); |
659 | 645 |
660 consumeDeclarationList(block, StyleRule::Viewport); | 646 consumeDeclarationList(block, StyleRule::Viewport); |
661 return StyleRuleViewport::create( | 647 return StyleRuleViewport::create( |
662 createStylePropertySet(m_parsedProperties, CSSViewportRuleMode)); | 648 createStylePropertySet(m_parsedProperties, CSSViewportRuleMode)); |
663 } | 649 } |
664 | 650 |
665 StyleRuleFontFace* CSSParserImpl::consumeFontFaceRule( | 651 StyleRuleFontFace* CSSParserImpl::consumeFontFaceRule( |
666 CSSParserTokenRange prelude, | 652 CSSParserTokenRange prelude, |
667 CSSParserTokenRange block) { | 653 CSSParserTokenStream& block, |
| 654 size_t preludeStartOffset) { |
668 if (!prelude.atEnd()) | 655 if (!prelude.atEnd()) |
669 return nullptr; // Parse error; @font-face prelude should be empty | 656 return nullptr; // Parse error; @font-face prelude should be empty |
670 | 657 |
671 if (m_observerWrapper) { | 658 if (m_observer) { |
672 unsigned endOffset = m_observerWrapper->endOffset(prelude); | 659 m_observer->startRuleHeader(StyleRule::FontFace, preludeStartOffset); |
673 m_observerWrapper->observer().startRuleHeader( | 660 m_observer->endRuleHeader(block.offset() - 1); |
674 StyleRule::FontFace, m_observerWrapper->startOffset(prelude)); | 661 m_observer->startRuleBody(block.offset() - 1); |
675 m_observerWrapper->observer().endRuleHeader(endOffset); | 662 m_observer->endRuleBody(block.offset() - 1); |
676 m_observerWrapper->observer().startRuleBody(endOffset); | |
677 m_observerWrapper->observer().endRuleBody(endOffset); | |
678 } | 663 } |
679 | 664 |
680 if (m_styleSheet) | 665 if (m_styleSheet) |
681 m_styleSheet->setHasFontFaceRule(); | 666 m_styleSheet->setHasFontFaceRule(); |
682 | 667 |
683 consumeDeclarationList(block, StyleRule::FontFace); | 668 consumeDeclarationList(block, StyleRule::FontFace); |
684 return StyleRuleFontFace::create( | 669 return StyleRuleFontFace::create( |
685 createStylePropertySet(m_parsedProperties, CSSFontFaceRuleMode)); | 670 createStylePropertySet(m_parsedProperties, CSSFontFaceRuleMode)); |
686 } | 671 } |
687 | 672 |
688 StyleRuleKeyframes* CSSParserImpl::consumeKeyframesRule( | 673 StyleRuleKeyframes* CSSParserImpl::consumeKeyframesRule( |
689 bool webkitPrefixed, | 674 bool webkitPrefixed, |
690 CSSParserTokenRange prelude, | 675 CSSParserTokenRange prelude, |
691 CSSParserTokenRange block) { | 676 CSSParserTokenStream& block, |
692 CSSParserTokenRange rangeCopy = prelude; // For inspector callbacks | 677 size_t preludeStartOffset) { |
693 const CSSParserToken& nameToken = prelude.consumeIncludingWhitespace(); | 678 const CSSParserToken& nameToken = prelude.consumeIncludingWhitespace(); |
694 if (!prelude.atEnd()) | 679 if (!prelude.atEnd()) |
695 return nullptr; // Parse error; expected single non-whitespace token in | 680 return nullptr; // Parse error; expected single non-whitespace token in |
696 // @keyframes header | 681 // @keyframes header |
697 | 682 |
698 String name; | 683 String name; |
699 if (nameToken.type() == IdentToken) { | 684 if (nameToken.type() == IdentToken) { |
700 name = nameToken.value().toString(); | 685 name = nameToken.value().toString(); |
701 } else if (nameToken.type() == StringToken && webkitPrefixed) { | 686 } else if (nameToken.type() == StringToken && webkitPrefixed) { |
702 if (m_context.useCounter()) | 687 if (m_context.useCounter()) |
703 m_context.useCounter()->count(UseCounter::QuotedKeyframesRule); | 688 m_context.useCounter()->count(UseCounter::QuotedKeyframesRule); |
704 name = nameToken.value().toString(); | 689 name = nameToken.value().toString(); |
705 } else { | 690 } else { |
706 return nullptr; // Parse error; expected ident token in @keyframes header | 691 return nullptr; // Parse error; expected ident token in @keyframes header |
707 } | 692 } |
708 | 693 |
709 if (m_observerWrapper) { | 694 if (m_observer) { |
710 m_observerWrapper->observer().startRuleHeader( | 695 m_observer->startRuleHeader(StyleRule::Keyframes, preludeStartOffset); |
711 StyleRule::Keyframes, m_observerWrapper->startOffset(rangeCopy)); | 696 m_observer->endRuleHeader(block.offset() - 1); |
712 m_observerWrapper->observer().endRuleHeader( | 697 m_observer->startRuleBody(block.offset() - 1); |
713 m_observerWrapper->endOffset(prelude)); | |
714 m_observerWrapper->observer().startRuleBody( | |
715 m_observerWrapper->previousTokenStartOffset(block)); | |
716 m_observerWrapper->observer().endRuleBody( | |
717 m_observerWrapper->endOffset(block)); | |
718 } | 698 } |
719 | 699 |
720 StyleRuleKeyframes* keyframeRule = StyleRuleKeyframes::create(); | 700 StyleRuleKeyframes* keyframeRule = StyleRuleKeyframes::create(); |
721 consumeRuleList( | 701 consumeRuleList( |
722 block, KeyframesRuleList, [keyframeRule](StyleRuleBase* keyframe) { | 702 block, KeyframesRuleList, [keyframeRule](StyleRuleBase* keyframe) { |
723 keyframeRule->parserAppendKeyframe(toStyleRuleKeyframe(keyframe)); | 703 keyframeRule->parserAppendKeyframe(toStyleRuleKeyframe(keyframe)); |
724 }); | 704 }); |
725 keyframeRule->setName(name); | 705 keyframeRule->setName(name); |
726 keyframeRule->setVendorPrefixed(webkitPrefixed); | 706 keyframeRule->setVendorPrefixed(webkitPrefixed); |
| 707 |
| 708 if (m_observer) |
| 709 m_observer->endRuleBody(block.offset()); |
| 710 |
727 return keyframeRule; | 711 return keyframeRule; |
728 } | 712 } |
729 | 713 |
730 StyleRulePage* CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, | 714 StyleRulePage* CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, |
731 CSSParserTokenRange block) { | 715 CSSParserTokenStream& block, |
| 716 size_t preludeStartOffset) { |
732 CSSSelectorList selectorList = parsePageSelector(prelude, m_styleSheet); | 717 CSSSelectorList selectorList = parsePageSelector(prelude, m_styleSheet); |
733 if (!selectorList.isValid()) | 718 if (!selectorList.isValid()) |
734 return nullptr; // Parse error, invalid @page selector | 719 return nullptr; // Parse error, invalid @page selector |
735 | 720 |
736 if (m_observerWrapper) { | 721 if (m_observer) { |
737 unsigned endOffset = m_observerWrapper->endOffset(prelude); | 722 m_observer->startRuleHeader(StyleRule::Page, preludeStartOffset); |
738 m_observerWrapper->observer().startRuleHeader( | 723 m_observer->endRuleHeader(block.offset() - 1); |
739 StyleRule::Page, m_observerWrapper->startOffset(prelude)); | |
740 m_observerWrapper->observer().endRuleHeader(endOffset); | |
741 } | 724 } |
742 | 725 |
743 consumeDeclarationList(block, StyleRule::Style); | 726 consumeDeclarationList(block, StyleRule::Style); |
744 | 727 |
745 return StyleRulePage::create( | 728 return StyleRulePage::create( |
746 std::move(selectorList), | 729 std::move(selectorList), |
747 createStylePropertySet(m_parsedProperties, m_context.mode())); | 730 createStylePropertySet(m_parsedProperties, m_context.mode())); |
748 } | 731 } |
749 | 732 |
750 void CSSParserImpl::consumeApplyRule(CSSParserTokenRange prelude) { | 733 void CSSParserImpl::consumeApplyRule(CSSParserTokenRange prelude) { |
751 ASSERT(RuntimeEnabledFeatures::cssApplyAtRulesEnabled()); | 734 ASSERT(RuntimeEnabledFeatures::cssApplyAtRulesEnabled()); |
752 | 735 |
753 const CSSParserToken& ident = prelude.consumeIncludingWhitespace(); | 736 const CSSParserToken& ident = prelude.consumeIncludingWhitespace(); |
754 if (!prelude.atEnd() || !CSSVariableParser::isValidVariableName(ident)) | 737 if (!prelude.atEnd() || !CSSVariableParser::isValidVariableName(ident)) |
755 return; // Parse error, expected a single custom property name | 738 return; // Parse error, expected a single custom property name |
756 m_parsedProperties.push_back(CSSProperty( | 739 m_parsedProperties.push_back(CSSProperty( |
757 CSSPropertyApplyAtRule, | 740 CSSPropertyApplyAtRule, |
758 *CSSCustomIdentValue::create(ident.value().toAtomicString()))); | 741 *CSSCustomIdentValue::create(ident.value().toAtomicString()))); |
759 } | 742 } |
760 | 743 |
761 StyleRuleKeyframe* CSSParserImpl::consumeKeyframeStyleRule( | 744 StyleRuleKeyframe* CSSParserImpl::consumeKeyframeStyleRule( |
762 CSSParserTokenRange prelude, | 745 CSSParserTokenRange prelude, |
763 CSSParserTokenRange block) { | 746 CSSParserTokenStream& block, |
| 747 size_t preludeStartOffset) { |
764 std::unique_ptr<Vector<double>> keyList = consumeKeyframeKeyList(prelude); | 748 std::unique_ptr<Vector<double>> keyList = consumeKeyframeKeyList(prelude); |
765 if (!keyList) | 749 if (!keyList) |
766 return nullptr; | 750 return nullptr; |
767 | 751 |
768 if (m_observerWrapper) { | 752 if (m_observer) { |
769 m_observerWrapper->observer().startRuleHeader( | 753 m_observer->startRuleHeader(StyleRule::Keyframe, preludeStartOffset); |
770 StyleRule::Keyframe, m_observerWrapper->startOffset(prelude)); | 754 m_observer->endRuleHeader(block.offset() - 1); |
771 m_observerWrapper->observer().endRuleHeader( | |
772 m_observerWrapper->endOffset(prelude)); | |
773 } | 755 } |
774 | 756 |
775 consumeDeclarationList(block, StyleRule::Keyframe); | 757 consumeDeclarationList(block, StyleRule::Keyframe); |
776 return StyleRuleKeyframe::create( | 758 return StyleRuleKeyframe::create( |
777 std::move(keyList), | 759 std::move(keyList), |
778 createStylePropertySet(m_parsedProperties, m_context.mode())); | 760 createStylePropertySet(m_parsedProperties, m_context.mode())); |
779 } | 761 } |
780 | 762 |
781 static void observeSelectors(CSSParserObserverWrapper& wrapper, | 763 StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenStream& stream, |
782 CSSParserTokenRange selectors) { | 764 size_t startOffset) { |
783 // This is easier than hooking into the CSSSelectorParser | 765 if (m_observer) |
784 selectors.consumeWhitespace(); | 766 m_observer->startRuleHeader(StyleRule::Style, startOffset); |
785 CSSParserTokenRange originalRange = selectors; | 767 CSSSelectorList selectorList = CSSSelectorParser::consumeSelector( |
786 wrapper.observer().startRuleHeader(StyleRule::Style, | 768 stream, m_context, m_styleSheet, startOffset, m_observer); |
787 wrapper.startOffset(originalRange)); | |
788 | 769 |
789 while (!selectors.atEnd()) { | 770 if (!selectorList.isValid()) |
790 const CSSParserToken* selectorStart = &selectors.peek(); | 771 stream.consumeUntilAtEndOrPeekedTypeIs<LeftBraceToken>(); |
791 while (!selectors.atEnd() && selectors.peek().type() != CommaToken) | |
792 selectors.consumeComponentValue(); | |
793 CSSParserTokenRange selector = | |
794 selectors.makeSubRange(selectorStart, &selectors.peek()); | |
795 selectors.consumeIncludingWhitespace(); | |
796 | 772 |
797 wrapper.observer().observeSelector(wrapper.startOffset(selector), | 773 DCHECK(stream.atEnd() || stream.peek().type() == LeftBraceToken); |
798 wrapper.endOffset(selector)); | 774 |
| 775 if (m_observer) |
| 776 m_observer->endRuleHeader(stream.previousOffset()); |
| 777 |
| 778 if (!selectorList.isValid()) { |
| 779 if (!stream.atEnd()) |
| 780 stream.skipBlock(); |
| 781 return nullptr; // Parse error, invalid selector list |
799 } | 782 } |
800 | 783 |
801 wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange)); | 784 if (m_lazyState && m_lazyState->shouldLazilyParseProperties(selectorList)) { |
802 } | 785 DCHECK(m_styleSheet); |
| 786 size_t blockOffset = stream.previousOffset(); |
| 787 stream.skipBlock(); |
| 788 return StyleRule::createLazy(std::move(selectorList), |
| 789 m_lazyState->createLazyParser(blockOffset)); |
| 790 } |
803 | 791 |
804 StyleRule* CSSParserImpl::consumeStyleRule(CSSParserTokenRange prelude, | 792 CSSParserTokenStream block(stream, CSSParserTokenStream::MakeSubStream); |
805 CSSParserTokenRange block) { | |
806 CSSSelectorList selectorList = | |
807 CSSSelectorParser::parseSelector(prelude, m_context, m_styleSheet); | |
808 if (!selectorList.isValid()) | |
809 return nullptr; // Parse error, invalid selector list | |
810 | |
811 // TODO(csharrison): How should we lazily parse css that needs the observer? | |
812 if (m_observerWrapper) { | |
813 observeSelectors(*m_observerWrapper, prelude); | |
814 } else if (m_lazyState && | |
815 m_lazyState->shouldLazilyParseProperties(selectorList, block)) { | |
816 DCHECK(m_styleSheet); | |
817 return StyleRule::createLazy(std::move(selectorList), | |
818 m_lazyState->createLazyParser(block)); | |
819 } | |
820 consumeDeclarationList(block, StyleRule::Style); | 793 consumeDeclarationList(block, StyleRule::Style); |
821 | 794 |
822 return StyleRule::create( | 795 return StyleRule::create( |
823 std::move(selectorList), | 796 std::move(selectorList), |
824 createStylePropertySet(m_parsedProperties, m_context.mode())); | 797 createStylePropertySet(m_parsedProperties, m_context.mode())); |
825 } | 798 } |
826 | 799 |
827 void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, | 800 void CSSParserImpl::consumeDeclarationListForAtApply( |
828 StyleRule::RuleType ruleType) { | 801 CSSParserTokenRange range) { |
829 ASSERT(m_parsedProperties.isEmpty()); | 802 DCHECK(m_parsedProperties.isEmpty()); |
830 | 803 DCHECK(RuntimeEnabledFeatures::cssApplyAtRulesEnabled()); |
831 bool useObserver = m_observerWrapper && (ruleType == StyleRule::Style || | 804 DCHECK(!m_observer); |
832 ruleType == StyleRule::Keyframe); | |
833 if (useObserver) { | |
834 m_observerWrapper->observer().startRuleBody( | |
835 m_observerWrapper->previousTokenStartOffset(range)); | |
836 m_observerWrapper->skipCommentsBefore(range, true); | |
837 } | |
838 | |
839 while (!range.atEnd()) { | 805 while (!range.atEnd()) { |
840 switch (range.peek().type()) { | 806 switch (range.peek().type()) { |
841 case WhitespaceToken: | 807 case WhitespaceToken: |
842 case SemicolonToken: | 808 case SemicolonToken: |
843 range.consume(); | 809 range.consume(); |
844 break; | 810 break; |
845 case IdentToken: { | 811 case IdentToken: { |
846 const CSSParserToken* declarationStart = &range.peek(); | 812 const CSSParserToken* declarationStart = &range.peek(); |
847 | |
848 if (useObserver) | |
849 m_observerWrapper->yieldCommentsBefore(range); | |
850 | |
851 while (!range.atEnd() && range.peek().type() != SemicolonToken) | 813 while (!range.atEnd() && range.peek().type() != SemicolonToken) |
852 range.consumeComponentValue(); | 814 range.consumeComponentValue(); |
| 815 consumeDeclaration(range.makeSubRange(declarationStart, &range.peek()), |
| 816 StyleRule::Style, 0, 0); |
| 817 break; |
| 818 } |
| 819 case AtKeywordToken: |
| 820 range.consume(); |
| 821 while (!range.atEnd() && range.peek().type() != LeftBraceToken && |
| 822 range.peek().type() != SemicolonToken) |
| 823 range.consumeComponentValue(); |
| 824 range.consumeComponentValue(); |
| 825 break; |
| 826 default: // Parse error, unexpected token in declaration list |
| 827 while (!range.atEnd() && range.peek().type() != SemicolonToken) |
| 828 range.consumeComponentValue(); |
| 829 break; |
| 830 } |
| 831 } |
| 832 } |
853 | 833 |
854 consumeDeclaration(range.makeSubRange(declarationStart, &range.peek()), | 834 void CSSParserImpl::consumeDeclarationList(CSSParserTokenStream& stream, |
855 ruleType); | 835 StyleRule::RuleType ruleType) { |
| 836 DCHECK(m_parsedProperties.isEmpty()); |
856 | 837 |
857 if (useObserver) | 838 bool useObserver = m_observer && (ruleType == StyleRule::Style || |
858 m_observerWrapper->skipCommentsBefore(range, false); | 839 ruleType == StyleRule::Keyframe); |
| 840 if (useObserver) |
| 841 m_observer->startRuleBody(stream.offset() ? stream.offset() - 1 : 0); |
| 842 |
| 843 while (true) { |
| 844 if (useObserver) |
| 845 stream.yieldComments(*m_observer); |
| 846 size_t declarationStartOffset = stream.offset(); |
| 847 if (stream.atEnd()) |
| 848 break; |
| 849 switch (stream.peek().type()) { |
| 850 case WhitespaceToken: |
| 851 case SemicolonToken: |
| 852 stream.consume(); |
| 853 break; |
| 854 case IdentToken: { |
| 855 consumeDeclaration(stream, ruleType, declarationStartOffset); |
| 856 if (!stream.atEnd()) |
| 857 stream.consume(); |
859 break; | 858 break; |
860 } | 859 } |
861 case AtKeywordToken: { | 860 case AtKeywordToken: { |
862 AllowedRulesType allowedRules = | 861 AllowedRulesType allowedRules = |
863 ruleType == StyleRule::Style && | 862 ruleType == StyleRule::Style && |
864 RuntimeEnabledFeatures::cssApplyAtRulesEnabled() | 863 RuntimeEnabledFeatures::cssApplyAtRulesEnabled() |
865 ? ApplyRules | 864 ? ApplyRules |
866 : NoRules; | 865 : NoRules; |
867 StyleRuleBase* rule = consumeAtRule(range, allowedRules); | 866 StyleRuleBase* rule = consumeAtRule(stream, allowedRules); |
868 DCHECK(!rule); | 867 DCHECK(!rule); |
869 break; | 868 break; |
870 } | 869 } |
871 default: // Parse error, unexpected token in declaration list | 870 default: // Parse error, unexpected token in declaration list |
872 while (!range.atEnd() && range.peek().type() != SemicolonToken) | 871 stream.consumeUntilAtEndOrPeekedTypeIs<SemicolonToken>(); |
873 range.consumeComponentValue(); | 872 if (!stream.atEnd()) |
| 873 stream.consume(); |
874 break; | 874 break; |
875 } | 875 } |
876 } | 876 } |
877 | 877 |
878 // Yield remaining comments | 878 if (useObserver) |
879 if (useObserver) { | 879 m_observer->endRuleBody(stream.offset()); |
880 m_observerWrapper->yieldCommentsBefore(range); | 880 } |
881 m_observerWrapper->observer().endRuleBody( | 881 |
882 m_observerWrapper->endOffset(range)); | 882 void CSSParserImpl::consumeDeclaration(CSSParserTokenStream& stream, |
883 } | 883 StyleRule::RuleType ruleType, |
| 884 size_t declarationStartOffset) { |
| 885 DCHECK_EQ(stream.peek().type(), IdentToken); |
| 886 size_t startIndex = stream.index(); |
| 887 stream.consume(); |
| 888 stream.consumeUntilAtEndOrPeekedTypeIs<SemicolonToken>(); |
| 889 consumeDeclaration(stream.makeSubRangeFrom(startIndex), ruleType, |
| 890 declarationStartOffset, stream.previousOffset()); |
| 891 stream.clean(); |
884 } | 892 } |
885 | 893 |
886 void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, | 894 void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, |
887 StyleRule::RuleType ruleType) { | 895 StyleRule::RuleType ruleType, |
888 CSSParserTokenRange rangeCopy = range; // For inspector callbacks | 896 size_t declarationStartOffset, |
889 | 897 size_t declarationEndOffset) { |
890 ASSERT(range.peek().type() == IdentToken); | 898 ASSERT(range.peek().type() == IdentToken); |
891 const CSSParserToken& token = range.consumeIncludingWhitespace(); | 899 const CSSParserToken& token = range.consumeIncludingWhitespace(); |
892 CSSPropertyID unresolvedProperty = token.parseAsUnresolvedCSSPropertyID(); | 900 CSSPropertyID unresolvedProperty = token.parseAsUnresolvedCSSPropertyID(); |
893 if (range.consume().type() != ColonToken) | 901 if (range.consume().type() != ColonToken) |
894 return; // Parse error | 902 return; // Parse error |
895 | 903 |
896 bool important = false; | 904 bool important = false; |
897 const CSSParserToken* declarationValueEnd = range.end(); | 905 const CSSParserToken* declarationValueEnd = range.end(); |
898 const CSSParserToken* last = range.end() - 1; | 906 const CSSParserToken* last = range.end() - 1; |
899 while (last->type() == WhitespaceToken) | 907 while (last->type() == WhitespaceToken) |
(...skipping 24 matching lines...) Expand all Loading... |
924 variableName, important, isAnimationTainted); | 932 variableName, important, isAnimationTainted); |
925 } else if (unresolvedProperty != CSSPropertyInvalid) { | 933 } else if (unresolvedProperty != CSSPropertyInvalid) { |
926 if (m_styleSheet && m_styleSheet->singleOwnerDocument()) | 934 if (m_styleSheet && m_styleSheet->singleOwnerDocument()) |
927 Deprecation::warnOnDeprecatedProperties( | 935 Deprecation::warnOnDeprecatedProperties( |
928 m_styleSheet->singleOwnerDocument()->frame(), unresolvedProperty); | 936 m_styleSheet->singleOwnerDocument()->frame(), unresolvedProperty); |
929 consumeDeclarationValue( | 937 consumeDeclarationValue( |
930 range.makeSubRange(&range.peek(), declarationValueEnd), | 938 range.makeSubRange(&range.peek(), declarationValueEnd), |
931 unresolvedProperty, important, ruleType); | 939 unresolvedProperty, important, ruleType); |
932 } | 940 } |
933 | 941 |
934 if (m_observerWrapper && | 942 if (m_observer && |
935 (ruleType == StyleRule::Style || ruleType == StyleRule::Keyframe)) { | 943 (ruleType == StyleRule::Style || ruleType == StyleRule::Keyframe)) { |
936 m_observerWrapper->observer().observeProperty( | 944 m_observer->observeProperty(declarationStartOffset, declarationEndOffset, |
937 m_observerWrapper->startOffset(rangeCopy), | 945 important, |
938 m_observerWrapper->endOffset(rangeCopy), important, | 946 m_parsedProperties.size() != propertiesCount); |
939 m_parsedProperties.size() != propertiesCount); | |
940 } | 947 } |
941 } | 948 } |
942 | 949 |
943 void CSSParserImpl::consumeVariableValue(CSSParserTokenRange range, | 950 void CSSParserImpl::consumeVariableValue(CSSParserTokenRange range, |
944 const AtomicString& variableName, | 951 const AtomicString& variableName, |
945 bool important, | 952 bool important, |
946 bool isAnimationTainted) { | 953 bool isAnimationTainted) { |
947 if (CSSCustomPropertyDeclaration* value = | 954 if (CSSCustomPropertyDeclaration* value = |
948 CSSVariableParser::parseDeclarationValue(variableName, range, | 955 CSSVariableParser::parseDeclarationValue(variableName, range, |
949 isAnimationTainted)) | 956 isAnimationTainted)) |
(...skipping 27 matching lines...) Expand all Loading... |
977 else | 984 else |
978 return nullptr; // Parser error, invalid value in keyframe selector | 985 return nullptr; // Parser error, invalid value in keyframe selector |
979 if (range.atEnd()) | 986 if (range.atEnd()) |
980 return result; | 987 return result; |
981 if (range.consume().type() != CommaToken) | 988 if (range.consume().type() != CommaToken) |
982 return nullptr; // Parser error | 989 return nullptr; // Parser error |
983 } | 990 } |
984 } | 991 } |
985 | 992 |
986 } // namespace blink | 993 } // namespace blink |
OLD | NEW |