@@ -18,11 +18,12 @@ use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
18
18
use crate :: stylesheets:: keyframes_rule:: parse_keyframe_list;
19
19
use crate :: stylesheets:: stylesheet:: Namespaces ;
20
20
use crate :: stylesheets:: supports_rule:: SupportsCondition ;
21
+ use crate :: stylesheets:: layer_rule:: { LayerName , LayerRuleKind } ;
21
22
use crate :: stylesheets:: viewport_rule;
22
23
use crate :: stylesheets:: AllowImportRules ;
23
24
use crate :: stylesheets:: { CorsMode , DocumentRule , FontFeatureValuesRule , KeyframesRule , MediaRule } ;
24
25
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 } ;
26
27
use crate :: values:: computed:: font:: FamilyName ;
27
28
use crate :: values:: { CssUrl , CustomIdent , KeyframesName } ;
28
29
use crate :: { Namespace , Prefix } ;
@@ -128,12 +129,14 @@ impl<'b> TopLevelRuleParser<'b> {
128
129
pub enum State {
129
130
/// We haven't started parsing rules.
130
131
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 ,
133
136
/// We're parsing `@namespace` rules.
134
- Namespaces = 3 ,
137
+ Namespaces = 4 ,
135
138
/// We're parsing the main body of the stylesheet.
136
- Body = 4 ,
139
+ Body = 5 ,
137
140
}
138
141
139
142
#[ derive( Clone , Debug , MallocSizeOf , ToShmem ) ]
@@ -169,6 +172,8 @@ pub enum AtRulePrelude {
169
172
Import ( CssUrl , Arc < Locked < MediaList > > ) ,
170
173
/// A @namespace rule prelude.
171
174
Namespace ( Option < Prefix > , Namespace ) ,
175
+ /// A @layer rule prelude.
176
+ Layer ( Vec < LayerName > ) ,
172
177
}
173
178
174
179
impl < ' a , ' i > AtRuleParser < ' i > for TopLevelRuleParser < ' a > {
@@ -290,6 +295,20 @@ impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a> {
290
295
source_location : start. source_location ( ) ,
291
296
} ) ) )
292
297
} ,
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
+ } ,
293
312
_ => return Err ( ( ) ) ,
294
313
} ;
295
314
@@ -374,41 +393,37 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
374
393
name : CowRcStr < ' i > ,
375
394
input : & mut Parser < ' i , ' t > ,
376
395
) -> Result < Self :: Prelude , ParseError < ' i > > {
377
- match_ignore_ascii_case ! { & * name,
396
+ Ok ( match_ignore_ascii_case ! { & * name,
378
397
"media" => {
379
398
let media_queries = MediaList :: parse( self . context, input) ;
380
399
let arc = Arc :: new( self . shared_lock. wrap( media_queries) ) ;
381
- Ok ( AtRulePrelude :: Media ( arc) )
400
+ AtRulePrelude :: Media ( arc)
382
401
} ,
383
402
"supports" => {
384
403
let cond = SupportsCondition :: parse( input) ?;
385
- Ok ( AtRulePrelude :: Supports ( cond) )
404
+ AtRulePrelude :: Supports ( cond)
386
405
} ,
387
406
"font-face" => {
388
- Ok ( AtRulePrelude :: FontFace )
407
+ AtRulePrelude :: FontFace
389
408
} ,
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" ) => {
395
418
let family_names = parse_family_name_list( self . context, input) ?;
396
- Ok ( AtRulePrelude :: FontFeatureValues ( family_names) )
419
+ AtRulePrelude :: FontFeatureValues ( family_names)
397
420
} ,
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" ) => {
403
422
let name = parse_counter_style_name_definition( input) ?;
404
- Ok ( AtRulePrelude :: CounterStyle ( name) )
423
+ AtRulePrelude :: CounterStyle ( name)
405
424
} ,
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
412
427
} ,
413
428
"keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
414
429
let prefix = if starts_with_ignore_ascii_case( & * name, "-webkit-" ) {
@@ -424,27 +439,17 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
424
439
return Err ( input. new_custom_error( StyleParseErrorKind :: UnsupportedAtRule ( name. clone( ) ) ) )
425
440
}
426
441
let name = KeyframesName :: parse( self . context, input) ?;
427
- Ok ( AtRulePrelude :: Keyframes ( name, prefix) )
442
+ AtRulePrelude :: Keyframes ( name, prefix)
428
443
} ,
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
435
446
} ,
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" ) => {
443
448
let cond = DocumentCondition :: parse( self . context, input) ?;
444
- Ok ( AtRulePrelude :: Document ( cond) )
449
+ AtRulePrelude :: Document ( cond)
445
450
} ,
446
- _ => Err ( input. new_custom_error( StyleParseErrorKind :: UnsupportedAtRule ( name. clone( ) ) ) )
447
- }
451
+ _ => return Err ( input. new_custom_error( StyleParseErrorKind :: UnsupportedAtRule ( name. clone( ) ) ) )
452
+ } )
448
453
}
449
454
450
455
fn parse_block < ' t > (
@@ -571,6 +576,22 @@ impl<'a, 'b, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'b> {
571
576
} ,
572
577
) ) ) )
573
578
} ,
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
+ } ,
574
595
AtRulePrelude :: Import ( ..) | AtRulePrelude :: Namespace ( ..) => {
575
596
// These rules don't have blocks.
576
597
Err ( input. new_unexpected_token_error ( cssparser:: Token :: CurlyBracketBlock ) )
0 commit comments