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