mirror of
https://github.com/servo/servo.git
synced 2025-06-22 08:08:59 +01:00
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
This commit is contained in:
parent
623c8d8d45
commit
dbb51abc62
3 changed files with 68 additions and 49 deletions
|
@ -90,11 +90,11 @@ pub enum LayerRuleKind {
|
||||||
/// A statement `@layer <name>, <name>, <name>;`
|
/// A statement `@layer <name>, <name>, <name>;`
|
||||||
Statement {
|
Statement {
|
||||||
/// The list of layers to sort.
|
/// 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
|
/// [layer]: https://drafts.csswg.org/css-cascade-5/#layering
|
||||||
#[derive(Debug, ToShmem)]
|
#[derive(Debug, ToShmem)]
|
||||||
|
|
|
@ -372,8 +372,7 @@ impl CssRule {
|
||||||
// CssRule::Charset(..) => State::Start,
|
// CssRule::Charset(..) => State::Start,
|
||||||
CssRule::Import(..) => State::Imports,
|
CssRule::Import(..) => State::Imports,
|
||||||
CssRule::Namespace(..) => State::Namespaces,
|
CssRule::Namespace(..) => State::Namespaces,
|
||||||
// TODO(emilio): We'll need something here for non-block layer
|
// TODO(emilio): Do we need something for EarlyLayers?
|
||||||
// rules.
|
|
||||||
_ => State::Body,
|
_ => State::Body,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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::keyframes_rule::parse_keyframe_list;
|
||||||
use crate::stylesheets::stylesheet::Namespaces;
|
use crate::stylesheets::stylesheet::Namespaces;
|
||||||
use crate::stylesheets::supports_rule::SupportsCondition;
|
use crate::stylesheets::supports_rule::SupportsCondition;
|
||||||
|
use crate::stylesheets::layer_rule::{LayerName, LayerRuleKind};
|
||||||
use crate::stylesheets::viewport_rule;
|
use crate::stylesheets::viewport_rule;
|
||||||
use crate::stylesheets::AllowImportRules;
|
use crate::stylesheets::AllowImportRules;
|
||||||
use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
|
use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
|
||||||
use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader};
|
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::computed::font::FamilyName;
|
||||||
use crate::values::{CssUrl, CustomIdent, KeyframesName};
|
use crate::values::{CssUrl, CustomIdent, KeyframesName};
|
||||||
use crate::{Namespace, Prefix};
|
use crate::{Namespace, Prefix};
|
||||||
|
@ -128,12 +129,14 @@ impl<'b> TopLevelRuleParser<'b> {
|
||||||
pub enum State {
|
pub enum State {
|
||||||
/// We haven't started parsing rules.
|
/// We haven't started parsing rules.
|
||||||
Start = 1,
|
Start = 1,
|
||||||
/// We're parsing `@import` rules.
|
/// We're parsing early `@layer` statement rules.
|
||||||
Imports = 2,
|
EarlyLayers = 2,
|
||||||
|
/// We're parsing `@import` and early `@layer` statement rules.
|
||||||
|
Imports = 3,
|
||||||
/// We're parsing `@namespace` rules.
|
/// We're parsing `@namespace` rules.
|
||||||
Namespaces = 3,
|
Namespaces = 4,
|
||||||
/// We're parsing the main body of the stylesheet.
|
/// We're parsing the main body of the stylesheet.
|
||||||
Body = 4,
|
Body = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
|
#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
|
||||||
|
@ -169,6 +172,8 @@ pub enum AtRulePrelude {
|
||||||
Import(CssUrl, Arc<Locked<MediaList>>),
|
Import(CssUrl, Arc<Locked<MediaList>>),
|
||||||
/// A @namespace rule prelude.
|
/// A @namespace rule prelude.
|
||||||
Namespace(Option<Prefix>, Namespace),
|
Namespace(Option<Prefix>, Namespace),
|
||||||
|
/// A @layer rule prelude.
|
||||||
|
Layer(Vec<LayerName>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
|
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(),
|
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(()),
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -374,41 +393,37 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
|
||||||
name: CowRcStr<'i>,
|
name: CowRcStr<'i>,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self::Prelude, ParseError<'i>> {
|
) -> Result<Self::Prelude, ParseError<'i>> {
|
||||||
match_ignore_ascii_case! { &*name,
|
Ok(match_ignore_ascii_case! { &*name,
|
||||||
"media" => {
|
"media" => {
|
||||||
let media_queries = MediaList::parse(self.context, input);
|
let media_queries = MediaList::parse(self.context, input);
|
||||||
let arc = Arc::new(self.shared_lock.wrap(media_queries));
|
let arc = Arc::new(self.shared_lock.wrap(media_queries));
|
||||||
Ok(AtRulePrelude::Media(arc))
|
AtRulePrelude::Media(arc)
|
||||||
},
|
},
|
||||||
"supports" => {
|
"supports" => {
|
||||||
let cond = SupportsCondition::parse(input)?;
|
let cond = SupportsCondition::parse(input)?;
|
||||||
Ok(AtRulePrelude::Supports(cond))
|
AtRulePrelude::Supports(cond)
|
||||||
},
|
},
|
||||||
"font-face" => {
|
"font-face" => {
|
||||||
Ok(AtRulePrelude::FontFace)
|
AtRulePrelude::FontFace
|
||||||
},
|
},
|
||||||
"font-feature-values" => {
|
"layer" if static_prefs::pref!("layout.css.cascade-layers.enabled") => {
|
||||||
if !cfg!(feature = "gecko") {
|
let names = input.try_parse(|input| {
|
||||||
// Support for this rule is not fully implemented in Servo yet.
|
input.parse_comma_separated(|input| {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
|
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)?;
|
let family_names = parse_family_name_list(self.context, input)?;
|
||||||
Ok(AtRulePrelude::FontFeatureValues(family_names))
|
AtRulePrelude::FontFeatureValues(family_names)
|
||||||
},
|
},
|
||||||
"counter-style" => {
|
"counter-style" if cfg!(feature = "gecko") => {
|
||||||
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())))
|
|
||||||
}
|
|
||||||
let name = parse_counter_style_name_definition(input)?;
|
let name = parse_counter_style_name_definition(input)?;
|
||||||
Ok(AtRulePrelude::CounterStyle(name))
|
AtRulePrelude::CounterStyle(name)
|
||||||
},
|
},
|
||||||
"viewport" => {
|
"viewport" if viewport_rule::enabled() => {
|
||||||
if viewport_rule::enabled() {
|
AtRulePrelude::Viewport
|
||||||
Ok(AtRulePrelude::Viewport)
|
|
||||||
} else {
|
|
||||||
Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
|
"keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
|
||||||
let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
|
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())))
|
return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
|
||||||
}
|
}
|
||||||
let name = KeyframesName::parse(self.context, input)?;
|
let name = KeyframesName::parse(self.context, input)?;
|
||||||
|
AtRulePrelude::Keyframes(name, prefix)
|
||||||
Ok(AtRulePrelude::Keyframes(name, prefix))
|
|
||||||
},
|
},
|
||||||
"page" => {
|
"page" if cfg!(feature = "gecko") => {
|
||||||
if cfg!(feature = "gecko") {
|
AtRulePrelude::Page
|
||||||
Ok(Self::Prelude::Page)
|
|
||||||
} else {
|
|
||||||
Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"-moz-document" => {
|
"-moz-document" if cfg!(feature = "gecko") => {
|
||||||
if !cfg!(feature = "gecko") {
|
|
||||||
return Err(input.new_custom_error(
|
|
||||||
StyleParseErrorKind::UnsupportedAtRule(name.clone())
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
let cond = DocumentCondition::parse(self.context, input)?;
|
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>(
|
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(..) => {
|
AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => {
|
||||||
// These rules don't have blocks.
|
// These rules don't have blocks.
|
||||||
Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock))
|
Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue