diff options
Diffstat (limited to 'components/style/stylesheets')
-rw-r--r-- | components/style/stylesheets/layer_rule.rs | 4 | ||||
-rw-r--r-- | components/style/stylesheets/mod.rs | 3 | ||||
-rw-r--r-- | components/style/stylesheets/rule_parser.rs | 110 |
3 files changed, 68 insertions, 49 deletions
diff --git a/components/style/stylesheets/layer_rule.rs b/components/style/stylesheets/layer_rule.rs index 873c9e1275c..c8a04ca6563 100644 --- a/components/style/stylesheets/layer_rule.rs +++ b/components/style/stylesheets/layer_rule.rs @@ -90,11 +90,11 @@ pub enum LayerRuleKind { /// A statement `@layer <name>, <name>, <name>;` Statement { /// The list of layers to sort. - names: SmallVec<[LayerName; 3]>, + names: Vec<LayerName>, }, } -/// A [`@layer`][layer] urle. +/// A [`@layer`][layer] rule. /// /// [layer]: https://drafts.csswg.org/css-cascade-5/#layering #[derive(Debug, ToShmem)] diff --git a/components/style/stylesheets/mod.rs b/components/style/stylesheets/mod.rs index dc3f39e03b0..b4e10ee368e 100644 --- a/components/style/stylesheets/mod.rs +++ b/components/style/stylesheets/mod.rs @@ -372,8 +372,7 @@ impl CssRule { // CssRule::Charset(..) => State::Start, CssRule::Import(..) => State::Imports, CssRule::Namespace(..) => State::Namespaces, - // TODO(emilio): We'll need something here for non-block layer - // rules. + // TODO(emilio): Do we need something for EarlyLayers? _ => State::Body, } } diff --git a/components/style/stylesheets/rule_parser.rs b/components/style/stylesheets/rule_parser.rs index 930d6360061..fa92351ae01 100644 --- a/components/style/stylesheets/rule_parser.rs +++ b/components/style/stylesheets/rule_parser.rs @@ -18,11 +18,12 @@ use crate::stylesheets::font_feature_values_rule::parse_family_name_list; use crate::stylesheets::keyframes_rule::parse_keyframe_list; use crate::stylesheets::stylesheet::Namespaces; use crate::stylesheets::supports_rule::SupportsCondition; +use crate::stylesheets::layer_rule::{LayerName, LayerRuleKind}; use crate::stylesheets::viewport_rule; use crate::stylesheets::AllowImportRules; use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule}; use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader}; -use crate::stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule}; +use crate::stylesheets::{LayerRule, NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule}; use crate::values::computed::font::FamilyName; use crate::values::{CssUrl, CustomIdent, KeyframesName}; use crate::{Namespace, Prefix}; @@ -128,12 +129,14 @@ impl<'b> TopLevelRuleParser<'b> { pub enum State { /// We haven't started parsing rules. Start = 1, - /// We're parsing `@import` rules. - Imports = 2, + /// We're parsing early `@layer` statement rules. + EarlyLayers = 2, + /// We're parsing `@import` and early `@layer` statement rules. + Imports = 3, /// We're parsing `@namespace` rules. - Namespaces = 3, + Namespaces = 4, /// We're parsing the main body of the stylesheet. - Body = 4, + Body = 5, } #[derive(Clone, Debug, MallocSizeOf, ToShmem)] @@ -169,6 +172,8 @@ pub enum AtRulePrelude { Import(CssUrl, Arc<Locked<MediaList>>), /// A @namespace rule prelude. Namespace(Option<Prefix>, Namespace), + /// A @layer rule prelude. + Layer(Vec<LayerName>), } impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> { @@ -290,6 +295,20 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> { source_location: start.source_location(), }))) }, + AtRulePrelude::Layer(names) => { + if names.is_empty() { + return Err(()); + } + if self.state <= State::EarlyLayers { + self.state = State::EarlyLayers; + } else { + self.state = State::Body; + } + CssRule::Layer(Arc::new(self.shared_lock.wrap(LayerRule { + kind: LayerRuleKind::Statement { names }, + source_location: start.source_location(), + }))) + }, _ => return Err(()), }; @@ -374,41 +393,37 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> { name: CowRcStr<'i>, input: &mut Parser<'i, 't>, ) -> Result<Self::Prelude, ParseError<'i>> { - match_ignore_ascii_case! { &*name, + Ok(match_ignore_ascii_case! { &*name, "media" => { let media_queries = MediaList::parse(self.context, input); let arc = Arc::new(self.shared_lock.wrap(media_queries)); - Ok(AtRulePrelude::Media(arc)) + AtRulePrelude::Media(arc) }, "supports" => { let cond = SupportsCondition::parse(input)?; - Ok(AtRulePrelude::Supports(cond)) + AtRulePrelude::Supports(cond) }, "font-face" => { - Ok(AtRulePrelude::FontFace) + AtRulePrelude::FontFace }, - "font-feature-values" => { - if !cfg!(feature = "gecko") { - // Support for this rule is not fully implemented in Servo yet. - return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone()))) - } + "layer" if static_prefs::pref!("layout.css.cascade-layers.enabled") => { + let names = input.try_parse(|input| { + input.parse_comma_separated(|input| { + LayerName::parse(self.context, input) + }) + }).unwrap_or_default(); + AtRulePrelude::Layer(names) + }, + "font-feature-values" if cfg!(feature = "gecko") => { let family_names = parse_family_name_list(self.context, input)?; - Ok(AtRulePrelude::FontFeatureValues(family_names)) + AtRulePrelude::FontFeatureValues(family_names) }, - "counter-style" => { - if !cfg!(feature = "gecko") { - // Support for this rule is not fully implemented in Servo yet. - return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone()))) - } + "counter-style" if cfg!(feature = "gecko") => { let name = parse_counter_style_name_definition(input)?; - Ok(AtRulePrelude::CounterStyle(name)) + AtRulePrelude::CounterStyle(name) }, - "viewport" => { - if viewport_rule::enabled() { - Ok(AtRulePrelude::Viewport) - } else { - Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone()))) - } + "viewport" if viewport_rule::enabled() => { + AtRulePrelude::Viewport }, "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => { let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") { @@ -424,28 +439,17 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> { return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone()))) } let name = KeyframesName::parse(self.context, input)?; - - Ok(AtRulePrelude::Keyframes(name, prefix)) + AtRulePrelude::Keyframes(name, prefix) }, - "page" => { - if cfg!(feature = "gecko") { - Ok(Self::Prelude::Page) - } else { - Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone()))) - } + "page" if cfg!(feature = "gecko") => { + AtRulePrelude::Page }, - "-moz-document" => { - if !cfg!(feature = "gecko") { - return Err(input.new_custom_error( - StyleParseErrorKind::UnsupportedAtRule(name.clone()) - )) - } - + "-moz-document" if cfg!(feature = "gecko") => { let cond = DocumentCondition::parse(self.context, input)?; - Ok(AtRulePrelude::Document(cond)) + AtRulePrelude::Document(cond) }, - _ => Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone()))) - } + _ => return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone()))) + }) } fn parse_block<'t>( @@ -572,6 +576,22 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> { }, )))) }, + AtRulePrelude::Layer(names) => { + let name = match names.len() { + 0 => None, + 1 => Some(names.into_iter().next().unwrap()), + _ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)), + }; + Ok(CssRule::Layer(Arc::new(self.shared_lock.wrap( + LayerRule { + kind: LayerRuleKind::Block { + name, + rules: self.parse_nested_rules(input, CssRuleType::Layer), + }, + source_location: start.source_location(), + }, + )))) + }, AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => { // These rules don't have blocks. Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock)) |