1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 //! Parsing of the stylesheet contents.
6
7 use {Namespace, Prefix};
8 use counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
9 use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser};
10 use cssparser::{CowRcStr, SourceLocation, BasicParseError, BasicParseErrorKind};
11 use error_reporting::{ContextualParseError, ParseErrorReporter};
12 use font_face::parse_font_face_block;
13 use media_queries::{parse_media_query_list, MediaList};
14 use parser::{Parse, ParserContext, ParserErrorContext};
15 use properties::parse_property_declaration_list;
16 use selector_parser::{SelectorImpl, SelectorParser};
17 use selectors::SelectorList;
18 use servo_arc::Arc;
19 use shared_lock::{Locked, SharedRwLock};
20 use str::starts_with_ignore_ascii_case;
21 use style_traits::{StyleParseErrorKind, ParseError};
22 use stylesheets::{CssRule, CssRules, CssRuleType, Origin, StylesheetLoader};
23 use stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
24 use stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
25 use stylesheets::document_rule::DocumentCondition;
26 use stylesheets::font_feature_values_rule::parse_family_name_list;
27 use stylesheets::keyframes_rule::parse_keyframe_list;
28 use stylesheets::stylesheet::Namespaces;
29 use stylesheets::supports_rule::SupportsCondition;
30 use stylesheets::viewport_rule;
31 use values::{CssUrl, CustomIdent, KeyframesName};
32 use values::computed::font::FamilyName;
33
34 /// The parser for the top-level rules in a stylesheet.
35 pub struct TopLevelRuleParser<'a, R: 'a> {
36 /// The origin of the stylesheet we're parsing.
37 pub stylesheet_origin: Origin,
38 /// A reference to the lock we need to use to create rules.
39 pub shared_lock: &'a SharedRwLock,
40 /// A reference to a stylesheet loader if applicable, for `@import` rules.
41 pub loader: Option<&'a StylesheetLoader>,
42 /// The top-level parser context.
43 ///
44 /// This won't contain any namespaces, and only nested parsers created with
45 /// `ParserContext::new_with_rule_type` will.
46 pub context: ParserContext<'a>,
47 /// The context required for reporting parse errors.
48 pub error_context: ParserErrorContext<'a, R>,
49 /// The current state of the parser.
50 pub state: State,
51 /// Whether we have tried to parse was invalid due to being in the wrong
52 /// place (e.g. an @import rule was found while in the `Body` state). Reset
53 /// to `false` when `take_had_hierarchy_error` is called.
54 pub had_hierarchy_error: bool,
55 /// The namespace map we use for parsing. Needs to start as `Some()`, and
56 /// will be taken out after parsing namespace rules, and that reference will
57 /// be moved to `ParserContext`.
58 pub namespaces: &'a mut Namespaces,
59 }
60
61 impl<'b, R> TopLevelRuleParser<'b, R> {
nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b, R>62 fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b, R> {
63 NestedRuleParser {
64 stylesheet_origin: self.stylesheet_origin,
65 shared_lock: self.shared_lock,
66 context: &self.context,
67 error_context: &self.error_context,
68 namespaces: &self.namespaces,
69 }
70 }
71
72 /// Returns the current state of the parser.
state(&self) -> State73 pub fn state(&self) -> State {
74 self.state
75 }
76
77 /// Returns whether we previously tried to parse a rule that was invalid
78 /// due to being in the wrong place (e.g. an @import rule was found after
79 /// a regular style rule). The state of this flag is reset when this
80 /// function is called.
take_had_hierarchy_error(&mut self) -> bool81 pub fn take_had_hierarchy_error(&mut self) -> bool {
82 let had_hierarchy_error = self.had_hierarchy_error;
83 self.had_hierarchy_error = false;
84 had_hierarchy_error
85 }
86 }
87
88 /// The current state of the parser.
89 #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
90 pub enum State {
91 /// We haven't started parsing rules.
92 Start = 1,
93 /// We're parsing `@import` rules.
94 Imports = 2,
95 /// We're parsing `@namespace` rules.
96 Namespaces = 3,
97 /// We're parsing the main body of the stylesheet.
98 Body = 4,
99 }
100
101 #[derive(Clone, Debug, MallocSizeOf)]
102 /// Vendor prefix.
103 pub enum VendorPrefix {
104 /// -moz prefix.
105 Moz,
106 /// -webkit prefix.
107 WebKit,
108 }
109
110 /// A rule prelude for at-rule with block.
111 pub enum AtRuleBlockPrelude {
112 /// A @font-face rule prelude.
113 FontFace(SourceLocation),
114 /// A @font-feature-values rule prelude, with its FamilyName list.
115 FontFeatureValues(Vec<FamilyName>, SourceLocation),
116 /// A @counter-style rule prelude, with its counter style name.
117 CounterStyle(CustomIdent),
118 /// A @media rule prelude, with its media queries.
119 Media(Arc<Locked<MediaList>>, SourceLocation),
120 /// An @supports rule, with its conditional
121 Supports(SupportsCondition, SourceLocation),
122 /// A @viewport rule prelude.
123 Viewport,
124 /// A @keyframes rule, with its animation name and vendor prefix if exists.
125 Keyframes(KeyframesName, Option<VendorPrefix>, SourceLocation),
126 /// A @page rule prelude.
127 Page(SourceLocation),
128 /// A @document rule, with its conditional.
129 Document(DocumentCondition, SourceLocation),
130 }
131
132 /// A rule prelude for at-rule without block.
133 pub enum AtRuleNonBlockPrelude {
134 /// A @import rule prelude.
135 Import(CssUrl, Arc<Locked<MediaList>>, SourceLocation),
136 /// A @namespace rule prelude.
137 Namespace(Option<Prefix>, Namespace, SourceLocation),
138 }
139
140
141 #[cfg(feature = "gecko")]
register_namespace(ns: &Namespace) -> i32142 fn register_namespace(ns: &Namespace) -> i32 {
143 use gecko_bindings::bindings;
144 let id = unsafe { bindings::Gecko_RegisterNamespace(ns.0.as_ptr()) };
145 debug_assert!(id >= 0);
146 id
147 }
148
149 #[cfg(feature = "servo")]
register_namespace(_: &Namespace)150 fn register_namespace(_: &Namespace) {
151 // servo doesn't use namespace ids
152 }
153
154 impl<'a, 'i, R: ParseErrorReporter> AtRuleParser<'i> for TopLevelRuleParser<'a, R> {
155 type PreludeNoBlock = AtRuleNonBlockPrelude;
156 type PreludeBlock = AtRuleBlockPrelude;
157 type AtRule = CssRule;
158 type Error = StyleParseErrorKind<'i>;
159
parse_prelude<'t>( &mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't> ) -> Result<AtRuleType<AtRuleNonBlockPrelude, AtRuleBlockPrelude>, ParseError<'i>>160 fn parse_prelude<'t>(
161 &mut self,
162 name: CowRcStr<'i>,
163 input: &mut Parser<'i, 't>
164 ) -> Result<AtRuleType<AtRuleNonBlockPrelude, AtRuleBlockPrelude>, ParseError<'i>> {
165 let location = input.current_source_location();
166 match_ignore_ascii_case! { &*name,
167 "import" => {
168 if self.state > State::Imports {
169 // "@import must be before any rule but @charset"
170 self.had_hierarchy_error = true;
171 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
172 }
173
174 let url_string = input.expect_url_or_string()?.as_ref().to_owned();
175 let url = CssUrl::parse_from_string(url_string, &self.context)?;
176
177 let media = parse_media_query_list(&self.context, input,
178 self.error_context.error_reporter);
179 let media = Arc::new(self.shared_lock.wrap(media));
180
181 let prelude = AtRuleNonBlockPrelude::Import(url, media, location);
182 return Ok(AtRuleType::WithoutBlock(prelude));
183 },
184 "namespace" => {
185 if self.state > State::Namespaces {
186 // "@namespace must be before any rule but @charset and @import"
187 self.had_hierarchy_error = true;
188 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedNamespaceRule))
189 }
190
191 let prefix = input.try(|i| i.expect_ident_cloned())
192 .map(|s| Prefix::from(s.as_ref())).ok();
193 let maybe_namespace = match input.expect_url_or_string() {
194 Ok(url_or_string) => url_or_string,
195 Err(BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location }) => {
196 return Err(location.new_custom_error(StyleParseErrorKind::UnexpectedTokenWithinNamespace(t)))
197 }
198 Err(e) => return Err(e.into()),
199 };
200 let url = Namespace::from(maybe_namespace.as_ref());
201 let prelude = AtRuleNonBlockPrelude::Namespace(prefix, url, location);
202 return Ok(AtRuleType::WithoutBlock(prelude));
203 },
204 // @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
205 // anything left is invalid.
206 "charset" => {
207 self.had_hierarchy_error = true;
208 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
209 }
210 _ => {}
211 }
212
213 AtRuleParser::parse_prelude(&mut self.nested(), name, input)
214 }
215
216 #[inline]
parse_block<'t>( &mut self, prelude: AtRuleBlockPrelude, input: &mut Parser<'i, 't> ) -> Result<CssRule, ParseError<'i>>217 fn parse_block<'t>(
218 &mut self,
219 prelude: AtRuleBlockPrelude,
220 input: &mut Parser<'i, 't>
221 ) -> Result<CssRule, ParseError<'i>> {
222 AtRuleParser::parse_block(&mut self.nested(), prelude, input)
223 .map(|rule| { self.state = State::Body; rule })
224 }
225
226 #[inline]
rule_without_block(&mut self, prelude: AtRuleNonBlockPrelude) -> CssRule227 fn rule_without_block(&mut self, prelude: AtRuleNonBlockPrelude) -> CssRule {
228 match prelude {
229 AtRuleNonBlockPrelude::Import(url, media, location) => {
230 let loader =
231 self.loader.expect("Expected a stylesheet loader for @import");
232
233 let import_rule = loader.request_stylesheet(
234 url,
235 location,
236 &self.context,
237 &self.shared_lock,
238 media,
239 );
240
241 self.state = State::Imports;
242 CssRule::Import(import_rule)
243 }
244 AtRuleNonBlockPrelude::Namespace(prefix, url, location) => {
245 let id = register_namespace(&url);
246
247 let opt_prefix = if let Some(prefix) = prefix {
248 self.namespaces
249 .prefixes
250 .insert(prefix.clone(), (url.clone(), id));
251 Some(prefix)
252 } else {
253 self.namespaces.default = Some((url.clone(), id));
254 None
255 };
256
257 self.state = State::Namespaces;
258 CssRule::Namespace(Arc::new(
259 self.shared_lock.wrap(NamespaceRule {
260 prefix: opt_prefix,
261 url: url,
262 source_location: location,
263 })
264 ))
265 }
266 }
267 }
268 }
269
270 pub struct QualifiedRuleParserPrelude {
271 selectors: SelectorList<SelectorImpl>,
272 source_location: SourceLocation,
273 }
274
275 impl<'a, 'i, R: ParseErrorReporter> QualifiedRuleParser<'i> for TopLevelRuleParser<'a, R> {
276 type Prelude = QualifiedRuleParserPrelude;
277 type QualifiedRule = CssRule;
278 type Error = StyleParseErrorKind<'i>;
279
280 #[inline]
parse_prelude<'t>( &mut self, input: &mut Parser<'i, 't>, ) -> Result<QualifiedRuleParserPrelude, ParseError<'i>>281 fn parse_prelude<'t>(
282 &mut self,
283 input: &mut Parser<'i, 't>,
284 ) -> Result<QualifiedRuleParserPrelude, ParseError<'i>> {
285 QualifiedRuleParser::parse_prelude(&mut self.nested(), input)
286 }
287
288 #[inline]
parse_block<'t>( &mut self, prelude: QualifiedRuleParserPrelude, input: &mut Parser<'i, 't> ) -> Result<CssRule, ParseError<'i>>289 fn parse_block<'t>(
290 &mut self,
291 prelude: QualifiedRuleParserPrelude,
292 input: &mut Parser<'i, 't>
293 ) -> Result<CssRule, ParseError<'i>> {
294 QualifiedRuleParser::parse_block(&mut self.nested(), prelude, input)
295 .map(|result| { self.state = State::Body; result })
296 }
297 }
298
299 #[derive(Clone)] // shallow, relatively cheap .clone
300 struct NestedRuleParser<'a, 'b: 'a, R: 'b> {
301 stylesheet_origin: Origin,
302 shared_lock: &'a SharedRwLock,
303 context: &'a ParserContext<'b>,
304 error_context: &'a ParserErrorContext<'b, R>,
305 namespaces: &'a Namespaces,
306 }
307
308 impl<'a, 'b, R: ParseErrorReporter> NestedRuleParser<'a, 'b, R> {
parse_nested_rules( &mut self, input: &mut Parser, rule_type: CssRuleType ) -> Arc<Locked<CssRules>>309 fn parse_nested_rules(
310 &mut self,
311 input: &mut Parser,
312 rule_type: CssRuleType
313 ) -> Arc<Locked<CssRules>> {
314 let context = ParserContext::new_with_rule_type(
315 self.context,
316 rule_type,
317 self.namespaces,
318 );
319
320 let nested_parser = NestedRuleParser {
321 stylesheet_origin: self.stylesheet_origin,
322 shared_lock: self.shared_lock,
323 context: &context,
324 error_context: &self.error_context,
325 namespaces: self.namespaces,
326 };
327
328 let mut iter = RuleListParser::new_for_nested_rule(input, nested_parser);
329 let mut rules = Vec::new();
330 while let Some(result) = iter.next() {
331 match result {
332 Ok(rule) => rules.push(rule),
333 Err((error, slice)) => {
334 let location = error.location;
335 let error = ContextualParseError::InvalidRule(slice, error);
336 self.context.log_css_error(self.error_context, location, error);
337 }
338 }
339 }
340 CssRules::new(rules, self.shared_lock)
341 }
342 }
343
344 impl<'a, 'b, 'i, R: ParseErrorReporter> AtRuleParser<'i> for NestedRuleParser<'a, 'b, R> {
345 type PreludeNoBlock = AtRuleNonBlockPrelude;
346 type PreludeBlock = AtRuleBlockPrelude;
347 type AtRule = CssRule;
348 type Error = StyleParseErrorKind<'i>;
349
parse_prelude<'t>( &mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't> ) -> Result<AtRuleType<AtRuleNonBlockPrelude, AtRuleBlockPrelude>, ParseError<'i>>350 fn parse_prelude<'t>(
351 &mut self,
352 name: CowRcStr<'i>,
353 input: &mut Parser<'i, 't>
354 ) -> Result<AtRuleType<AtRuleNonBlockPrelude, AtRuleBlockPrelude>, ParseError<'i>> {
355 let location = input.current_source_location();
356
357 match_ignore_ascii_case! { &*name,
358 "media" => {
359 let media_queries = parse_media_query_list(self.context, input,
360 self.error_context.error_reporter);
361 let arc = Arc::new(self.shared_lock.wrap(media_queries));
362 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Media(arc, location)))
363 },
364 "supports" => {
365 let cond = SupportsCondition::parse(input)?;
366 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Supports(cond, location)))
367 },
368 "font-face" => {
369 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::FontFace(location)))
370 },
371 "font-feature-values" => {
372 if !cfg!(feature = "gecko") {
373 // Support for this rule is not fully implemented in Servo yet.
374 return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
375 }
376 let family_names = parse_family_name_list(self.context, input)?;
377 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::FontFeatureValues(family_names, location)))
378 },
379 "counter-style" => {
380 if !cfg!(feature = "gecko") {
381 // Support for this rule is not fully implemented in Servo yet.
382 return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
383 }
384 let name = parse_counter_style_name_definition(input)?;
385 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::CounterStyle(name)))
386 },
387 "viewport" => {
388 if viewport_rule::enabled() {
389 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Viewport))
390 } else {
391 Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
392 }
393 },
394 "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
395 let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
396 Some(VendorPrefix::WebKit)
397 } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
398 Some(VendorPrefix::Moz)
399 } else {
400 None
401 };
402 if cfg!(feature = "servo") &&
403 prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) {
404 // Servo should not support @-moz-keyframes.
405 return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
406 }
407 let name = KeyframesName::parse(self.context, input)?;
408
409 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Keyframes(name, prefix, location)))
410 },
411 "page" => {
412 if cfg!(feature = "gecko") {
413 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Page(location)))
414 } else {
415 Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
416 }
417 },
418 "-moz-document" => {
419 if !cfg!(feature = "gecko") {
420 return Err(input.new_custom_error(
421 StyleParseErrorKind::UnsupportedAtRule(name.clone())
422 ))
423 }
424
425 #[cfg(feature = "gecko")]
426 {
427 use gecko_bindings::structs;
428
429 if self.stylesheet_origin == Origin::Author &&
430 unsafe { !structs::StylePrefs_sMozDocumentEnabledInContent }
431 {
432 return Err(input.new_custom_error(
433 StyleParseErrorKind::UnsupportedAtRule(name.clone())
434 ))
435 }
436 }
437
438 let cond = DocumentCondition::parse(self.context, input)?;
439 Ok(AtRuleType::WithBlock(AtRuleBlockPrelude::Document(cond, location)))
440 },
441 _ => Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
442 }
443 }
444
parse_block<'t>( &mut self, prelude: AtRuleBlockPrelude, input: &mut Parser<'i, 't> ) -> Result<CssRule, ParseError<'i>>445 fn parse_block<'t>(
446 &mut self,
447 prelude: AtRuleBlockPrelude,
448 input: &mut Parser<'i, 't>
449 ) -> Result<CssRule, ParseError<'i>> {
450 match prelude {
451 AtRuleBlockPrelude::FontFace(location) => {
452 let context = ParserContext::new_with_rule_type(
453 self.context,
454 CssRuleType::FontFace,
455 self.namespaces,
456 );
457
458 Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
459 parse_font_face_block(&context, self.error_context, input, location).into()))))
460 }
461 AtRuleBlockPrelude::FontFeatureValues(family_names, location) => {
462 let context = ParserContext::new_with_rule_type(
463 self.context,
464 CssRuleType::FontFeatureValues,
465 self.namespaces,
466 );
467
468 Ok(CssRule::FontFeatureValues(Arc::new(self.shared_lock.wrap(
469 FontFeatureValuesRule::parse(&context, self.error_context, input, family_names, location)))))
470 }
471 AtRuleBlockPrelude::CounterStyle(name) => {
472 let context = ParserContext::new_with_rule_type(
473 self.context,
474 CssRuleType::CounterStyle,
475 self.namespaces,
476 );
477
478 Ok(CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(
479 parse_counter_style_body(name, &context, self.error_context, input)?.into()))))
480 }
481 AtRuleBlockPrelude::Media(media_queries, location) => {
482 Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
483 media_queries: media_queries,
484 rules: self.parse_nested_rules(input, CssRuleType::Media),
485 source_location: location,
486 }))))
487 }
488 AtRuleBlockPrelude::Supports(cond, location) => {
489 let eval_context = ParserContext::new_with_rule_type(
490 self.context,
491 CssRuleType::Style,
492 self.namespaces,
493 );
494
495 let enabled = cond.eval(&eval_context);
496 Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(SupportsRule {
497 condition: cond,
498 rules: self.parse_nested_rules(input, CssRuleType::Supports),
499 enabled: enabled,
500 source_location: location,
501 }))))
502 }
503 AtRuleBlockPrelude::Viewport => {
504 let context = ParserContext::new_with_rule_type(
505 self.context,
506 CssRuleType::Viewport,
507 self.namespaces,
508 );
509
510 Ok(CssRule::Viewport(Arc::new(self.shared_lock.wrap(
511 ViewportRule::parse(&context, self.error_context, input)?))))
512 }
513 AtRuleBlockPrelude::Keyframes(name, prefix, location) => {
514 let context = ParserContext::new_with_rule_type(
515 self.context,
516 CssRuleType::Keyframes,
517 self.namespaces,
518 );
519
520 Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule {
521 name: name,
522 keyframes: parse_keyframe_list(&context, self.error_context, input, self.shared_lock),
523 vendor_prefix: prefix,
524 source_location: location,
525 }))))
526 }
527 AtRuleBlockPrelude::Page(location) => {
528 let context = ParserContext::new_with_rule_type(
529 self.context,
530 CssRuleType::Page,
531 self.namespaces,
532 );
533
534 let declarations = parse_property_declaration_list(&context, self.error_context, input);
535 Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule {
536 block: Arc::new(self.shared_lock.wrap(declarations)),
537 source_location: location,
538 }))))
539 }
540 AtRuleBlockPrelude::Document(cond, location) => {
541 if cfg!(feature = "gecko") {
542 Ok(CssRule::Document(Arc::new(self.shared_lock.wrap(DocumentRule {
543 condition: cond,
544 rules: self.parse_nested_rules(input, CssRuleType::Document),
545 source_location: location,
546 }))))
547 } else {
548 unreachable!()
549 }
550 }
551 }
552 }
553 }
554
555 impl<'a, 'b, 'i, R: ParseErrorReporter> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b, R> {
556 type Prelude = QualifiedRuleParserPrelude;
557 type QualifiedRule = CssRule;
558 type Error = StyleParseErrorKind<'i>;
559
parse_prelude<'t>( &mut self, input: &mut Parser<'i, 't> ) -> Result<QualifiedRuleParserPrelude, ParseError<'i>>560 fn parse_prelude<'t>(
561 &mut self,
562 input: &mut Parser<'i, 't>
563 ) -> Result<QualifiedRuleParserPrelude, ParseError<'i>> {
564 let selector_parser = SelectorParser {
565 stylesheet_origin: self.stylesheet_origin,
566 namespaces: self.namespaces,
567 url_data: Some(self.context.url_data),
568 };
569
570 let location = input.current_source_location();
571 let selectors = SelectorList::parse(&selector_parser, input)?;
572
573 Ok(QualifiedRuleParserPrelude {
574 selectors: selectors,
575 source_location: location,
576 })
577 }
578
parse_block<'t>( &mut self, prelude: QualifiedRuleParserPrelude, input: &mut Parser<'i, 't> ) -> Result<CssRule, ParseError<'i>>579 fn parse_block<'t>(
580 &mut self,
581 prelude: QualifiedRuleParserPrelude,
582 input: &mut Parser<'i, 't>
583 ) -> Result<CssRule, ParseError<'i>> {
584 let context = ParserContext::new_with_rule_type(
585 self.context,
586 CssRuleType::Style,
587 self.namespaces,
588 );
589
590 let declarations = parse_property_declaration_list(&context, self.error_context, input);
591 Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
592 selectors: prelude.selectors,
593 block: Arc::new(self.shared_lock.wrap(declarations)),
594 source_location: prelude.source_location,
595 }))))
596 }
597 }
598