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