Skip to content

Commit e008c6d

Browse files
committed
Bug 1728633 - Hook up basic @layer rule parsing. r=boris
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 w3c/csswg-drafts#6522. Differential Revision: https://phabricator.services.mozilla.com/D124229
1 parent c634713 commit e008c6d

File tree

4 files changed

+75
-48
lines changed

4 files changed

+75
-48
lines changed

modules/libpref/init/StaticPrefList.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6821,6 +6821,13 @@
68216821
mirror: always
68226822
rust: true
68236823

6824+
# Whether @layer is enabled
6825+
- name: layout.css.cascade-layers.enabled
6826+
type: RelaxedAtomicBool
6827+
value: false
6828+
mirror: always
6829+
rust: true
6830+
68246831
# Whether Constructable Stylesheets are enabled in script.
68256832
- name: layout.css.constructable-stylesheets.enabled
68266833
type: bool

servo/components/style/stylesheets/layer_rule.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ pub enum LayerRuleKind {
9090
/// A statement `@layer , , ;`
9191
Statement {
9292
/// The list of layers to sort.
93-
names: SmallVec<[LayerName; 3]>,
93+
names: Vec<LayerName>,
9494
},
9595
}
9696

97-
/// A [`@layer`][layer] urle.
97+
/// A [`@layer`][layer] rule.
9898
///
9999
/// [layer]: https://drafts.csswg.org/css-cascade-5/#layering
100100
#[derive(Debug, ToShmem)]

servo/components/style/stylesheets/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,7 @@ impl CssRule {
372372
// CssRule::Charset(..) => State::Start,
373373
CssRule::Import(..) => State::Imports,
374374
CssRule::Namespace(..) => State::Namespaces,
375-
// TODO(emilio): We'll need something here for non-block layer
376-
// rules.
375+
// TODO(emilio): Do we need something for EarlyLayers?
377376
_ => State::Body,
378377
}
379378
}

servo/components/style/stylesheets/rule_parser.rs

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
1818
use crate::stylesheets::keyframes_rule::parse_keyframe_list;
1919
use crate::stylesheets::stylesheet::Namespaces;
2020
use crate::stylesheets::supports_rule::SupportsCondition;
21+
use crate::stylesheets::layer_rule::{LayerName, LayerRuleKind};
2122
use crate::stylesheets::viewport_rule;
2223
use crate::stylesheets::AllowImportRules;
2324
use crate::stylesheets::{CorsMode, DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule};
2425
use crate::stylesheets::{CssRule, CssRuleType, CssRules, RulesMutateError, StylesheetLoader};
25-
use crate::stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
26+
use crate::stylesheets::{LayerRule, NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule};
2627
use crate::values::computed::font::FamilyName;
2728
use crate::values::{CssUrl, CustomIdent, KeyframesName};
2829
use crate::{Namespace, Prefix};
@@ -128,12 +129,14 @@ impl<'b> TopLevelRuleParser<'b> {
128129
pub enum State {
129130
/// We haven't started parsing rules.
130131
Start = 1,
131-
/// We're parsing `@import` rules.
132-
Imports = 2,
132+
/// We're parsing early `@layer` statement rules.
133+
EarlyLayers = 2,
134+
/// We're parsing `@import` and early `@layer` statement rules.
135+
Imports = 3,
133136
/// We're parsing `@namespace` rules.
134-
Namespaces = 3,
137+
Namespaces = 4,
135138
/// We're parsing the main body of the stylesheet.
136-
Body = 4,
139+
Body = 5,
137140
}
138141

139142
#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
@@ -169,6 +172,8 @@ pub enum AtRulePrelude {
169172
Import(CssUrl, Arc<Locked<MediaList>>),
170173
/// A @namespace rule prelude.
171174
Namespace(Option<Prefix>, Namespace),
175+
/// A @layer rule prelude.
176+
Layer(Vec<LayerName>),
172177
}
173178

174179
impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
@@ -290,6 +295,20 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
290295
source_location: start.source_location(),
291296
})))
292297
},
298+
AtRulePrelude::Layer(names) => {
299+
if names.is_empty() {
300+
return Err(());
301+
}
302+
if self.state <= State::EarlyLayers {
303+
self.state = State::EarlyLayers;
304+
} else {
305+
self.state = State::Body;
306+
}
307+
CssRule::Layer(Arc::new(self.shared_lock.wrap(LayerRule {
308+
kind: LayerRuleKind::Statement { names },
309+
source_location: start.source_location(),
310+
})))
311+
},
293312
_ => return Err(()),
294313
};
295314

