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