tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rule_parser.rs (43557B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! Parsing of the stylesheet contents.
      6 
      7 use crate::counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
      8 use crate::custom_properties::parse_name as parse_custom_property_name;
      9 use crate::derives::*;
     10 use crate::error_reporting::ContextualParseError;
     11 use crate::font_face::parse_font_face_block;
     12 use crate::media_queries::MediaList;
     13 use crate::parser::{Parse, ParserContext};
     14 use crate::properties::declaration_block::{
     15    parse_property_declaration_list, DeclarationParserState, PropertyDeclarationBlock,
     16 };
     17 use crate::properties_and_values::rule::{parse_property_block, PropertyRuleName};
     18 use crate::selector_parser::{SelectorImpl, SelectorParser};
     19 use crate::shared_lock::{Locked, SharedRwLock};
     20 use crate::str::starts_with_ignore_ascii_case;
     21 use crate::stylesheets::container_rule::{ContainerCondition, ContainerRule};
     22 use crate::stylesheets::document_rule::DocumentCondition;
     23 use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
     24 use crate::stylesheets::import_rule::{ImportLayer, ImportRule, ImportSupportsCondition};
     25 use crate::stylesheets::keyframes_rule::parse_keyframe_list;
     26 use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
     27 use crate::stylesheets::scope_rule::{ScopeBounds, ScopeRule};
     28 use crate::stylesheets::supports_rule::SupportsCondition;
     29 use 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 };
     36 use crate::values::computed::font::FamilyName;
     37 use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
     38 use crate::{Atom, Namespace, Prefix};
     39 use cssparser::{
     40    match_ignore_ascii_case, AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr,
     41    DeclarationParser, Parser, ParserState, QualifiedRuleParser, RuleBodyItemParser,
     42    RuleBodyParser, SourcePosition,
     43 };
     44 use selectors::parser::{ParseRelative, SelectorList};
     45 use servo_arc::Arc;
     46 use style_traits::{ParseError, StyleParseErrorKind};
     47 
     48 /// The information we need particularly to do CSSOM insertRule stuff.
     49 pub 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 
     60 impl<'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.
     91 pub 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 
    124 impl<'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)]
    226 pub 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.
    241 pub enum VendorPrefix {
    242    /// -moz prefix.
    243    Moz,
    244    /// -webkit prefix.
    245    WebKit,
    246 }
    247 
    248 /// A rule prelude for at-rule with block.
    249 pub 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 
    295 impl 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 
    321 impl<'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 
    474 impl<'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)]
    506 struct NestedRuleParser<'a, 'i>(TopLevelRuleParser<'a, 'i>);
    507 
    508 struct NestedParseResult {
    509    first_declaration_block: PropertyDeclarationBlock,
    510    rules: Vec<CssRule>,
    511 }
    512 
    513 impl<'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 
    690 impl<'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 
   1001 impl<'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 
   1052 impl<'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 
   1067 impl<'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 }