aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/stylesheets
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2023-05-26 15:16:47 +0200
committerOriol Brufau <obrufau@igalia.com>2023-05-26 15:23:26 +0200
commitdbb51abc62a8eb8e3e46549fb0b78038386b7bf9 (patch)
tree691f67b9837cd59c8eabf4e4fd2b1a6e3383cf88 /components/style/stylesheets
parent623c8d8d450baa167b13e6b5b245e93fab60e7e6 (diff)
downloadservo-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.rs4
-rw-r--r--components/style/stylesheets/mod.rs3
-rw-r--r--components/style/stylesheets/rule_parser.rs110
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))