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::stylesheets::container_rule::{ContainerCondition, ContainerConditions, ContainerRule};
21use crate::stylesheets::document_rule::DocumentCondition;
22use crate::stylesheets::font_feature_values_rule::{
23 parse_family_name_list, FontFeatureValuesBlockType,
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 match_ignore_ascii_case, AtRuleParser, BasicParseError, BasicParseErrorKind, CowRcStr,
42 DeclarationParser, Parser, ParserState, QualifiedRuleParser, RuleBodyItemParser,
43 RuleBodyParser, SourcePosition,
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 if matches!(*non_layer, CssRule::Import(..) | CssRule::Namespace(..)) {
82 return State::EarlyLayers;
83 }
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 if let Some(rule_type) = MarginRuleType::from_name(name) {
305 return Some(Self::Margin(rule_type));
306 }
307 }
308
309 if cfg!(feature = "gecko") && FontFeatureValuesBlockType::from_name(name).is_some() {
311 return Some(Self::FontFeatureValuesBlock);
312 }
313
314 return None;
315 },
316 })
317 }
318
319 pub fn is_supported(name: &str, context: &ParserContext) -> bool {
323 AtRuleType::from_name(name, context).is_some()
324 }
325}
326
327pub enum AtRulePrelude {
329 FontFace,
331 FontFeatureValues(Vec<FamilyName>),
333 FontPaletteValues(DashedIdent),
335 CounterStyle(CustomIdent),
337 Media(Arc<Locked<MediaList>>),
339 Container(ArcSlice<ContainerCondition>),
341 Supports(SupportsCondition),
343 Keyframes(KeyframesName, Option<VendorPrefix>),
345 Page(PageSelectors),
347 Property(PropertyRuleName),
349 Document(DocumentCondition),
351 Import(
353 CssUrl,
354 Arc<Locked<MediaList>>,
355 Option<ImportSupportsCondition>,
356 ImportLayer,
357 ),
358 Margin(MarginRuleType),
360 Namespace(Option<Prefix>, Namespace),
362 Layer(Vec<LayerName>),
364 Scope(ScopeBounds),
366 StartingStyle,
368 AppearanceBase,
370 PositionTry(DashedIdent),
372 CustomMedia(DashedIdent, CustomMediaCondition),
374 ViewTransition,
376}
377
378impl<'a, 'i> AtRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
379 type Prelude = AtRulePrelude;
380 type AtRule = SourcePosition;
381 type Error = StyleParseErrorKind;
382
383 fn parse_prelude(
384 &mut self,
385 name: CowRcStr<'i>,
386 input: &mut Parser<'i>,
387 ) -> Result<AtRulePrelude, ParseError> {
388 if name.eq_ignore_ascii_case("charset") {
391 self.dom_error = Some(RulesMutateError::HierarchyRequest);
392 return Err(ParseError::custom(
393 StyleParseErrorKind::UnexpectedCharsetRule,
394 ));
395 }
396
397 let Some(rule_type) = AtRuleType::from_name(&name, &self.context) else {
398 return Err(ParseError::from_basic_kind(
399 BasicParseErrorKind::AtRuleInvalid,
400 ));
401 };
402
403 match rule_type {
404 AtRuleType::Import => {
405 if !self.check_state(State::Imports) {
406 return Err(ParseError::custom(
407 StyleParseErrorKind::UnexpectedImportRule,
408 ));
409 }
410
411 if let AllowImportRules::No = self.allow_import_rules {
412 return Err(ParseError::custom(
413 StyleParseErrorKind::DisallowedImportRule,
414 ));
415 }
416
417 if self.loader.is_none() {
420 error!("Saw @import rule, but no way to trigger the load");
421 return Err(ParseError::custom(
422 StyleParseErrorKind::UnexpectedImportRule,
423 ));
424 }
425
426 let url_string = input.expect_url_or_string()?.as_ref().to_owned();
427 let url =
428 CssUrl::new_from_untainted_string(url_string, &self.context, CorsMode::None);
429
430 let (layer, supports) =
431 ImportRule::parse_layer_and_supports(input, &mut self.context);
432
433 let media = MediaList::parse(&mut self.context, input);
434 let media = Arc::new(self.shared_lock.wrap(media));
435
436 return Ok(AtRulePrelude::Import(url, media, supports, layer));
437 },
438 AtRuleType::Namespace => {
439 if !self.check_state(State::Namespaces) {
440 return Err(ParseError::custom(
441 StyleParseErrorKind::UnexpectedNamespaceRule,
442 ));
443 }
444
445 let prefix = input
446 .try_parse(|i| i.expect_ident_cloned())
447 .map(|s| Prefix::from(s.as_ref()))
448 .ok();
449 let maybe_namespace = match input.expect_url_or_string() {
450 Ok(url_or_string) => url_or_string,
451 Err(BasicParseError {
452 kind: BasicParseErrorKind::UnexpectedToken,
453 }) => {
454 return Err(ParseError::custom(
455 StyleParseErrorKind::UnexpectedTokenWithinNamespace,
456 ))
457 },
458 Err(e) => return Err(e.into()),
459 };
460 let url = Namespace::from(maybe_namespace.as_ref());
461 return Ok(AtRulePrelude::Namespace(prefix, url));
462 },
463 AtRuleType::Layer => {
464 let state_to_check = if self.state <= State::EarlyLayers {
465 State::EarlyLayers
469 } else {
470 State::Body
471 };
472 if !self.check_state(state_to_check) {
473 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
474 }
475 },
476 _ => {
477 },
480 }
481
482 self.nested().parse_at_rule_prelude(rule_type, input)
483 }
484
485 #[inline]
486 fn parse_block(
487 &mut self,
488 prelude: AtRulePrelude,
489 start: &ParserState,
490 input: &mut Parser<'i>,
491 ) -> Result<Self::AtRule, ParseError> {
492 if !self.check_state(State::Body) {
493 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
494 }
495 AtRuleParser::parse_block(self.nested(), prelude, start, input)?;
496 self.state = State::Body;
497 Ok(start.position())
498 }
499
500 #[inline]
501 fn rule_without_block(
502 &mut self,
503 prelude: AtRulePrelude,
504 start: &ParserState,
505 ) -> Result<Self::AtRule, ()> {
506 match prelude {
507 AtRulePrelude::Import(url, media, supports, layer) => {
508 let loader = self
509 .loader
510 .expect("Expected a stylesheet loader for @import");
511
512 let import_rule = loader.request_stylesheet(
513 url,
514 start.source_location(),
515 self.shared_lock,
516 media,
517 supports,
518 layer,
519 );
520
521 self.state = State::Imports;
522 self.rules.push(CssRule::Import(import_rule))
523 },
524 AtRulePrelude::Namespace(prefix, url) => {
525 let namespaces = self.context.namespaces.to_mut();
526 let prefix = if let Some(prefix) = prefix {
527 namespaces.prefixes.insert(prefix.clone(), url.clone());
528 Some(prefix)
529 } else {
530 namespaces.default = Some(url.clone());
531 None
532 };
533
534 self.state = State::Namespaces;
535 self.rules.push(CssRule::Namespace(Arc::new(NamespaceRule {
536 prefix,
537 url,
538 source_location: start.source_location(),
539 })));
540 },
541 AtRulePrelude::Layer(..) => {
542 AtRuleParser::rule_without_block(self.nested(), prelude, start)?;
543 if self.state <= State::EarlyLayers {
544 self.state = State::EarlyLayers;
545 } else {
546 self.state = State::Body;
547 }
548 },
549 _ => AtRuleParser::rule_without_block(self.nested(), prelude, start)?,
550 };
551
552 Ok(start.position())
553 }
554}
555
556impl<'a, 'i> QualifiedRuleParser<'i> for TopLevelRuleParser<'a, 'i> {
557 type Prelude = SelectorList<SelectorImpl>;
558 type QualifiedRule = SourcePosition;
559 type Error = StyleParseErrorKind;
560
561 #[inline]
562 fn parse_prelude(&mut self, input: &mut Parser<'i>) -> Result<Self::Prelude, ParseError> {
563 if !self.check_state(State::Body) {
564 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
565 }
566
567 QualifiedRuleParser::parse_prelude(self.nested(), input)
568 }
569
570 #[inline]
571 fn parse_block(
572 &mut self,
573 prelude: Self::Prelude,
574 start: &ParserState,
575 input: &mut Parser<'i>,
576 ) -> Result<Self::QualifiedRule, ParseError> {
577 QualifiedRuleParser::parse_block(self.nested(), prelude, start, input)?;
578 self.state = State::Body;
579 Ok(start.position())
580 }
581}
582
583#[repr(transparent)]
584#[derive(Deref, DerefMut)]
585struct NestedRuleParser<'a, 'i>(TopLevelRuleParser<'a, 'i>);
586
587struct NestedParseResult {
588 first_declaration_block: PropertyDeclarationBlock,
589 rules: Vec<CssRule>,
590}
591
592impl<'a, 'i> NestedRuleParser<'a, 'i> {
593 fn parse_at_rule_prelude(
594 &mut self,
595 rule_type: AtRuleType,
596 input: &mut Parser<'i>,
597 ) -> Result<AtRulePrelude, ParseError> {
598 Ok(match rule_type {
599 AtRuleType::Media => {
600 let media_queries = MediaList::parse(&mut self.context, input);
601 let arc = Arc::new(self.shared_lock.wrap(media_queries));
602 AtRulePrelude::Media(arc)
603 },
604 AtRuleType::Supports => {
605 let cond = SupportsCondition::parse(input)?;
606 AtRulePrelude::Supports(cond)
607 },
608 AtRuleType::FontFace => AtRulePrelude::FontFace,
609 AtRuleType::Container => {
610 let conditions = input.parse_comma_separated(|input| {
611 ContainerCondition::parse(&self.context, input)
612 })?;
613 debug_assert!(!conditions.is_empty());
615 let conditions = ArcSlice::from_iter(conditions.into_iter());
616 AtRulePrelude::Container(conditions)
617 },
618 AtRuleType::Layer => {
619 let names = input
620 .try_parse(|input| {
621 input.parse_comma_separated(|input| LayerName::parse(&self.context, input))
622 })
623 .unwrap_or_default();
624 AtRulePrelude::Layer(names)
625 },
626 AtRuleType::FontFeatureValues => {
627 let family_names = parse_family_name_list(&self.context, input)?;
628 AtRulePrelude::FontFeatureValues(family_names)
629 },
630 AtRuleType::FontPaletteValues => {
631 let name = DashedIdent::parse(&self.context, input)?;
632 AtRulePrelude::FontPaletteValues(name)
633 },
634 AtRuleType::CounterStyle => {
635 let name = parse_counter_style_name_definition(input)?;
636 AtRulePrelude::CounterStyle(name)
637 },
638 AtRuleType::Keyframes(prefix) => {
639 let name = KeyframesName::parse(&self.context, input)?;
640 AtRulePrelude::Keyframes(name, prefix)
641 },
642 AtRuleType::Page => AtRulePrelude::Page(
643 input
644 .try_parse(|i| PageSelectors::parse(&self.context, i))
645 .unwrap_or_default(),
646 ),
647 AtRuleType::Property => {
648 let name = input.expect_ident_cloned()?;
649 let name = parse_custom_property_name(&name)
650 .map_err(|_| ParseError::custom(StyleParseErrorKind::UnexpectedIdent))?;
651 AtRulePrelude::Property(PropertyRuleName(Atom::from(name)))
652 },
653 AtRuleType::Document => {
654 let cond = DocumentCondition::parse(&self.context, input)?;
655 AtRulePrelude::Document(cond)
656 },
657 AtRuleType::Scope => {
658 let bounds = ScopeBounds::parse(&self.context, input, self.parse_relative())?;
659 AtRulePrelude::Scope(bounds)
660 },
661 AtRuleType::StartingStyle => AtRulePrelude::StartingStyle,
662 AtRuleType::AppearanceBase => {
663 AtRulePrelude::AppearanceBase
666 },
667 AtRuleType::PositionTry => {
668 let name = DashedIdent::parse(&self.context, input)?;
669 AtRulePrelude::PositionTry(name)
670 },
671 AtRuleType::CustomMedia => {
672 let name = DashedIdent::parse(&self.context, input)?;
673 let condition = input
674 .try_parse(CustomMediaCondition::parse_keyword)
675 .unwrap_or_else(|_| {
676 CustomMediaCondition::MediaList(Arc::new(
677 self.shared_lock
678 .wrap(MediaList::parse(&mut self.context, input)),
679 ))
680 });
681 AtRulePrelude::CustomMedia(name, condition)
682 },
683 AtRuleType::ViewTransition => AtRulePrelude::ViewTransition,
684 AtRuleType::Margin(rule_type) => AtRulePrelude::Margin(rule_type),
685 AtRuleType::Import | AtRuleType::Namespace | AtRuleType::FontFeatureValuesBlock => {
686 return Err(ParseError::from_basic_kind(
689 BasicParseErrorKind::AtRuleInvalid,
690 ));
691 },
692 })
693 }
694
695 #[inline]
696 fn parse_relative(&self) -> ParseRelative {
697 self.context.nesting_context.parse_relative
698 }
699
700 fn at_rule_allowed(&self, prelude: &AtRulePrelude) -> bool {
705 match prelude {
706 AtRulePrelude::Media(..)
707 | AtRulePrelude::Supports(..)
708 | AtRulePrelude::Container(..)
709 | AtRulePrelude::Document(..)
710 | AtRulePrelude::Layer(..)
711 | AtRulePrelude::CustomMedia(..)
712 | AtRulePrelude::Scope(..)
713 | AtRulePrelude::StartingStyle
714 | AtRulePrelude::AppearanceBase => true,
715
716 AtRulePrelude::Namespace(..)
717 | AtRulePrelude::FontFace
718 | AtRulePrelude::FontFeatureValues(..)
719 | AtRulePrelude::FontPaletteValues(..)
720 | AtRulePrelude::CounterStyle(..)
721 | AtRulePrelude::Keyframes(..)
722 | AtRulePrelude::Page(..)
723 | AtRulePrelude::Property(..)
724 | AtRulePrelude::Import(..)
725 | AtRulePrelude::PositionTry(..)
726 | AtRulePrelude::ViewTransition => !self.in_style_or_page_rule(),
727 AtRulePrelude::Margin(..) => self.in_page_rule(),
728 }
729 }
730
731 fn nest_for_rule<R>(&mut self, rule_type: CssRuleType, cb: impl FnOnce(&mut Self) -> R) -> R {
732 let old = self.context.nesting_context.save(rule_type);
733 let r = cb(self);
734 self.context.nesting_context.restore(old);
735 r
736 }
737
738 fn parse_nested_rules(
739 &mut self,
740 input: &mut Parser<'i>,
741 rule_type: CssRuleType,
742 ) -> Arc<Locked<CssRules>> {
743 let rules = self
744 .parse_nested(
745 input, rule_type, false,
746 )
747 .rules;
748 CssRules::new(rules, self.shared_lock)
749 }
750
751 fn parse_nested(
752 &mut self,
753 input: &mut Parser<'i>,
754 rule_type: CssRuleType,
755 wants_first_declaration_block: bool,
756 ) -> NestedParseResult {
757 debug_assert!(
758 !self.wants_first_declaration_block,
759 "Should've flushed previous declarations"
760 );
761 self.nest_for_rule(rule_type, |parser| {
762 parser.wants_first_declaration_block = wants_first_declaration_block;
763 let parse_declarations = parser.parse_declarations();
764 let mut rules = std::mem::take(&mut parser.rules);
765 let mut first_declaration_block = std::mem::take(&mut parser.first_declaration_block);
766 let mut iter = RuleBodyParser::new(input, parser);
767 while let Some(result) = iter.next() {
768 match result {
769 Ok(()) => {},
770 Err((error, slice, location)) => {
771 if parse_declarations {
772 let top = &mut **iter.parser;
773 top.declaration_parser_state.did_error(
774 &top.context,
775 error,
776 slice,
777 location,
778 );
779 } else {
780 let error = ContextualParseError::InvalidRule(slice, error);
781 iter.parser.context.log_css_error(location, error);
782 }
783 },
784 }
785 }
786 parser.flush_declarations();
787 debug_assert!(
788 !parser.wants_first_declaration_block,
789 "Flushing declarations should take care of this."
790 );
791 debug_assert!(
792 !parser.declaration_parser_state.has_parsed_declarations(),
793 "Parsed but didn't consume declarations"
794 );
795 std::mem::swap(&mut parser.rules, &mut rules);
796 std::mem::swap(
797 &mut parser.first_declaration_block,
798 &mut first_declaration_block,
799 );
800 NestedParseResult {
801 first_declaration_block,
802 rules,
803 }
804 })
805 }
806
807 #[inline(never)]
808 fn handle_error_reporting_selectors_pre(
809 &mut self,
810 start: &ParserState,
811 selectors: &SelectorList<SelectorImpl>,
812 ) {
813 use cssparser::ToCss;
814 debug_assert!(self.context.error_reporting_enabled());
815 self.error_reporting_state.push(selectors.clone());
816 'selector_loop: for selector in selectors.slice().iter() {
817 let mut current = selector.iter();
818 loop {
819 let mut found_host = false;
820 let mut found_non_host = false;
821 for component in &mut current {
822 if component.is_host() {
823 found_host = true;
824 } else {
825 found_non_host = true;
826 }
827 if found_host && found_non_host {
828 self.context.log_css_error(
829 start.source_location(),
830 ContextualParseError::NeverMatchingHostSelector(
831 selector.to_css_string(),
832 ),
833 );
834 continue 'selector_loop;
835 }
836 }
837 if current.next_sequence().is_none() {
838 break;
839 }
840 }
841 }
842 }
843
844 fn handle_error_reporting_selectors_post(&mut self) {
845 self.error_reporting_state.pop();
846 }
847
848 #[inline]
849 fn flush_declarations(&mut self) {
850 let parser = &mut **self;
851 let wants_first_declaration_block = parser.wants_first_declaration_block;
852 parser.wants_first_declaration_block = false;
853 parser
854 .declaration_parser_state
855 .report_errors_if_needed(&parser.context, &parser.error_reporting_state);
856 if !parser.declaration_parser_state.has_parsed_declarations() {
857 return;
858 }
859 let source_location = parser.declaration_parser_state.first_declaration_start();
860 let declarations = parser.declaration_parser_state.take_declarations();
861 if wants_first_declaration_block {
862 debug_assert!(parser.first_declaration_block.is_empty(), "How?");
863 parser.first_declaration_block = declarations;
864 } else {
865 let nested_rule = CssRule::NestedDeclarations(Arc::new(parser.shared_lock.wrap(
866 NestedDeclarationsRule {
867 block: Arc::new(parser.shared_lock.wrap(declarations)),
868 source_location,
869 },
870 )));
871 parser.rules.push(nested_rule);
872 }
873 }
874}
875
876impl<'a, 'i> AtRuleParser<'i> for NestedRuleParser<'a, 'i> {
877 type Prelude = AtRulePrelude;
878 type AtRule = ();
879 type Error = StyleParseErrorKind;
880
881 fn parse_prelude(
882 &mut self,
883 name: CowRcStr<'i>,
884 input: &mut Parser<'i>,
885 ) -> Result<Self::Prelude, ParseError> {
886 let Some(rule_type) = AtRuleType::from_name(&name, &self.context) else {
887 return Err(ParseError::from_basic_kind(
888 BasicParseErrorKind::AtRuleInvalid,
889 ));
890 };
891
892 self.parse_at_rule_prelude(rule_type, input)
893 }
894
895 fn parse_block(
896 &mut self,
897 prelude: AtRulePrelude,
898 start: &ParserState,
899 input: &mut Parser<'i>,
900 ) -> Result<(), ParseError> {
901 if !self.at_rule_allowed(&prelude) {
902 self.dom_error = Some(RulesMutateError::HierarchyRequest);
903 return Err(ParseError::from_basic_kind(
904 BasicParseErrorKind::AtRuleInvalid,
905 ));
906 }
907 let source_location = start.source_location();
908 self.flush_declarations();
909 let rule = match prelude {
910 AtRulePrelude::FontFace => self.nest_for_rule(CssRuleType::FontFace, |p| {
911 CssRule::FontFace(Arc::new(p.shared_lock.wrap(parse_font_face_block(
912 &p.context,
913 input,
914 source_location,
915 ))))
916 }),
917 AtRulePrelude::FontFeatureValues(family_names) => {
918 self.nest_for_rule(CssRuleType::FontFeatureValues, |p| {
919 CssRule::FontFeatureValues(Arc::new(FontFeatureValuesRule::parse(
920 &p.context,
921 input,
922 family_names,
923 source_location,
924 )))
925 })
926 },
927 AtRulePrelude::FontPaletteValues(name) => {
928 self.nest_for_rule(CssRuleType::FontPaletteValues, |p| {
929 CssRule::FontPaletteValues(Arc::new(FontPaletteValuesRule::parse(
930 &p.context,
931 input,
932 name,
933 source_location,
934 )))
935 })
936 },
937 AtRulePrelude::CounterStyle(name) => {
938 let body = self.nest_for_rule(CssRuleType::CounterStyle, |p| {
939 parse_counter_style_body(name, &p.context, input, source_location)
940 })?;
941 CssRule::CounterStyle(Arc::new(self.shared_lock.wrap(body)))
942 },
943 AtRulePrelude::Media(media_queries) => CssRule::Media(Arc::new(MediaRule {
944 media_queries,
945 rules: self.parse_nested_rules(input, CssRuleType::Media),
946 source_location,
947 })),
948 AtRulePrelude::Supports(condition) => {
949 let enabled =
950 self.nest_for_rule(CssRuleType::Style, |p| condition.eval(&p.context));
951 CssRule::Supports(Arc::new(SupportsRule {
952 condition,
953 rules: self.parse_nested_rules(input, CssRuleType::Supports),
954 enabled,
955 source_location,
956 }))
957 },
958 AtRulePrelude::Keyframes(name, vendor_prefix) => {
959 self.nest_for_rule(CssRuleType::Keyframe, |p| {
960 let top = &mut **p;
961 CssRule::Keyframes(Arc::new(top.shared_lock.wrap(KeyframesRule {
962 name,
963 keyframes: parse_keyframe_list(&mut top.context, input, top.shared_lock),
964 vendor_prefix,
965 source_location,
966 })))
967 })
968 },
969 AtRulePrelude::Page(selectors) => {
970 let page_rule = if !crate::pref!("layout.css.margin-rules.enabled") {
971 let declarations = self.nest_for_rule(CssRuleType::Page, |p| {
972 parse_property_declaration_list(&p.context, input, &[])
973 });
974 PageRule {
975 selectors,
976 rules: CssRules::new(vec![], self.shared_lock),
977 block: Arc::new(self.shared_lock.wrap(declarations)),
978 source_location,
979 }
980 } else {
981 let result = self.parse_nested(input, CssRuleType::Page, true);
982 PageRule {
983 selectors,
984 rules: CssRules::new(result.rules, self.shared_lock),
985 block: Arc::new(self.shared_lock.wrap(result.first_declaration_block)),
986 source_location,
987 }
988 };
989 CssRule::Page(Arc::new(self.shared_lock.wrap(page_rule)))
990 },
991 AtRulePrelude::Property(name) => self.nest_for_rule(CssRuleType::Property, |p| {
992 let rule_data = parse_property_block(&p.context, input, name, source_location)?;
993 Ok::<CssRule, ParseError>(CssRule::Property(Arc::new(rule_data)))
994 })?,
995 AtRulePrelude::Document(condition) => {
996 if !cfg!(feature = "gecko") {
997 unreachable!()
998 }
999 CssRule::Document(Arc::new(DocumentRule {
1000 condition,
1001 rules: self.parse_nested_rules(input, CssRuleType::Document),
1002 source_location,
1003 }))
1004 },
1005 AtRulePrelude::Container(conditions) => {
1006 let source_location = start.source_location();
1007 CssRule::Container(Arc::new(ContainerRule {
1008 conditions: ContainerConditions(conditions),
1009 rules: self.parse_nested_rules(input, CssRuleType::Container),
1010 source_location,
1011 }))
1012 },
1013 AtRulePrelude::Layer(names) => {
1014 let name = match names.len() {
1015 0 | 1 => names.into_iter().next(),
1016 _ => {
1017 return Err(ParseError::from_basic_kind(
1018 BasicParseErrorKind::AtRuleBodyInvalid,
1019 ))
1020 },
1021 };
1022 CssRule::LayerBlock(Arc::new(LayerBlockRule {
1023 name,
1024 rules: self.parse_nested_rules(input, CssRuleType::LayerBlock),
1025 source_location,
1026 }))
1027 },
1028 AtRulePrelude::Margin(rule_type) => {
1029 let declarations = self.nest_for_rule(CssRuleType::Margin, |p| {
1030 parse_property_declaration_list(&p.context, input, &[])
1031 });
1032 CssRule::Margin(Arc::new(MarginRule {
1033 rule_type,
1034 block: Arc::new(self.shared_lock.wrap(declarations)),
1035 source_location,
1036 }))
1037 },
1038 AtRulePrelude::CustomMedia(..)
1039 | AtRulePrelude::Import(..)
1040 | AtRulePrelude::Namespace(..) => {
1041 return Err(ParseError::unexpected_token());
1043 },
1044 AtRulePrelude::Scope(bounds) => CssRule::Scope(Arc::new(ScopeRule {
1045 bounds,
1046 rules: self.parse_nested_rules(input, CssRuleType::Scope),
1047 source_location,
1048 })),
1049 AtRulePrelude::StartingStyle => CssRule::StartingStyle(Arc::new(StartingStyleRule {
1050 rules: self.parse_nested_rules(input, CssRuleType::StartingStyle),
1051 source_location,
1052 })),
1053 AtRulePrelude::AppearanceBase => {
1054 CssRule::AppearanceBase(Arc::new(AppearanceBaseRule {
1055 rules: self.parse_nested_rules(input, CssRuleType::AppearanceBase),
1056 source_location,
1057 }))
1058 },
1059 AtRulePrelude::PositionTry(name) => {
1060 let declarations = self.nest_for_rule(CssRuleType::PositionTry, |p| {
1061 parse_property_declaration_list(&p.context, input, &[])
1062 });
1063 CssRule::PositionTry(Arc::new(self.shared_lock.wrap(PositionTryRule {
1064 name,
1065 block: Arc::new(self.shared_lock.wrap(declarations)),
1066 source_location,
1067 })))
1068 },
1069 AtRulePrelude::ViewTransition => self.nest_for_rule(CssRuleType::ViewTransition, |p| {
1070 CssRule::ViewTransition(Arc::new(ViewTransitionRule::parse(
1071 &p.context,
1072 input,
1073 source_location,
1074 )))
1075 }),
1076 };
1077 self.rules.push(rule);
1078 Ok(())
1079 }
1080
1081 #[inline]
1082 fn rule_without_block(
1083 &mut self,
1084 prelude: AtRulePrelude,
1085 start: &ParserState,
1086 ) -> Result<(), ()> {
1087 if self.in_style_rule() {
1088 return Err(());
1089 }
1090 let source_location = start.source_location();
1091 let rule = match prelude {
1092 AtRulePrelude::CustomMedia(name, condition) => {
1093 CssRule::CustomMedia(Arc::new(CustomMediaRule {
1094 name,
1095 condition,
1096 source_location,
1097 }))
1098 },
1099 AtRulePrelude::Layer(names) => {
1100 if names.is_empty() {
1101 return Err(());
1102 }
1103 CssRule::LayerStatement(Arc::new(LayerStatementRule {
1104 names,
1105 source_location,
1106 }))
1107 },
1108 _ => return Err(()),
1109 };
1110 self.flush_declarations();
1111 self.rules.push(rule);
1112 Ok(())
1113 }
1114}
1115
1116impl<'a, 'i> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'i> {
1117 type Prelude = SelectorList<SelectorImpl>;
1118 type QualifiedRule = ();
1119 type Error = StyleParseErrorKind;
1120
1121 fn parse_prelude(&mut self, input: &mut Parser<'i>) -> Result<Self::Prelude, ParseError> {
1122 let selector_parser = SelectorParser {
1123 stylesheet_origin: self.context.stylesheet_origin,
1124 namespaces: &self.context.namespaces,
1125 url_data: self.context.url_data,
1126 for_supports_rule: false,
1127 };
1128 SelectorList::parse(&selector_parser, input, self.parse_relative())
1129 }
1130
1131 fn parse_block(
1132 &mut self,
1133 selectors: Self::Prelude,
1134 start: &ParserState,
1135 input: &mut Parser<'i>,
1136 ) -> Result<(), ParseError> {
1137 let source_location = start.source_location();
1138 let reporting_errors = self.context.error_reporting_enabled();
1139 if reporting_errors {
1140 self.handle_error_reporting_selectors_pre(start, &selectors);
1141 }
1142 self.flush_declarations();
1143 let result = self.parse_nested(input, CssRuleType::Style, true);
1144 if reporting_errors {
1145 self.handle_error_reporting_selectors_post();
1146 }
1147 let block = Arc::new(self.shared_lock.wrap(result.first_declaration_block));
1148 let top = &mut **self;
1149 top.rules
1150 .push(CssRule::Style(Arc::new(top.shared_lock.wrap(StyleRule {
1151 selectors,
1152 block,
1153 rules: if result.rules.is_empty() {
1154 None
1155 } else {
1156 Some(CssRules::new(result.rules, top.shared_lock))
1157 },
1158 source_location,
1159 }))));
1160 Ok(())
1161 }
1162}
1163
1164impl<'a, 'i> DeclarationParser<'i> for NestedRuleParser<'a, 'i> {
1165 type Declaration = ();
1166 type Error = StyleParseErrorKind;
1167 fn parse_value(
1168 &mut self,
1169 name: CowRcStr<'i>,
1170 input: &mut Parser<'i>,
1171 declaration_start: &ParserState,
1172 ) -> Result<(), ParseError> {
1173 let top = &mut **self;
1174 top.declaration_parser_state
1175 .parse_value(&top.context, name, input, declaration_start)
1176 }
1177}
1178
1179impl<'a, 'i> RuleBodyItemParser<'i, (), StyleParseErrorKind> for NestedRuleParser<'a, 'i> {
1180 fn parse_qualified(&self) -> bool {
1181 true
1182 }
1183
1184 fn parse_declarations(&self) -> bool {
1187 self.can_parse_declarations()
1188 }
1189}