@@ -374,41 +393,37 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
374393
name: CowRcStr<'i>,
375394
input: &mut Parser<'i, 't>,
376395
) -> Result<Self::Prelude, ParseError<'i>> {
377-
match_ignore_ascii_case! { &*name,
396+
Ok(match_ignore_ascii_case! { &*name,
378397
"media" => {
379398
let media_queries = MediaList::parse(self.context, input);
380399
let arc = Arc::new(self.shared_lock.wrap(media_queries));
381-
Ok(AtRulePrelude::Media(arc))
400+
AtRulePrelude::Media(arc)
382401
},
383402
"supports" => {
384403
let cond = SupportsCondition::parse(input)?;
385-
Ok(AtRulePrelude::Supports(cond))
404+
AtRulePrelude::Supports(cond)
386405
},
387406
"font-face" => {
388-
Ok(AtRulePrelude::FontFace)
407+
AtRulePrelude::FontFace
389408
},
390-
"font-feature-values" => {
391-
if !cfg!(feature = "gecko") {
392-
// Support for this rule is not fully implemented in Servo yet.
393-
return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
394-
}
409+
"layer" if static_prefs::pref!("layout.css.cascade-layers.enabled") => {
410+
let names = input.try_parse(|input| {
411+
input.parse_comma_separated(|input| {
412+
LayerName::parse(self.context, input)
413+
})
414+
}).unwrap_or_default();
415+
AtRulePrelude::Layer(names)
416+
},
417+
"font-feature-values" if cfg!(feature = "gecko") => {
395418
let family_names = parse_family_name_list(self.context, input)?;
396-
Ok(AtRulePrelude::FontFeatureValues(family_names))
419+
AtRulePrelude::FontFeatureValues(family_names)
397420
},
398-
"counter-style" => {
399-
if !cfg!(feature = "gecko") {
400-
// Support for this rule is not fully implemented in Servo yet.
401-
return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
402-
}
421+
"counter-style" if cfg!(feature = "gecko") => {
403422
let name = parse_counter_style_name_definition(input)?;
404-
Ok(AtRulePrelude::CounterStyle(name))
423+
AtRulePrelude::CounterStyle(name)
405424
},
406-
"viewport" => {
407-
if viewport_rule::enabled() {
408-
Ok(AtRulePrelude::Viewport)
409-
} else {
410-
Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
411-
}
425+
"viewport" if viewport_rule::enabled() => {
426+
AtRulePrelude::Viewport
412427
},
413428
"keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
414429
let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
@@ -424,27 +439,17 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
424439
return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
425440
}
426441
let name = KeyframesName::parse(self.context, input)?;
427-
Ok(AtRulePrelude::Keyframes(name, prefix))
442+
AtRulePrelude::Keyframes(name, prefix)
428443
},
429-
"page" => {
430-
if cfg!(feature = "gecko") {
431-
Ok(AtRulePrelude::Page)
432-
} else {
433-
Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
434-
}
444+
"page" if cfg!(feature = "gecko") => {
445+
AtRulePrelude::Page
435446
},
436-
"-moz-document" => {
437-
if !cfg!(feature = "gecko") {
438-
return Err(input.new_custom_error(
439-
StyleParseErrorKind::UnsupportedAtRule(name.clone())
440-
))
441-
}
442-
447+
"-moz-document" if cfg!(feature = "gecko") => {
443448
let cond = DocumentCondition::parse(self.context, input)?;
444-
Ok(AtRulePrelude::Document(cond))
449+
AtRulePrelude::Document(cond)
445450
},
446-
_ => Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
447-
}
451+
_ => return Err(input.new_custom_error(StyleParseErrorKind::UnsupportedAtRule(name.clone())))
452+
})
448453
}
449454

450455
fn parse_block<'t>(
@@ -571,6 +576,22 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
571576
},
572577
))))
573578
},
579+
AtRulePrelude::Layer(names) => {
580+
let name = match names.len() {
581+
0 => None,
582+
1 => Some(names.into_iter().next().unwrap()),
583+
_ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
584+
};
585+
Ok(CssRule::Layer(Arc::new(self.shared_lock.wrap(
586+
LayerRule {
587+
kind: LayerRuleKind::Block {
588+
name,
589+
rules: self.parse_nested_rules(input, CssRuleType::Layer),
590+
},
591+
source_location: start.source_location(),
592+
},
593+
))))
594+
},
574595
AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => {
575596
// These rules don't have blocks.
576597
Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock))

0 commit comments

Comments
 (0)