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