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 https://mozilla.org/MPL/2.0/. */
4
5 //! Parsing of the stylesheet contents.
6
7 use crate::counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
8 use crate::error_reporting::ContextualParseError;
9 use crate::font_face::parse_font_face_block;
10 use crate::media_queries::MediaList;
11 use crate::parser::{Parse, ParserContext};
12 use crate::properties::parse_property_declaration_list;
13 use crate::selector_parser::{SelectorImpl, SelectorParser};
14 use crate::shared_lock::{Locked, SharedRwLock};
15 use crate::str::starts_with_ignore_ascii_case;
16 use crate::stylesheets::document_rule::DocumentCondition;
17 use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
18 use crate::stylesheets::import_rule::ImportLayer;
19 use crate::stylesheets::keyframes_rule::parse_keyframe_list;
20 use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
21 use crate::stylesheets::scroll_timeline_rule::ScrollTimelineDescriptors;
22 use crate::stylesheets::stylesheet::Namespaces;
23 use crate::stylesheets::supports_rule::SupportsCondition;
24 use crate::stylesheets::{
25 viewport_rule, AllowImportRules, CorsMode, CssRule, CssRuleType, CssRules, DocumentRule,
26 FontFeatureValuesRule, KeyframesRule, MediaRule, NamespaceRule, PageRule, PageSelectors,
27 RulesMutateError, ScrollTimelineRule, StyleRule, StylesheetLoader, SupportsRule, ViewportRule,
28 };
29 use crate::values::computed::font::FamilyName;
30 use crate::values::{CssUrl, CustomIdent, KeyframesName, TimelineName};
31 use crate::{Namespace, Prefix};
32 use cssparser::{
33 AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, Parser, ParserState,
34 QualifiedRuleParser, RuleListParser, SourcePosition,
35 };
36 use selectors::SelectorList;
37 use servo_arc::Arc;
38 use style_traits::{ParseError, StyleParseErrorKind};
39
40 /// The information we need particularly to do CSSOM insertRule stuff.
41 pub struct InsertRuleContext<'a> {
42 /// The rule list we're about to insert into.
43 pub rule_list: &'a [CssRule],
44 /// The index we're about to get inserted at.
45 pub index: usize,
46 }
47
48 /// The parser for the top-level rules in a stylesheet.
49 pub struct TopLevelRuleParser<'a> {
50 /// A reference to the lock we need to use to create rules.
51 pub shared_lock: &'a SharedRwLock,
52 /// A reference to a stylesheet loader if applicable, for `@import` rules.
53 pub loader: Option<&'a dyn StylesheetLoader>,
54 /// The top-level parser context.
55 ///
56 /// This won't contain any namespaces, and only nested parsers created with
57 /// `ParserContext::new_with_rule_type` will.
58 pub context: ParserContext<'a>,
59 /// The current state of the parser.
60 pub state: State,
61 /// Whether we have tried to parse was invalid due to being in the wrong
62 /// place (e.g. an @import rule was found while in the `Body` state). Reset
63 /// to `false` when `take_had_hierarchy_error` is called.
64 pub dom_error: Option<RulesMutateError>,
65 /// The namespace map we use for parsing. Needs to start as `Some()`, and
66 /// will be taken out after parsing namespace rules, and that reference will
67 /// be moved to `ParserContext`.
68 pub namespaces: &'a mut Namespaces,
69 /// The info we need insert a rule in a list.
70 pub insert_rule_context: Option<InsertRuleContext<'a>>,
71 /// Whether @import rules will be allowed.
72 pub allow_import_rules: AllowImportRules,
73 }
74
75 impl<'b> TopLevelRuleParser<'b> {
nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b>76 fn nested<'a: 'b>(&'a self) -> NestedRuleParser<'a, 'b> {
77 NestedRuleParser {
78 shared_lock: self.shared_lock,
79 context: &self.context,
80 namespaces: &self.namespaces,
81 }
82 }
83
84 /// Returns the current state of the parser.
state(&self) -> State85 pub fn state(&self) -> State {
86 self.state
87 }
88
89 /// Checks whether we can parse a rule that would transition us to
90 /// `new_state`.
91 ///
92 /// This is usually a simple branch, but we may need more bookkeeping if
93 /// doing `insertRule` from CSSOM.
check_state(&mut self, new_state: State) -> bool94 fn check_state(&mut self, new_state: State) -> bool {
95 if self.state > new_state {
96 self.dom_error = Some(RulesMutateError::HierarchyRequest);
97 return false;
98 }
99
100 let ctx = match self.insert_rule_context {
101 Some(ref ctx) => ctx,
102 None => return true,
103 };
104
105 let next_rule_state = match ctx.rule_list.get(ctx.index) {
106 None => return true,
107 Some(rule) => rule.rule_state(),
108 };
109
110 if new_state > next_rule_state {
111 self.dom_error = Some(RulesMutateError::HierarchyRequest);
112 return false;
113 }
114
115 // If there's anything that isn't a namespace rule (or import rule, but
116 // we checked that already at the beginning), reject with a
117 // StateError.
118 if new_state == State::Namespaces &&
119 ctx.rule_list[ctx.index..]
120 .iter()
121 .any(|r| !matches!(*r, CssRule::Namespace(..)))
122 {
123 self.dom_error = Some(RulesMutateError::InvalidState);
124 return false;
125 }
126
127 true
128 }
129 }
130
131 /// The current state of the parser.
132 #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
133 pub enum State {
134 /// We haven't started parsing rules.
135 Start = 1,
136 /// We're parsing early `@layer` statement rules.
137 EarlyLayers = 2,
138 /// We're parsing `@import` and early `@layer` statement rules.
139 Imports = 3,
140 /// We're parsing `@namespace` rules.
141 Namespaces = 4,
142 /// We're parsing the main body of the stylesheet.
143 Body = 5,
144 }
145
146 #[derive(Clone, Debug, MallocSizeOf, ToShmem)]
147 /// Vendor prefix.
148 pub enum VendorPrefix {
149 /// -moz prefix.
150 Moz,
151 /// -webkit prefix.
152 WebKit,
153 }
154
155 /// A rule prelude for at-rule with block.
156 pub enum AtRulePrelude {
157 /// A @font-face rule prelude.
158 FontFace,
159 /// A @font-feature-values rule prelude, with its FamilyName list.
160 FontFeatureValues(Vec<FamilyName>),
161 /// A @counter-style rule prelude, with its counter style name.
162 CounterStyle(CustomIdent),
163 /// A @media rule prelude, with its media queries.
164 Media(Arc<Locked<MediaList>>),
165 /// An @supports rule, with its conditional
166 Supports(SupportsCondition),
167 /// A @viewport rule prelude.
168 Viewport,
169 /// A @keyframes rule, with its animation name and vendor prefix if exists.
170 Keyframes(KeyframesName, Option<VendorPrefix>),
171 /// A @page rule prelude, with its page name if it exists.
172 Page(PageSelectors),
173 /// A @document rule, with its conditional.
174 Document(DocumentCondition),
175 /// A @import rule prelude.
176 Import(CssUrl, Arc<Locked<MediaList>>, Option<ImportLayer>),
177 /// A @namespace rule prelude.
178 Namespace(Option<Prefix>, Namespace),
179 /// A @layer rule prelude.
180 Layer(Vec<LayerName>),
181 /// A @scroll-timeline rule prelude.
182 ScrollTimeline(TimelineName),
183 }
184
185 impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
186 type Prelude = AtRulePrelude;
187 type AtRule = (SourcePosition, CssRule);
188 type Error = StyleParseErrorKind<'i>;
189
parse_prelude<'t>( &mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>, ) -> Result<AtRulePrelude, ParseError<'i>>190 fn parse_prelude<'t>(
191 &mut self,
192 name: CowRcStr<'i>,
193 input: &mut Parser<'i, 't>,
194 ) -> Result<AtRulePrelude, ParseError<'i>> {
195 match_ignore_ascii_case! { &*name,
196 "import" => {
197 if !self.check_state(State::Imports) {
198 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
199 }
200
201 if let AllowImportRules::No = self.allow_import_rules {
202 return Err(input.new_custom_error(StyleParseErrorKind::DisallowedImportRule))
203 }
204
205 // FIXME(emilio): We should always be able to have a loader
206 // around! See bug 1533783.
207 if self.loader.is_none() {
208 error!("Saw @import rule, but no way to trigger the load");
209 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
210 }
211
212 let url_string = input.expect_url_or_string()?.as_ref().to_owned();
213 let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
214
215 let layer = if !static_prefs::pref!("layout.css.cascade-layers.enabled") {
216 None
217 } else if input.try_parse(|input| input.expect_ident_matching("layer")).is_ok() {
218 Some(ImportLayer {
219 name: None,
220 })
221 } else {
222 input.try_parse(|input| {
223 input.expect_function_matching("layer")?;
224 input.parse_nested_block(|input| {
225 LayerName::parse(&self.context, input)
226 }).map(|name| ImportLayer {
227 name: Some(name),
228 })
229 }).ok()
230 };
231
232 let media = MediaList::parse(&self.context, input);
233 let media = Arc::new(self.shared_lock.wrap(media));
234
235 return Ok(AtRulePrelude::Import(url, media, layer));
236 },
237 "namespace" => {
238 if !self.check_state(State::Namespaces) {
239 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedNamespaceRule))
240 }
241
242 let prefix = input.try_parse(|i| i.expect_ident_cloned())
243 .map(|s| Prefix::from(s.as_ref())).ok();
244 let maybe_namespace = match input.expect_url_or_string() {
245 Ok(url_or_string) => url_or_string,
246 Err(BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location }) => {
247 return Err(location.new_custom_error(StyleParseErrorKind::UnexpectedTokenWithinNamespace(t)))
248 }
249 Err(e) => return Err(e.into()),
250 };
251 let url = Namespace::from(maybe_namespace.as_ref());
252 return Ok(AtRulePrelude::Namespace(prefix, url));
253 },
254 // @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
255 // anything left is invalid.
256 "charset" => {
257 self.dom_error = Some(RulesMutateError::HierarchyRequest);
258 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
259 },
260 _ => {}
261 }
262
263 if !self.check_state(State::Body) {
264 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
265 }
266
267 AtRuleParser::parse_prelude(&mut self.nested(), name, input)
268 }
269
270 #[inline]
parse_block<'t>( &mut self, prelude: AtRulePrelude, start: &ParserState, input: &mut Parser<'i, 't>, ) -> Result<Self::AtRule, ParseError<'i>>271 fn parse_block<'t>(
272 &mut self,
273 prelude: AtRulePrelude,
274 start: &ParserState,
275 input: &mut Parser<'i, 't>,
276 ) -> Result<Self::AtRule, ParseError<'i>> {
277 let rule = AtRuleParser::parse_block(&mut self.nested(), prelude, start, input)?;
278 self.state = State::Body;
279 Ok((start.position(), rule))
280 }
281
282 #[inline]
rule_without_block( &mut self, prelude: AtRulePrelude, start: &ParserState, ) -> Result<Self::AtRule, ()>283 fn rule_without_block(
284 &mut self,
285 prelude: AtRulePrelude,
286 start: &ParserState,
287 ) -> Result<Self::AtRule, ()> {
288 let rule = match prelude {
289 AtRulePrelude::Import(url, media, layer) => {
290 let loader = self
291 .loader
292 .expect("Expected a stylesheet loader for @import");
293
294 let import_rule = loader.request_stylesheet(
295 url,
296 start.source_location(),
297 &self.context,
298 &self.shared_lock,
299 media,
300 layer,
301 );
302
303 self.state = State::Imports;
304 CssRule::Import(import_rule)
305 },
306 AtRulePrelude::Namespace(prefix, url) => {
307 let prefix = if let Some(prefix) = prefix {
308 self.namespaces.prefixes.insert(prefix.clone(), url.clone());
309 Some(prefix)
310 } else {
311 self.namespaces.default = Some(url.clone());
312 None
313 };
314
315 self.state = State::Namespaces;
316 CssRule::Namespace(Arc::new(self.shared_lock.wrap(NamespaceRule {
317 prefix,
318 url,
319 source_location: start.source_location(),
320 })))
321 },
322 AtRulePrelude::Layer(ref names) => {
323 if names.is_empty() {
324 return Err(());
325 }
326 if self.state <= State::EarlyLayers {
327 self.state = State::EarlyLayers;
328 } else {
329 self.state = State::Body;
330 }
331 AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)
332 .expect("All validity checks on the nested parser should be done before changing self.state")
333 },
334 _ => AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)?,
335 };
336
337 Ok((start.position(), rule))
338 }
339 }
340
341 impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a> {
342 type Prelude = SelectorList<SelectorImpl>;
343 type QualifiedRule = (SourcePosition, CssRule);
344 type Error = StyleParseErrorKind<'i>;
345
346 #[inline]
parse_prelude<'t>( &mut self, input: &mut Parser<'i, 't>, ) -> Result<Self::Prelude, ParseError<'i>>347 fn parse_prelude<'t>(
348 &mut self,
349 input: &mut Parser<'i, 't>,
350 ) -> Result<Self::Prelude, ParseError<'i>> {
351 if !self.check_state(State::Body) {
352 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
353 }
354
355 QualifiedRuleParser::parse_prelude(&mut self.nested(), input)
356 }
357
358 #[inline]
parse_block<'t>( &mut self, prelude: Self::Prelude, start: &ParserState, input: &mut Parser<'i, 't>, ) -> Result<Self::QualifiedRule, ParseError<'i>>359 fn parse_block<'t>(
360 &mut self,
361 prelude: Self::Prelude,
362 start: &ParserState,
363 input: &mut Parser<'i, 't>,
364 ) -> Result<Self::QualifiedRule, ParseError<'i>> {
365 let rule = QualifiedRuleParser::parse_block(&mut self.nested(), prelude, start, input)?;
366 self.state = State::Body;
367 Ok((start.position(), rule))
368 }
369 }
370
371 #[derive(Clone)] // shallow, relatively cheap .clone
372 struct NestedRuleParser<'a, 'b: 'a> {
373 shared_lock: &'a SharedRwLock,
374 context: &'a ParserContext<'b>,
375 namespaces: &'a Namespaces,
376 }
377
378 impl<'a, 'b> NestedRuleParser<'a, 'b> {
parse_nested_rules( &mut self, input: &mut Parser, rule_type: CssRuleType, ) -> Arc<Locked<CssRules>>379 fn parse_nested_rules(
380 &mut self,
381 input: &mut Parser,
382 rule_type: CssRuleType,
383 ) -> Arc<Locked<CssRules>> {
384 let context = ParserContext::new_with_rule_type(self.context, rule_type, self.namespaces);
385
386 let nested_parser = NestedRuleParser {
387 shared_lock: self.shared_lock,
388 context: &context,
389 namespaces: self.namespaces,
390 };
391
392 let mut iter = RuleListParser::new_for_nested_rule(input, nested_parser);
393 let mut rules = Vec::new();
394 while let Some(result) = iter.next() {
395 match result {
396 Ok(rule) => rules.push(rule),
397 Err((error, slice)) => {
398 let location = error.location;
399 let error = ContextualParseError::InvalidRule(slice, error);
400 self.context.log_css_error(location, error);
401 },
402 }
403 }
404 CssRules::new(rules, self.shared_lock)
405 }
406 }
407
408 impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
409 type Prelude = AtRulePrelude;
410 type AtRule = CssRule;
411 type Error = StyleParseErrorKind<'i>;
412
parse_prelude<'t>( &mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>, ) -> Result<Self::Prelude, ParseError<'i>>413 fn parse_prelude<'t>(
414 &mut self,
415 name: CowRcStr<'i>,
416 input: &mut Parser<'i, 't>,
417 ) -> Result<Self::Prelude, ParseError<'i>> {
418 Ok(match_ignore_ascii_case! { &*name,
419 "media" => {
420 let media_queries = MediaList::parse(self.context, input);
421 let arc = Arc::new(self.shared_lock.wrap(media_queries));
422 AtRulePrelude::Media(arc)
423 },
424 "supports" => {
425 let cond = SupportsCondition::parse(input)?;
426 AtRulePrelude::Supports(cond)
427 },
428 "font-face" => {
429 AtRulePrelude::FontFace
430 },
431 "layer" if static_prefs::pref!("layout.css.cascade-layers.enabled") => {
432 let names = input.try_parse(|input| {
433 input.parse_comma_separated(|input| {
434 LayerName::parse(self.context, input)
435 })
436 }).unwrap_or_default();
437 AtRulePrelude::Layer(names)
438 },
439 "font-feature-values" if cfg!(feature = "gecko") => {
440 let family_names = parse_family_name_list(self.context, input)?;
441 AtRulePrelude::FontFeatureValues(family_names)
442 },
443 "counter-style" if cfg!(feature = "gecko") => {
444 let name = parse_counter_style_name_definition(input)?;
445 AtRulePrelude::CounterStyle(name)
446 },
447 "viewport" if viewport_rule::enabled() => {
448 AtRulePrelude::Viewport
449 },
450 "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
451 let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
452 Some(VendorPrefix::WebKit)
453 } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
454 Some(VendorPrefix::Moz)
455 } else {
456 None
457 };
458 if cfg!(feature = "servo") &&
459 prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) {
460 // Servo should not support @-moz-keyframes.
461 return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
462 }
463 let name = KeyframesName::parse(self.context, input)?;
464 AtRulePrelude::Keyframes(name, prefix)
465 },
466 "page" if cfg!(feature = "gecko") => {
467 AtRulePrelude::Page(if static_prefs::pref!("layout.css.named-pages.enabled") {
468 input.try_parse(|i| PageSelectors::parse(self.context, i)).unwrap_or_default()
469 } else {
470 PageSelectors::default()
471 })
472 },
473 "-moz-document" if cfg!(feature = "gecko") => {
474 let cond = DocumentCondition::parse(self.context, input)?;
475 AtRulePrelude::Document(cond)
476 },
477 "scroll-timeline" if static_prefs::pref!("layout.css.scroll-linked-animations.enabled") => {
478 let name = TimelineName::parse(self.context, input)?;
479 AtRulePrelude::ScrollTimeline(name)
480 },
481 _ => return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
482 })
483 }
484
parse_block<'t>( &mut self, prelude: AtRulePrelude, start: &ParserState, input: &mut Parser<'i, 't>, ) -> Result<CssRule, ParseError<'i>>485 fn parse_block<'t>(
486 &mut self,
487 prelude: AtRulePrelude,
488 start: &ParserState,
489 input: &mut Parser<'i, 't>,
490 ) -> Result<CssRule, ParseError<'i>> {
491 match prelude {
492 AtRulePrelude::FontFace => {
493 let context = ParserContext::new_with_rule_type(
494 self.context,
495 CssRuleType::FontFace,
496 self.namespaces,
497 );
498
499 Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
500 parse_font_face_block(&context, input, start.source_location()).into(),
501 ))))
502 },
503 AtRulePrelude::FontFeatureValues(family_names) => {
504 let context = ParserContext::new_with_rule_type(
505 self.context,
506 CssRuleType::FontFeatureValues,
507 self.namespaces,
508 );
509
510 Ok(CssRule::FontFeatureValues(Arc::new(self.shared_lock.wrap(
511 FontFeatureValuesRule::parse(
512 &context,
513 input,
514 family_names,
515 start.source_location(),
516 ),
517 ))))
518 },
519 AtRulePrelude::CounterStyle(name) => {
520 let context = ParserContext::new_with_rule_type(
521 self.context,
522 CssRuleType::CounterStyle,
523 self.namespaces,
524 );
525
526 Ok(CssRule::CounterStyle(Arc::new(
527 self.shared_lock.wrap(
528 parse_counter_style_body(name, &context, input, start.source_location())?
529 .into(),
530 ),
531 )))
532 },
533 AtRulePrelude::Media(media_queries) => {
534 Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule {
535 media_queries,
536 rules: self.parse_nested_rules(input, CssRuleType::Media),
537 source_location: start.source_location(),
538 }))))
539 },
540 AtRulePrelude::Supports(condition) => {
541 let eval_context = ParserContext::new_with_rule_type(
542 self.context,
543 CssRuleType::Style,
544 self.namespaces,
545 );
546
547 let enabled = condition.eval(&eval_context, self.namespaces);
548 Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap(
549 SupportsRule {
550 condition,
551 rules: self.parse_nested_rules(input, CssRuleType::Supports),
552 enabled,
553 source_location: start.source_location(),
554 },
555 ))))
556 },
557 AtRulePrelude::Viewport => {
558 let context = ParserContext::new_with_rule_type(
559 self.context,
560 CssRuleType::Viewport,
561 self.namespaces,
562 );
563
564 Ok(CssRule::Viewport(Arc::new(
565 self.shared_lock.wrap(ViewportRule::parse(&context, input)?),
566 )))
567 },
568 AtRulePrelude::Keyframes(name, vendor_prefix) => {
569 let context = ParserContext::new_with_rule_type(
570 self.context,
571 CssRuleType::Keyframes,
572 self.namespaces,
573 );
574
575 Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(
576 KeyframesRule {
577 name,
578 keyframes: parse_keyframe_list(&context, input, self.shared_lock),
579 vendor_prefix,
580 source_location: start.source_location(),
581 },
582 ))))
583 },
584 AtRulePrelude::Page(selectors) => {
585 let context = ParserContext::new_with_rule_type(
586 self.context,
587 CssRuleType::Page,
588 self.namespaces,
589 );
590
591 let declarations = parse_property_declaration_list(&context, input, None);
592 Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule {
593 selectors,
594 block: Arc::new(self.shared_lock.wrap(declarations)),
595 source_location: start.source_location(),
596 }))))
597 },
598 AtRulePrelude::Document(condition) => {
599 if !cfg!(feature = "gecko") {
600 unreachable!()
601 }
602 Ok(CssRule::Document(Arc::new(self.shared_lock.wrap(
603 DocumentRule {
604 condition,
605 rules: self.parse_nested_rules(input, CssRuleType::Document),
606 source_location: start.source_location(),
607 },
608 ))))
609 },
610 AtRulePrelude::Layer(names) => {
611 let name = match names.len() {
612 0 | 1 => names.into_iter().next(),
613 _ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
614 };
615 Ok(CssRule::LayerBlock(Arc::new(self.shared_lock.wrap(
616 LayerBlockRule {
617 name,
618 rules: self.parse_nested_rules(input, CssRuleType::LayerBlock),
619 source_location: start.source_location(),
620 },
621 ))))
622 },
623 AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => {
624 // These rules don't have blocks.
625 Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock))
626 },
627 AtRulePrelude::ScrollTimeline(name) => {
628 let context = ParserContext::new_with_rule_type(
629 self.context,
630 CssRuleType::ScrollTimeline,
631 self.namespaces,
632 );
633
634 Ok(CssRule::ScrollTimeline(Arc::new(self.shared_lock.wrap(
635 ScrollTimelineRule {
636 name,
637 descriptors: ScrollTimelineDescriptors::parse(&context, input)?,
638 source_location: start.source_location(),
639 },
640 ))))
641 },
642 }
643 }
644
645 #[inline]
rule_without_block( &mut self, prelude: AtRulePrelude, start: &ParserState, ) -> Result<Self::AtRule, ()>646 fn rule_without_block(
647 &mut self,
648 prelude: AtRulePrelude,
649 start: &ParserState,
650 ) -> Result<Self::AtRule, ()> {
651 Ok(match prelude {
652 AtRulePrelude::Layer(names) => {
653 if names.is_empty() {
654 return Err(());
655 }
656 CssRule::LayerStatement(Arc::new(self.shared_lock.wrap(LayerStatementRule {
657 names,
658 source_location: start.source_location(),
659 })))
660 },
661 _ => return Err(()),
662 })
663 }
664 }
665
666 #[inline(never)]
check_for_useless_selector( input: &mut Parser, context: &ParserContext, selectors: &SelectorList<SelectorImpl>, )667 fn check_for_useless_selector(
668 input: &mut Parser,
669 context: &ParserContext,
670 selectors: &SelectorList<SelectorImpl>,
671 ) {
672 use cssparser::ToCss;
673
674 'selector_loop: for selector in selectors.0.iter() {
675 let mut current = selector.iter();
676 loop {
677 let mut found_host = false;
678 let mut found_non_host = false;
679 for component in &mut current {
680 if component.is_host() {
681 found_host = true;
682 } else {
683 found_non_host = true;
684 }
685 if found_host && found_non_host {
686 let location = input.current_source_location();
687 context.log_css_error(
688 location,
689 ContextualParseError::NeverMatchingHostSelector(selector.to_css_string()),
690 );
691 continue 'selector_loop;
692 }
693 }
694 if current.next_sequence().is_none() {
695 break;
696 }
697 }
698 }
699 }
700
701 impl<'a, 'b, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'b> {
702 type Prelude = SelectorList<SelectorImpl>;
703 type QualifiedRule = CssRule;
704 type Error = StyleParseErrorKind<'i>;
705
parse_prelude<'t>( &mut self, input: &mut Parser<'i, 't>, ) -> Result<Self::Prelude, ParseError<'i>>706 fn parse_prelude<'t>(
707 &mut self,
708 input: &mut Parser<'i, 't>,
709 ) -> Result<Self::Prelude, ParseError<'i>> {
710 let selector_parser = SelectorParser {
711 stylesheet_origin: self.context.stylesheet_origin,
712 namespaces: self.namespaces,
713 url_data: self.context.url_data,
714 };
715 let selectors = SelectorList::parse(&selector_parser, input)?;
716 if self.context.error_reporting_enabled() {
717 check_for_useless_selector(input, &self.context, &selectors);
718 }
719 Ok(selectors)
720 }
721
parse_block<'t>( &mut self, selectors: Self::Prelude, start: &ParserState, input: &mut Parser<'i, 't>, ) -> Result<CssRule, ParseError<'i>>722 fn parse_block<'t>(
723 &mut self,
724 selectors: Self::Prelude,
725 start: &ParserState,
726 input: &mut Parser<'i, 't>,
727 ) -> Result<CssRule, ParseError<'i>> {
728 let context =
729 ParserContext::new_with_rule_type(self.context, CssRuleType::Style, self.namespaces);
730
731 let declarations = parse_property_declaration_list(&context, input, Some(&selectors));
732 let block = Arc::new(self.shared_lock.wrap(declarations));
733 Ok(CssRule::Style(Arc::new(self.shared_lock.wrap(StyleRule {
734 selectors,
735 block,
736 source_location: start.source_location(),
737 }))))
738 }
739 }
740