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