diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2023-05-26 15:16:47 +0200 |
---|---|---|
committer | Oriol Brufau <obrufau@igalia.com> | 2023-05-26 15:23:26 +0200 |
commit | dbb51abc62a8eb8e3e46549fb0b78038386b7bf9 (patch) | |
tree | 691f67b9837cd59c8eabf4e4fd2b1a6e3383cf88 /components/style/stylesheets | |
parent | 623c8d8d450baa167b13e6b5b245e93fab60e7e6 (diff) | |
download | servo-dbb51abc62a8eb8e3e46549fb0b78038386b7bf9.tar.gz servo-dbb51abc62a8eb8e3e46549fb0b78038386b7bf9.zip |
style: Hook up basic @layer rule parsing
Disabled, and of course doing nothing for now still, but this is another
piece that is useful to get reviewed separately.
Don't allow layers to be interleaved with @import / @namespace rules as
per https://github.com/w3c/csswg-drafts/issues/6522.
Differential Revision: https://phabricator.services.mozilla.com/D124229
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)) |