diff options
Diffstat (limited to 'servo/components/style/parser.rs')
-rw-r--r-- | servo/components/style/parser.rs | 70 |
1 files changed, 62 insertions, 8 deletions
diff --git a/servo/components/style/parser.rs b/servo/components/style/parser.rs index 893625854f..1e339841a9 100644 --- a/servo/components/style/parser.rs +++ b/servo/components/style/parser.rs @@ -9,9 +9,64 @@ use crate::error_reporting::{ContextualParseError, ParseErrorReporter}; use crate::stylesheets::{CssRuleType, CssRuleTypes, Namespaces, Origin, UrlExtraData}; use crate::use_counters::UseCounters; use cssparser::{Parser, SourceLocation, UnicodeRange}; +use selectors::parser::ParseRelative; use std::borrow::Cow; use style_traits::{OneOrMoreSeparated, ParseError, ParsingMode, Separator}; +/// Nesting context for parsing rules. +#[derive(Clone, Copy)] +pub struct NestingContext { + /// All rule types we've nested into, if any. + pub rule_types: CssRuleTypes, + /// Whether or not parsing relative selector syntax should be allowed. + pub parse_relative: ParseRelative, +} + +impl NestingContext { + fn parse_relative_for(rule_type: CssRuleType) -> ParseRelative { + match rule_type { + CssRuleType::Scope => ParseRelative::ForScope, + CssRuleType::Style => ParseRelative::ForNesting, + _ => ParseRelative::No, + } + } + + /// Create a new nesting context. + pub fn new(rule_types: CssRuleTypes, parse_nested_rule_type: Option<CssRuleType>) -> Self { + Self { + rule_types, + parse_relative: parse_nested_rule_type + .map_or(ParseRelative::No, Self::parse_relative_for) + } + } + + /// Create a new nesting context based on the given rule. + pub fn new_from_rule(rule_type: Option<CssRuleType>) -> Self { + Self { + rule_types: rule_type.map(CssRuleTypes::from).unwrap_or_default(), + parse_relative: rule_type + .map(Self::parse_relative_for) + .unwrap_or(ParseRelative::No), + } + } + + /// Save the current nesting context. + pub fn save(&mut self, rule_type: CssRuleType) -> Self { + let old = *self; + self.rule_types.insert(rule_type); + let new_parse_relative = Self::parse_relative_for(rule_type); + if new_parse_relative != ParseRelative::No { + self.parse_relative = new_parse_relative; + } + old + } + + /// Load the saved nesting context. + pub fn restore(&mut self, saved: Self) { + *self = saved; + } +} + /// The data that the parser needs from outside in order to parse a stylesheet. pub struct ParserContext<'a> { /// The `Origin` of the stylesheet, whether it's a user, author or @@ -19,8 +74,6 @@ pub struct ParserContext<'a> { pub stylesheet_origin: Origin, /// The extra data we need for resolving url values. pub url_data: &'a UrlExtraData, - /// The current rule types, if any. - pub rule_types: CssRuleTypes, /// The mode to use when parsing. pub parsing_mode: ParsingMode, /// The quirks mode of this stylesheet. @@ -31,6 +84,8 @@ pub struct ParserContext<'a> { pub namespaces: Cow<'a, Namespaces>, /// The use counters we want to record while parsing style rules, if any. pub use_counters: Option<&'a UseCounters>, + /// Current nesting context. + pub nesting_context: NestingContext, } impl<'a> ParserContext<'a> { @@ -49,12 +104,12 @@ impl<'a> ParserContext<'a> { Self { stylesheet_origin, url_data, - rule_types: rule_type.map(CssRuleTypes::from).unwrap_or_default(), parsing_mode, quirks_mode, error_reporter, namespaces, use_counters, + nesting_context: NestingContext::new_from_rule(rule_type), } } @@ -64,22 +119,21 @@ impl<'a> ParserContext<'a> { rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R, ) -> R { - let old_rule_types = self.rule_types; - self.rule_types.insert(rule_type); + let old = self.nesting_context.save(rule_type); let r = cb(self); - self.rule_types = old_rule_types; + self.nesting_context.restore(old); r } /// Whether we're in a @page rule. #[inline] pub fn in_page_rule(&self) -> bool { - self.rule_types.contains(CssRuleType::Page) + self.nesting_context.rule_types.contains(CssRuleType::Page) } /// Get the rule type, which assumes that one is available. pub fn rule_types(&self) -> CssRuleTypes { - self.rule_types + self.nesting_context.rule_types } /// Returns whether CSS error reporting is enabled. |