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