1use crate::counter_style::{parse_counter_style_body, parse_counter_style_name_definition};
8use crate::custom_properties::parse_name as parse_custom_property_name;
9use crate::error_reporting::ContextualParseError;
10use crate::font_face::parse_font_face_block;
11use crate::media_queries::MediaList;
12use crate::parser::{Parse, ParserContext};
13use crate::properties::declaration_block::{
14 parse_property_declaration_list, DeclarationParserState, PropertyDeclarationBlock,
15};
16use crate::properties_and_values::rule::{parse_property_block, PropertyRuleName};
17use crate::selector_parser::{SelectorImpl, SelectorParser};
18use crate::shared_lock::{Locked, SharedRwLock};
19use crate::str::starts_with_ignore_ascii_case;
20use crate::stylesheets::container_rule::{ContainerCondition, ContainerRule};
21use crate::stylesheets::document_rule::DocumentCondition;
22use crate::stylesheets::font_feature_values_rule::parse_family_name_list;
23use crate::stylesheets::import_rule::{ImportLayer, ImportRule, ImportSupportsCondition};
24use crate::stylesheets::keyframes_rule::parse_keyframe_list;
25use crate::stylesheets::layer_rule::{LayerBlockRule, LayerName, LayerStatementRule};
26use crate::stylesheets::scope_rule::{ScopeBounds, ScopeRule};
27use crate::stylesheets::supports_rule::SupportsCondition;
28use crate::stylesheets::{
29 AllowImportRules, CorsMode, CssRule, CssRuleType, CssRuleTypes, CssRules, DocumentRule,
30 FontFeatureValuesRule, FontPaletteValuesRule, KeyframesRule, MarginRule, MarginRuleType,
31 MediaRule, NamespaceRule, NestedDeclarationsRule, PageRule, PageSelectors, PositionTryRule,
32 RulesMutateError, StartingStyleRule, StyleRule, StylesheetLoader, SupportsRule,
33};
34use crate::values::computed::font::FamilyName;
35use crate::values::{CssUrl, CustomIdent, DashedIdent, KeyframesName};
36use crate::{Atom, Namespace, Prefix};
37use cssparser::{
38 AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr, DeclarationParser, Parser,
39 ParserState, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, SourcePosition,
40};
41use selectors::parser::{ParseRelative, SelectorList};
42use servo_arc::Arc;
43use style_traits::{ParseError, StyleParseErrorKind};
44
45pub struct InsertRuleContext<'a> {
47 pub rule_list: &'a [CssRule],
49 pub index: usize,
51 pub containing_rule_types: CssRuleTypes,
53 pub parse_relative_rule_type: Option<CssRuleType>,
55}
56
57impl<'a> InsertRuleContext<'a> {
58 pub fn max_rule_state_at_index(&self, index: usize) -> State {
61 let rule = match self.rule_list.get(index) {
62 Some(rule) => rule,
63 None => return State::Body,
64 };
65 match rule {
66 CssRule::Import(..) => State::Imports,
67 CssRule::Namespace(..) => State::Namespaces,
68 CssRule::LayerStatement(..) => {
69 let next_non_layer_statement_rule = self.rule_list[index + 1..]
73 .iter()
74 .find(|r| !matches!(*r, CssRule::LayerStatement(..)));
75 if let Some(non_layer) = next_non_layer_statement_rule {
76 if matches!(*non_layer, CssRule::Import(..) | CssRule::Namespace(..)) {
77 return State::EarlyLayers;
78 }
79 }
80 State::Body
81 },
82 _ => State::Body,
83 }
84 }
85}
86
87pub struct TopLevelRuleParser<'a, 'i> {
89 pub shared_lock: &'a SharedRwLock,
91 pub loader: Option<&'a dyn StylesheetLoader>,
93 pub context: ParserContext<'a>,
95 pub state: State,
97 pub dom_error: Option<RulesMutateError>,
101 pub insert_rule_context: Option<InsertRuleContext<'a>>,
103 pub allow_import_rules: AllowImportRules,
105 pub wants_first_declaration_block: bool,
108 pub first_declaration_block: PropertyDeclarationBlock,
110 pub declaration_parser_state: DeclarationParserState<'i>,
112 pub error_reporting_state: Vec<SelectorList<SelectorImpl>>,
117 pub rules: Vec<CssRule>,
119}
120
121impl<'a, 'i> TopLevelRuleParser<'a, 'i> {
122 #[inline]
123 fn nested(&mut self) -> &mut NestedRuleParser<'a, 'i> {
124 const_assert!(
126 std::mem::size_of::<TopLevelRuleParser<'static, 'static>>()
127 == std::mem::size_of::<NestedRuleParser<'static, 'static>>()
128 );
129 const_assert!(
130 std::mem::align_of::<TopLevelRuleParser<'static, 'static>>()
131 == std::mem::align_of::<NestedRuleParser<'static, 'static>>()
132 );
133 unsafe { &mut *(self as *mut _ as *mut NestedRuleParser<'a, 'i>) }
134 }
135
136 #[inline]
138 pub fn state(&self) -> State {
139 self.state
140 }
141
142 #[inline]
145 pub fn can_parse_declarations(&self) -> bool {
146 self.in_specified_rule(
152 CssRuleType::Style.bit() | CssRuleType::Page.bit() | CssRuleType::Scope.bit(),
153 )
154 }
155
156 #[inline]
157 fn in_style_rule(&self) -> bool {
158 self.context
159 .nesting_context
160 .rule_types
161 .contains(CssRuleType::Style)
162 }
163
164 #[inline]
165 fn in_page_rule(&self) -> bool {
166 self.context
167 .nesting_context
168 .rule_types
169 .contains(CssRuleType::Page)
170 }
171
172 #[inline]
173 fn in_specified_rule(&self, bits: u32) -> bool {
174 let types = CssRuleTypes::from_bits(bits);
175 self.context.nesting_context.rule_types.intersects(types)
176 }
177
178 #[inline]
179 fn in_style_or_page_rule(&self) -> bool {
180 self.in_specified_rule(CssRuleType::Style.bit() | CssRuleType::Page.bit())
181 }
182
183 fn check_state(&mut self, new_state: State) -> bool {
189 if self.state > new_state {
190 self.dom_error = Some(RulesMutateError::HierarchyRequest);
191 return false;
192 }
193
194 let ctx = match self.insert_rule_context {
195 Some(ref ctx) => ctx,
196 None => return true,
197 };
198
199 let max_rule_state = ctx.max_rule_state_at_index(ctx.index);
200 if new_state > max_rule_state {
201 self.dom_error = Some(RulesMutateError::HierarchyRequest);
202 return false;
203 }
204
205 if new_state == State::Namespaces
209 && ctx.rule_list[ctx.index..]
210 .iter()
211 .any(|r| !matches!(*r, CssRule::Namespace(..)))
212 {
213 self.dom_error = Some(RulesMutateError::InvalidState);
214 return false;
215 }
216
217 true
218 }
219}
220
221#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
223pub enum State {
224 Start = 1,
226 EarlyLayers = 2,
228 Imports = 3,
230 Namespaces = 4,
232 Body = 5,
234}
235
236#[derive(Clone, Debug, MallocSizeOf, ToShmem)]
237pub enum VendorPrefix {
239 Moz,
241 WebKit,
243}
244
245pub enum AtRulePrelude {
247 FontFace,
249 FontFeatureValues(Vec<FamilyName>),
251 FontPaletteValues(DashedIdent),
253 CounterStyle(CustomIdent),
255 Media(Arc<Locked<MediaList>>),
257 Container(Arc<ContainerCondition>),
259 Supports(SupportsCondition),
261 Keyframes(KeyframesName, Option<VendorPrefix>),
263 Page(PageSelectors),
265 Property(PropertyRuleName),
267 Document(DocumentCondition),
269 Import(
271 CssUrl,
272 Arc<Locked<MediaList>>,
273 Option<ImportSupportsCondition>,
274 ImportLayer,
275 ),
276 Margin(MarginRuleType),
278 Namespace(Option<Prefix>, Namespace),
280 Layer(Vec<LayerName>),
282 Scope(ScopeBounds),
284 StartingStyle,
286 PositionTry(DashedIdent),
288}
289
290impl AtRulePrelude {
291 fn name(&self) -> &'static str {
292 match *self {
293 Self::FontFace => "font-face",
294 Self::FontFeatureValues(..) => "font-feature-values",
295 Self::FontPaletteValues(..) => "font-palette-values",
296 Self::CounterStyle(..) => "counter-style",
297 Self::Media(..) => "media",
298 Self::Container(..) => "container",
299 Self::Supports(..) => "supports",
300 Self::Keyframes(..) => "keyframes",
301 Self::Page(..) => "page",
302 Self::Property(..) => "property",
303 Self::Document(..) => "-moz-document",
304 Self::Import(..) => "import",
305 Self::Margin(..) => "margin",
306 Self::Namespace(..) => "namespace",
307 Self::Layer(..) => "layer",
308 Self::Scope(..) => "scope",
309 Self::StartingStyle => "starting-style",
310 Self::PositionTry(..) => "position-try",
311 }
312 }
313}
314
315impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
316 type Prelude = AtRulePrelude;
317 type AtRule = SourcePosition;
318 type Error = StyleParseErrorKind<'i>;
319
320 fn parse_prelude<'t>(
321 &mut self,
322 name: CowRcStr<'i>,
323 input: &mut Parser<'i, 't>,
324 ) -> Result<AtRulePrelude, ParseError<'i>> {
325 match_ignore_ascii_case! { &*name,
326 "import" => {
327 if !self.check_state(State::Imports) {
328 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
329 }
330
331 if let AllowImportRules::No = self.allow_import_rules {
332 return Err(input.new_custom_error(StyleParseErrorKind::DisallowedImportRule))
333 }
334
335 if self.loader.is_none() {
338 error!("Saw @import rule, but no way to trigger the load");
339 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedImportRule))
340 }
341
342 let url_string = input.expect_url_or_string()?.as_ref().to_owned();
343 let url = CssUrl::parse_from_string(url_string, &self.context, CorsMode::None);
344
345 let (layer, supports) = ImportRule::parse_layer_and_supports(input, &mut self.context);
346
347 let media = MediaList::parse(&self.context, input);
348 let media = Arc::new(self.shared_lock.wrap(media));
349
350 return Ok(AtRulePrelude::Import(url, media, supports, layer));
351 },
352 "namespace" => {
353 if !self.check_state(State::Namespaces) {
354 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedNamespaceRule))
355 }
356
357 let prefix = input.try_parse(|i| i.expect_ident_cloned())
358 .map(|s| Prefix::from(s.as_ref())).ok();
359 let maybe_namespace = match input.expect_url_or_string() {
360 Ok(url_or_string) => url_or_string,
361 Err(BasicParseError { kind: BasicParseErrorKind::UnexpectedToken(t), location }) => {
362 return Err(location.new_custom_error(StyleParseErrorKind::UnexpectedTokenWithinNamespace(t)))
363 }
364 Err(e) => return Err(e.into()),
365 };
366 let url = Namespace::from(maybe_namespace.as_ref());
367 return Ok(AtRulePrelude::Namespace(prefix, url));
368 },
369 "charset" => {
372 self.dom_error = Some(RulesMutateError::HierarchyRequest);
373 return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule))
374 },
375 "layer" => {
376 let state_to_check = if self.state <= State::EarlyLayers {
377 State::EarlyLayers
381 } else {
382 State::Body
383 };
384 if !self.check_state(state_to_check) {
385 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
386 }
387 },
388 _ => {
389 }
392 }
393
394 AtRuleParser::parse_prelude(self.nested(), name, input)
395 }
396
397 #[inline]
398 fn parse_block<'t>(
399 &mut self,
400 prelude: AtRulePrelude,
401 start: &ParserState,
402 input: &mut Parser<'i, 't>,
403 ) -> Result<Self::AtRule, ParseError<'i>> {
404 if !self.check_state(State::Body) {
405 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
406 }
407 AtRuleParser::parse_block(self.nested(), prelude, start, input)?;
408 self.state = State::Body;
409 Ok(start.position())
410 }
411
412 #[inline]
413 fn rule_without_block(
414 &mut self,
415 prelude: AtRulePrelude,
416 start: &ParserState,
417 ) -> Result<Self::AtRule, ()> {
418 match prelude {
419 AtRulePrelude::Import(url, media, supports, layer) => {
420 let loader = self
421 .loader
422 .expect("Expected a stylesheet loader for @import");
423
424 let import_rule = loader.request_stylesheet(
425 url,
426 start.source_location(),
427 &self.shared_lock,
428 media,
429 supports,
430 layer,
431 );
432
433 self.state = State::Imports;
434 self.rules.push(CssRule::Import(import_rule))
435 },
436 AtRulePrelude::Namespace(prefix, url) => {
437 let namespaces = self.context.namespaces.to_mut();
438 let prefix = if let Some(prefix) = prefix {
439 namespaces.prefixes.insert(prefix.clone(), url.clone());
440 Some(prefix)
441 } else {
442 namespaces.default = Some(url.clone());
443 None
444 };
445
446 self.state = State::Namespaces;
447 self.rules.push(CssRule::Namespace(Arc::new(NamespaceRule {
448 prefix,
449 url,
450 source_location: start.source_location(),
451 })));
452 },
453 AtRulePrelude::Layer(..) => {
454 AtRuleParser::rule_without_block(self.nested(), prelude, start)?;
455 if self.state <= State::EarlyLayers {
456 self.state = State::EarlyLayers;
457 } else {
458 self.state = State::Body;
459 }
460 },
461 _ => AtRuleParser::rule_without_block(self.nested(), prelude, start)?,
462 };
463
464 Ok(start.position())
465 }
466}
467
468impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
469 type Prelude = SelectorList<SelectorImpl>;
470 type QualifiedRule = SourcePosition;
471 type Error = StyleParseErrorKind<'i>;
472
473 #[inline]
474 fn parse_prelude<'t>(
475 &mut self,
476 input: &mut Parser<'i, 't>,
477 ) -> Result<Self::Prelude, ParseError<'i>> {
478 if !self.check_state(State::Body) {
479 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
480 }
481
482 QualifiedRuleParser::parse_prelude(self.nested(), input)
483 }
484
485 #[inline]
486 fn parse_block<'t>(
487 &mut self,
488 prelude: Self::Prelude,
489 start: &ParserState,
490 input: &mut Parser<'i, 't>,
491 ) -> Result<Self::QualifiedRule, ParseError<'i>> {
492 QualifiedRuleParser::parse_block(self.nested(), prelude, start, input)?;
493 self.state = State::Body;
494 Ok(start.position())
495 }
496}
497
498#[repr(transparent)]
499#[derive(Deref, DerefMut)]
500struct NestedRuleParser<'a, 'i>(TopLevelRuleParser<'a, 'i>);
501
502struct NestedParseResult {
503 first_declaration_block: PropertyDeclarationBlock,
504 rules: Vec<CssRule>,
505}
506
507impl<'a, 'i> NestedRuleParser<'a, 'i> {
508 #[inline]
509 fn parse_relative(&self) -> ParseRelative {
510 self.context.nesting_context.parse_relative
511 }
512
513 fn at_rule_allowed(&self, prelude: &AtRulePrelude) -> bool {
518 match prelude {
519 AtRulePrelude::Media(..)
520 | AtRulePrelude::Supports(..)
521 | AtRulePrelude::Container(..)
522 | AtRulePrelude::Document(..)
523 | AtRulePrelude::Layer(..)
524 | AtRulePrelude::Scope(..)
525 | AtRulePrelude::StartingStyle => true,
526
527 AtRulePrelude::Namespace(..)
528 | AtRulePrelude::FontFace
529 | AtRulePrelude::FontFeatureValues(..)
530 | AtRulePrelude::FontPaletteValues(..)
531 | AtRulePrelude::CounterStyle(..)
532 | AtRulePrelude::Keyframes(..)
533 | AtRulePrelude::Page(..)
534 | AtRulePrelude::Property(..)
535 | AtRulePrelude::Import(..)
536 | AtRulePrelude::PositionTry(..) => !self.in_style_or_page_rule(),
537 AtRulePrelude::Margin(..) => self.in_page_rule(),
538 }
539 }
540
541 fn nest_for_rule<R>(&mut self, rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R) -> R {
542 let old = self.context.nesting_context.save(rule_type);
543 let r = cb(self);
544 self.context.nesting_context.restore(old);
545 r
546 }
547
548 fn parse_nested_rules(
549 &mut self,
550 input: &mut Parser<'i, '_>,
551 rule_type: CssRuleType,
552 ) -> Arc<Locked<CssRules>> {
553 let rules = self
554 .parse_nested(
555 input, rule_type, false,
556 )
557 .rules;
558 CssRules::new(rules, &self.shared_lock)
559 }
560
561 fn parse_nested(
562 &mut self,
563 input: &mut Parser<'i, '_>,
564 rule_type: CssRuleType,
565 wants_first_declaration_block: bool,
566 ) -> NestedParseResult {
567 debug_assert!(
568 !self.wants_first_declaration_block,
569 "Should've flushed previous declarations"
570 );
571 self.nest_for_rule(rule_type, |parser| {
572 parser.wants_first_declaration_block = wants_first_declaration_block;
573 let parse_declarations = parser.parse_declarations();
574 let mut rules = std::mem::take(&mut parser.rules);
575 let mut first_declaration_block = std::mem::take(&mut parser.first_declaration_block);
576 let mut iter = RuleBodyParser::new(input, parser);
577 while let Some(result) = iter.next() {
578 match result {
579 Ok(()) => {},
580 Err((error, slice)) => {
581 if parse_declarations {
582 let top = &mut **iter.parser;
583 top.declaration_parser_state
584 .did_error(&top.context, error, slice);
585 } else {
586 let location = error.location;
587 let error = ContextualParseError::InvalidRule(slice, error);
588 iter.parser.context.log_css_error(location, error);
589 }
590 },
591 }
592 }
593 parser.flush_declarations();
594 debug_assert!(
595 !parser.wants_first_declaration_block,
596 "Flushing declarations should take care of this."
597 );
598 debug_assert!(
599 !parser.declaration_parser_state.has_parsed_declarations(),
600 "Parsed but didn't consume declarations"
601 );
602 std::mem::swap(&mut parser.rules, &mut rules);
603 std::mem::swap(
604 &mut parser.first_declaration_block,
605 &mut first_declaration_block,
606 );
607 NestedParseResult {
608 first_declaration_block,
609 rules,
610 }
611 })
612 }
613
614 #[inline(never)]
615 fn handle_error_reporting_selectors_pre(
616 &mut self,
617 start: &ParserState,
618 selectors: &SelectorList<SelectorImpl>,
619 ) {
620 use cssparser::ToCss;
621 debug_assert!(self.context.error_reporting_enabled());
622 self.error_reporting_state.push(selectors.clone());
623 'selector_loop: for selector in selectors.slice().iter() {
624 let mut current = selector.iter();
625 loop {
626 let mut found_host = false;
627 let mut found_non_host = false;
628 for component in &mut current {
629 if component.is_host() {
630 found_host = true;
631 } else {
632 found_non_host = true;
633 }
634 if found_host && found_non_host {
635 self.context.log_css_error(
636 start.source_location(),
637 ContextualParseError::NeverMatchingHostSelector(
638 selector.to_css_string(),
639 ),
640 );
641 continue 'selector_loop;
642 }
643 }
644 if current.next_sequence().is_none() {
645 break;
646 }
647 }
648 }
649 }
650
651 fn handle_error_reporting_selectors_post(&mut self) {
652 self.error_reporting_state.pop();
653 }
654
655 #[inline]
656 fn flush_declarations(&mut self) {
657 let parser = &mut **self;
658 let wants_first_declaration_block = parser.wants_first_declaration_block;
659 parser.wants_first_declaration_block = false;
660 parser
661 .declaration_parser_state
662 .report_errors_if_needed(&parser.context, &parser.error_reporting_state);
663 if !parser.declaration_parser_state.has_parsed_declarations() {
664 return;
665 }
666 let source_location = parser.declaration_parser_state.first_declaration_start();
667 let declarations = parser.declaration_parser_state.take_declarations();
668 if wants_first_declaration_block {
669 debug_assert!(parser.first_declaration_block.is_empty(), "How?");
670 parser.first_declaration_block = declarations;
671 } else {
672 let nested_rule = CssRule::NestedDeclarations(Arc::new(parser.shared_lock.wrap(
673 NestedDeclarationsRule {
674 block: Arc::new(parser.shared_lock.wrap(declarations)),
675 source_location,
676 },
677 )));
678 parser.rules.push(nested_rule);
679 }
680 }
681}
682
683impl<'a, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'i> {
684 type Prelude = AtRulePrelude;
685 type AtRule = ();
686 type Error = StyleParseErrorKind<'i>;
687
688 fn parse_prelude<'t>(
689 &mut self,
690 name: CowRcStr<'i>,
691 input: &mut Parser<'i, 't>,
692 ) -> Result<Self::Prelude, ParseError<'i>> {
693 Ok(match_ignore_ascii_case! { &*name,
694 "media" => {
695 let media_queries = MediaList::parse(&self.context, input);
696 let arc = Arc::new(self.shared_lock.wrap(media_queries));
697 AtRulePrelude::Media(arc)
698 },
699 "supports" => {
700 let cond = SupportsCondition::parse(input)?;
701 AtRulePrelude::Supports(cond)
702 },
703 "font-face" => {
704 AtRulePrelude::FontFace
705 },
706 "container" if cfg!(feature = "gecko") => {
707 let condition = Arc::new(ContainerCondition::parse(&self.context, input)?);
708 AtRulePrelude::Container(condition)
709 },
710 "layer" => {
711 let names = input.try_parse(|input| {
712 input.parse_comma_separated(|input| {
713 LayerName::parse(&self.context, input)
714 })
715 }).unwrap_or_default();
716 AtRulePrelude::Layer(names)
717 },
718 "font-feature-values" if cfg!(feature = "gecko") => {
719 let family_names = parse_family_name_list(&self.context, input)?;
720 AtRulePrelude::FontFeatureValues(family_names)
721 },
722 "font-palette-values" if static_prefs::pref!("layout.css.font-palette.enabled") => {
723 let name = DashedIdent::parse(&self.context, input)?;
724 AtRulePrelude::FontPaletteValues(name)
725 },
726 "counter-style" if cfg!(feature = "gecko") => {
727 let name = parse_counter_style_name_definition(input)?;
728 AtRulePrelude::CounterStyle(name)
729 },
730 "keyframes" | "-webkit-keyframes" | "-moz-keyframes" => {
731 let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
732 Some(VendorPrefix::WebKit)
733 } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
734 Some(VendorPrefix::Moz)
735 } else {
736 None
737 };
738 if cfg!(feature = "servo") &&
739 prefix.as_ref().map_or(false, |p| matches!(*p, VendorPrefix::Moz)) {
740 return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
742 }
743 let name = KeyframesName::parse(&self.context, input)?;
744 AtRulePrelude::Keyframes(name, prefix)
745 },
746 "page" if cfg!(feature = "gecko") => {
747 AtRulePrelude::Page(
748 input.try_parse(|i| PageSelectors::parse(&self.context, i)).unwrap_or_default()
749 )
750 },
751 "property" if static_prefs::pref!("layout.css.properties-and-values.enabled") => {
752 let name = input.expect_ident_cloned()?;
753 let name = parse_custom_property_name(&name).map_err(|_| {
754 input.new_custom_error(StyleParseErrorKind::UnexpectedIdent(name.clone()))
755 })?;
756 AtRulePrelude::Property(PropertyRuleName(Atom::from(name)))
757 },
758 "-moz-document" if cfg!(feature = "gecko") => {
759 let cond = DocumentCondition::parse(&self.context, input)?;
760 AtRulePrelude::Document(cond)
761 },
762 "scope" if static_prefs::pref!("layout.css.at-scope.enabled") => {
763 let bounds = ScopeBounds::parse(&self.context, input, self.parse_relative())?;
764 AtRulePrelude::Scope(bounds)
765 },
766 "starting-style" if static_prefs::pref!("layout.css.starting-style-at-rules.enabled") => {
767 AtRulePrelude::StartingStyle
768 },
769 "position-try" if static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
770 let name = DashedIdent::parse(&self.context, input)?;
771 AtRulePrelude::PositionTry(name)
772 },
773 _ => {
774 if static_prefs::pref!("layout.css.margin-rules.enabled") {
775 if let Some(margin_rule_type) = MarginRuleType::match_name(&name) {
776 return Ok(AtRulePrelude::Margin(margin_rule_type));
777 }
778 }
779 return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())))
780 },
781 })
782 }
783
784 fn parse_block<'t>(
785 &mut self,
786 prelude: AtRulePrelude,
787 start: &ParserState,
788 input: &mut Parser<'i, 't>,
789 ) -> Result<(), ParseError<'i>> {
790 if !self.at_rule_allowed(&prelude) {
791 self.dom_error = Some(RulesMutateError::HierarchyRequest);
792 return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(prelude.name().into())));
793 }
794 let source_location = start.source_location();
795 self.flush_declarations();
796 let rule = match prelude {
797 AtRulePrelude::FontFace => self.nest_for_rule(CssRuleType::FontFace, |p| {
798 CssRule::FontFace(Arc::new(
799 p.shared_lock
800 .wrap(parse_font_face_block(&p.context, input, source_location).into()),
801 ))
802 }),
803 AtRulePrelude::FontFeatureValues(family_names) => {
804 self.nest_for_rule(CssRuleType::FontFeatureValues, |p| {
805 CssRule::FontFeatureValues(Arc::new(FontFeatureValuesRule::parse(
806 &p.context,
807 input,
808 family_names,
809 source_location,
810 )))
811 })
812 },
813 AtRulePrelude::FontPaletteValues(name) => {
814 self.nest_for_rule(CssRuleType::FontPaletteValues, |p| {
815 CssRule::FontPaletteValues(Arc::new(FontPaletteValuesRule::parse(
816 &p.context,
817 input,
818 name,
819 source_location,
820 )))
821 })
822 },
823 AtRulePrelude::CounterStyle(name) => {
824 let body = self.nest_for_rule(CssRuleType::CounterStyle, |p| {
825 parse_counter_style_body(name, &p.context, input, source_location)
826 })?;
827 CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(body)))
828 },
829 AtRulePrelude::Media(media_queries) => CssRule::Media(Arc::new(MediaRule {
830 media_queries,
831 rules: self.parse_nested_rules(input, CssRuleType::Media),
832 source_location,
833 })),
834 AtRulePrelude::Supports(condition) => {
835 let enabled =
836 self.nest_for_rule(CssRuleType::Style, |p| condition.eval(&p.context));
837 CssRule::Supports(Arc::new(SupportsRule {
838 condition,
839 rules: self.parse_nested_rules(input, CssRuleType::Supports),
840 enabled,
841 source_location,
842 }))
843 },
844 AtRulePrelude::Keyframes(name, vendor_prefix) => {
845 self.nest_for_rule(CssRuleType::Keyframe, |p| {
846 let top = &mut **p;
847 CssRule::Keyframes(Arc::new(top.shared_lock.wrap(KeyframesRule {
848 name,
849 keyframes: parse_keyframe_list(&mut top.context, input, top.shared_lock),
850 vendor_prefix,
851 source_location,
852 })))
853 })
854 },
855 AtRulePrelude::Page(selectors) => {
856 let page_rule = if !static_prefs::pref!("layout.css.margin-rules.enabled") {
857 let declarations = self.nest_for_rule(CssRuleType::Page, |p| {
858 parse_property_declaration_list(&p.context, input, &[])
859 });
860 PageRule {
861 selectors,
862 rules: CssRules::new(vec![], self.shared_lock),
863 block: Arc::new(self.shared_lock.wrap(declarations)),
864 source_location,
865 }
866 } else {
867 let result = self.parse_nested(input, CssRuleType::Page, true);
868 PageRule {
869 selectors,
870 rules: CssRules::new(result.rules, self.shared_lock),
871 block: Arc::new(self.shared_lock.wrap(result.first_declaration_block)),
872 source_location,
873 }
874 };
875 CssRule::Page(Arc::new(self.shared_lock.wrap(page_rule)))
876 },
877 AtRulePrelude::Property(name) => self.nest_for_rule(CssRuleType::Property, |p| {
878 let rule_data = parse_property_block(&p.context, input, name, source_location)?;
879 Ok::<CssRule, ParseError<'i>>(CssRule::Property(Arc::new(rule_data)))
880 })?,
881 AtRulePrelude::Document(condition) => {
882 if !cfg!(feature = "gecko") {
883 unreachable!()
884 }
885 CssRule::Document(Arc::new(DocumentRule {
886 condition,
887 rules: self.parse_nested_rules(input, CssRuleType::Document),
888 source_location,
889 }))
890 },
891 AtRulePrelude::Container(condition) => {
892 let source_location = start.source_location();
893 CssRule::Container(Arc::new(ContainerRule {
894 condition,
895 rules: self.parse_nested_rules(input, CssRuleType::Container),
896 source_location,
897 }))
898 },
899 AtRulePrelude::Layer(names) => {
900 let name = match names.len() {
901 0 | 1 => names.into_iter().next(),
902 _ => return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid)),
903 };
904 CssRule::LayerBlock(Arc::new(LayerBlockRule {
905 name,
906 rules: self.parse_nested_rules(input, CssRuleType::LayerBlock),
907 source_location,
908 }))
909 },
910 AtRulePrelude::Margin(rule_type) => {
911 let declarations = self.nest_for_rule(CssRuleType::Margin, |p| {
912 parse_property_declaration_list(&p.context, input, &[])
913 });
914 CssRule::Margin(Arc::new(MarginRule {
915 rule_type,
916 block: Arc::new(self.shared_lock.wrap(declarations)),
917 source_location,
918 }))
919 },
920 AtRulePrelude::Import(..) | AtRulePrelude::Namespace(..) => {
921 return Err(input.new_unexpected_token_error(cssparser::Token::CurlyBracketBlock));
923 },
924 AtRulePrelude::Scope(bounds) => CssRule::Scope(Arc::new(ScopeRule {
925 bounds,
926 rules: self.parse_nested_rules(input, CssRuleType::Scope),
927 source_location,
928 })),
929 AtRulePrelude::StartingStyle => CssRule::StartingStyle(Arc::new(StartingStyleRule {
930 rules: self.parse_nested_rules(input, CssRuleType::StartingStyle),
931 source_location,
932 })),
933 AtRulePrelude::PositionTry(name) => {
934 let declarations = self.nest_for_rule(CssRuleType::PositionTry, |p| {
935 parse_property_declaration_list(&p.context, input, &[])
936 });
937 CssRule::PositionTry(Arc::new(self.shared_lock.wrap(PositionTryRule {
938 name,
939 block: Arc::new(self.shared_lock.wrap(declarations)),
940 source_location,
941 })))
942 },
943 };
944 self.rules.push(rule);
945 Ok(())
946 }
947
948 #[inline]
949 fn rule_without_block(
950 &mut self,
951 prelude: AtRulePrelude,
952 start: &ParserState,
953 ) -> Result<(), ()> {
954 if self.in_style_rule() {
955 return Err(());
956 }
957 let source_location = start.source_location();
958 let rule = match prelude {
959 AtRulePrelude::Layer(names) => {
960 if names.is_empty() {
961 return Err(());
962 }
963 CssRule::LayerStatement(Arc::new(LayerStatementRule {
964 names,
965 source_location,
966 }))
967 },
968 _ => return Err(()),
969 };
970 self.flush_declarations();
971 self.rules.push(rule);
972 Ok(())
973 }
974}
975
976impl<'a, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'i> {
977 type Prelude = SelectorList<SelectorImpl>;
978 type QualifiedRule = ();
979 type Error = StyleParseErrorKind<'i>;
980
981 fn parse_prelude<'t>(
982 &mut self,
983 input: &mut Parser<'i, 't>,
984 ) -> Result<Self::Prelude, ParseError<'i>> {
985 let selector_parser = SelectorParser {
986 stylesheet_origin: self.context.stylesheet_origin,
987 namespaces: &self.context.namespaces,
988 url_data: self.context.url_data,
989 for_supports_rule: false,
990 };
991 SelectorList::parse(&selector_parser, input, self.parse_relative())
992 }
993
994 fn parse_block<'t>(
995 &mut self,
996 selectors: Self::Prelude,
997 start: &ParserState,
998 input: &mut Parser<'i, 't>,
999 ) -> Result<(), ParseError<'i>> {
1000 let source_location = start.source_location();
1001 let reporting_errors = self.context.error_reporting_enabled();
1002 if reporting_errors {
1003 self.handle_error_reporting_selectors_pre(start, &selectors);
1004 }
1005 self.flush_declarations();
1006 let result = self.parse_nested(input, CssRuleType::Style, true);
1007 if reporting_errors {
1008 self.handle_error_reporting_selectors_post();
1009 }
1010 let block = Arc::new(self.shared_lock.wrap(result.first_declaration_block));
1011 let top = &mut **self;
1012 top.rules
1013 .push(CssRule::Style(Arc::new(top.shared_lock.wrap(StyleRule {
1014 selectors,
1015 block,
1016 rules: if result.rules.is_empty() {
1017 None
1018 } else {
1019 Some(CssRules::new(result.rules, top.shared_lock))
1020 },
1021 source_location,
1022 }))));
1023 Ok(())
1024 }
1025}
1026
1027impl<'a, 'i> DeclarationParser<'i> for NestedRuleParser<'a, 'i> {
1028 type Declaration = ();
1029 type Error = StyleParseErrorKind<'i>;
1030 fn parse_value<'t>(
1031 &mut self,
1032 name: CowRcStr<'i>,
1033 input: &mut Parser<'i, 't>,
1034 declaration_start: &ParserState,
1035 ) -> Result<(), ParseError<'i>> {
1036 let top = &mut **self;
1037 top.declaration_parser_state
1038 .parse_value(&top.context, name, input, declaration_start)
1039 }
1040}
1041
1042impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind<'i>> for NestedRuleParser<'a, 'i> {
1043 fn parse_qualified(&self) -> bool {
1044 true
1045 }
1046
1047 fn parse_declarations(&self) -> bool {
1050 self.can_parse_declarations()
1051 }
1052}