style/stylesheets/
rule_parser.rs

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
7use crate::counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
8use crate::custom_properties::parse_name as parse_custom_property_name;
9use crate::error_reporting::ContextualParseError;
10use crate::font_face::parse_font_face_block;
11use crate::media_queries::MediaList;
12use crate::parser::{Parse, ParserContext};
13use crate::properties::declaration_block::{
14    parse_property_declaration_list, DeclarationParserState, PropertyDeclarationBlock,
15};
16use crate::properties_and_values::rule::{parse_property_block, PropertyRuleName};
17use crate::selector_parser::{SelectorImpl, SelectorParser};
18use crate::shared_lock::{Locked, SharedRwLock};
19use crate::str::starts_with_ignore_ascii_case;
20use crate::stylesheets::container_rule::{ContainerCondition, ContainerRule};
21use crate::stylesheets::document_rule::DocumentCondition;
22use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
23use crate::stylesheets::import_rule::{ImportLayer, ImportRule, ImportSupportsCondition};
24use crate::stylesheets::keyframes_rule::parse_keyframe_list;
25use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
26use crate::stylesheets::scope_rule::{ScopeBounds, ScopeRule};
27use crate::stylesheets::supports_rule::SupportsCondition;
28use crate::stylesheets::{
29    AllowImportRules, CorsMode, CssRule, CssRuleType, CssRuleTypes, CssRules, CustomMediaCondition,
30    CustomMediaRule, DocumentRule, FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule,
31    MarginRule, MarginRuleType, MediaRule, NamespaceRule, NestedDeclarationsRule, PageRule,
32    PageSelectors, PositionTryRule, RulesMutateError, StartingStyleRule, StyleRule,
33    StylesheetLoader, SupportsRule,
34};
35use crate::values::computed::font::FamilyName;
36use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
37use crate::{Atom, Namespace, Prefix};
38use cssparser::{
39    AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, DeclarationParser, Parser,
40    ParserState, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourcePosition,
41};
42use selectors::parser::{ParseRelative, SelectorList};
43use servo_arc::Arc;
44use style_traits::{ParseError, StyleParseErrorKind};
45
46/// The information we need particularly to do CSSOM insertRule stuff.
47pub struct InsertRuleContext<'a> {
48    /// The rule list we're about to insert into.
49    pub rule_list: &'a [CssRule],
50    /// The index we're about to get inserted at.
51    pub index: usize,
52    /// The containing rule types of our ancestors.
53    pub containing_rule_types: CssRuleTypes,
54    /// Rule type determining if and how we parse relative selector syntax.
55    pub parse_relative_rule_type: Option<CssRuleType>,
56}
57
58impl<'a> InsertRuleContext<'a> {
59    /// Returns the max rule state allowable for insertion at a given index in
60    /// the rule list.
61    pub fn max_rule_state_at_index(&self, index: usize) -> State {
62        let rule = match self.rule_list.get(index) {
63            Some(rule) => rule,
64            None => return State::Body,
65        };
66        match rule {
67            CssRule::Import(..) => State::Imports,
68            CssRule::Namespace(..) => State::Namespaces,
69            CssRule::LayerStatement(..) => {
70                // If there are @import / @namespace after this layer, then
71                // we're in the early-layers phase, otherwise we're in the body
72                // and everything is fair game.
73                let next_non_layer_statement_rule = self.rule_list[index + 1..]
74                    .iter()
75                    .find(|r| !matches!(*r, CssRule::LayerStatement(..)));
76                if let Some(non_layer) = next_non_layer_statement_rule {
77                    if matches!(*non_layer, CssRule::Import(..) | CssRule::Namespace(..)) {
78                        return State::EarlyLayers;
79                    }
80                }
81                State::Body
82            },
83            _ => State::Body,
84        }
85    }
86}
87
88/// The parser for the top-level rules in a stylesheet.
89pub struct TopLevelRuleParser<'a, 'i> {
90    /// A reference to the lock we need to use to create rules.
91    pub shared_lock: &'a SharedRwLock,
92    /// A reference to a stylesheet loader if applicable, for `@import` rules.
93    pub loader: Option<&'a dyn StylesheetLoader>,
94    /// The top-level parser context.
95    pub context: ParserContext<'a>,
96    /// The current state of the parser.
97    pub state: State,
98    /// Whether we have tried to parse was invalid due to being in the wrong
99    /// place (e.g. an @import rule was found while in the `Body` state). Reset
100    /// to `false` when `take_had_hierarchy_error` is called.
101    pub dom_error: Option<RulesMutateError>,
102    /// The info we need insert a rule in a list.
103    pub insert_rule_context: Option<InsertRuleContext<'a>>,
104    /// Whether @import rules will be allowed.
105    pub allow_import_rules: AllowImportRules,
106    /// Whether to keep declarations into first_declaration_block, rather than turning it into a
107    /// nested declarations rule.
108    pub wants_first_declaration_block: bool,
109    /// The first declaration block, only relevant when wants_first_declaration_block is true.
110    pub first_declaration_block: PropertyDeclarationBlock,
111    /// Parser state for declaration blocks in either nested rules or style rules.
112    pub declaration_parser_state: DeclarationParserState<'i>,
113    /// State we keep around only for error reporting purposes. Right now that contains just the
114    /// selectors stack for nesting, if any.
115    ///
116    /// TODO(emilio): This isn't populated properly for `insertRule()` but...
117    pub error_reporting_state: Vec<SelectorList<SelectorImpl>>,
118    /// The rules we've parsed so far.
119    pub rules: Vec<CssRule>,
120}
121
122impl<'a, 'i> TopLevelRuleParser<'a, 'i> {
123    #[inline]
124    fn nested(&mut self) -> &mut NestedRuleParser<'a, 'i> {
125        // SAFETY: NestedRuleParser is just a repr(transparent) wrapper over TopLevelRuleParser
126        const_assert!(
127            std::mem::size_of::<TopLevelRuleParser<'static, 'static>>()
128                == std::mem::size_of::<NestedRuleParser<'static, 'static>>()
129        );
130        const_assert!(
131            std::mem::align_of::<TopLevelRuleParser<'static, 'static>>()
132                == std::mem::align_of::<NestedRuleParser<'static, 'static>>()
133        );
134        unsafe { &mut *(self as *mut _ as *mut NestedRuleParser<'a, 'i>) }
135    }
136
137    /// Returns the current state of the parser.
138    #[inline]
139    pub fn state(&self) -> State {
140        self.state
141    }
142
143    /// If we're in a nested state, this returns whether declarations can be parsed. See
144    /// RuleBodyItemParser::parse_declarations().
145    #[inline]
146    pub fn can_parse_declarations(&self) -> bool {
147        // We also have to check for page rules here because we currently don't
148        // have a bespoke parser for page rules, and parse them as though they
149        // are style rules.
150        // Scope rules can have direct declarations, behaving as if `:where(:scope)`.
151        // See https://drafts.csswg.org/css-cascade-6/#scoped-declarations
152        self.in_specified_rule(
153            CssRuleType::Style.bit() | CssRuleType::Page.bit() | CssRuleType::Scope.bit(),
154        )
155    }
156
157    #[inline]
158    fn in_style_rule(&self) -> bool {
159        self.context
160            .nesting_context
161            .rule_types
162            .contains(CssRuleType::Style)
163    }
164
165    #[inline]
166    fn in_page_rule(&self) -> bool {
167        self.context
168            .nesting_context
169            .rule_types
170            .contains(CssRuleType::Page)
171    }
172
173    #[inline]
174    fn in_specified_rule(&self, bits: u32) -> bool {
175        let types = CssRuleTypes::from_bits(bits);
176        self.context.nesting_context.rule_types.intersects(types)
177    }
178
179    #[inline]
180    fn in_style_or_page_rule(&self) -> bool {
181        self.in_specified_rule(CssRuleType::Style.bit() | CssRuleType::Page.bit())
182    }
183
184    /// Checks whether we can parse a rule that would transition us to
185    /// `new_state`.
186    ///
187    /// This is usually a simple branch, but we may need more bookkeeping if
188    /// doing `insertRule` from CSSOM.
189    fn check_state(&mut self, new_state: State) -> bool {
190        if self.state > new_state {
191            self.dom_error = Some(RulesMutateError::HierarchyRequest);
192            return false;
193        }
194
195        let ctx = match self.insert_rule_context {
196            Some(ref ctx) => ctx,
197            None => return true,
198        };
199
200        let max_rule_state = ctx.max_rule_state_at_index(ctx.index);
201        if new_state > max_rule_state {
202            self.dom_error = Some(RulesMutateError::HierarchyRequest);
203            return false;
204        }
205
206        // If there's anything that isn't a namespace rule (or import rule, but
207        // we checked that already at the beginning), reject with a
208        // StateError.
209        if new_state == State::Namespaces
210            && ctx.rule_list[ctx.index..]
211                .iter()
212                .any(|r| !matches!(*r, CssRule::Namespace(..)))
213        {
214            self.dom_error = Some(RulesMutateError::InvalidState);
215            return false;
216        }
217
218        true
219    }
220}
221
222/// The current state of the parser.
223#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
224pub enum State {
225    /// We haven't started parsing rules.
226    Start = 1,
227    /// We're parsing early `@layer` statement rules.
228    EarlyLayers = 2,
229    /// We're parsing `@import` and early `@layer` statement rules.
230    Imports = 3,
231    /// We're parsing `@namespace` rules.
232    Namespaces = 4,
233    /// We're parsing the main body of the stylesheet.
234    Body = 5,
235}
236
237#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
238/// Vendor prefix.
239pub enum VendorPrefix {
240    /// -moz prefix.
241    Moz,
242    /// -webkit prefix.
243    WebKit,
244}
245
246/// A rule prelude for at-rule with block.
247pub enum AtRulePrelude {
248    /// A @font-face rule prelude.
249    FontFace,
250    /// A @font-feature-values rule prelude, with its FamilyName list.
251    FontFeatureValues(Vec<FamilyName>),
252    /// A @font-palette-values rule prelude, with its identifier.
253    FontPaletteValues(DashedIdent),
254    /// A @counter-style rule prelude, with its counter style name.
255    CounterStyle(CustomIdent),
256    /// A @media rule prelude, with its media queries.
257    Media(Arc<Locked<MediaList>>),
258    /// A @container rule prelude.
259    Container(Arc<ContainerCondition>),
260    /// An @supports rule, with its conditional
261    Supports(SupportsCondition),
262    /// A @keyframes rule, with its animation name and vendor prefix if exists.
263    Keyframes(KeyframesName, Option<VendorPrefix>),
264    /// A @page rule prelude, with its page name if it exists.
265    Page(PageSelectors),
266    /// A @property rule prelude.
267    Property(PropertyRuleName),
268    /// A @document rule, with its conditional.
269    Document(DocumentCondition),
270    /// A @import rule prelude.
271    Import(
272        CssUrl,
273        Arc<Locked<MediaList>>,
274        Option<ImportSupportsCondition>,
275        ImportLayer,
276    ),
277    /// A @margin rule prelude.
278    Margin(MarginRuleType),
279    /// A @namespace rule prelude.
280    Namespace(Option<Prefix>, Namespace),
281    /// A @layer rule prelude.
282    Layer(Vec<LayerName>),
283    /// A @scope rule prelude.
284    Scope(ScopeBounds),
285    /// A @starting-style prelude.
286    StartingStyle,
287    /// A @position-try prelude for Anchor Positioning.
288    PositionTry(DashedIdent),
289    /// A @custom-media prelude.
290    CustomMedia(DashedIdent, CustomMediaCondition),
291}
292
293impl AtRulePrelude {
294    fn name(&self) -> &'static str {
295        match *self {
296            Self::FontFace => "font-face",
297            Self::FontFeatureValues(..) => "font-feature-values",
298            Self::FontPaletteValues(..) => "font-palette-values",
299            Self::CounterStyle(..) => "counter-style",
300            Self::Media(..) => "media",
301            Self::CustomMedia(..) => "custom-media",
302            Self::Container(..) => "container",
303            Self::Supports(..) => "supports",
304            Self::Keyframes(..) => "keyframes",
305            Self::Page(..) => "page",
306            Self::Property(..) => "property",
307            Self::Document(..) => "-moz-document",
308            Self::Import(..) => "import",
309            Self::Margin(..) => "margin",
310            Self::Namespace(..) => "namespace",
311            Self::Layer(..) => "layer",
312            Self::Scope(..) => "scope",
313            Self::StartingStyle => "starting-style",
314            Self::PositionTry(..) => "position-try",
315        }
316    }
317}
318
319impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
320    type Prelude = AtRulePrelude;
321    type AtRule = SourcePosition;
322    type Error = StyleParseErrorKind<'i>;
323
324    fn parse_prelude<'t>(
325        &mut self,
326        name: CowRcStr<'i>,
327        input: &mut Parser<'i, 't>,
328    ) -> Result<AtRulePrelude, ParseError<'i>> {
329        match_ignore_ascii_case! { &*name,
330            "import" => {
331                if !self.check_state(State::Imports) {
332                    return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
333                }
334
335                if let AllowImportRules::No = self.allow_import_rules {
336                    return Err(input.new_custom_error(StyleParseErrorKind::DisallowedImportRule))
337                }
338
339                // FIXME(emilio): We should always be able to have a loader
340                // around! See bug 1533783.
341                if self.loader.is_none() {
342                    error!("Saw @import rule, but no way to trigger the load");
343                    return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
344                }
345
346                let url_string = input.expect_url_or_string()?.as_ref().to_owned();
347                let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
348
349                let (layer, supports) = ImportRule::parse_layer_and_supports(input, &mut self.context);
350
351                let media = MediaList::parse(&self.context, input);
352                let media = Arc::new(self.shared_lock.wrap(media));
353
354                return Ok(AtRulePrelude::Import(url, media, supports, layer));
355            },
356            "namespace" => {
357                if !self.check_state(State::Namespaces) {
358                    return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedNamespaceRule))
359                }
360
361                let prefix = input.try_parse(|i| i.expect_ident_cloned())
362                                  .map(|s| Prefix::from(s.as_ref())).ok();
363                let maybe_namespace = match input.expect_url_or_string() {
364                    Ok(url_or_string) => url_or_string,
365                    Err(BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location }) => {
366                        return Err(location.new_custom_error(StyleParseErrorKind::UnexpectedTokenWithinNamespace(t)))
367                    }
368                    Err(e) => return Err(e.into()),
369                };
370                let url = Namespace::from(maybe_namespace.as_ref());
371                return Ok(AtRulePrelude::Namespace(prefix, url));
372            },
373            // @charset is removed by rust-cssparser if it’s the first rule in the stylesheet
374            // anything left is invalid.
375            "charset" => {
376                self.dom_error = Some(RulesMutateError::HierarchyRequest);
377                return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
378            },
379            "layer" => {
380                let state_to_check = if self.state <= State::EarlyLayers {
381                    // The real state depends on whether there's a block or not.
382                    // We don't know that yet, but the parse_block check deals
383                    // with that.
384                    State::EarlyLayers
385                } else {
386                    State::Body
387                };
388                if !self.check_state(state_to_check) {
389                    return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
390                }
391            },
392            _ => {
393                // All other rules have blocks, so we do this check early in
394                // parse_block instead.
395            }
396        }
397
398        AtRuleParser::parse_prelude(self.nested(), name, input)
399    }
400
401    #[inline]
402    fn parse_block<'t>(
403        &mut self,
404        prelude: AtRulePrelude,
405        start: &ParserState,
406        input: &mut Parser<'i, 't>,
407    ) -> Result<Self::AtRule, ParseError<'i>> {
408        if !self.check_state(State::Body) {
409            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
410        }
411        AtRuleParser::parse_block(self.nested(), prelude, start, input)?;
412        self.state = State::Body;
413        Ok(start.position())
414    }
415
416    #[inline]
417    fn rule_without_block(
418        &mut self,
419        prelude: AtRulePrelude,
420        start: &ParserState,
421    ) -> Result<Self::AtRule, ()> {
422        match prelude {
423            AtRulePrelude::Import(url, media, supports, layer) => {
424                let loader = self
425                    .loader
426                    .expect("Expected a stylesheet loader for @import");
427
428                let import_rule = loader.request_stylesheet(
429                    url,
430                    start.source_location(),
431                    &self.shared_lock,
432                    media,
433                    supports,
434                    layer,
435                );
436
437                self.state = State::Imports;
438                self.rules.push(CssRule::Import(import_rule))
439            },
440            AtRulePrelude::Namespace(prefix, url) => {
441                let namespaces = self.context.namespaces.to_mut();
442                let prefix = if let Some(prefix) = prefix {
443                    namespaces.prefixes.insert(prefix.clone(), url.clone());
444                    Some(prefix)
445                } else {
446                    namespaces.default = Some(url.clone());
447                    None
448                };
449
450                self.state = State::Namespaces;
451                self.rules.push(CssRule::Namespace(Arc::new(NamespaceRule {
452                    prefix,
453                    url,
454                    source_location: start.source_location(),
455                })));
456            },
457            AtRulePrelude::Layer(..) => {
458                AtRuleParser::rule_without_block(self.nested(), prelude, start)?;
459                if self.state <= State::EarlyLayers {
460                    self.state = State::EarlyLayers;
461                } else {
462                    self.state = State::Body;
463                }
464            },
465            _ => AtRuleParser::rule_without_block(self.nested(), prelude, start)?,
466        };
467
468        Ok(start.position())
469    }
470}
471
472impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
473    type Prelude = SelectorList<SelectorImpl>;
474    type QualifiedRule = SourcePosition;
475    type Error = StyleParseErrorKind<'i>;
476
477    #[inline]
478    fn parse_prelude<'t>(
479        &mut self,
480        input: &mut Parser<'i, 't>,
481    ) -> Result<Self::Prelude, ParseError<'i>> {
482        if !self.check_state(State::Body) {
483            return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
484        }
485
486        QualifiedRuleParser::parse_prelude(self.nested(), input)
487    }
488
489    #[inline]
490    fn parse_block<'t>(
491        &mut self,
492        prelude: Self::Prelude,
493        start: &ParserState,
494        input: &mut Parser<'i, 't>,
495    ) -> Result<Self::QualifiedRule, ParseError<'i>> {
496        QualifiedRuleParser::parse_block(self.nested(), prelude, start, input)?;
497        self.state = State::Body;
498        Ok(start.position())
499    }
500}
501
502#[repr(transparent)]
503#[derive(Deref, DerefMut)]
504struct NestedRuleParser<'a, 'i>(TopLevelRuleParser<'a, 'i>);
505
506struct NestedParseResult {
507    first_declaration_block: PropertyDeclarationBlock,
508    rules: Vec<CssRule>,
509}
510
511impl<'a, 'i> NestedRuleParser<'a, 'i> {
512    #[inline]
513    fn parse_relative(&self) -> ParseRelative {
514        self.context.nesting_context.parse_relative
515    }
516
517    // https://drafts.csswg.org/css-nesting/#conditionals
518    //     In addition to nested style rules, this specification allows nested group rules inside
519    //     of style rules: any at-rule whose body contains style rules can be nested inside of a
520    //     style rule as well.
521    fn at_rule_allowed(&self, prelude: &AtRulePrelude) -> bool {
522        match prelude {
523            AtRulePrelude::Media(..)
524            | AtRulePrelude::Supports(..)
525            | AtRulePrelude::Container(..)
526            | AtRulePrelude::Document(..)
527            | AtRulePrelude::Layer(..)
528            | AtRulePrelude::CustomMedia(..)
529            | AtRulePrelude::Scope(..)
530            | AtRulePrelude::StartingStyle => true,
531
532            AtRulePrelude::Namespace(..)
533            | AtRulePrelude::FontFace
534            | AtRulePrelude::FontFeatureValues(..)
535            | AtRulePrelude::FontPaletteValues(..)
536            | AtRulePrelude::CounterStyle(..)
537            | AtRulePrelude::Keyframes(..)
538            | AtRulePrelude::Page(..)
539            | AtRulePrelude::Property(..)
540            | AtRulePrelude::Import(..)
541            | AtRulePrelude::PositionTry(..) => !self.in_style_or_page_rule(),
542            AtRulePrelude::Margin(..) => self.in_page_rule(),
543        }
544    }
545
546    fn nest_for_rule<R>(&mut self, rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R) -> R {
547        let old = self.context.nesting_context.save(rule_type);
548        let r = cb(self);
549        self.context.nesting_context.restore(old);
550        r
551    }
552
553    fn parse_nested_rules(
554        &mut self,
555        input: &mut Parser<'i, '_>,
556        rule_type: CssRuleType,
557    ) -> Arc<Locked<CssRules>> {
558        let rules = self
559            .parse_nested(
560                input, rule_type, /* wants_first_declaration_block = */ false,
561            )
562            .rules;
563        CssRules::new(rules, &self.shared_lock)
564    }
565
566    fn parse_nested(
567        &mut self,
568        input: &mut Parser<'i, '_>,
569        rule_type: CssRuleType,
570        wants_first_declaration_block: bool,
571    ) -> NestedParseResult {
572        debug_assert!(
573            !self.wants_first_declaration_block,
574            "Should've flushed previous declarations"
575        );
576        self.nest_for_rule(rule_type, |parser| {
577            parser.wants_first_declaration_block = wants_first_declaration_block;
578            let parse_declarations = parser.parse_declarations();
579            let mut rules = std::mem::take(&mut parser.rules);
580            let mut first_declaration_block = std::mem::take(&mut parser.first_declaration_block);
581            let mut iter = RuleBodyParser::new(input, parser);
582            while let Some(result) = iter.next() {
583                match result {
584                    Ok(()) => {},
585                    Err((error, slice)) => {
586                        if parse_declarations {
587                            let top = &mut **iter.parser;
588                            top.declaration_parser_state
589                                .did_error(&top.context, error, slice);
590                        } else {
591                            let location = error.location;
592                            let error = ContextualParseError::InvalidRule(slice, error);
593                            iter.parser.context.log_css_error(location, error);
594                        }
595                    },
596                }
597            }
598            parser.flush_declarations();
599            debug_assert!(
600                !parser.wants_first_declaration_block,
601                "Flushing declarations should take care of this."
602            );
603            debug_assert!(
604                !parser.declaration_parser_state.has_parsed_declarations(),
605                "Parsed but didn't consume declarations"
606            );
607            std::mem::swap(&mut parser.rules, &mut rules);
608            std::mem::swap(
609                &mut parser.first_declaration_block,
610                &mut first_declaration_block,
611            );
612            NestedParseResult {
613                first_declaration_block,
614                rules,
615            }
616        })
617    }
618
619    #[inline(never)]
620    fn handle_error_reporting_selectors_pre(
621        &mut self,
622        start: &ParserState,
623        selectors: &SelectorList<SelectorImpl>,
624    ) {
625        use cssparser::ToCss;
626        debug_assert!(self.context.error_reporting_enabled());
627        self.error_reporting_state.push(selectors.clone());
628        'selector_loop: for selector in selectors.slice().iter() {
629            let mut current = selector.iter();
630            loop {
631                let mut found_host = false;
632                let mut found_non_host = false;
633                for component in &mut current {
634                    if component.is_host() {
635                        found_host = true;
636                    } else {
637                        found_non_host = true;
638                    }
639                    if found_host && found_non_host {
640                        self.context.log_css_error(
641                            start.source_location(),
642                            ContextualParseError::NeverMatchingHostSelector(
643                                selector.to_css_string(),
644                            ),
645                        );
646                        continue 'selector_loop;
647                    }
648                }
649                if current.next_sequence().is_none() {
650                    break;
651                }
652            }
653        }
654    }
655
656    fn handle_error_reporting_selectors_post(&mut self) {
657        self.error_reporting_state.pop();
658    }
659
660    #[inline]
661    fn flush_declarations(&mut self) {
662        let parser = &mut **self;
663        let wants_first_declaration_block = parser.wants_first_declaration_block;
664        parser.wants_first_declaration_block = false;
665        parser
666            .declaration_parser_state
667            .report_errors_if_needed(&parser.context, &parser.error_reporting_state);
668        if !parser.declaration_parser_state.has_parsed_declarations() {
669            return;
670        }
671        let source_location = parser.declaration_parser_state.first_declaration_start();
672        let declarations = parser.declaration_parser_state.take_declarations();
673        if wants_first_declaration_block {
674            debug_assert!(parser.first_declaration_block.is_empty(), "How?");
675            parser.first_declaration_block = declarations;
676        } else {
677            let nested_rule = CssRule::NestedDeclarations(Arc::new(parser.shared_lock.wrap(
678                NestedDeclarationsRule {
679                    block: Arc::new(parser.shared_lock.wrap(declarations)),
680                    source_location,
681                },
682            )));
683            parser.rules.push(nested_rule);
684        }
685    }
686}
687
688impl<'a, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'i> {
689    type Prelude = AtRulePrelude;
690    type AtRule = ();
691    type Error = StyleParseErrorKind<'i>;
692
693    fn parse_prelude<'t>(
694        &mut self,
695        name: CowRcStr<'i>,
696        input: &mut Parser<'i, 't>,
697    ) -> Result<Self::Prelude, ParseError<'i>> {
698        Ok(match_ignore_ascii_case! { &*name,
699            "media" => {
700                let media_queries = MediaList::parse(&self.context, input);
701                let arc = Arc::new(self.shared_lock.wrap(media_queries));
702                AtRulePrelude::Media(arc)
703            },
704            "supports" => {
705                let cond = SupportsCondition::parse(input)?;
706                AtRulePrelude::Supports(cond)
707            },
708            "font-face" => {
709                AtRulePrelude::FontFace
710            },
711            "container" if cfg!(feature = "gecko") => {
712                let condition = Arc::new(ContainerCondition::parse(&self.context, input)?);
713                AtRulePrelude::Container(condition)
714            },
715            "layer" => {
716                let names = input.try_parse(|input| {
717                    input.parse_comma_separated(|input| {
718                        LayerName::parse(&self.context, input)
719                    })
720                }).unwrap_or_default();
721                AtRulePrelude::Layer(names)
722            },
723            "font-feature-values" if cfg!(feature = "gecko") => {
724                let family_names = parse_family_name_list(&self.context, input)?;
725                AtRulePrelude::FontFeatureValues(family_names)
726            },
727            "font-palette-values" if static_prefs::pref!("layout.css.font-palette.enabled") => {
728                let name = DashedIdent::parse(&self.context, input)?;
729                AtRulePrelude::FontPaletteValues(name)
730            },
731            "counter-style" if cfg!(feature = "gecko") => {
732                let name = parse_counter_style_name_definition(input)?;
733                AtRulePrelude::CounterStyle(name)
734            },
735            "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
736                let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
737                    Some(VendorPrefix::WebKit)
738                } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
739                    Some(VendorPrefix::Moz)
740                } else {
741                    None
742                };
743                if cfg!(feature = "servo") &&
744                   prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) {
745                    // Servo should not support @-moz-keyframes.
746                    return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
747                }
748                let name = KeyframesName::parse(&self.context, input)?;
749                AtRulePrelude::Keyframes(name, prefix)
750            },
751            "page" if cfg!(feature = "gecko") => {
752                AtRulePrelude::Page(
753                    input.try_parse(|i| PageSelectors::parse(&self.context, i)).unwrap_or_default()
754                )
755            },
756            "property" if static_prefs::pref!("layout.css.properties-and-values.enabled") => {
757                let name = input.expect_ident_cloned()?;
758                let name = parse_custom_property_name(&name).map_err(|_| {
759                    input.new_custom_error(StyleParseErrorKind::UnexpectedIdent(name.clone()))
760                })?;
761                AtRulePrelude::Property(PropertyRuleName(Atom::from(name)))
762            },
763            "-moz-document" if cfg!(feature = "gecko") => {
764                let cond = DocumentCondition::parse(&self.context, input)?;
765                AtRulePrelude::Document(cond)
766            },
767            "scope" if static_prefs::pref!("layout.css.at-scope.enabled") => {
768                let bounds = ScopeBounds::parse(&self.context, input, self.parse_relative())?;
769                AtRulePrelude::Scope(bounds)
770            },
771            "starting-style" if static_prefs::pref!("layout.css.starting-style-at-rules.enabled") => {
772                AtRulePrelude::StartingStyle
773            },
774            "position-try" if static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
775                let name = DashedIdent::parse(&self.context, input)?;
776                AtRulePrelude::PositionTry(name)
777            },
778            "custom-media" if static_prefs::pref!("layout.css.custom-media.enabled") => {
779                let name = DashedIdent::parse(&self.context, input)?;
780                let condition = input.try_parse(CustomMediaCondition::parse_keyword).unwrap_or_else(|_| {
781                    CustomMediaCondition::MediaList(Arc::new(self.shared_lock.wrap(
782                        MediaList::parse(&self.context, input)
783                    )))
784                });
785                AtRulePrelude::CustomMedia(name, condition)
786            },
787            _ => {
788                if static_prefs::pref!("layout.css.margin-rules.enabled") {
789                    if let Some(margin_rule_type) = MarginRuleType::match_name(&name) {
790                        return Ok(AtRulePrelude::Margin(margin_rule_type));
791                    }
792                }
793                return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
794            },
795        })
796    }
797
798    fn parse_block<'t>(
799        &mut self,
800        prelude: AtRulePrelude,
801        start: &ParserState,
802        input: &mut Parser<'i, 't>,
803    ) -> Result<(), ParseError<'i>> {
804        if !self.at_rule_allowed(&prelude) {
805            self.dom_error = Some(RulesMutateError::HierarchyRequest);
806            return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(prelude.name().into())));
807        }
808        let source_location = start.source_location();
809        self.flush_declarations();
810        let rule = match prelude {
811            AtRulePrelude::FontFace => self.nest_for_rule(CssRuleType::FontFace, |p| {
812                CssRule::FontFace(Arc::new(
813                    p.shared_lock
814                        .wrap(parse_font_face_block(&p.context, input, source_location).into()),
815                ))
816            }),
817            AtRulePrelude::FontFeatureValues(family_names) => {
818                self.nest_for_rule(CssRuleType::FontFeatureValues, |p| {
819                    CssRule::FontFeatureValues(Arc::new(FontFeatureValuesRule::parse(
820                        &p.context,
821                        input,
822                        family_names,
823                        source_location,
824                    )))
825                })
826            },
827            AtRulePrelude::FontPaletteValues(name) => {
828                self.nest_for_rule(CssRuleType::FontPaletteValues, |p| {
829                    CssRule::FontPaletteValues(Arc::new(FontPaletteValuesRule::parse(
830                        &p.context,
831                        input,
832                        name,
833                        source_location,
834                    )))
835                })
836            },
837            AtRulePrelude::CounterStyle(name) => {
838                let body = self.nest_for_rule(CssRuleType::CounterStyle, |p| {
839                    parse_counter_style_body(name, &p.context, input, source_location)
840                })?;
841                CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(body)))
842            },
843            AtRulePrelude::Media(media_queries) => CssRule::Media(Arc::new(MediaRule {
844                media_queries,
845                rules: self.parse_nested_rules(input, CssRuleType::Media),
846                source_location,
847            })),
848            AtRulePrelude::Supports(condition) => {
849                let enabled =
850                    self.nest_for_rule(CssRuleType::Style, |p| condition.eval(&p.context));
851                CssRule::Supports(Arc::new(SupportsRule {
852                    condition,
853                    rules: self.parse_nested_rules(input, CssRuleType::Supports),
854                    enabled,
855                    source_location,
856                }))
857            },
858            AtRulePrelude::Keyframes(name, vendor_prefix) => {
859                self.nest_for_rule(CssRuleType::Keyframe, |p| {
860                    let top = &mut **p;
861                    CssRule::Keyframes(Arc::new(top.shared_lock.wrap(KeyframesRule {
862                        name,
863                        keyframes: parse_keyframe_list(&mut top.context, input, top.shared_lock),
864                        vendor_prefix,
865                        source_location,
866                    })))
867                })
868            },
869            AtRulePrelude::Page(selectors) => {
870                let page_rule = if !static_prefs::pref!("layout.css.margin-rules.enabled") {
871                    let declarations = self.nest_for_rule(CssRuleType::Page, |p| {
872                        parse_property_declaration_list(&p.context, input, &[])
873                    });
874                    PageRule {
875                        selectors,
876                        rules: CssRules::new(vec![], self.shared_lock),
877                        block: Arc::new(self.shared_lock.wrap(declarations)),
878                        source_location,
879                    }
880                } else {
881                    let result = self.parse_nested(input, CssRuleType::Page, true);
882                    PageRule {
883                        selectors,
884                        rules: CssRules::new(result.rules, self.shared_lock),
885                        block: Arc::new(self.shared_lock.wrap(result.first_declaration_block)),
886                        source_location,
887                    }
888                };
889                CssRule::Page(Arc::new(self.shared_lock.wrap(page_rule)))
890            },
891            AtRulePrelude::Property(name) => self.nest_for_rule(CssRuleType::Property, |p| {
892                let rule_data = parse_property_block(&p.context, input, name, source_location)?;
893                Ok::<CssRule, ParseError<'i>>(CssRule::Property(Arc::new(rule_data)))
894            })?,
895            AtRulePrelude::Document(condition) => {
896                if !cfg!(feature = "gecko") {
897                    unreachable!()
898                }
899                CssRule::Document(Arc::new(DocumentRule {
900                    condition,
901                    rules: self.parse_nested_rules(input, CssRuleType::Document),
902                    source_location,
903                }))
904            },
905            AtRulePrelude::Container(condition) => {
906                let source_location = start.source_location();
907                CssRule::Container(Arc::new(ContainerRule {
908                    condition,
909                    rules: self.parse_nested_rules(input, CssRuleType::Container),
910                    source_location,
911                }))
912            },
913            AtRulePrelude::Layer(names) => {
914                let name = match names.len() {
915                    0 | 1 => names.into_iter().next(),
916                    _ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
917                };
918                CssRule::LayerBlock(Arc::new(LayerBlockRule {
919                    name,
920                    rules: self.parse_nested_rules(input, CssRuleType::LayerBlock),
921                    source_location,
922                }))
923            },
924            AtRulePrelude::Margin(rule_type) => {
925                let declarations = self.nest_for_rule(CssRuleType::Margin, |p| {
926                    parse_property_declaration_list(&p.context, input, &[])
927                });
928                CssRule::Margin(Arc::new(MarginRule {
929                    rule_type,
930                    block: Arc::new(self.shared_lock.wrap(declarations)),
931                    source_location,
932                }))
933            },
934            AtRulePrelude::CustomMedia(..)
935            | AtRulePrelude::Import(..)
936            | AtRulePrelude::Namespace(..) => {
937                // These rules don't have blocks.
938                return Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock));
939            },
940            AtRulePrelude::Scope(bounds) => CssRule::Scope(Arc::new(ScopeRule {
941                bounds,
942                rules: self.parse_nested_rules(input, CssRuleType::Scope),
943                source_location,
944            })),
945            AtRulePrelude::StartingStyle => CssRule::StartingStyle(Arc::new(StartingStyleRule {
946                rules: self.parse_nested_rules(input, CssRuleType::StartingStyle),
947                source_location,
948            })),
949            AtRulePrelude::PositionTry(name) => {
950                let declarations = self.nest_for_rule(CssRuleType::PositionTry, |p| {
951                    parse_property_declaration_list(&p.context, input, &[])
952                });
953                CssRule::PositionTry(Arc::new(self.shared_lock.wrap(PositionTryRule {
954                    name,
955                    block: Arc::new(self.shared_lock.wrap(declarations)),
956                    source_location,
957                })))
958            },
959        };
960        self.rules.push(rule);
961        Ok(())
962    }
963
964    #[inline]
965    fn rule_without_block(
966        &mut self,
967        prelude: AtRulePrelude,
968        start: &ParserState,
969    ) -> Result<(), ()> {
970        if self.in_style_rule() {
971            return Err(());
972        }
973        let source_location = start.source_location();
974        let rule = match prelude {
975            AtRulePrelude::CustomMedia(name, condition) => {
976                CssRule::CustomMedia(Arc::new(CustomMediaRule {
977                    name,
978                    condition,
979                    source_location,
980                }))
981            },
982            AtRulePrelude::Layer(names) => {
983                if names.is_empty() {
984                    return Err(());
985                }
986                CssRule::LayerStatement(Arc::new(LayerStatementRule {
987                    names,
988                    source_location,
989                }))
990            },
991            _ => return Err(()),
992        };
993        self.flush_declarations();
994        self.rules.push(rule);
995        Ok(())
996    }
997}
998
999impl<'a, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'i> {
1000    type Prelude = SelectorList<SelectorImpl>;
1001    type QualifiedRule = ();
1002    type Error = StyleParseErrorKind<'i>;
1003
1004    fn parse_prelude<'t>(
1005        &mut self,
1006        input: &mut Parser<'i, 't>,
1007    ) -> Result<Self::Prelude, ParseError<'i>> {
1008        let selector_parser = SelectorParser {
1009            stylesheet_origin: self.context.stylesheet_origin,
1010            namespaces: &self.context.namespaces,
1011            url_data: self.context.url_data,
1012            for_supports_rule: false,
1013        };
1014        SelectorList::parse(&selector_parser, input, self.parse_relative())
1015    }
1016
1017    fn parse_block<'t>(
1018        &mut self,
1019        selectors: Self::Prelude,
1020        start: &ParserState,
1021        input: &mut Parser<'i, 't>,
1022    ) -> Result<(), ParseError<'i>> {
1023        let source_location = start.source_location();
1024        let reporting_errors = self.context.error_reporting_enabled();
1025        if reporting_errors {
1026            self.handle_error_reporting_selectors_pre(start, &selectors);
1027        }
1028        self.flush_declarations();
1029        let result = self.parse_nested(input, CssRuleType::Style, true);
1030        if reporting_errors {
1031            self.handle_error_reporting_selectors_post();
1032        }
1033        let block = Arc::new(self.shared_lock.wrap(result.first_declaration_block));
1034        let top = &mut **self;
1035        top.rules
1036            .push(CssRule::Style(Arc::new(top.shared_lock.wrap(StyleRule {
1037                selectors,
1038                block,
1039                rules: if result.rules.is_empty() {
1040                    None
1041                } else {
1042                    Some(CssRules::new(result.rules, top.shared_lock))
1043                },
1044                source_location,
1045            }))));
1046        Ok(())
1047    }
1048}
1049
1050impl<'a, 'i> DeclarationParser<'i> for NestedRuleParser<'a, 'i> {
1051    type Declaration = ();
1052    type Error = StyleParseErrorKind<'i>;
1053    fn parse_value<'t>(
1054        &mut self,
1055        name: CowRcStr<'i>,
1056        input: &mut Parser<'i, 't>,
1057        declaration_start: &ParserState,
1058    ) -> Result<(), ParseError<'i>> {
1059        let top = &mut **self;
1060        top.declaration_parser_state
1061            .parse_value(&top.context, name, input, declaration_start)
1062    }
1063}
1064
1065impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for NestedRuleParser<'a, 'i> {
1066    fn parse_qualified(&self) -> bool {
1067        true
1068    }
1069
1070    /// If nesting is disabled, we can't get there for a non-style-rule. If it's enabled, we parse
1071    /// raw declarations there.
1072    fn parse_declarations(&self) -> bool {
1073        self.can_parse_declarations()
1074    }
1075}