1use crate::attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
6use crate::attr::{NamespaceConstraint, ParsedAttrSelectorOperation, ParsedCaseSensitivity};
7use crate::bloom::BLOOM_HASH_MASK;
8use crate::builder::{
9 SelectorBuilder, SelectorFlags, Specificity, SpecificityAndFlags,
10 relative_selector_list_specificity_and_flags, selector_list_specificity_and_flags,
11};
12use crate::context::QuirksMode;
13use crate::sink::Push;
14use crate::visitor::SelectorListKind;
15pub use crate::visitor::SelectorVisitor;
16use bitflags::bitflags;
17use cssparser::match_ignore_ascii_case;
18use cssparser::parse_nth;
19use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind};
20use cssparser::{CowRcStr, Delimiter};
21use cssparser::{Parser as CssParser, ToCss, Token};
22use debug_unreachable::debug_unreachable;
23use precomputed_hash::PrecomputedHash;
24use servo_arc::{Arc, ArcUnionBorrow, ThinArc, ThinArcUnion, UniqueArc};
25use smallvec::SmallVec;
26use std::borrow::{Borrow, Cow};
27use std::fmt::{self, Debug};
28use std::iter::Rev;
29use std::slice;
30
31#[cfg(feature = "to_shmem")]
32use to_shmem_derive::ToShmem;
33
34pub trait PseudoElement: Sized + ToCss {
36 fn accepts_state_pseudo_classes(&self) -> bool {
39 false
40 }
41
42 fn valid_after_slotted(&self) -> bool {
44 false
45 }
46
47 fn valid_after_before_or_after(&self) -> bool {
49 false
50 }
51
52 fn parses_as_element_backed(&self) -> bool {
55 false
56 }
57
58 fn is_before_or_after(&self) -> bool {
62 false
63 }
64
65 fn specificity_count(&self) -> u32 {
67 1
68 }
69
70 fn is_in_pseudo_element_tree(&self) -> bool {
74 false
75 }
76}
77
78pub trait NonTSPseudoClass: Sized + ToCss {
80 fn is_active_or_hover(&self) -> bool;
82
83 fn is_user_action_state(&self) -> bool;
87
88 fn visit<V>(&self, _visitor: &mut V) -> bool
89 where
90 V: SelectorVisitor,
91 <V as SelectorVisitor>::Impl: SelectorImpl<NonTSPseudoClass = Self>,
92 {
93 true
94 }
95}
96
97fn to_ascii_lowercase(s: &str) -> Cow<'_, str> {
100 if let Some(first_uppercase) = s.bytes().position(|byte: u8| byte.is_ascii_uppercase()) {
101 let mut string = s.to_owned();
102 string[first_uppercase..].make_ascii_lowercase();
103 string.into()
104 } else {
105 s.into()
106 }
107}
108
109bitflags! {
110 #[derive(Copy, Clone)]
112 struct SelectorParsingState: u16 {
113 const SKIP_DEFAULT_NAMESPACE = 1 << 0;
116
117 const AFTER_SLOTTED = 1 << 1;
122 const AFTER_PART_LIKE = 1 << 2;
127 const AFTER_NON_ELEMENT_BACKED_PSEUDO = 1 << 3;
134 const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
139 const AFTER_BEFORE_OR_AFTER_PSEUDO = 1 << 5;
143
144 const AFTER_PSEUDO = Self::AFTER_PART_LIKE.bits() | Self::AFTER_SLOTTED.bits() | Self::AFTER_NON_ELEMENT_BACKED_PSEUDO.bits() | Self::AFTER_BEFORE_OR_AFTER_PSEUDO.bits();
146
147 const DISALLOW_COMBINATORS = 1 << 6;
149
150 const DISALLOW_PSEUDOS = 1 << 7;
152
153 const DISALLOW_RELATIVE_SELECTOR = 1 << 8;
155
156 const IN_PSEUDO_ELEMENT_TREE = 1 << 9;
159 }
160}
161
162impl SelectorParsingState {
163 #[inline]
164 fn allows_slotted(self) -> bool {
165 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
166 }
167
168 #[inline]
169 fn allows_part(self) -> bool {
170 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
171 }
172
173 #[inline]
174 fn allows_non_functional_pseudo_classes(self) -> bool {
175 !self.intersects(Self::AFTER_SLOTTED | Self::AFTER_NON_STATEFUL_PSEUDO_ELEMENT)
176 }
177
178 #[inline]
179 fn allows_tree_structural_pseudo_classes(self) -> bool {
180 !self.intersects(Self::AFTER_PSEUDO) || self.intersects(Self::IN_PSEUDO_ELEMENT_TREE)
181 }
182
183 #[inline]
184 fn allows_combinators(self) -> bool {
185 !self.intersects(Self::DISALLOW_COMBINATORS)
186 }
187
188 #[inline]
189 fn allows_only_child_pseudo_class_only(self) -> bool {
190 self.intersects(Self::IN_PSEUDO_ELEMENT_TREE)
191 }
192}
193
194pub type SelectorParseError = ParseError<SelectorParseErrorKind>;
195
196#[derive(Clone, Debug, PartialEq)]
197pub enum SelectorParseErrorKind {
198 NoQualifiedNameInAttributeSelector,
199 EmptySelector,
200 DanglingCombinator,
201 NonCompoundSelector,
202 NonPseudoElementAfterSlotted,
203 InvalidPseudoElementAfterSlotted,
204 InvalidPseudoElementInsideWhere,
205 InvalidState,
206 UnexpectedTokenInAttributeSelector,
207 PseudoElementExpectedColon,
208 PseudoElementExpectedIdent,
209 NoIdentForPseudo,
210 UnsupportedPseudoClassOrElement,
211 UnexpectedIdent,
212 ExpectedNamespace,
213 ExpectedBarInAttr,
214 BadValueInAttr,
215 InvalidQualNameInAttr,
216 ExplicitNamespaceUnexpectedToken,
217 ClassNeedsIdent,
218}
219
220macro_rules! with_all_bounds {
221 (
222 [ $( $InSelector: tt )* ]
223 [ $( $CommonBounds: tt )* ]
224 [ $( $FromStr: tt )* ]
225 ) => {
226 pub trait SelectorImpl: Clone + Debug + Sized + 'static {
233 type ExtraMatchingData<'a>: Sized + Default;
234 type AttrValue: $($InSelector)*;
235 type Identifier: $($InSelector)* + PrecomputedHash;
236 type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName> + PrecomputedHash;
237 type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl> + PrecomputedHash;
238 type NamespacePrefix: $($InSelector)* + Default;
239 type BorrowedNamespaceUrl: ?Sized + Eq;
240 type BorrowedLocalName: ?Sized + Eq;
241
242 type NonTSPseudoClass: $($CommonBounds)* + NonTSPseudoClass;
245
246 type PseudoElement: $($CommonBounds)* + PseudoElement;
248
249 fn should_collect_attr_hash(_name: &Self::LocalName) -> bool {
252 false
253 }
254 }
255 }
256}
257
258macro_rules! with_bounds {
259 ( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
260 with_all_bounds! {
261 [$($CommonBounds)* + $($FromStr)* + ToCss]
262 [$($CommonBounds)*]
263 [$($FromStr)*]
264 }
265 }
266}
267
268with_bounds! {
269 [Clone + Eq]
270 [for<'a> From<&'a str>]
271}
272
273pub trait Parser<'i> {
274 type Impl: SelectorImpl;
275 type Error: From<SelectorParseErrorKind>;
276
277 fn parse_slotted(&self) -> bool {
279 false
280 }
281
282 fn parse_part(&self) -> bool {
284 false
285 }
286
287 fn parse_nth_child_of(&self) -> bool {
289 false
290 }
291
292 fn parse_is_and_where(&self) -> bool {
294 false
295 }
296
297 fn parse_has(&self) -> bool {
299 false
300 }
301
302 fn parse_parent_selector(&self) -> bool {
304 false
305 }
306
307 fn is_is_alias(&self, _name: &str) -> bool {
309 false
310 }
311
312 fn parse_host(&self) -> bool {
314 false
315 }
316
317 fn allow_forgiving_selectors(&self) -> bool {
319 true
320 }
321
322 fn parse_non_ts_pseudo_class(
325 &self,
326 _name: &str,
327 ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<Self::Error>> {
328 Err(ParseError::custom(
329 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
330 ))
331 }
332
333 fn parse_non_ts_functional_pseudo_class(
334 &self,
335 _name: &str,
336 _parser: &mut CssParser<'i>,
337 _after_part: bool,
338 ) -> Result<<Self::Impl as SelectorImpl>::NonTSPseudoClass, ParseError<Self::Error>> {
339 Err(ParseError::custom(
340 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
341 ))
342 }
343
344 fn parse_pseudo_element(
345 &self,
346 _name: &str,
347 ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<Self::Error>> {
348 Err(ParseError::custom(
349 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
350 ))
351 }
352
353 fn parse_functional_pseudo_element(
354 &self,
355 _name: &str,
356 _arguments: &mut CssParser<'i>,
357 ) -> Result<<Self::Impl as SelectorImpl>::PseudoElement, ParseError<Self::Error>> {
358 Err(ParseError::custom(
359 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
360 ))
361 }
362
363 fn default_namespace(&self) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
364 None
365 }
366
367 fn namespace_for_prefix(
368 &self,
369 _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix,
370 ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
371 None
372 }
373}
374
375#[derive(Clone, Eq, Debug, PartialEq)]
378#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
379#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
380pub struct SelectorList<Impl: SelectorImpl>(
381 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
382 ThinArcUnion<SpecificityAndFlags, Component<Impl>, (), Selector<Impl>>,
383);
384
385impl<Impl: SelectorImpl> SelectorList<Impl> {
386 pub fn mark_as_intentionally_leaked(&self) {
388 if let ArcUnionBorrow::Second(ref list) = self.0.borrow() {
389 list.with_arc(|list| list.mark_as_intentionally_leaked())
390 }
391 self.slice()
392 .iter()
393 .for_each(|s| s.mark_as_intentionally_leaked())
394 }
395
396 pub fn from_one(selector: Selector<Impl>) -> Self {
397 #[cfg(debug_assertions)]
398 let selector_repr = unsafe { *(&selector as *const _ as *const usize) };
399 let list = Self(ThinArcUnion::from_first(selector.into_data()));
400 #[cfg(debug_assertions)]
401 debug_assert_eq!(
402 selector_repr,
403 unsafe { *(&list as *const _ as *const usize) },
404 "We rely on the same bit representation for the single selector variant"
405 );
406 list
407 }
408
409 #[allow(clippy::should_implement_trait)]
410 pub fn from_iter(mut iter: impl ExactSizeIterator<Item = Selector<Impl>>) -> Self {
411 if iter.len() == 1 {
412 Self::from_one(iter.next().unwrap())
413 } else {
414 Self(ThinArcUnion::from_second(ThinArc::from_header_and_iter(
415 (),
416 iter,
417 )))
418 }
419 }
420
421 #[inline]
422 pub fn slice(&self) -> &[Selector<Impl>] {
423 match self.0.borrow() {
424 ArcUnionBorrow::First(..) => {
425 let selector: &Selector<Impl> = unsafe { std::mem::transmute(self) };
427 std::slice::from_ref(selector)
428 },
429 ArcUnionBorrow::Second(list) => list.get().slice(),
430 }
431 }
432
433 #[inline]
434 #[allow(clippy::len_without_is_empty)]
435 pub fn len(&self) -> usize {
436 match self.0.borrow() {
437 ArcUnionBorrow::First(..) => 1,
438 ArcUnionBorrow::Second(list) => list.len(),
439 }
440 }
441
442 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
444 match self.0.borrow() {
445 ArcUnionBorrow::First(s) => s.with_arc(|a| a.heap_ptr()),
446 ArcUnionBorrow::Second(s) => s.with_arc(|a| a.heap_ptr()),
447 }
448 }
449}
450
451#[derive(Clone, Copy, Hash, Eq, PartialEq)]
454pub struct SelectorKey(usize);
455
456impl SelectorKey {
457 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>) -> Self {
459 Self(selector.0.slice().as_ptr() as usize)
460 }
461}
462
463#[derive(PartialEq)]
465enum ForgivingParsing {
466 No,
469 Yes,
473}
474
475#[derive(Copy, Clone, PartialEq)]
477pub enum ParseRelative {
478 ForHas,
480 ForNesting,
483 ForScope,
486 No,
488}
489
490impl<Impl: SelectorImpl> SelectorList<Impl> {
491 pub fn scope() -> Self {
493 Self::from_one(Selector::scope())
494 }
495 pub fn implicit_scope() -> Self {
497 Self::from_one(Selector::implicit_scope())
498 }
499
500 pub fn parse<'i, P>(
505 parser: &P,
506 input: &mut CssParser<'i>,
507 parse_relative: ParseRelative,
508 ) -> Result<Self, ParseError<P::Error>>
509 where
510 P: Parser<'i, Impl = Impl>,
511 {
512 Self::parse_with_state(
513 parser,
514 input,
515 SelectorParsingState::empty(),
516 ForgivingParsing::No,
517 parse_relative,
518 )
519 }
520
521 pub fn parse_disallow_pseudo<'i, P>(
523 parser: &P,
524 input: &mut CssParser<'i>,
525 parse_relative: ParseRelative,
526 ) -> Result<Self, ParseError<P::Error>>
527 where
528 P: Parser<'i, Impl = Impl>,
529 {
530 Self::parse_with_state(
531 parser,
532 input,
533 SelectorParsingState::DISALLOW_PSEUDOS,
534 ForgivingParsing::No,
535 parse_relative,
536 )
537 }
538
539 pub fn parse_forgiving<'i, P>(
540 parser: &P,
541 input: &mut CssParser<'i>,
542 parse_relative: ParseRelative,
543 ) -> Result<Self, ParseError<P::Error>>
544 where
545 P: Parser<'i, Impl = Impl>,
546 {
547 Self::parse_with_state(
548 parser,
549 input,
550 SelectorParsingState::empty(),
551 ForgivingParsing::Yes,
552 parse_relative,
553 )
554 }
555
556 #[inline]
557 fn parse_with_state<'i, P>(
558 parser: &P,
559 input: &mut CssParser<'i>,
560 state: SelectorParsingState,
561 recovery: ForgivingParsing,
562 parse_relative: ParseRelative,
563 ) -> Result<Self, ParseError<P::Error>>
564 where
565 P: Parser<'i, Impl = Impl>,
566 {
567 let mut values = SmallVec::<[_; 4]>::new();
568 let forgiving = recovery == ForgivingParsing::Yes && parser.allow_forgiving_selectors();
569 loop {
570 let selector = input.parse_until_before(Delimiter::Comma, |input| {
571 let start = input.position();
572 let mut selector = parse_selector(parser, input, state, parse_relative);
573 if forgiving && (selector.is_err() || input.expect_exhausted().is_err()) {
574 input.expect_no_error_token()?;
575 selector = Ok(Selector::new_invalid(input.slice_from(start)));
576 }
577 selector
578 })?;
579
580 values.push(selector);
581
582 match input.next() {
583 Ok(&Token::Comma) => {},
584 Ok(_) => unreachable!(),
585 Err(_) => break,
586 }
587 }
588 Ok(Self::from_iter(values.into_iter()))
589 }
590
591 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
593 Self::from_iter(
594 self.slice()
595 .iter()
596 .map(|selector| selector.replace_parent_selector(parent)),
597 )
598 }
599
600 #[allow(dead_code)]
602 pub(crate) fn from_vec(v: Vec<Selector<Impl>>) -> Self {
603 SelectorList::from_iter(v.into_iter())
604 }
605}
606
607fn parse_inner_compound_selector<'i, P, Impl>(
609 parser: &P,
610 input: &mut CssParser<'i>,
611 state: SelectorParsingState,
612) -> Result<Selector<Impl>, ParseError<P::Error>>
613where
614 P: Parser<'i, Impl = Impl>,
615 Impl: SelectorImpl,
616{
617 parse_selector(
618 parser,
619 input,
620 state | SelectorParsingState::DISALLOW_PSEUDOS | SelectorParsingState::DISALLOW_COMBINATORS,
621 ParseRelative::No,
622 )
623}
624
625#[derive(Clone, Debug, Eq, PartialEq)]
641pub struct AncestorHashes {
642 pub packed_hashes: [u32; 3],
643}
644
645pub(crate) fn collect_selector_hashes<'a, Impl: SelectorImpl, Iter>(
646 iter: Iter,
647 quirks_mode: QuirksMode,
648 hashes: &mut [u32; 4],
649 len: &mut usize,
650 create_inner_iterator: fn(&'a Selector<Impl>) -> Iter,
651) -> bool
652where
653 Iter: Iterator<Item = &'a Component<Impl>>,
654{
655 for component in iter {
656 let hash = match *component {
657 Component::LocalName(LocalName {
658 ref name,
659 ref lower_name,
660 }) => {
661 if name != lower_name {
665 continue;
666 }
667 name.precomputed_hash()
668 },
669 Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => {
670 url.precomputed_hash()
671 },
672 Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => id.precomputed_hash(),
675 Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
676 class.precomputed_hash()
677 },
678 Component::AttributeInNoNamespace { ref local_name, .. }
679 if Impl::should_collect_attr_hash(local_name) =>
680 {
681 local_name.precomputed_hash()
684 },
685 Component::AttributeInNoNamespaceExists {
686 ref local_name,
687 ref local_name_lower,
688 ..
689 } => {
690 if local_name != local_name_lower || !Impl::should_collect_attr_hash(local_name) {
694 continue;
695 }
696 local_name.precomputed_hash()
697 },
698 Component::AttributeOther(ref selector) => {
699 if selector.local_name != selector.local_name_lower
700 || !Impl::should_collect_attr_hash(&selector.local_name)
701 {
702 continue;
703 }
704 selector.local_name.precomputed_hash()
705 },
706 Component::Is(ref list) | Component::Where(ref list) => {
707 let slice = list.slice();
711 if slice.len() == 1
712 && !collect_selector_hashes(
713 create_inner_iterator(&slice[0]),
714 quirks_mode,
715 hashes,
716 len,
717 create_inner_iterator,
718 )
719 {
720 return false;
721 }
722 continue;
723 },
724 _ => continue,
725 };
726
727 hashes[*len] = hash & BLOOM_HASH_MASK;
728 *len += 1;
729 if *len == hashes.len() {
730 return false;
731 }
732 }
733 true
734}
735
736fn collect_ancestor_hashes<Impl: SelectorImpl>(
737 mut iter: SelectorIter<Impl>,
738 quirks_mode: QuirksMode,
739 hashes: &mut [u32; 4],
740 len: &mut usize,
741) -> bool {
742 loop {
743 for item in iter.by_ref() {
744 if let Component::Is(list) | Component::Where(list) = item {
745 let slice = list.slice();
746 if slice.len() == 1
747 && !collect_ancestor_hashes(slice[0].iter(), quirks_mode, hashes, len)
748 {
749 return false;
750 }
751 }
752 }
753 let Some(c) = iter.next_sequence() else {
754 return true;
755 };
756 match c {
757 Combinator::Child | Combinator::Descendant => break,
759 Combinator::LaterSibling | Combinator::NextSibling => {
760 iter.skip_until_ancestor();
761 break;
762 },
763 Combinator::Part | Combinator::SlotAssignment | Combinator::PseudoElement => {},
768 }
769 }
770
771 collect_selector_hashes(AncestorIter(iter), quirks_mode, hashes, len, |s| {
772 AncestorIter(s.iter())
773 })
774}
775
776impl AncestorHashes {
777 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self {
778 let mut hashes = [0u32; 4];
780 let mut len = 0;
781 collect_ancestor_hashes(selector.iter(), quirks_mode, &mut hashes, &mut len);
782 debug_assert!(len <= 4);
783
784 if len == 4 {
787 let fourth = hashes[3];
788 hashes[0] |= (fourth & 0x000000ff) << 24;
789 hashes[1] |= (fourth & 0x0000ff00) << 16;
790 hashes[2] |= (fourth & 0x00ff0000) << 8;
791 }
792
793 AncestorHashes {
794 packed_hashes: [hashes[0], hashes[1], hashes[2]],
795 }
796 }
797
798 pub fn fourth_hash(&self) -> u32 {
800 ((self.packed_hashes[0] & 0xff000000) >> 24)
801 | ((self.packed_hashes[1] & 0xff000000) >> 16)
802 | ((self.packed_hashes[2] & 0xff000000) >> 8)
803 }
804}
805
806#[inline]
807pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
808 Impl::NamespaceUrl::default()
810}
811
812pub(super) type SelectorData<Impl> = ThinArc<SpecificityAndFlags, Component<Impl>>;
813
814#[derive(Clone, Copy, Debug, Eq, PartialEq)]
817pub enum MatchesFeaturelessHost {
818 Yes,
820 Only,
822 Never,
824}
825
826impl MatchesFeaturelessHost {
827 #[inline]
829 pub fn may_match(self) -> bool {
830 !matches!(self, Self::Never)
831 }
832}
833
834#[derive(Clone, Eq, PartialEq)]
849#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
850#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
851#[repr(transparent)]
852pub struct Selector<Impl: SelectorImpl>(
853 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] SelectorData<Impl>,
854);
855
856impl<Impl: SelectorImpl> Selector<Impl> {
857 pub fn mark_as_intentionally_leaked(&self) {
859 self.0.mark_as_intentionally_leaked()
860 }
861
862 fn scope() -> Self {
863 Self(ThinArc::from_header_and_iter(
864 SpecificityAndFlags {
865 specificity: Specificity::single_class_like().into(),
866 flags: SelectorFlags::HAS_SCOPE,
867 },
868 std::iter::once(Component::Scope),
869 ))
870 }
871
872 fn implicit_scope() -> Self {
874 Self(ThinArc::from_header_and_iter(
875 SpecificityAndFlags {
876 specificity: 0,
877 flags: SelectorFlags::HAS_SCOPE,
878 },
879 std::iter::once(Component::ImplicitScope),
880 ))
881 }
882
883 #[inline]
884 pub fn specificity(&self) -> u32 {
885 self.0.header.specificity
886 }
887
888 #[inline]
889 pub(crate) fn flags(&self) -> SelectorFlags {
890 self.0.header.flags
891 }
892
893 #[inline]
894 pub fn has_pseudo_element(&self) -> bool {
895 self.flags().intersects(SelectorFlags::HAS_PSEUDO)
896 }
897
898 #[inline]
899 pub fn has_parent_selector(&self) -> bool {
900 self.flags().intersects(SelectorFlags::HAS_PARENT)
901 }
902
903 #[inline]
904 pub fn has_scope_selector(&self) -> bool {
905 self.flags().intersects(SelectorFlags::HAS_SCOPE)
906 }
907
908 #[inline]
909 pub fn is_slotted(&self) -> bool {
910 self.flags().intersects(SelectorFlags::HAS_SLOTTED)
911 }
912
913 #[inline]
914 pub fn is_part(&self) -> bool {
915 self.flags().intersects(SelectorFlags::HAS_PART)
916 }
917
918 #[inline]
919 pub fn parts(&self) -> Option<&[Impl::Identifier]> {
920 if !self.is_part() {
921 return None;
922 }
923
924 let mut iter = self.iter();
925 if self.has_pseudo_element() {
926 for _ in &mut iter {}
928
929 let combinator = iter.next_sequence()?;
930 debug_assert_eq!(combinator, Combinator::PseudoElement);
931 }
932
933 for component in iter {
934 if let Component::Part(ref part) = *component {
935 return Some(part);
936 }
937 }
938
939 debug_assert!(false, "is_part() lied somehow?");
940 None
941 }
942
943 #[inline]
944 pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
945 if !self.has_pseudo_element() {
946 return None;
947 }
948
949 for component in self.iter() {
950 if let Component::PseudoElement(ref pseudo) = *component {
951 return Some(pseudo);
952 }
953 }
954
955 debug_assert!(false, "has_pseudo_element lied!");
956 None
957 }
958
959 #[inline]
960 pub fn pseudo_elements(&self) -> SmallVec<[&Impl::PseudoElement; 3]> {
961 let mut pseudos = SmallVec::new();
962
963 if !self.has_pseudo_element() {
964 return pseudos;
965 }
966
967 let mut iter = self.iter();
968 loop {
969 for component in &mut iter {
970 if let Component::PseudoElement(ref pseudo) = *component {
971 pseudos.push(pseudo);
972 }
973 }
974 match iter.next_sequence() {
975 Some(Combinator::PseudoElement) => {},
976 _ => break,
977 }
978 }
979
980 debug_assert!(!pseudos.is_empty(), "has_pseudo_element lied!");
981
982 pseudos
983 }
984
985 #[inline]
989 pub fn is_universal(&self) -> bool {
990 self.iter_raw_match_order().all(|c| {
991 matches!(
992 *c,
993 Component::ExplicitUniversalType
994 | Component::ExplicitAnyNamespace
995 | Component::Combinator(Combinator::PseudoElement)
996 | Component::PseudoElement(..)
997 )
998 })
999 }
1000
1001 #[inline]
1004 pub fn matches_featureless_host(
1005 &self,
1006 scope_matches_featureless_host: bool,
1007 ) -> MatchesFeaturelessHost {
1008 let flags = self.flags();
1009 if !flags.intersects(SelectorFlags::HAS_HOST | SelectorFlags::HAS_SCOPE) {
1010 return MatchesFeaturelessHost::Never;
1011 }
1012
1013 let mut iter = self.iter();
1014 if flags.intersects(SelectorFlags::HAS_PSEUDO) {
1015 for _ in &mut iter {
1016 }
1018 match iter.next_sequence() {
1019 Some(c) if c.is_pseudo_element() => {},
1020 _ => {
1021 debug_assert!(false, "Pseudo selector without pseudo combinator?");
1022 return MatchesFeaturelessHost::Never;
1023 },
1024 }
1025 }
1026
1027 let compound_matches = crate::matching::compound_matches_featureless_host(
1028 &mut iter,
1029 scope_matches_featureless_host,
1030 );
1031 if iter.next_sequence().is_some() {
1032 return MatchesFeaturelessHost::Never;
1033 }
1034 compound_matches
1035 }
1036
1037 #[inline]
1041 pub fn iter(&self) -> SelectorIter<'_, Impl> {
1042 SelectorIter {
1043 iter: self.iter_raw_match_order(),
1044 next_combinator: None,
1045 }
1046 }
1047
1048 #[inline]
1050 pub fn iter_skip_relative_selector_anchor(&self) -> SelectorIter<'_, Impl> {
1051 if cfg!(debug_assertions) {
1052 let mut selector_iter = self.iter_raw_parse_order_from(0);
1053 assert!(
1054 matches!(
1055 selector_iter.next().unwrap(),
1056 Component::RelativeSelectorAnchor
1057 ),
1058 "Relative selector does not start with RelativeSelectorAnchor"
1059 );
1060 assert!(
1061 selector_iter.next().unwrap().is_combinator(),
1062 "Relative combinator does not exist"
1063 );
1064 }
1065
1066 SelectorIter {
1067 iter: self.0.slice()[..self.len() - 2].iter(),
1068 next_combinator: None,
1069 }
1070 }
1071
1072 #[inline]
1075 pub fn iter_from(&self, offset: usize) -> SelectorIter<'_, Impl> {
1076 let iter = self.0.slice()[offset..].iter();
1077 SelectorIter {
1078 iter,
1079 next_combinator: None,
1080 }
1081 }
1082
1083 #[inline]
1086 pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
1087 match self.0.slice()[index] {
1088 Component::Combinator(c) => c,
1089 ref other => panic!(
1090 "Not a combinator: {:?}, {:?}, index: {}",
1091 other, self, index
1092 ),
1093 }
1094 }
1095
1096 #[inline]
1099 pub fn iter_raw_match_order(&self) -> slice::Iter<'_, Component<Impl>> {
1100 self.0.slice().iter()
1101 }
1102
1103 #[inline]
1106 pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
1107 match self.0.slice()[self.len() - index - 1] {
1108 Component::Combinator(c) => c,
1109 ref other => panic!(
1110 "Not a combinator: {:?}, {:?}, index: {}",
1111 other, self, index
1112 ),
1113 }
1114 }
1115
1116 #[inline]
1120 pub fn iter_raw_parse_order_from(
1121 &self,
1122 offset: usize,
1123 ) -> Rev<slice::Iter<'_, Component<Impl>>> {
1124 self.0.slice()[..self.len() - offset].iter().rev()
1125 }
1126
1127 #[allow(dead_code)]
1129 pub(crate) fn from_vec(
1130 vec: Vec<Component<Impl>>,
1131 specificity: u32,
1132 flags: SelectorFlags,
1133 ) -> Self {
1134 let mut builder = SelectorBuilder::default();
1135 for component in vec.into_iter() {
1136 if let Some(combinator) = component.as_combinator() {
1137 builder.push_combinator(combinator);
1138 } else {
1139 builder.push_simple_selector(component);
1140 }
1141 }
1142 let spec = SpecificityAndFlags { specificity, flags };
1143 Selector(builder.build_with_specificity_and_flags(spec, ParseRelative::No))
1144 }
1145
1146 #[inline]
1147 fn into_data(self) -> SelectorData<Impl> {
1148 self.0
1149 }
1150
1151 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
1152 let parent_specificity_and_flags = selector_list_specificity_and_flags(
1153 parent.slice().iter(),
1154 true,
1155 );
1156
1157 let mut specificity = Specificity::from(self.specificity());
1158 let mut flags = self.flags() - SelectorFlags::HAS_PARENT;
1159 let forbidden_flags = SelectorFlags::forbidden_for_nesting();
1160
1161 fn replace_parent_on_selector_list<Impl: SelectorImpl>(
1162 orig: &[Selector<Impl>],
1163 parent: &SelectorList<Impl>,
1164 specificity: &mut Specificity,
1165 flags: &mut SelectorFlags,
1166 propagate_specificity: bool,
1167 forbidden_flags: SelectorFlags,
1168 ) -> Option<SelectorList<Impl>> {
1169 if !orig.iter().any(|s| s.has_parent_selector()) {
1170 return None;
1171 }
1172
1173 let result =
1174 SelectorList::from_iter(orig.iter().map(|s| s.replace_parent_selector(parent)));
1175
1176 let result_specificity_and_flags = selector_list_specificity_and_flags(
1177 result.slice().iter(),
1178 false,
1179 );
1180 if propagate_specificity {
1181 *specificity += Specificity::from(
1182 result_specificity_and_flags.specificity
1183 - selector_list_specificity_and_flags(
1184 orig.iter(),
1185 false,
1186 )
1187 .specificity,
1188 );
1189 }
1190 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1191 Some(result)
1192 }
1193
1194 fn replace_parent_on_relative_selector_list<Impl: SelectorImpl>(
1195 orig: &[RelativeSelector<Impl>],
1196 parent: &SelectorList<Impl>,
1197 specificity: &mut Specificity,
1198 flags: &mut SelectorFlags,
1199 forbidden_flags: SelectorFlags,
1200 ) -> Box<[RelativeSelector<Impl>]> {
1201 let mut any = false;
1202
1203 let result = orig
1204 .iter()
1205 .map(|s| {
1206 if !s.selector.has_parent_selector() {
1207 return s.clone();
1208 }
1209 any = true;
1210 RelativeSelector {
1211 match_hint: s.match_hint,
1212 selector: s.selector.replace_parent_selector(parent),
1213 }
1214 })
1215 .collect();
1216
1217 if !any {
1218 return result;
1219 }
1220
1221 let result_specificity_and_flags = relative_selector_list_specificity_and_flags(
1222 &result, false,
1223 );
1224 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1225 *specificity += Specificity::from(
1226 result_specificity_and_flags.specificity
1227 - relative_selector_list_specificity_and_flags(
1228 orig, false,
1229 )
1230 .specificity,
1231 );
1232 result
1233 }
1234
1235 fn replace_parent_on_selector<Impl: SelectorImpl>(
1236 orig: &Selector<Impl>,
1237 parent: &SelectorList<Impl>,
1238 specificity: &mut Specificity,
1239 flags: &mut SelectorFlags,
1240 forbidden_flags: SelectorFlags,
1241 ) -> Selector<Impl> {
1242 let new_selector = orig.replace_parent_selector(parent);
1243 *specificity += Specificity::from(new_selector.specificity() - orig.specificity());
1244 flags.insert(new_selector.flags() - forbidden_flags);
1245 new_selector
1246 }
1247
1248 if !self.has_parent_selector() {
1249 return self.clone();
1250 }
1251
1252 let iter = self.iter_raw_match_order().map(|component| {
1253 use self::Component::*;
1254 match *component {
1255 LocalName(..)
1256 | ID(..)
1257 | Class(..)
1258 | AttributeInNoNamespaceExists { .. }
1259 | AttributeInNoNamespace { .. }
1260 | AttributeOther(..)
1261 | ExplicitUniversalType
1262 | ExplicitAnyNamespace
1263 | ExplicitNoNamespace
1264 | DefaultNamespace(..)
1265 | Namespace(..)
1266 | Root
1267 | Empty
1268 | Scope
1269 | ImplicitScope
1270 | Nth(..)
1271 | NonTSPseudoClass(..)
1272 | PseudoElement(..)
1273 | Combinator(..)
1274 | Host(None)
1275 | Part(..)
1276 | Invalid(..)
1277 | RelativeSelectorAnchor => component.clone(),
1278 ParentSelector => {
1279 specificity += Specificity::from(parent_specificity_and_flags.specificity);
1280 flags.insert(parent_specificity_and_flags.flags - forbidden_flags);
1281 Is(parent.clone())
1282 },
1283 Negation(ref selectors) => {
1284 Negation(
1285 replace_parent_on_selector_list(
1286 selectors.slice(),
1287 parent,
1288 &mut specificity,
1289 &mut flags,
1290 true,
1291 forbidden_flags,
1292 )
1293 .unwrap_or_else(|| selectors.clone()),
1294 )
1295 },
1296 Is(ref selectors) => {
1297 Is(replace_parent_on_selector_list(
1298 selectors.slice(),
1299 parent,
1300 &mut specificity,
1301 &mut flags,
1302 true,
1303 forbidden_flags,
1304 )
1305 .unwrap_or_else(|| selectors.clone()))
1306 },
1307 Where(ref selectors) => {
1308 Where(
1309 replace_parent_on_selector_list(
1310 selectors.slice(),
1311 parent,
1312 &mut specificity,
1313 &mut flags,
1314 false,
1315 forbidden_flags,
1316 )
1317 .unwrap_or_else(|| selectors.clone()),
1318 )
1319 },
1320 Has(ref selectors) => Has(replace_parent_on_relative_selector_list(
1321 selectors,
1322 parent,
1323 &mut specificity,
1324 &mut flags,
1325 forbidden_flags,
1326 )),
1327 Host(Some(ref selector)) => Host(Some(replace_parent_on_selector(
1328 selector,
1329 parent,
1330 &mut specificity,
1331 &mut flags,
1332 forbidden_flags,
1333 ))),
1334 NthOf(ref data) => {
1335 let selectors = replace_parent_on_selector_list(
1336 data.selectors(),
1337 parent,
1338 &mut specificity,
1339 &mut flags,
1340 true,
1341 forbidden_flags,
1342 );
1343 NthOf(match selectors {
1344 Some(s) => {
1345 NthOfSelectorData::new(data.nth_data(), s.slice().iter().cloned())
1346 },
1347 None => data.clone(),
1348 })
1349 },
1350 Slotted(ref selector) => Slotted(replace_parent_on_selector(
1351 selector,
1352 parent,
1353 &mut specificity,
1354 &mut flags,
1355 forbidden_flags,
1356 )),
1357 }
1358 });
1359 let mut items = UniqueArc::from_header_and_iter(Default::default(), iter);
1360 *items.header_mut() = SpecificityAndFlags {
1361 specificity: specificity.into(),
1362 flags,
1363 };
1364 Selector(items.shareable())
1365 }
1366
1367 #[inline]
1369 #[allow(clippy::len_without_is_empty)]
1370 pub fn len(&self) -> usize {
1371 self.0.len()
1372 }
1373
1374 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
1376 self.0.heap_ptr()
1377 }
1378
1379 pub fn visit<V>(&self, visitor: &mut V) -> bool
1398 where
1399 V: SelectorVisitor<Impl = Impl>,
1400 {
1401 let mut current = self.iter();
1402 let mut combinator = None;
1403 loop {
1404 if !visitor.visit_complex_selector(combinator) {
1405 return false;
1406 }
1407
1408 for selector in &mut current {
1409 if !selector.visit(visitor) {
1410 return false;
1411 }
1412 }
1413
1414 combinator = current.next_sequence();
1415 if combinator.is_none() {
1416 break;
1417 }
1418 }
1419
1420 true
1421 }
1422
1423 #[inline]
1425 pub fn parse<'i, P>(parser: &P, input: &mut CssParser<'i>) -> Result<Self, ParseError<P::Error>>
1426 where
1427 P: Parser<'i, Impl = Impl>,
1428 {
1429 parse_selector(
1430 parser,
1431 input,
1432 SelectorParsingState::empty(),
1433 ParseRelative::No,
1434 )
1435 }
1436
1437 pub fn new_invalid(s: &str) -> Self {
1438 fn check_for_parent(input: &mut CssParser, has_parent: &mut bool) {
1439 while let Ok(t) = input.next() {
1440 match *t {
1441 Token::Function(_)
1442 | Token::ParenthesisBlock
1443 | Token::CurlyBracketBlock
1444 | Token::SquareBracketBlock => {
1445 let _ = input.parse_nested_block(
1446 |i| -> Result<(), ParseError<BasicParseError>> {
1447 check_for_parent(i, has_parent);
1448 Ok(())
1449 },
1450 );
1451 },
1452 Token::Delim('&') => {
1453 *has_parent = true;
1454 },
1455 _ => {},
1456 }
1457 if *has_parent {
1458 break;
1459 }
1460 }
1461 }
1462 let mut has_parent = false;
1463 {
1464 let mut parser = CssParser::new(s);
1465 check_for_parent(&mut parser, &mut has_parent);
1466 }
1467 Self(ThinArc::from_header_and_iter(
1468 SpecificityAndFlags {
1469 specificity: 0,
1470 flags: if has_parent {
1471 SelectorFlags::HAS_PARENT
1472 } else {
1473 SelectorFlags::empty()
1474 },
1475 },
1476 std::iter::once(Component::Invalid(Arc::new(String::from(s.trim())))),
1477 ))
1478 }
1479
1480 pub fn is_rightmost(&self, offset: usize) -> bool {
1482 offset == 0
1485 || matches!(
1486 self.combinator_at_match_order(offset - 1),
1487 Combinator::PseudoElement
1488 )
1489 }
1490}
1491
1492#[derive(Clone)]
1493pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
1494 iter: slice::Iter<'a, Component<Impl>>,
1495 next_combinator: Option<Combinator>,
1496}
1497
1498impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
1499 #[inline]
1502 pub fn next_sequence(&mut self) -> Option<Combinator> {
1503 self.next_combinator.take()
1504 }
1505
1506 fn skip_until_ancestor(&mut self) {
1509 loop {
1510 while self.next().is_some() {}
1511 if self.next_sequence().is_none_or(|c| c.is_ancestor()) {
1512 break;
1513 }
1514 }
1515 }
1516
1517 #[inline]
1518 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
1519 let first = match self.next() {
1520 Some(c) => c,
1521 None => return true,
1524 };
1525 self.matches_for_stateless_pseudo_element_internal(first)
1526 }
1527
1528 #[inline(never)]
1529 fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool {
1530 if !first.matches_for_stateless_pseudo_element() {
1531 return false;
1532 }
1533 for component in self {
1534 if !component.matches_for_stateless_pseudo_element() {
1538 return false;
1539 }
1540 }
1541 true
1542 }
1543
1544 #[inline]
1546 pub fn selector_length(&self) -> usize {
1547 self.iter.len()
1548 }
1549}
1550
1551impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
1552 type Item = &'a Component<Impl>;
1553
1554 #[inline]
1555 fn next(&mut self) -> Option<Self::Item> {
1556 debug_assert!(
1557 self.next_combinator.is_none(),
1558 "You should call next_sequence!"
1559 );
1560 match *self.iter.next()? {
1561 Component::Combinator(c) => {
1562 self.next_combinator = Some(c);
1563 None
1564 },
1565 ref x => Some(x),
1566 }
1567 }
1568}
1569
1570impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
1571 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1572 let iter = self.iter.clone().rev();
1573 for component in iter {
1574 component.to_css(f)?
1575 }
1576 Ok(())
1577 }
1578}
1579
1580struct CombinatorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1582impl<'a, Impl: 'a + SelectorImpl> CombinatorIter<'a, Impl> {
1583 fn new(inner: SelectorIter<'a, Impl>) -> Self {
1584 let mut result = CombinatorIter(inner);
1585 result.consume_non_combinators();
1586 result
1587 }
1588
1589 fn consume_non_combinators(&mut self) {
1590 while self.0.next().is_some() {}
1591 }
1592}
1593
1594impl<'a, Impl: SelectorImpl> Iterator for CombinatorIter<'a, Impl> {
1595 type Item = Combinator;
1596 fn next(&mut self) -> Option<Self::Item> {
1597 let result = self.0.next_sequence();
1598 self.consume_non_combinators();
1599 result
1600 }
1601}
1602
1603struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1605impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
1606 type Item = &'a Component<Impl>;
1607 fn next(&mut self) -> Option<Self::Item> {
1608 let next = self.0.next();
1610 if next.is_some() {
1611 return next;
1612 }
1613 if !self.0.next_sequence()?.is_ancestor() {
1615 self.0.skip_until_ancestor();
1616 }
1617 self.0.next()
1618 }
1619}
1620
1621#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1622#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1623pub enum Combinator {
1624 Child, Descendant, NextSibling, LaterSibling, PseudoElement,
1635 SlotAssignment,
1638 Part,
1641}
1642
1643impl Combinator {
1644 #[inline]
1646 pub fn is_pseudo_element(&self) -> bool {
1647 matches!(*self, Combinator::PseudoElement)
1648 }
1649
1650 #[inline]
1652 pub fn is_sibling(&self) -> bool {
1653 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
1654 }
1655
1656 #[inline]
1659 pub fn is_ancestor(&self) -> bool {
1660 !self.is_sibling()
1661 }
1662}
1663
1664#[derive(Copy, Clone, Eq, PartialEq)]
1666#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1667#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1668pub enum NthType {
1669 Child,
1670 LastChild,
1671 OnlyChild,
1672 OfType,
1673 LastOfType,
1674 OnlyOfType,
1675}
1676
1677impl NthType {
1678 pub fn is_only(self) -> bool {
1679 self == Self::OnlyChild || self == Self::OnlyOfType
1680 }
1681
1682 pub fn is_of_type(self) -> bool {
1683 self == Self::OfType || self == Self::LastOfType || self == Self::OnlyOfType
1684 }
1685
1686 pub fn is_from_end(self) -> bool {
1687 self == Self::LastChild || self == Self::LastOfType
1688 }
1689}
1690
1691#[derive(Copy, Clone, Eq, PartialEq, Debug)]
1693#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1694#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1695pub struct AnPlusB(pub i32, pub i32);
1696
1697impl AnPlusB {
1698 #[inline]
1699 pub fn matches_index(&self, i: i32) -> bool {
1700 match i.checked_sub(self.1) {
1702 None => false,
1703 Some(an) => match an.checked_div(self.0) {
1704 Some(n) => n >= 0 && self.0 * n == an,
1705 None => an == 0,
1706 },
1707 }
1708 }
1709}
1710
1711impl ToCss for AnPlusB {
1712 #[inline]
1715 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1716 where
1717 W: fmt::Write,
1718 {
1719 match (self.0, self.1) {
1720 (0, 0) => dest.write_char('0'),
1721
1722 (1, 0) => dest.write_char('n'),
1723 (-1, 0) => dest.write_str("-n"),
1724 (_, 0) => write!(dest, "{}n", self.0),
1725
1726 (0, _) => write!(dest, "{}", self.1),
1727 (1, _) => write!(dest, "n{:+}", self.1),
1728 (-1, _) => write!(dest, "-n{:+}", self.1),
1729 (_, _) => write!(dest, "{}n{:+}", self.0, self.1),
1730 }
1731 }
1732}
1733
1734#[derive(Copy, Clone, Eq, PartialEq)]
1738#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1739#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1740pub struct NthSelectorData {
1741 pub ty: NthType,
1742 pub is_function: bool,
1743 pub an_plus_b: AnPlusB,
1744}
1745
1746impl NthSelectorData {
1747 #[inline]
1749 pub const fn only(of_type: bool) -> Self {
1750 Self {
1751 ty: if of_type {
1752 NthType::OnlyOfType
1753 } else {
1754 NthType::OnlyChild
1755 },
1756 is_function: false,
1757 an_plus_b: AnPlusB(0, 1),
1758 }
1759 }
1760
1761 #[inline]
1763 pub const fn first(of_type: bool) -> Self {
1764 Self {
1765 ty: if of_type {
1766 NthType::OfType
1767 } else {
1768 NthType::Child
1769 },
1770 is_function: false,
1771 an_plus_b: AnPlusB(0, 1),
1772 }
1773 }
1774
1775 #[inline]
1777 pub const fn last(of_type: bool) -> Self {
1778 Self {
1779 ty: if of_type {
1780 NthType::LastOfType
1781 } else {
1782 NthType::LastChild
1783 },
1784 is_function: false,
1785 an_plus_b: AnPlusB(0, 1),
1786 }
1787 }
1788
1789 #[inline]
1791 pub fn is_simple_edge(&self) -> bool {
1792 self.an_plus_b.0 == 0
1793 && self.an_plus_b.1 == 1
1794 && !self.ty.is_of_type()
1795 && !self.ty.is_only()
1796 }
1797
1798 #[inline]
1800 fn write_start<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1801 dest.write_str(match self.ty {
1802 NthType::Child if self.is_function => ":nth-child(",
1803 NthType::Child => ":first-child",
1804 NthType::LastChild if self.is_function => ":nth-last-child(",
1805 NthType::LastChild => ":last-child",
1806 NthType::OfType if self.is_function => ":nth-of-type(",
1807 NthType::OfType => ":first-of-type",
1808 NthType::LastOfType if self.is_function => ":nth-last-of-type(",
1809 NthType::LastOfType => ":last-of-type",
1810 NthType::OnlyChild => ":only-child",
1811 NthType::OnlyOfType => ":only-of-type",
1812 })
1813 }
1814
1815 #[inline]
1816 fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1817 self.an_plus_b.to_css(dest)
1818 }
1819}
1820
1821#[derive(Clone, Eq, PartialEq)]
1825#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1826#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1827pub struct NthOfSelectorData<Impl: SelectorImpl>(
1828 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] ThinArc<NthSelectorData, Selector<Impl>>,
1829);
1830
1831impl<Impl: SelectorImpl> NthOfSelectorData<Impl> {
1832 #[inline]
1834 pub fn new<I>(nth_data: &NthSelectorData, selectors: I) -> Self
1835 where
1836 I: Iterator<Item = Selector<Impl>> + ExactSizeIterator,
1837 {
1838 Self(ThinArc::from_header_and_iter(*nth_data, selectors))
1839 }
1840
1841 #[inline]
1843 pub fn nth_data(&self) -> &NthSelectorData {
1844 &self.0.header
1845 }
1846
1847 #[inline]
1849 pub fn selectors(&self) -> &[Selector<Impl>] {
1850 self.0.slice()
1851 }
1852}
1853
1854#[derive(Clone, Copy, Eq, PartialEq)]
1856#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1857pub enum RelativeSelectorMatchHint {
1858 InSubtree,
1860 InChild,
1862 InNextSibling,
1864 InNextSiblingSubtree,
1866 InSibling,
1868 InSiblingSubtree,
1870}
1871
1872impl RelativeSelectorMatchHint {
1873 pub fn new(
1875 relative_combinator: Combinator,
1876 has_child_or_descendants: bool,
1877 has_adjacent_or_next_siblings: bool,
1878 ) -> Self {
1879 match relative_combinator {
1880 Combinator::Descendant => RelativeSelectorMatchHint::InSubtree,
1881 Combinator::Child => {
1882 if !has_child_or_descendants {
1883 RelativeSelectorMatchHint::InChild
1884 } else {
1885 RelativeSelectorMatchHint::InSubtree
1888 }
1889 },
1890 Combinator::NextSibling => {
1891 if !has_child_or_descendants && !has_adjacent_or_next_siblings {
1892 RelativeSelectorMatchHint::InNextSibling
1893 } else if !has_child_or_descendants && has_adjacent_or_next_siblings {
1894 RelativeSelectorMatchHint::InSibling
1895 } else if has_child_or_descendants && !has_adjacent_or_next_siblings {
1896 RelativeSelectorMatchHint::InNextSiblingSubtree
1898 } else {
1899 RelativeSelectorMatchHint::InSiblingSubtree
1900 }
1901 },
1902 Combinator::LaterSibling => {
1903 if !has_child_or_descendants {
1904 RelativeSelectorMatchHint::InSibling
1905 } else {
1906 RelativeSelectorMatchHint::InSiblingSubtree
1909 }
1910 },
1911 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1912 debug_assert!(false, "Unexpected relative combinator");
1913 RelativeSelectorMatchHint::InSubtree
1914 },
1915 }
1916 }
1917
1918 pub fn is_descendant_direction(&self) -> bool {
1920 matches!(*self, Self::InChild | Self::InSubtree)
1921 }
1922
1923 pub fn is_next_sibling(&self) -> bool {
1925 matches!(*self, Self::InNextSibling | Self::InNextSiblingSubtree)
1926 }
1927
1928 pub fn is_subtree(&self) -> bool {
1930 matches!(
1931 *self,
1932 Self::InSubtree | Self::InSiblingSubtree | Self::InNextSiblingSubtree
1933 )
1934 }
1935}
1936
1937#[derive(Clone, Copy)]
1939pub struct RelativeSelectorCombinatorCount {
1940 relative_combinator: Combinator,
1941 pub child_or_descendants: usize,
1942 pub adjacent_or_next_siblings: usize,
1943}
1944
1945impl RelativeSelectorCombinatorCount {
1946 pub fn new<Impl: SelectorImpl>(relative_selector: &RelativeSelector<Impl>) -> Self {
1948 let mut result = RelativeSelectorCombinatorCount {
1949 relative_combinator: relative_selector.selector.combinator_at_parse_order(1),
1950 child_or_descendants: 0,
1951 adjacent_or_next_siblings: 0,
1952 };
1953
1954 for combinator in CombinatorIter::new(
1955 relative_selector
1956 .selector
1957 .iter_skip_relative_selector_anchor(),
1958 ) {
1959 match combinator {
1960 Combinator::Descendant | Combinator::Child => {
1961 result.child_or_descendants += 1;
1962 },
1963 Combinator::NextSibling | Combinator::LaterSibling => {
1964 result.adjacent_or_next_siblings += 1;
1965 },
1966 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1967 continue;
1968 },
1969 };
1970 }
1971 result
1972 }
1973
1974 pub fn get_match_hint(&self) -> RelativeSelectorMatchHint {
1976 RelativeSelectorMatchHint::new(
1977 self.relative_combinator,
1978 self.child_or_descendants != 0,
1979 self.adjacent_or_next_siblings != 0,
1980 )
1981 }
1982}
1983
1984#[derive(Clone, Eq, PartialEq)]
1986#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1987#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1988pub struct RelativeSelector<Impl: SelectorImpl> {
1989 pub match_hint: RelativeSelectorMatchHint,
1991 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
1993 pub selector: Selector<Impl>,
1994}
1995
1996bitflags! {
1997 #[derive(Clone, Debug, Eq, PartialEq)]
1999 struct CombinatorComposition: u8 {
2000 const DESCENDANTS = 1 << 0;
2001 const SIBLINGS = 1 << 1;
2002 }
2003}
2004
2005impl CombinatorComposition {
2006 fn for_relative_selector<Impl: SelectorImpl>(inner_selector: &Selector<Impl>) -> Self {
2007 let mut result = CombinatorComposition::empty();
2008 for combinator in CombinatorIter::new(inner_selector.iter_skip_relative_selector_anchor()) {
2009 match combinator {
2010 Combinator::Descendant | Combinator::Child => {
2011 result.insert(Self::DESCENDANTS);
2012 },
2013 Combinator::NextSibling | Combinator::LaterSibling => {
2014 result.insert(Self::SIBLINGS);
2015 },
2016 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
2017 continue;
2018 },
2019 };
2020 if result.is_all() {
2021 break;
2022 }
2023 }
2024 result
2025 }
2026}
2027
2028impl<Impl: SelectorImpl> RelativeSelector<Impl> {
2029 fn from_selector_list(selector_list: SelectorList<Impl>) -> Box<[Self]> {
2030 selector_list
2031 .slice()
2032 .iter()
2033 .map(|selector| {
2034 if cfg!(debug_assertions) {
2037 let relative_selector_anchor = selector.iter_raw_parse_order_from(0).next();
2038 debug_assert!(
2039 relative_selector_anchor.is_some(),
2040 "Relative selector is empty"
2041 );
2042 debug_assert!(
2043 matches!(
2044 relative_selector_anchor.unwrap(),
2045 Component::RelativeSelectorAnchor
2046 ),
2047 "Relative selector anchor is missing"
2048 );
2049 }
2050 let composition = CombinatorComposition::for_relative_selector(selector);
2052 let match_hint = RelativeSelectorMatchHint::new(
2053 selector.combinator_at_parse_order(1),
2054 composition.intersects(CombinatorComposition::DESCENDANTS),
2055 composition.intersects(CombinatorComposition::SIBLINGS),
2056 );
2057 RelativeSelector {
2058 match_hint,
2059 selector: selector.clone(),
2060 }
2061 })
2062 .collect()
2063 }
2064}
2065
2066#[derive(Clone, Eq, PartialEq)]
2071#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2072#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2073pub enum Component<Impl: SelectorImpl> {
2074 LocalName(LocalName<Impl>),
2075
2076 ID(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2077 Class(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2078
2079 AttributeInNoNamespaceExists {
2080 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2081 local_name: Impl::LocalName,
2082 local_name_lower: Impl::LocalName,
2083 },
2084 AttributeInNoNamespace {
2086 local_name: Impl::LocalName,
2087 operator: AttrSelectorOperator,
2088 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2089 value: Impl::AttrValue,
2090 case_sensitivity: ParsedCaseSensitivity,
2091 },
2092 AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
2094
2095 ExplicitUniversalType,
2096 ExplicitAnyNamespace,
2097
2098 ExplicitNoNamespace,
2099 DefaultNamespace(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl),
2100 Namespace(
2101 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespacePrefix,
2102 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl,
2103 ),
2104
2105 Negation(SelectorList<Impl>),
2107 Root,
2108 Empty,
2109 Scope,
2110 ImplicitScope,
2118 ParentSelector,
2119 Nth(NthSelectorData),
2120 NthOf(NthOfSelectorData<Impl>),
2121 NonTSPseudoClass(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NonTSPseudoClass),
2122 Slotted(Selector<Impl>),
2134 Part(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Box<[Impl::Identifier]>),
2137 Host(Option<Selector<Impl>>),
2147 Where(SelectorList<Impl>),
2154 Is(SelectorList<Impl>),
2160 Has(Box<[RelativeSelector<Impl>]>),
2166 Invalid(Arc<String>),
2168 PseudoElement(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::PseudoElement),
2170
2171 Combinator(Combinator),
2172
2173 RelativeSelectorAnchor,
2178}
2179
2180impl<Impl: SelectorImpl> Component<Impl> {
2181 #[inline]
2183 pub fn is_combinator(&self) -> bool {
2184 matches!(*self, Component::Combinator(_))
2185 }
2186
2187 #[inline]
2189 pub fn is_host(&self) -> bool {
2190 matches!(*self, Component::Host(..))
2191 }
2192
2193 pub fn as_combinator(&self) -> Option<Combinator> {
2195 match *self {
2196 Component::Combinator(c) => Some(c),
2197 _ => None,
2198 }
2199 }
2200
2201 fn matches_for_stateless_pseudo_element(&self) -> bool {
2205 match *self {
2206 Component::Negation(ref selectors) => !selectors.slice().iter().all(|selector| {
2207 selector
2208 .iter_raw_match_order()
2209 .all(|c| c.matches_for_stateless_pseudo_element())
2210 }),
2211 Component::Is(ref selectors) | Component::Where(ref selectors) => {
2212 selectors.slice().iter().any(|selector| {
2213 selector
2214 .iter_raw_match_order()
2215 .all(|c| c.matches_for_stateless_pseudo_element())
2216 })
2217 },
2218 _ => false,
2219 }
2220 }
2221
2222 pub fn visit<V>(&self, visitor: &mut V) -> bool
2223 where
2224 V: SelectorVisitor<Impl = Impl>,
2225 {
2226 use self::Component::*;
2227 if !visitor.visit_simple_selector(self) {
2228 return false;
2229 }
2230
2231 match *self {
2232 Slotted(ref selector) => {
2233 if !selector.visit(visitor) {
2234 return false;
2235 }
2236 },
2237 Host(Some(ref selector)) => {
2238 if !selector.visit(visitor) {
2239 return false;
2240 }
2241 },
2242 AttributeInNoNamespaceExists {
2243 ref local_name,
2244 ref local_name_lower,
2245 } => {
2246 if !visitor.visit_attribute_selector(
2247 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2248 local_name,
2249 local_name_lower,
2250 ) {
2251 return false;
2252 }
2253 },
2254 AttributeInNoNamespace { ref local_name, .. } => {
2255 if !visitor.visit_attribute_selector(
2256 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2257 local_name,
2258 local_name,
2259 ) {
2260 return false;
2261 }
2262 },
2263 AttributeOther(ref attr_selector) => {
2264 let empty_string;
2265 let namespace = match attr_selector.namespace() {
2266 Some(ns) => ns,
2267 None => {
2268 empty_string = crate::parser::namespace_empty_string::<Impl>();
2269 NamespaceConstraint::Specific(&empty_string)
2270 },
2271 };
2272 if !visitor.visit_attribute_selector(
2273 &namespace,
2274 &attr_selector.local_name,
2275 &attr_selector.local_name_lower,
2276 ) {
2277 return false;
2278 }
2279 },
2280
2281 NonTSPseudoClass(ref pseudo_class) => {
2282 if !pseudo_class.visit(visitor) {
2283 return false;
2284 }
2285 },
2286 Negation(ref list) | Is(ref list) | Where(ref list) => {
2287 let list_kind = SelectorListKind::from_component(self);
2288 debug_assert!(!list_kind.is_empty());
2289 if !visitor.visit_selector_list(list_kind, list.slice()) {
2290 return false;
2291 }
2292 },
2293 NthOf(ref nth_of_data) => {
2294 if !visitor.visit_selector_list(SelectorListKind::NTH_OF, nth_of_data.selectors()) {
2295 return false;
2296 }
2297 },
2298 Has(ref list) if !visitor.visit_relative_selector_list(list) => {
2299 return false;
2300 },
2301 _ => {},
2302 }
2303
2304 true
2305 }
2306
2307 pub fn has_indexed_selector_in_subject(&self) -> bool {
2311 match *self {
2312 Component::NthOf(..) | Component::Nth(..) => return true,
2313 Component::Is(ref selectors)
2314 | Component::Where(ref selectors)
2315 | Component::Negation(ref selectors) => {
2316 for selector in selectors.slice() {
2318 for c in selector.iter() {
2319 if c.has_indexed_selector_in_subject() {
2320 return true;
2321 }
2322 }
2323 }
2324 },
2325 _ => (),
2326 };
2327 false
2328 }
2329}
2330
2331#[derive(Clone, Eq, PartialEq)]
2332#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2333#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2334pub struct LocalName<Impl: SelectorImpl> {
2335 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2336 pub name: Impl::LocalName,
2337 pub lower_name: Impl::LocalName,
2338}
2339
2340impl<Impl: SelectorImpl> Debug for Selector<Impl> {
2341 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2342 f.write_str("Selector(")?;
2343 self.to_css(f)?;
2344 write!(
2345 f,
2346 ", specificity = {:#x}, flags = {:?})",
2347 self.specificity(),
2348 self.flags()
2349 )
2350 }
2351}
2352
2353impl<Impl: SelectorImpl> Debug for Component<Impl> {
2354 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2355 self.to_css(f)
2356 }
2357}
2358impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
2359 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2360 self.to_css(f)
2361 }
2362}
2363impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
2364 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2365 self.to_css(f)
2366 }
2367}
2368
2369fn serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result
2370where
2371 Impl: SelectorImpl,
2372 I: Iterator<Item = &'a Selector<Impl>>,
2373 W: fmt::Write,
2374{
2375 let mut first = true;
2376 for selector in iter {
2377 if !first {
2378 dest.write_str(", ")?;
2379 }
2380 first = false;
2381 selector.to_css(dest)?;
2382 }
2383 Ok(())
2384}
2385
2386impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
2387 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2388 where
2389 W: fmt::Write,
2390 {
2391 serialize_selector_list(self.slice().iter(), dest)
2392 }
2393}
2394
2395impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
2396 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2397 where
2398 W: fmt::Write,
2399 {
2400 let mut combinators = self
2413 .iter_raw_match_order()
2414 .rev()
2415 .filter_map(|x| x.as_combinator());
2416 let compound_selectors = self
2417 .iter_raw_match_order()
2418 .as_slice()
2419 .split(|x| x.is_combinator())
2420 .rev();
2421
2422 let mut combinators_exhausted = false;
2423 for compound in compound_selectors {
2424 debug_assert!(!combinators_exhausted);
2425
2426 let first_compound = match compound.first() {
2428 None => continue,
2429 Some(c) => c,
2430 };
2431 if matches!(
2432 first_compound,
2433 Component::RelativeSelectorAnchor | Component::ImplicitScope
2434 ) {
2435 debug_assert!(
2436 compound.len() == 1,
2437 "RelativeSelectorAnchor/ImplicitScope should only be a simple selector"
2438 );
2439 if let Some(c) = combinators.next() {
2440 c.to_css_relative(dest)?;
2441 } else {
2442 debug_assert!(
2445 matches!(first_compound, Component::ImplicitScope),
2446 "Only implicit :scope may not have any combinator"
2447 );
2448 }
2449 continue;
2450 }
2451
2452 let (can_elide_namespace, first_non_namespace) = match compound[0] {
2463 Component::ExplicitAnyNamespace
2464 | Component::ExplicitNoNamespace
2465 | Component::Namespace(..) => (false, 1),
2466 Component::DefaultNamespace(..) => (true, 1),
2467 _ => (true, 0),
2468 };
2469 let mut perform_step_2 = true;
2470 let next_combinator = combinators.next();
2471 if first_non_namespace == compound.len() - 1 {
2472 match (next_combinator, &compound[first_non_namespace]) {
2473 (Some(Combinator::PseudoElement), _)
2481 | (Some(Combinator::SlotAssignment), _) => (),
2482 (_, &Component::ExplicitUniversalType) => {
2483 for simple in compound.iter() {
2486 simple.to_css(dest)?;
2487 }
2488 perform_step_2 = false;
2490 },
2491 _ => (),
2492 }
2493 }
2494
2495 if perform_step_2 {
2505 for simple in compound.iter() {
2506 if let Component::ExplicitUniversalType = *simple {
2507 if can_elide_namespace {
2512 continue;
2513 }
2514 }
2515 simple.to_css(dest)?;
2516 }
2517 }
2518
2519 match next_combinator {
2525 Some(c) => c.to_css(dest)?,
2526 None => combinators_exhausted = true,
2527 };
2528
2529 }
2535
2536 Ok(())
2537 }
2538}
2539
2540impl Combinator {
2541 fn to_css_internal<W>(self, dest: &mut W, prefix_space: bool) -> fmt::Result
2542 where
2543 W: fmt::Write,
2544 {
2545 if matches!(
2546 self,
2547 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment
2548 ) {
2549 return Ok(());
2550 }
2551 if prefix_space {
2552 dest.write_char(' ')?;
2553 }
2554 match self {
2555 Combinator::Child => dest.write_str("> "),
2556 Combinator::Descendant => Ok(()),
2557 Combinator::NextSibling => dest.write_str("+ "),
2558 Combinator::LaterSibling => dest.write_str("~ "),
2559 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => unsafe {
2560 debug_unreachable!("Already handled")
2561 },
2562 }
2563 }
2564
2565 fn to_css_relative<W>(self, dest: &mut W) -> fmt::Result
2566 where
2567 W: fmt::Write,
2568 {
2569 self.to_css_internal(dest, false)
2570 }
2571}
2572
2573impl ToCss for Combinator {
2574 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2575 where
2576 W: fmt::Write,
2577 {
2578 self.to_css_internal(dest, true)
2579 }
2580}
2581
2582impl<Impl: SelectorImpl> ToCss for Component<Impl> {
2583 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2584 where
2585 W: fmt::Write,
2586 {
2587 use self::Component::*;
2588
2589 match *self {
2590 Combinator(ref c) => c.to_css(dest),
2591 Slotted(ref selector) => {
2592 dest.write_str("::slotted(")?;
2593 selector.to_css(dest)?;
2594 dest.write_char(')')
2595 },
2596 Part(ref part_names) => {
2597 dest.write_str("::part(")?;
2598 for (i, name) in part_names.iter().enumerate() {
2599 if i != 0 {
2600 dest.write_char(' ')?;
2601 }
2602 name.to_css(dest)?;
2603 }
2604 dest.write_char(')')
2605 },
2606 PseudoElement(ref p) => p.to_css(dest),
2607 ID(ref s) => {
2608 dest.write_char('#')?;
2609 s.to_css(dest)
2610 },
2611 Class(ref s) => {
2612 dest.write_char('.')?;
2613 s.to_css(dest)
2614 },
2615 LocalName(ref s) => s.to_css(dest),
2616 ExplicitUniversalType => dest.write_char('*'),
2617
2618 DefaultNamespace(_) => Ok(()),
2619 ExplicitNoNamespace => dest.write_char('|'),
2620 ExplicitAnyNamespace => dest.write_str("*|"),
2621 Namespace(ref prefix, _) => {
2622 prefix.to_css(dest)?;
2623 dest.write_char('|')
2624 },
2625
2626 AttributeInNoNamespaceExists { ref local_name, .. } => {
2627 dest.write_char('[')?;
2628 local_name.to_css(dest)?;
2629 dest.write_char(']')
2630 },
2631 AttributeInNoNamespace {
2632 ref local_name,
2633 operator,
2634 ref value,
2635 case_sensitivity,
2636 ..
2637 } => {
2638 dest.write_char('[')?;
2639 local_name.to_css(dest)?;
2640 operator.to_css(dest)?;
2641 value.to_css(dest)?;
2642 match case_sensitivity {
2643 ParsedCaseSensitivity::CaseSensitive
2644 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2645 },
2646 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2647 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2648 }
2649 dest.write_char(']')
2650 },
2651 AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
2652
2653 Root => dest.write_str(":root"),
2655 Empty => dest.write_str(":empty"),
2656 Scope => dest.write_str(":scope"),
2657 ParentSelector => dest.write_char('&'),
2658 Host(ref selector) => {
2659 dest.write_str(":host")?;
2660 if let Some(ref selector) = *selector {
2661 dest.write_char('(')?;
2662 selector.to_css(dest)?;
2663 dest.write_char(')')?;
2664 }
2665 Ok(())
2666 },
2667 Nth(ref nth_data) => {
2668 nth_data.write_start(dest)?;
2669 if nth_data.is_function {
2670 nth_data.write_affine(dest)?;
2671 dest.write_char(')')?;
2672 }
2673 Ok(())
2674 },
2675 NthOf(ref nth_of_data) => {
2676 let nth_data = nth_of_data.nth_data();
2677 nth_data.write_start(dest)?;
2678 debug_assert!(
2679 nth_data.is_function,
2680 "A selector must be a function to hold An+B notation"
2681 );
2682 nth_data.write_affine(dest)?;
2683 debug_assert!(
2684 matches!(nth_data.ty, NthType::Child | NthType::LastChild),
2685 "Only :nth-child or :nth-last-child can be of a selector list"
2686 );
2687 debug_assert!(
2688 !nth_of_data.selectors().is_empty(),
2689 "The selector list should not be empty"
2690 );
2691 dest.write_str(" of ")?;
2692 serialize_selector_list(nth_of_data.selectors().iter(), dest)?;
2693 dest.write_char(')')
2694 },
2695 Is(ref list) | Where(ref list) | Negation(ref list) => {
2696 match *self {
2697 Where(..) => dest.write_str(":where(")?,
2698 Is(..) => dest.write_str(":is(")?,
2699 Negation(..) => dest.write_str(":not(")?,
2700 _ => unreachable!(),
2701 }
2702 serialize_selector_list(list.slice().iter(), dest)?;
2703 dest.write_str(")")
2704 },
2705 Has(ref list) => {
2706 dest.write_str(":has(")?;
2707 serialize_selector_list(list.iter().map(|rel| &rel.selector), dest)?;
2708 dest.write_str(")")
2709 },
2710 NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
2711 Invalid(ref css) => dest.write_str(css),
2712 RelativeSelectorAnchor | ImplicitScope => Ok(()),
2713 }
2714 }
2715}
2716
2717impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
2718 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2719 where
2720 W: fmt::Write,
2721 {
2722 dest.write_char('[')?;
2723 match self.namespace {
2724 Some(NamespaceConstraint::Specific((ref prefix, _))) => {
2725 prefix.to_css(dest)?;
2726 dest.write_char('|')?
2727 },
2728 Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
2729 None => {},
2730 }
2731 self.local_name.to_css(dest)?;
2732 match self.operation {
2733 ParsedAttrSelectorOperation::Exists => {},
2734 ParsedAttrSelectorOperation::WithValue {
2735 operator,
2736 case_sensitivity,
2737 ref value,
2738 } => {
2739 operator.to_css(dest)?;
2740 value.to_css(dest)?;
2741 match case_sensitivity {
2742 ParsedCaseSensitivity::CaseSensitive
2743 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2744 },
2745 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2746 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2747 }
2748 },
2749 }
2750 dest.write_char(']')
2751 }
2752}
2753
2754impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
2755 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2756 where
2757 W: fmt::Write,
2758 {
2759 self.name.to_css(dest)
2760 }
2761}
2762
2763fn parse_selector<'i, P, Impl>(
2768 parser: &P,
2769 input: &mut CssParser<'i>,
2770 mut state: SelectorParsingState,
2771 parse_relative: ParseRelative,
2772) -> Result<Selector<Impl>, ParseError<P::Error>>
2773where
2774 P: Parser<'i, Impl = Impl>,
2775 Impl: SelectorImpl,
2776{
2777 let mut builder = SelectorBuilder::default();
2778
2779 input.skip_whitespace();
2781
2782 if parse_relative != ParseRelative::No {
2783 let combinator = try_parse_combinator(input);
2784 match parse_relative {
2785 ParseRelative::ForHas => {
2786 builder.push_simple_selector(Component::RelativeSelectorAnchor);
2787 builder.push_combinator(combinator.unwrap_or(Combinator::Descendant));
2790 },
2791 ParseRelative::ForNesting | ParseRelative::ForScope => {
2792 if let Ok(combinator) = combinator {
2793 let selector = match parse_relative {
2794 ParseRelative::ForHas | ParseRelative::No => unreachable!(),
2795 ParseRelative::ForNesting => Component::ParentSelector,
2796 ParseRelative::ForScope => Component::ImplicitScope,
2800 };
2801 builder.push_simple_selector(selector);
2802 builder.push_combinator(combinator);
2803 }
2804 },
2805 ParseRelative::No => unreachable!(),
2806 }
2807 }
2808 loop {
2809 let empty = parse_compound_selector(parser, &mut state, input, &mut builder)?;
2811 if empty {
2812 return Err(ParseError::custom(if builder.has_combinators() {
2813 SelectorParseErrorKind::DanglingCombinator
2814 } else {
2815 SelectorParseErrorKind::EmptySelector
2816 }));
2817 }
2818
2819 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2820 debug_assert!(state.intersects(
2821 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO
2822 | SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO
2823 | SelectorParsingState::AFTER_SLOTTED
2824 | SelectorParsingState::AFTER_PART_LIKE
2825 ));
2826 break;
2827 }
2828
2829 let combinator = if let Ok(c) = try_parse_combinator(input) {
2830 c
2831 } else {
2832 break;
2833 };
2834
2835 if !state.allows_combinators() {
2836 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
2837 }
2838
2839 builder.push_combinator(combinator);
2840 }
2841 Ok(Selector(builder.build(parse_relative)))
2842}
2843
2844fn try_parse_combinator(input: &mut CssParser) -> Result<Combinator, ()> {
2845 let mut any_whitespace = false;
2846 loop {
2847 let before_this_token = input.state();
2848 match input.next_including_whitespace() {
2849 Err(_e) => return Err(()),
2850 Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
2851 Ok(&Token::Delim('>')) => {
2852 return Ok(Combinator::Child);
2853 },
2854 Ok(&Token::Delim('+')) => {
2855 return Ok(Combinator::NextSibling);
2856 },
2857 Ok(&Token::Delim('~')) => {
2858 return Ok(Combinator::LaterSibling);
2859 },
2860 Ok(_) => {
2861 input.reset(&before_this_token);
2862 if any_whitespace {
2863 return Ok(Combinator::Descendant);
2864 } else {
2865 return Err(());
2866 }
2867 },
2868 }
2869 }
2870}
2871
2872fn parse_type_selector<'i, P, Impl, S>(
2876 parser: &P,
2877 input: &mut CssParser<'i>,
2878 state: SelectorParsingState,
2879 sink: &mut S,
2880) -> Result<bool, ParseError<P::Error>>
2881where
2882 P: Parser<'i, Impl = Impl>,
2883 Impl: SelectorImpl,
2884 S: Push<Component<Impl>>,
2885{
2886 match parse_qualified_name(parser, input, false) {
2887 Err(ParseError {
2888 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
2889 ..
2890 })
2891 | Ok(None) => Ok(false),
2892 Ok(Some((namespace, local_name))) => {
2893 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2894 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
2895 }
2896 match namespace {
2897 QNamePrefix::ImplicitAnyNamespace => {},
2898 QNamePrefix::ImplicitDefaultNamespace(url) => {
2899 sink.push(Component::DefaultNamespace(url))
2900 },
2901 QNamePrefix::ExplicitNamespace(prefix, url) => {
2902 sink.push(match parser.default_namespace() {
2903 Some(ref default_url) if url == *default_url => {
2904 Component::DefaultNamespace(url)
2905 },
2906 _ => Component::Namespace(prefix, url),
2907 })
2908 },
2909 QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
2910 QNamePrefix::ExplicitAnyNamespace => {
2911 match parser.default_namespace() {
2912 None => {},
2924 Some(_) => sink.push(Component::ExplicitAnyNamespace),
2925 }
2926 },
2927 QNamePrefix::ImplicitNoNamespace => {
2928 unreachable!() },
2930 }
2931 match local_name {
2932 Some(name) => sink.push(Component::LocalName(LocalName {
2933 lower_name: to_ascii_lowercase(&name).as_ref().into(),
2934 name: name.as_ref().into(),
2935 })),
2936 None => sink.push(Component::ExplicitUniversalType),
2937 }
2938 Ok(true)
2939 },
2940 Err(e) => Err(e),
2941 }
2942}
2943
2944#[derive(Debug)]
2945enum SimpleSelectorParseResult<Impl: SelectorImpl> {
2946 SimpleSelector(Component<Impl>),
2947 PseudoElement(Impl::PseudoElement),
2948 SlottedPseudo(Selector<Impl>),
2949 PartPseudo(Box<[Impl::Identifier]>),
2950}
2951
2952#[derive(Debug)]
2953#[allow(clippy::enum_variant_names)]
2954enum QNamePrefix<Impl: SelectorImpl> {
2955 ImplicitNoNamespace, ImplicitAnyNamespace, ImplicitDefaultNamespace(Impl::NamespaceUrl), ExplicitNoNamespace, ExplicitAnyNamespace, ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), }
2962
2963type OptionalQName<'i, Impl> = Option<(QNamePrefix<Impl>, Option<CowRcStr<'i>>)>;
2964
2965fn parse_qualified_name<'i, P, Impl>(
2969 parser: &P,
2970 input: &mut CssParser<'i>,
2971 in_attr_selector: bool,
2972) -> Result<OptionalQName<'i, Impl>, ParseError<P::Error>>
2973where
2974 P: Parser<'i, Impl = Impl>,
2975 Impl: SelectorImpl,
2976{
2977 let default_namespace = |local_name| {
2978 let namespace = match parser.default_namespace() {
2979 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
2980 None => QNamePrefix::ImplicitAnyNamespace,
2981 };
2982 Ok(Some((namespace, local_name)))
2983 };
2984
2985 let explicit_namespace =
2986 |input: &mut CssParser<'i>, namespace| match input.next_including_whitespace() {
2987 Ok(&Token::Delim('*')) if !in_attr_selector => Ok(Some((namespace, None))),
2988 Ok(Token::Ident(local_name)) => Ok(Some((namespace, Some(local_name.clone())))),
2989 Ok(_) => {
2990 let e = if in_attr_selector {
2991 SelectorParseErrorKind::InvalidQualNameInAttr
2992 } else {
2993 SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken
2994 };
2995 Err(ParseError::custom(e))
2996 },
2997 Err(e) => Err(e.into()),
2998 };
2999
3000 let start = input.state();
3001 match input.next_including_whitespace() {
3002 Ok(Token::Ident(value)) => {
3003 let value = value.clone();
3004 let after_ident = input.state();
3005 match input.next_including_whitespace() {
3006 Ok(&Token::Delim('|')) => {
3007 let prefix = value.as_ref().into();
3008 let result = parser.namespace_for_prefix(&prefix);
3009 let url = result.ok_or(ParseError::custom(
3010 SelectorParseErrorKind::ExpectedNamespace,
3011 ))?;
3012 explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
3013 },
3014 _ => {
3015 input.reset(&after_ident);
3016 if in_attr_selector {
3017 Ok(Some((QNamePrefix::ImplicitNoNamespace, Some(value))))
3018 } else {
3019 default_namespace(Some(value))
3020 }
3021 },
3022 }
3023 },
3024 Ok(Token::Delim('*')) => {
3025 let after_star = input.state();
3026 match input.next_including_whitespace() {
3027 Ok(&Token::Delim('|')) => {
3028 explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
3029 },
3030 _ if !in_attr_selector => {
3031 input.reset(&after_star);
3032 default_namespace(None)
3033 },
3034 result => {
3035 result?;
3036 Err(ParseError::custom(
3037 SelectorParseErrorKind::ExpectedBarInAttr,
3038 ))
3039 },
3040 }
3041 },
3042 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
3043 Ok(_) => {
3044 input.reset(&start);
3045 Ok(None)
3046 },
3047 Err(e) => {
3048 input.reset(&start);
3049 Err(e.into())
3050 },
3051 }
3052}
3053
3054fn parse_attribute_selector<'i, P, Impl>(
3055 parser: &P,
3056 input: &mut CssParser<'i>,
3057) -> Result<Component<Impl>, ParseError<P::Error>>
3058where
3059 P: Parser<'i, Impl = Impl>,
3060 Impl: SelectorImpl,
3061{
3062 let namespace;
3063 let local_name;
3064
3065 input.skip_whitespace();
3066
3067 match parse_qualified_name(parser, input, true)? {
3068 None => {
3069 return Err(ParseError::custom(
3070 SelectorParseErrorKind::NoQualifiedNameInAttributeSelector,
3071 ));
3072 },
3073 Some((_, None)) => unreachable!(),
3074 Some((ns, Some(ln))) => {
3075 local_name = ln;
3076 namespace = match ns {
3077 QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
3078 QNamePrefix::ExplicitNamespace(prefix, url) => {
3079 Some(NamespaceConstraint::Specific((prefix, url)))
3080 },
3081 QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
3082 QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
3083 unreachable!() },
3085 }
3086 },
3087 }
3088
3089 let operator = match input.next() {
3090 Err(_) => {
3092 let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
3093 let local_name = local_name.as_ref().into();
3094 if let Some(namespace) = namespace {
3095 return Ok(Component::AttributeOther(Box::new(
3096 AttrSelectorWithOptionalNamespace {
3097 namespace: Some(namespace),
3098 local_name,
3099 local_name_lower,
3100 operation: ParsedAttrSelectorOperation::Exists,
3101 },
3102 )));
3103 } else {
3104 return Ok(Component::AttributeInNoNamespaceExists {
3105 local_name,
3106 local_name_lower,
3107 });
3108 }
3109 },
3110
3111 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
3113 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
3115 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
3117 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
3119 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
3121 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
3123 Ok(_) => {
3124 return Err(ParseError::custom(
3125 SelectorParseErrorKind::UnexpectedTokenInAttributeSelector,
3126 ));
3127 },
3128 };
3129
3130 let value = match input.expect_ident_or_string() {
3131 Ok(t) => t.clone(),
3132 Err(BasicParseError {
3133 kind: BasicParseErrorKind::UnexpectedToken,
3134 }) => return Err(ParseError::custom(SelectorParseErrorKind::BadValueInAttr)),
3135 Err(e) => return Err(e.into()),
3136 };
3137
3138 let attribute_flags = parse_attribute_flags(input)?;
3139 let value = value.as_ref().into();
3140 let local_name_lower: Impl::LocalName;
3141 let local_name_is_ascii_lowercase;
3142 let case_sensitivity;
3143 {
3144 let local_name_lower_cow = to_ascii_lowercase(&local_name);
3145 case_sensitivity =
3146 attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
3147 local_name_lower = local_name_lower_cow.as_ref().into();
3148 local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
3149 }
3150 if namespace.is_some() || !local_name_is_ascii_lowercase {
3151 let local_name = if local_name_is_ascii_lowercase {
3152 local_name_lower.clone()
3153 } else {
3154 local_name.as_ref().into()
3155 };
3156 Ok(Component::AttributeOther(Box::new(
3157 AttrSelectorWithOptionalNamespace {
3158 namespace,
3159 local_name,
3160 local_name_lower,
3161 operation: ParsedAttrSelectorOperation::WithValue {
3162 operator,
3163 case_sensitivity,
3164 value,
3165 },
3166 },
3167 )))
3168 } else {
3169 Ok(Component::AttributeInNoNamespace {
3170 local_name: local_name_lower,
3171 operator,
3172 value,
3173 case_sensitivity,
3174 })
3175 }
3176}
3177
3178#[derive(Copy, Clone)]
3180enum AttributeFlags {
3181 CaseSensitive,
3183 AsciiCaseInsensitive,
3185 CaseSensitivityDependsOnName,
3187}
3188
3189fn is_ascii_case_insensitive_html_attribute(name: &str) -> bool {
3200 matches!(
3201 name,
3202 "accept"
3203 | "accept-charset"
3204 | "align"
3205 | "alink"
3206 | "axis"
3207 | "bgcolor"
3208 | "charset"
3209 | "checked"
3210 | "clear"
3211 | "codetype"
3212 | "color"
3213 | "compact"
3214 | "declare"
3215 | "defer"
3216 | "dir"
3217 | "direction"
3218 | "disabled"
3219 | "enctype"
3220 | "face"
3221 | "frame"
3222 | "hreflang"
3223 | "http-equiv"
3224 | "lang"
3225 | "language"
3226 | "link"
3227 | "media"
3228 | "method"
3229 | "multiple"
3230 | "nohref"
3231 | "noresize"
3232 | "noshade"
3233 | "nowrap"
3234 | "readonly"
3235 | "rel"
3236 | "rev"
3237 | "rules"
3238 | "scope"
3239 | "scrolling"
3240 | "selected"
3241 | "shape"
3242 | "target"
3243 | "text"
3244 | "type"
3245 | "valign"
3246 | "valuetype"
3247 | "vlink"
3248 )
3249}
3250
3251impl AttributeFlags {
3252 fn to_case_sensitivity(
3253 self,
3254 local_name_lower: &str,
3255 have_namespace: bool,
3256 ) -> ParsedCaseSensitivity {
3257 match self {
3258 AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
3259 AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
3260 AttributeFlags::CaseSensitivityDependsOnName => {
3261 if !have_namespace && is_ascii_case_insensitive_html_attribute(local_name_lower) {
3262 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
3263 } else {
3264 ParsedCaseSensitivity::CaseSensitive
3265 }
3266 },
3267 }
3268 }
3269}
3270
3271fn parse_attribute_flags(input: &mut CssParser) -> Result<AttributeFlags, BasicParseError> {
3272 let token = match input.next() {
3273 Ok(t) => t,
3274 Err(..) => {
3275 return Ok(AttributeFlags::CaseSensitivityDependsOnName);
3278 },
3279 };
3280
3281 let ident = match *token {
3282 Token::Ident(ref i) => i,
3283 _ => return Err(BasicParseError::unexpected_token()),
3284 };
3285
3286 Ok(match_ignore_ascii_case! {
3287 ident,
3288 "i" => AttributeFlags::AsciiCaseInsensitive,
3289 "s" => AttributeFlags::CaseSensitive,
3290 _ => return Err(BasicParseError::unexpected_token()),
3291 })
3292}
3293
3294fn parse_negation<'i, P, Impl>(
3297 parser: &P,
3298 input: &mut CssParser<'i>,
3299 state: SelectorParsingState,
3300) -> Result<Component<Impl>, ParseError<P::Error>>
3301where
3302 P: Parser<'i, Impl = Impl>,
3303 Impl: SelectorImpl,
3304{
3305 let list = SelectorList::parse_with_state(
3306 parser,
3307 input,
3308 state
3309 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3310 | SelectorParsingState::DISALLOW_PSEUDOS,
3311 ForgivingParsing::No,
3312 ParseRelative::No,
3313 )?;
3314
3315 Ok(Component::Negation(list))
3316}
3317
3318fn parse_compound_selector<'i, P, Impl>(
3325 parser: &P,
3326 state: &mut SelectorParsingState,
3327 input: &mut CssParser<'i>,
3328 builder: &mut SelectorBuilder<Impl>,
3329) -> Result<bool, ParseError<P::Error>>
3330where
3331 P: Parser<'i, Impl = Impl>,
3332 Impl: SelectorImpl,
3333{
3334 input.skip_whitespace();
3335
3336 let mut empty = true;
3337 if parse_type_selector(parser, input, *state, builder)? {
3338 empty = false;
3339 }
3340
3341 loop {
3342 let result = match parse_one_simple_selector(parser, input, *state)? {
3343 None => break,
3344 Some(result) => result,
3345 };
3346
3347 if empty && let Some(url) = parser.default_namespace() {
3348 let ignore_default_ns = state.intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE)
3376 || matches!(
3377 result,
3378 SimpleSelectorParseResult::SimpleSelector(Component::Host(..))
3379 );
3380 if !ignore_default_ns {
3381 builder.push_simple_selector(Component::DefaultNamespace(url));
3382 }
3383 }
3384
3385 empty = false;
3386
3387 match result {
3388 SimpleSelectorParseResult::SimpleSelector(s) => {
3389 builder.push_simple_selector(s);
3390 },
3391 SimpleSelectorParseResult::PartPseudo(part_names) => {
3392 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3393 builder.push_combinator(Combinator::Part);
3394 builder.push_simple_selector(Component::Part(part_names));
3395 },
3396 SimpleSelectorParseResult::SlottedPseudo(selector) => {
3397 state.insert(SelectorParsingState::AFTER_SLOTTED);
3398 builder.push_combinator(Combinator::SlotAssignment);
3399 builder.push_simple_selector(Component::Slotted(selector));
3400 },
3401 SimpleSelectorParseResult::PseudoElement(p) => {
3402 if p.parses_as_element_backed() {
3403 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3404 } else {
3405 state.insert(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO);
3406 if p.is_before_or_after() {
3407 state.insert(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO);
3408 }
3409 }
3410 if !p.accepts_state_pseudo_classes() {
3411 state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
3412 }
3413 if p.is_in_pseudo_element_tree() {
3414 state.insert(SelectorParsingState::IN_PSEUDO_ELEMENT_TREE);
3415 }
3416 builder.push_combinator(Combinator::PseudoElement);
3417 builder.push_simple_selector(Component::PseudoElement(p));
3418 },
3419 }
3420 }
3421 Ok(empty)
3422}
3423
3424fn parse_is_where<'i, P, Impl>(
3425 parser: &P,
3426 input: &mut CssParser<'i>,
3427 state: SelectorParsingState,
3428 component: impl FnOnce(SelectorList<Impl>) -> Component<Impl>,
3429) -> Result<Component<Impl>, ParseError<P::Error>>
3430where
3431 P: Parser<'i, Impl = Impl>,
3432 Impl: SelectorImpl,
3433{
3434 debug_assert!(parser.parse_is_and_where());
3435 let inner = SelectorList::parse_with_state(
3441 parser,
3442 input,
3443 state
3444 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3445 | SelectorParsingState::DISALLOW_PSEUDOS,
3446 ForgivingParsing::Yes,
3447 ParseRelative::No,
3448 )?;
3449 Ok(component(inner))
3450}
3451
3452fn parse_has<'i, P, Impl>(
3453 parser: &P,
3454 input: &mut CssParser<'i>,
3455 state: SelectorParsingState,
3456) -> Result<Component<Impl>, ParseError<P::Error>>
3457where
3458 P: Parser<'i, Impl = Impl>,
3459 Impl: SelectorImpl,
3460{
3461 debug_assert!(parser.parse_has());
3462 if state.intersects(
3463 SelectorParsingState::DISALLOW_RELATIVE_SELECTOR | SelectorParsingState::AFTER_PSEUDO,
3464 ) {
3465 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3466 }
3467 let inner = SelectorList::parse_with_state(
3472 parser,
3473 input,
3474 state
3475 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3476 | SelectorParsingState::DISALLOW_PSEUDOS
3477 | SelectorParsingState::DISALLOW_RELATIVE_SELECTOR,
3478 ForgivingParsing::No,
3479 ParseRelative::ForHas,
3480 )?;
3481 Ok(Component::Has(RelativeSelector::from_selector_list(inner)))
3482}
3483
3484fn parse_functional_pseudo_class<'i, P, Impl>(
3485 parser: &P,
3486 input: &mut CssParser<'i>,
3487 name: &str,
3488 state: SelectorParsingState,
3489) -> Result<Component<Impl>, ParseError<P::Error>>
3490where
3491 P: Parser<'i, Impl = Impl>,
3492 Impl: SelectorImpl,
3493{
3494 match_ignore_ascii_case! { name,
3495 "nth-child" => return parse_nth_pseudo_class(parser, input, state, NthType::Child),
3496 "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::OfType),
3497 "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, NthType::LastChild),
3498 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::LastOfType),
3499 "is" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Is),
3500 "where" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Where),
3501 "has" if parser.parse_has() => return parse_has(parser, input, state),
3502 "host" => {
3503 if !state.allows_tree_structural_pseudo_classes() {
3504 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3505 }
3506 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
3507 },
3508 "not" => {
3509 return parse_negation(parser, input, state)
3510 },
3511 _ => {}
3512 }
3513
3514 if parser.parse_is_and_where() && parser.is_is_alias(name) {
3515 return parse_is_where(parser, input, state, Component::Is);
3516 }
3517
3518 if state.intersects(
3519 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO | SelectorParsingState::AFTER_SLOTTED,
3520 ) {
3521 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3522 }
3523
3524 let after_part = state.intersects(SelectorParsingState::AFTER_PART_LIKE);
3525 P::parse_non_ts_functional_pseudo_class(parser, name, input, after_part)
3526 .map(Component::NonTSPseudoClass)
3527}
3528
3529fn parse_nth_pseudo_class<'i, P, Impl>(
3530 parser: &P,
3531 input: &mut CssParser<'i>,
3532 state: SelectorParsingState,
3533 ty: NthType,
3534) -> Result<Component<Impl>, ParseError<P::Error>>
3535where
3536 P: Parser<'i, Impl = Impl>,
3537 Impl: SelectorImpl,
3538{
3539 if !state.allows_tree_structural_pseudo_classes() {
3540 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3541 }
3542 let (a, b) = parse_nth(input)?;
3543 let nth_data = NthSelectorData {
3544 ty,
3545 is_function: true,
3546 an_plus_b: AnPlusB(a, b),
3547 };
3548 if !parser.parse_nth_child_of() || ty.is_of_type() {
3549 return Ok(Component::Nth(nth_data));
3550 }
3551
3552 if input.try_parse(|i| i.expect_ident_matching("of")).is_err() {
3554 return Ok(Component::Nth(nth_data));
3555 }
3556 let selectors = SelectorList::parse_with_state(
3559 parser,
3560 input,
3561 state
3562 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3563 | SelectorParsingState::DISALLOW_PSEUDOS,
3564 ForgivingParsing::No,
3565 ParseRelative::No,
3566 )?;
3567 Ok(Component::NthOf(NthOfSelectorData::new(
3568 &nth_data,
3569 selectors.slice().iter().cloned(),
3570 )))
3571}
3572
3573pub fn is_css2_pseudo_element(name: &str) -> bool {
3577 match_ignore_ascii_case! { name,
3579 "before" | "after" | "first-line" | "first-letter" => true,
3580 _ => false,
3581 }
3582}
3583
3584fn parse_one_simple_selector<'i, P, Impl>(
3590 parser: &P,
3591 input: &mut CssParser<'i>,
3592 state: SelectorParsingState,
3593) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<P::Error>>
3594where
3595 P: Parser<'i, Impl = Impl>,
3596 Impl: SelectorImpl,
3597{
3598 let start = input.state();
3599 let token = match input.next_including_whitespace() {
3600 Ok(t) => t,
3601 Err(..) => {
3602 input.reset(&start);
3603 return Ok(None);
3604 },
3605 };
3606
3607 Ok(Some(match token {
3608 Token::IDHash(id) => {
3609 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3610 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3611 }
3612 let id = Component::ID(id.as_ref().into());
3613 SimpleSelectorParseResult::SimpleSelector(id)
3614 },
3615 Token::Delim(delim)
3616 if *delim == '.' || (*delim == '&' && parser.parse_parent_selector()) =>
3617 {
3618 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3619 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3620 }
3621 SimpleSelectorParseResult::SimpleSelector(if *delim == '&' {
3622 Component::ParentSelector
3623 } else {
3624 let class = match *input.next_including_whitespace()? {
3625 Token::Ident(ref class) => class,
3626 _ => {
3627 let e = SelectorParseErrorKind::ClassNeedsIdent;
3628 return Err(ParseError::custom(e));
3629 },
3630 };
3631 Component::Class(class.as_ref().into())
3632 })
3633 },
3634 Token::SquareBracketBlock => {
3635 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3636 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3637 }
3638 let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
3639 SimpleSelectorParseResult::SimpleSelector(attr)
3640 },
3641 Token::Colon => {
3642 let (is_single_colon, next_token) = match input.next_including_whitespace()? {
3643 Token::Colon => (false, input.next_including_whitespace()?),
3644 t => (true, t),
3645 };
3646 let (name, is_functional) = match next_token {
3647 Token::Ident(name) => (name, false),
3648 Token::Function(name) => (name, true),
3649 _ => {
3650 let e = SelectorParseErrorKind::PseudoElementExpectedIdent;
3651 return Err(ParseError::custom(e));
3652 },
3653 };
3654 let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(name);
3655 if is_pseudo_element {
3656 if state.intersects(SelectorParsingState::DISALLOW_PSEUDOS)
3662 || (state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3663 && !state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO))
3664 {
3665 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3666 }
3667 let pseudo_element = if is_functional {
3668 if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
3669 if !state.allows_part() {
3670 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3671 }
3672 let names = input.parse_nested_block(|input| {
3673 let mut result = Vec::with_capacity(1);
3674 result.push(input.expect_ident()?.as_ref().into());
3675 while !input.is_exhausted() {
3676 result.push(input.expect_ident()?.as_ref().into());
3677 }
3678 Ok(result.into_boxed_slice())
3679 })?;
3680 return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
3681 }
3682 if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
3683 if !state.allows_slotted() {
3684 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3685 }
3686 let selector = input.parse_nested_block(|input| {
3687 parse_inner_compound_selector(parser, input, state)
3688 })?;
3689 return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
3690 }
3691 let name = name.clone();
3692 input.parse_nested_block(|input| {
3693 P::parse_functional_pseudo_element(parser, name.as_ref(), input)
3694 })?
3695 } else {
3696 P::parse_pseudo_element(parser, name.as_ref())?
3697 };
3698
3699 if state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO)
3700 && !pseudo_element.valid_after_before_or_after()
3701 {
3702 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3703 }
3704
3705 if state.intersects(SelectorParsingState::AFTER_SLOTTED)
3706 && !pseudo_element.valid_after_slotted()
3707 {
3708 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3709 }
3710 SimpleSelectorParseResult::PseudoElement(pseudo_element)
3711 } else {
3712 let pseudo_class = if is_functional {
3713 let name = name.clone();
3714 input.parse_nested_block(|input| {
3715 parse_functional_pseudo_class(parser, input, name.as_ref(), state)
3716 })?
3717 } else {
3718 parse_simple_pseudo_class(parser, name, state)?
3719 };
3720 SimpleSelectorParseResult::SimpleSelector(pseudo_class)
3721 }
3722 },
3723 _ => {
3724 input.reset(&start);
3725 return Ok(None);
3726 },
3727 }))
3728}
3729
3730fn parse_simple_pseudo_class<'i, P, Impl>(
3731 parser: &P,
3732 name: &str,
3733 state: SelectorParsingState,
3734) -> Result<Component<Impl>, ParseError<P::Error>>
3735where
3736 P: Parser<'i, Impl = Impl>,
3737 Impl: SelectorImpl,
3738{
3739 if !state.allows_non_functional_pseudo_classes() {
3740 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3741 }
3742
3743 if state.allows_tree_structural_pseudo_classes() {
3744 if state.allows_only_child_pseudo_class_only() {
3749 if name.eq_ignore_ascii_case("only-child") {
3750 return Ok(Component::Nth(NthSelectorData::only(
3751 false,
3752 )));
3753 }
3754 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3758 }
3759
3760 match_ignore_ascii_case! { &name,
3761 "first-child" => return Ok(Component::Nth(NthSelectorData::first(false))),
3762 "last-child" => return Ok(Component::Nth(NthSelectorData::last(false))),
3763 "only-child" => return Ok(Component::Nth(NthSelectorData::only(false))),
3764 "root" => return Ok(Component::Root),
3765 "empty" => return Ok(Component::Empty),
3766 "scope" => return Ok(Component::Scope),
3767 "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
3768 "first-of-type" => return Ok(Component::Nth(NthSelectorData::first(true))),
3769 "last-of-type" => return Ok(Component::Nth(NthSelectorData::last(true))),
3770 "only-of-type" => return Ok(Component::Nth(NthSelectorData::only(true))),
3771 _ => {},
3772 }
3773 }
3774
3775 let pseudo_class = P::parse_non_ts_pseudo_class(parser, name)?;
3776 if state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3777 && !pseudo_class.is_user_action_state()
3778 {
3779 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3780 }
3781 Ok(Component::NonTSPseudoClass(pseudo_class))
3782}
3783
3784#[cfg(test)]
3786pub mod tests {
3787 use super::*;
3788 use crate::builder::SelectorFlags;
3789 use crate::parser;
3790 use cssparser::{Parser as CssParser, ToCss, serialize_identifier};
3791 use std::collections::HashMap;
3792 use std::fmt;
3793
3794 #[derive(Clone, Debug, Eq, PartialEq)]
3795 pub enum PseudoClass {
3796 Hover,
3797 Active,
3798 Lang(String),
3799 }
3800
3801 #[derive(Clone, Debug, Eq, PartialEq)]
3802 pub enum PseudoElement {
3803 Before,
3804 After,
3805 Marker,
3806 DetailsContent,
3807 Highlight(String),
3808 }
3809
3810 impl parser::PseudoElement for PseudoElement {
3811 fn accepts_state_pseudo_classes(&self) -> bool {
3812 true
3813 }
3814
3815 fn valid_after_slotted(&self) -> bool {
3816 true
3817 }
3818
3819 fn valid_after_before_or_after(&self) -> bool {
3820 matches!(self, Self::Marker)
3821 }
3822
3823 fn is_before_or_after(&self) -> bool {
3824 matches!(self, Self::Before | Self::After)
3825 }
3826
3827 fn parses_as_element_backed(&self) -> bool {
3828 matches!(self, Self::DetailsContent)
3829 }
3830 }
3831
3832 impl parser::NonTSPseudoClass for PseudoClass {
3833 #[inline]
3834 fn is_active_or_hover(&self) -> bool {
3835 matches!(*self, PseudoClass::Active | PseudoClass::Hover)
3836 }
3837
3838 #[inline]
3839 fn is_user_action_state(&self) -> bool {
3840 self.is_active_or_hover()
3841 }
3842 }
3843
3844 impl ToCss for PseudoClass {
3845 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3846 where
3847 W: fmt::Write,
3848 {
3849 match *self {
3850 PseudoClass::Hover => dest.write_str(":hover"),
3851 PseudoClass::Active => dest.write_str(":active"),
3852 PseudoClass::Lang(ref lang) => {
3853 dest.write_str(":lang(")?;
3854 serialize_identifier(lang, dest)?;
3855 dest.write_char(')')
3856 },
3857 }
3858 }
3859 }
3860
3861 impl ToCss for PseudoElement {
3862 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3863 where
3864 W: fmt::Write,
3865 {
3866 match *self {
3867 PseudoElement::Before => dest.write_str("::before"),
3868 PseudoElement::After => dest.write_str("::after"),
3869 PseudoElement::Marker => dest.write_str("::marker"),
3870 PseudoElement::DetailsContent => dest.write_str("::details-content"),
3871 PseudoElement::Highlight(ref name) => {
3872 dest.write_str("::highlight(")?;
3873 serialize_identifier(&name, dest)?;
3874 dest.write_char(')')
3875 },
3876 }
3877 }
3878 }
3879
3880 #[derive(Clone, Debug, PartialEq)]
3881 pub struct DummySelectorImpl;
3882
3883 #[derive(Default)]
3884 pub struct DummyParser {
3885 default_ns: Option<DummyAtom>,
3886 ns_prefixes: HashMap<DummyAtom, DummyAtom>,
3887 }
3888
3889 impl DummyParser {
3890 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
3891 DummyParser {
3892 default_ns: Some(default_ns),
3893 ns_prefixes: Default::default(),
3894 }
3895 }
3896 }
3897
3898 impl SelectorImpl for DummySelectorImpl {
3899 type ExtraMatchingData<'a> = std::marker::PhantomData<&'a ()>;
3900 type AttrValue = DummyAttrValue;
3901 type Identifier = DummyAtom;
3902 type LocalName = DummyAtom;
3903 type NamespaceUrl = DummyAtom;
3904 type NamespacePrefix = DummyAtom;
3905 type BorrowedLocalName = DummyAtom;
3906 type BorrowedNamespaceUrl = DummyAtom;
3907 type NonTSPseudoClass = PseudoClass;
3908 type PseudoElement = PseudoElement;
3909 }
3910
3911 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3912 pub struct DummyAttrValue(String);
3913
3914 impl ToCss for DummyAttrValue {
3915 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3916 where
3917 W: fmt::Write,
3918 {
3919 use std::fmt::Write;
3920
3921 dest.write_char('"')?;
3922 write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)?;
3923 dest.write_char('"')
3924 }
3925 }
3926
3927 impl<'a> From<&'a str> for DummyAttrValue {
3928 fn from(string: &'a str) -> Self {
3929 Self(string.into())
3930 }
3931 }
3932
3933 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3934 pub struct DummyAtom(String);
3935
3936 impl ToCss for DummyAtom {
3937 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3938 where
3939 W: fmt::Write,
3940 {
3941 serialize_identifier(&self.0, dest)
3942 }
3943 }
3944
3945 impl From<String> for DummyAtom {
3946 fn from(string: String) -> Self {
3947 DummyAtom(string)
3948 }
3949 }
3950
3951 impl<'a> From<&'a str> for DummyAtom {
3952 fn from(string: &'a str) -> Self {
3953 DummyAtom(string.into())
3954 }
3955 }
3956
3957 impl PrecomputedHash for DummyAtom {
3958 fn precomputed_hash(&self) -> u32 {
3959 self.0.as_ptr() as u32
3960 }
3961 }
3962
3963 impl<'i> Parser<'i> for DummyParser {
3964 type Impl = DummySelectorImpl;
3965 type Error = SelectorParseErrorKind;
3966
3967 fn parse_slotted(&self) -> bool {
3968 true
3969 }
3970
3971 fn parse_nth_child_of(&self) -> bool {
3972 true
3973 }
3974
3975 fn parse_is_and_where(&self) -> bool {
3976 true
3977 }
3978
3979 fn parse_has(&self) -> bool {
3980 true
3981 }
3982
3983 fn parse_parent_selector(&self) -> bool {
3984 true
3985 }
3986
3987 fn parse_part(&self) -> bool {
3988 true
3989 }
3990
3991 fn parse_host(&self) -> bool {
3992 true
3993 }
3994
3995 fn parse_non_ts_pseudo_class(&self, name: &str) -> Result<PseudoClass, SelectorParseError> {
3996 match_ignore_ascii_case! { &name,
3997 "hover" => return Ok(PseudoClass::Hover),
3998 "active" => return Ok(PseudoClass::Active),
3999 _ => {}
4000 }
4001 Err(ParseError::custom(
4002 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
4003 ))
4004 }
4005
4006 fn parse_non_ts_functional_pseudo_class(
4007 &self,
4008 name: &str,
4009 parser: &mut CssParser<'i>,
4010 after_part: bool,
4011 ) -> Result<PseudoClass, SelectorParseError> {
4012 match_ignore_ascii_case! { &name,
4013 "lang" if !after_part => {
4014 let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
4015 return Ok(PseudoClass::Lang(lang));
4016 },
4017 _ => {}
4018 }
4019 Err(ParseError::custom(
4020 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
4021 ))
4022 }
4023
4024 fn parse_pseudo_element(&self, name: &str) -> Result<PseudoElement, SelectorParseError> {
4025 match_ignore_ascii_case! { &name,
4026 "before" => return Ok(PseudoElement::Before),
4027 "after" => return Ok(PseudoElement::After),
4028 "marker" => return Ok(PseudoElement::Marker),
4029 "details-content" => return Ok(PseudoElement::DetailsContent),
4030 _ => {}
4031 }
4032 Err(ParseError::custom(
4033 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
4034 ))
4035 }
4036
4037 fn parse_functional_pseudo_element(
4038 &self,
4039 name: &str,
4040 parser: &mut CssParser<'i>,
4041 ) -> Result<PseudoElement, SelectorParseError> {
4042 match_ignore_ascii_case! { &name,
4043 "highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())),
4044 _ => {}
4045 }
4046 Err(ParseError::custom(
4047 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
4048 ))
4049 }
4050
4051 fn default_namespace(&self) -> Option<DummyAtom> {
4052 self.default_ns.clone()
4053 }
4054
4055 fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
4056 self.ns_prefixes.get(prefix).cloned()
4057 }
4058 }
4059
4060 fn parse<'i>(input: &'i str) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4061 parse_relative(input, ParseRelative::No)
4062 }
4063
4064 fn parse_relative<'i>(
4065 input: &'i str,
4066 parse_relative: ParseRelative,
4067 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4068 parse_ns_relative(input, &DummyParser::default(), parse_relative)
4069 }
4070
4071 fn parse_expected<'i, 'a>(
4072 input: &'i str,
4073 expected: Option<&'a str>,
4074 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4075 parse_ns_expected(input, &DummyParser::default(), expected)
4076 }
4077
4078 fn parse_relative_expected<'i, 'a>(
4079 input: &'i str,
4080 parse_relative: ParseRelative,
4081 expected: Option<&'a str>,
4082 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4083 parse_ns_relative_expected(input, &DummyParser::default(), parse_relative, expected)
4084 }
4085
4086 fn parse_ns<'i>(
4087 input: &'i str,
4088 parser: &DummyParser,
4089 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4090 parse_ns_relative(input, parser, ParseRelative::No)
4091 }
4092
4093 fn parse_ns_relative<'i>(
4094 input: &'i str,
4095 parser: &DummyParser,
4096 parse_relative: ParseRelative,
4097 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4098 parse_ns_relative_expected(input, parser, parse_relative, None)
4099 }
4100
4101 fn parse_ns_expected<'i, 'a>(
4102 input: &'i str,
4103 parser: &DummyParser,
4104 expected: Option<&'a str>,
4105 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4106 parse_ns_relative_expected(input, parser, ParseRelative::No, expected)
4107 }
4108
4109 fn parse_ns_relative_expected<'i, 'a>(
4110 input: &'i str,
4111 parser: &DummyParser,
4112 parse_relative: ParseRelative,
4113 expected: Option<&'a str>,
4114 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4115 let result = SelectorList::parse(parser, &mut CssParser::new(input), parse_relative);
4116 if let Ok(ref selectors) = result {
4117 assert_eq!(
4121 selectors.to_css_string(),
4122 match expected {
4123 Some(x) => x,
4124 None => input,
4125 }
4126 );
4127 }
4128 result
4129 }
4130
4131 fn specificity(a: u32, b: u32, c: u32) -> u32 {
4132 a << 20 | b << 10 | c
4133 }
4134
4135 #[test]
4136 fn test_ancestor_hashes_in_subject_position() {
4137 fn ancestor_hash_count(selector: &str) -> usize {
4138 let list = parse(selector).unwrap();
4139 assert_eq!(list.slice().len(), 1);
4140 let mut hashes = [0u32; 4];
4141 let mut len = 0;
4142 collect_ancestor_hashes(
4143 list.slice()[0].iter(),
4144 QuirksMode::NoQuirks,
4145 &mut hashes,
4146 &mut len,
4147 );
4148 len
4149 }
4150
4151 assert_eq!(ancestor_hash_count(".subject"), 0);
4153 assert_eq!(ancestor_hash_count(":where(.subject)"), 0);
4154
4155 assert_eq!(ancestor_hash_count(":where(.ancestor > .subject)"), 1);
4158 assert_eq!(ancestor_hash_count(":is(.ancestor .subject)"), 1);
4159 assert_eq!(
4160 ancestor_hash_count(":where(.ancestor > :not(:last-child))"),
4161 1
4162 );
4163
4164 assert_eq!(
4167 ancestor_hash_count(".real-ancestor :where(.inner-ancestor > .subject)"),
4168 2
4169 );
4170
4171 assert_eq!(ancestor_hash_count(":is(.a, .b) .subject"), 0);
4175 assert_eq!(
4176 ancestor_hash_count(":where(.ancestor > .subject, .other)"),
4177 0
4178 );
4179 assert_eq!(ancestor_hash_count(".real-ancestor :where(.a > .b, .c)"), 1);
4182
4183 assert_eq!(ancestor_hash_count(".subject::before"), 0);
4187 assert_eq!(ancestor_hash_count(".real-ancestor .subject::before"), 1);
4188 assert_eq!(
4191 ancestor_hash_count(":where(.ancestor > .subject)::before"),
4192 1
4193 );
4194 }
4195
4196 #[test]
4197 fn test_empty() {
4198 let list = SelectorList::parse(
4199 &DummyParser::default(),
4200 &mut CssParser::new(":empty"),
4201 ParseRelative::No,
4202 );
4203 assert!(list.is_ok());
4204 }
4205
4206 const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
4207 const SVG: &str = "http://www.w3.org/2000/svg";
4208
4209 #[test]
4210 fn test_parsing() {
4211 assert!(parse("").is_err());
4212 assert!(parse(":lang(4)").is_err());
4213 assert!(parse(":lang(en US)").is_err());
4214 assert_eq!(
4215 parse("EeÉ"),
4216 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4217 vec![Component::LocalName(LocalName {
4218 name: DummyAtom::from("EeÉ"),
4219 lower_name: DummyAtom::from("eeÉ"),
4220 })],
4221 specificity(0, 0, 1),
4222 SelectorFlags::empty(),
4223 )]))
4224 );
4225 assert_eq!(
4226 parse("|e"),
4227 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4228 vec![
4229 Component::ExplicitNoNamespace,
4230 Component::LocalName(LocalName {
4231 name: DummyAtom::from("e"),
4232 lower_name: DummyAtom::from("e"),
4233 }),
4234 ],
4235 specificity(0, 0, 1),
4236 SelectorFlags::empty(),
4237 )]))
4238 );
4239 assert_eq!(
4242 parse_expected("*|e", Some("e")),
4243 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4244 vec![Component::LocalName(LocalName {
4245 name: DummyAtom::from("e"),
4246 lower_name: DummyAtom::from("e"),
4247 })],
4248 specificity(0, 0, 1),
4249 SelectorFlags::empty(),
4250 )]))
4251 );
4252 assert_eq!(
4257 parse_ns(
4258 "*|e",
4259 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4260 ),
4261 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4262 vec![
4263 Component::ExplicitAnyNamespace,
4264 Component::LocalName(LocalName {
4265 name: DummyAtom::from("e"),
4266 lower_name: DummyAtom::from("e"),
4267 }),
4268 ],
4269 specificity(0, 0, 1),
4270 SelectorFlags::empty(),
4271 )]))
4272 );
4273 assert_eq!(
4274 parse("*"),
4275 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4276 vec![Component::ExplicitUniversalType],
4277 specificity(0, 0, 0),
4278 SelectorFlags::empty(),
4279 )]))
4280 );
4281 assert_eq!(
4282 parse("|*"),
4283 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4284 vec![
4285 Component::ExplicitNoNamespace,
4286 Component::ExplicitUniversalType,
4287 ],
4288 specificity(0, 0, 0),
4289 SelectorFlags::empty(),
4290 )]))
4291 );
4292 assert_eq!(
4293 parse_expected("*|*", Some("*")),
4294 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4295 vec![Component::ExplicitUniversalType],
4296 specificity(0, 0, 0),
4297 SelectorFlags::empty(),
4298 )]))
4299 );
4300 assert_eq!(
4301 parse_ns(
4302 "*|*",
4303 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4304 ),
4305 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4306 vec![
4307 Component::ExplicitAnyNamespace,
4308 Component::ExplicitUniversalType,
4309 ],
4310 specificity(0, 0, 0),
4311 SelectorFlags::empty(),
4312 )]))
4313 );
4314 assert_eq!(
4315 parse(".foo:lang(en-US)"),
4316 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4317 vec![
4318 Component::Class(DummyAtom::from("foo")),
4319 Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
4320 ],
4321 specificity(0, 2, 0),
4322 SelectorFlags::empty(),
4323 )]))
4324 );
4325 assert_eq!(
4326 parse("#bar"),
4327 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4328 vec![Component::ID(DummyAtom::from("bar"))],
4329 specificity(1, 0, 0),
4330 SelectorFlags::empty(),
4331 )]))
4332 );
4333 assert_eq!(
4334 parse("e.foo#bar"),
4335 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4336 vec![
4337 Component::LocalName(LocalName {
4338 name: DummyAtom::from("e"),
4339 lower_name: DummyAtom::from("e"),
4340 }),
4341 Component::Class(DummyAtom::from("foo")),
4342 Component::ID(DummyAtom::from("bar")),
4343 ],
4344 specificity(1, 1, 1),
4345 SelectorFlags::empty(),
4346 )]))
4347 );
4348 assert_eq!(
4349 parse("e.foo #bar"),
4350 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4351 vec![
4352 Component::LocalName(LocalName {
4353 name: DummyAtom::from("e"),
4354 lower_name: DummyAtom::from("e"),
4355 }),
4356 Component::Class(DummyAtom::from("foo")),
4357 Component::Combinator(Combinator::Descendant),
4358 Component::ID(DummyAtom::from("bar")),
4359 ],
4360 specificity(1, 1, 1),
4361 SelectorFlags::empty(),
4362 )]))
4363 );
4364 let mut parser = DummyParser::default();
4367 assert_eq!(
4368 parse_ns("[Foo]", &parser),
4369 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4370 vec![Component::AttributeInNoNamespaceExists {
4371 local_name: DummyAtom::from("Foo"),
4372 local_name_lower: DummyAtom::from("foo"),
4373 }],
4374 specificity(0, 1, 0),
4375 SelectorFlags::empty(),
4376 )]))
4377 );
4378 assert!(parse_ns("svg|circle", &parser).is_err());
4379 parser
4380 .ns_prefixes
4381 .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
4382 assert_eq!(
4383 parse_ns("svg|circle", &parser),
4384 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4385 vec![
4386 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4387 Component::LocalName(LocalName {
4388 name: DummyAtom::from("circle"),
4389 lower_name: DummyAtom::from("circle"),
4390 }),
4391 ],
4392 specificity(0, 0, 1),
4393 SelectorFlags::empty(),
4394 )]))
4395 );
4396 assert_eq!(
4397 parse_ns("svg|*", &parser),
4398 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4399 vec![
4400 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4401 Component::ExplicitUniversalType,
4402 ],
4403 specificity(0, 0, 0),
4404 SelectorFlags::empty(),
4405 )]))
4406 );
4407 parser.default_ns = Some(MATHML.into());
4412 assert_eq!(
4413 parse_ns("[Foo]", &parser),
4414 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4415 vec![
4416 Component::DefaultNamespace(MATHML.into()),
4417 Component::AttributeInNoNamespaceExists {
4418 local_name: DummyAtom::from("Foo"),
4419 local_name_lower: DummyAtom::from("foo"),
4420 },
4421 ],
4422 specificity(0, 1, 0),
4423 SelectorFlags::empty(),
4424 )]))
4425 );
4426 assert_eq!(
4428 parse_ns("e", &parser),
4429 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4430 vec![
4431 Component::DefaultNamespace(MATHML.into()),
4432 Component::LocalName(LocalName {
4433 name: DummyAtom::from("e"),
4434 lower_name: DummyAtom::from("e"),
4435 }),
4436 ],
4437 specificity(0, 0, 1),
4438 SelectorFlags::empty(),
4439 )]))
4440 );
4441 assert_eq!(
4442 parse_ns("*", &parser),
4443 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4444 vec![
4445 Component::DefaultNamespace(MATHML.into()),
4446 Component::ExplicitUniversalType,
4447 ],
4448 specificity(0, 0, 0),
4449 SelectorFlags::empty(),
4450 )]))
4451 );
4452 assert_eq!(
4453 parse_ns("*|*", &parser),
4454 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4455 vec![
4456 Component::ExplicitAnyNamespace,
4457 Component::ExplicitUniversalType,
4458 ],
4459 specificity(0, 0, 0),
4460 SelectorFlags::empty(),
4461 )]))
4462 );
4463 assert_eq!(
4466 parse_ns(":not(.cl)", &parser),
4467 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4468 vec![
4469 Component::DefaultNamespace(MATHML.into()),
4470 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4471 vec![Component::Class(DummyAtom::from("cl"))],
4472 specificity(0, 1, 0),
4473 SelectorFlags::empty(),
4474 )])),
4475 ],
4476 specificity(0, 1, 0),
4477 SelectorFlags::empty(),
4478 )]))
4479 );
4480 assert_eq!(
4481 parse_ns(":not(*)", &parser),
4482 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4483 vec![
4484 Component::DefaultNamespace(MATHML.into()),
4485 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4486 vec![
4487 Component::DefaultNamespace(MATHML.into()),
4488 Component::ExplicitUniversalType,
4489 ],
4490 specificity(0, 0, 0),
4491 SelectorFlags::empty(),
4492 )]),),
4493 ],
4494 specificity(0, 0, 0),
4495 SelectorFlags::empty(),
4496 )]))
4497 );
4498 assert_eq!(
4499 parse_ns(":not(e)", &parser),
4500 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4501 vec![
4502 Component::DefaultNamespace(MATHML.into()),
4503 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4504 vec![
4505 Component::DefaultNamespace(MATHML.into()),
4506 Component::LocalName(LocalName {
4507 name: DummyAtom::from("e"),
4508 lower_name: DummyAtom::from("e"),
4509 }),
4510 ],
4511 specificity(0, 0, 1),
4512 SelectorFlags::empty(),
4513 )])),
4514 ],
4515 specificity(0, 0, 1),
4516 SelectorFlags::empty(),
4517 )]))
4518 );
4519 assert_eq!(
4520 parse("[attr|=\"foo\"]"),
4521 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4522 vec![Component::AttributeInNoNamespace {
4523 local_name: DummyAtom::from("attr"),
4524 operator: AttrSelectorOperator::DashMatch,
4525 value: DummyAttrValue::from("foo"),
4526 case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
4527 }],
4528 specificity(0, 1, 0),
4529 SelectorFlags::empty(),
4530 )]))
4531 );
4532 assert_eq!(
4534 parse("::before"),
4535 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4536 vec![
4537 Component::Combinator(Combinator::PseudoElement),
4538 Component::PseudoElement(PseudoElement::Before),
4539 ],
4540 specificity(0, 0, 1),
4541 SelectorFlags::HAS_PSEUDO,
4542 )]))
4543 );
4544 assert_eq!(
4545 parse("::before:hover"),
4546 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4547 vec![
4548 Component::Combinator(Combinator::PseudoElement),
4549 Component::PseudoElement(PseudoElement::Before),
4550 Component::NonTSPseudoClass(PseudoClass::Hover),
4551 ],
4552 specificity(0, 1, 1),
4553 SelectorFlags::HAS_PSEUDO,
4554 )]))
4555 );
4556 assert_eq!(
4557 parse("::before:hover:hover"),
4558 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4559 vec![
4560 Component::Combinator(Combinator::PseudoElement),
4561 Component::PseudoElement(PseudoElement::Before),
4562 Component::NonTSPseudoClass(PseudoClass::Hover),
4563 Component::NonTSPseudoClass(PseudoClass::Hover),
4564 ],
4565 specificity(0, 2, 1),
4566 SelectorFlags::HAS_PSEUDO,
4567 )]))
4568 );
4569 assert!(parse("::before:hover:lang(foo)").is_err());
4570 assert!(parse("::before:hover .foo").is_err());
4571 assert!(parse("::before .foo").is_err());
4572 assert!(parse("::before ~ bar").is_err());
4573 assert!(parse("::before:active").is_ok());
4574
4575 assert!(parse(":: before").is_err());
4577 assert_eq!(
4578 parse("div ::after"),
4579 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4580 vec![
4581 Component::LocalName(LocalName {
4582 name: DummyAtom::from("div"),
4583 lower_name: DummyAtom::from("div"),
4584 }),
4585 Component::Combinator(Combinator::Descendant),
4586 Component::Combinator(Combinator::PseudoElement),
4587 Component::PseudoElement(PseudoElement::After),
4588 ],
4589 specificity(0, 0, 2),
4590 SelectorFlags::HAS_PSEUDO,
4591 )]))
4592 );
4593 assert_eq!(
4594 parse("#d1 > .ok"),
4595 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4596 vec![
4597 Component::ID(DummyAtom::from("d1")),
4598 Component::Combinator(Combinator::Child),
4599 Component::Class(DummyAtom::from("ok")),
4600 ],
4601 specificity(1, 1, 0),
4602 SelectorFlags::empty(),
4603 )]))
4604 );
4605 parser.default_ns = None;
4606 assert!(parse(":not(#provel.old)").is_ok());
4607 assert!(parse(":not(#provel > old)").is_ok());
4608 assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
4609 assert_eq!(
4611 parse_ns(":not(*)", &parser),
4612 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4613 vec![Component::Negation(SelectorList::from_vec(vec![
4614 Selector::from_vec(
4615 vec![Component::ExplicitUniversalType],
4616 specificity(0, 0, 0),
4617 SelectorFlags::empty(),
4618 )
4619 ]))],
4620 specificity(0, 0, 0),
4621 SelectorFlags::empty(),
4622 )]))
4623 );
4624 assert_eq!(
4625 parse_ns(":not(|*)", &parser),
4626 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4627 vec![Component::Negation(SelectorList::from_vec(vec![
4628 Selector::from_vec(
4629 vec![
4630 Component::ExplicitNoNamespace,
4631 Component::ExplicitUniversalType,
4632 ],
4633 specificity(0, 0, 0),
4634 SelectorFlags::empty(),
4635 )
4636 ]))],
4637 specificity(0, 0, 0),
4638 SelectorFlags::empty(),
4639 )]))
4640 );
4641 assert_eq!(
4644 parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
4645 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4646 vec![Component::Negation(SelectorList::from_vec(vec![
4647 Selector::from_vec(
4648 vec![Component::ExplicitUniversalType],
4649 specificity(0, 0, 0),
4650 SelectorFlags::empty(),
4651 )
4652 ]))],
4653 specificity(0, 0, 0),
4654 SelectorFlags::empty(),
4655 )]))
4656 );
4657
4658 assert!(parse("::highlight(foo)").is_ok());
4659
4660 assert!(parse("::slotted()").is_err());
4661 assert!(parse("::slotted(div)").is_ok());
4662 assert!(parse("::slotted(div).foo").is_err());
4663 assert!(parse("::slotted(div + bar)").is_err());
4664 assert!(parse("::slotted(div) + foo").is_err());
4665
4666 assert!(parse("::part()").is_err());
4667 assert!(parse("::part(42)").is_err());
4668 assert!(parse("::part(foo bar)").is_ok());
4669 assert!(parse("::part(foo):hover").is_ok());
4670 assert!(parse("::part(foo) + bar").is_err());
4671
4672 assert!(parse("div ::slotted(div)").is_ok());
4673 assert!(parse("div + slot::slotted(div)").is_ok());
4674 assert!(parse("div + slot::slotted(div.foo)").is_ok());
4675 assert!(parse("slot::slotted(div,foo)::first-line").is_err());
4676 assert!(parse("::slotted(div)::before").is_ok());
4677 assert!(parse("slot::slotted(div,foo)").is_err());
4678
4679 assert!(parse("foo:where()").is_ok());
4680 assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
4681 assert!(parse("foo:where(::before)").is_ok());
4682 }
4683
4684 #[test]
4685 fn parent_selector() {
4686 assert!(parse("foo &").is_ok());
4687 assert_eq!(
4688 parse("#foo &.bar"),
4689 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4690 vec![
4691 Component::ID(DummyAtom::from("foo")),
4692 Component::Combinator(Combinator::Descendant),
4693 Component::ParentSelector,
4694 Component::Class(DummyAtom::from("bar")),
4695 ],
4696 specificity(1, 1, 0),
4697 SelectorFlags::HAS_PARENT
4698 )]))
4699 );
4700
4701 let parent = parse(".bar, div .baz").unwrap();
4702 let child = parse("#foo &.bar").unwrap();
4703 assert_eq!(
4704 child.replace_parent_selector(&parent),
4705 parse("#foo :is(.bar, div .baz).bar").unwrap()
4706 );
4707
4708 let has_child = parse("#foo:has(&.bar)").unwrap();
4709 assert_eq!(
4710 has_child.replace_parent_selector(&parent),
4711 parse("#foo:has(:is(.bar, div .baz).bar)").unwrap()
4712 );
4713
4714 let child =
4715 parse_relative_expected("#foo", ParseRelative::ForNesting, Some("& #foo")).unwrap();
4716 assert_eq!(
4717 child.replace_parent_selector(&parent),
4718 parse(":is(.bar, div .baz) #foo").unwrap()
4719 );
4720
4721 let child =
4722 parse_relative_expected("+ #foo", ParseRelative::ForNesting, Some("& + #foo")).unwrap();
4723 assert_eq!(child, parse("& + #foo").unwrap());
4724 }
4725
4726 #[test]
4727 fn test_pseudo_iter() {
4728 let list = parse("q::before").unwrap();
4729 let selector = &list.slice()[0];
4730 assert!(!selector.is_universal());
4731 let mut iter = selector.iter();
4732 assert_eq!(
4733 iter.next(),
4734 Some(&Component::PseudoElement(PseudoElement::Before))
4735 );
4736 assert_eq!(iter.next(), None);
4737 let combinator = iter.next_sequence();
4738 assert_eq!(combinator, Some(Combinator::PseudoElement));
4739 assert_eq!(
4740 iter.next(),
4741 Some(&Component::LocalName(LocalName {
4742 name: DummyAtom::from("q"),
4743 lower_name: DummyAtom::from("q"),
4744 }))
4745 );
4746 assert_eq!(iter.next(), None);
4747 assert_eq!(iter.next_sequence(), None);
4748 }
4749
4750 #[test]
4751 fn test_pseudo_before_marker() {
4752 let list = parse("::before::marker").unwrap();
4753 let selector = &list.slice()[0];
4754 let mut iter = selector.iter();
4755 assert_eq!(
4756 iter.next(),
4757 Some(&Component::PseudoElement(PseudoElement::Marker))
4758 );
4759 assert_eq!(iter.next(), None);
4760 let combinator = iter.next_sequence();
4761 assert_eq!(combinator, Some(Combinator::PseudoElement));
4762 assert_eq!(
4763 iter.next(),
4764 Some(&Component::PseudoElement(PseudoElement::Before))
4765 );
4766 assert_eq!(iter.next(), None);
4767 let combinator = iter.next_sequence();
4768 assert_eq!(combinator, Some(Combinator::PseudoElement));
4769 assert_eq!(iter.next(), None);
4770 assert_eq!(iter.next_sequence(), None);
4771 }
4772
4773 #[test]
4774 fn test_pseudo_duplicate_before_after_or_marker() {
4775 assert!(parse("::before::before").is_err());
4776 assert!(parse("::after::after").is_err());
4777 assert!(parse("::marker::marker").is_err());
4778 }
4779
4780 #[test]
4781 fn test_pseudo_on_element_backed_pseudo() {
4782 let list = parse("::details-content::before").unwrap();
4783 let selector = &list.slice()[0];
4784 let mut iter = selector.iter();
4785 assert_eq!(
4786 iter.next(),
4787 Some(&Component::PseudoElement(PseudoElement::Before))
4788 );
4789 assert_eq!(iter.next(), None);
4790 let combinator = iter.next_sequence();
4791 assert_eq!(combinator, Some(Combinator::PseudoElement));
4792 assert_eq!(
4793 iter.next(),
4794 Some(&Component::PseudoElement(PseudoElement::DetailsContent))
4795 );
4796 assert_eq!(iter.next(), None);
4797 let combinator = iter.next_sequence();
4798 assert_eq!(combinator, Some(Combinator::PseudoElement));
4799 assert_eq!(iter.next(), None);
4800 assert_eq!(iter.next_sequence(), None);
4801 }
4802
4803 #[test]
4804 fn test_universal() {
4805 let list = parse_ns(
4806 "*|*::before",
4807 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
4808 )
4809 .unwrap();
4810 let selector = &list.slice()[0];
4811 assert!(selector.is_universal());
4812 }
4813
4814 #[test]
4815 fn test_empty_pseudo_iter() {
4816 let list = parse("::before").unwrap();
4817 let selector = &list.slice()[0];
4818 assert!(selector.is_universal());
4819 let mut iter = selector.iter();
4820 assert_eq!(
4821 iter.next(),
4822 Some(&Component::PseudoElement(PseudoElement::Before))
4823 );
4824 assert_eq!(iter.next(), None);
4825 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
4826 assert_eq!(iter.next(), None);
4827 assert_eq!(iter.next_sequence(), None);
4828 }
4829
4830 #[test]
4831 fn test_parse_implicit_scope() {
4832 assert_eq!(
4833 parse_relative_expected(".foo", ParseRelative::ForScope, None).unwrap(),
4834 SelectorList::from_vec(vec![Selector::from_vec(
4835 vec![
4836 Component::ImplicitScope,
4837 Component::Combinator(Combinator::Descendant),
4838 Component::Class(DummyAtom::from("foo")),
4839 ],
4840 specificity(0, 1, 0),
4841 SelectorFlags::HAS_SCOPE,
4842 )])
4843 );
4844
4845 assert_eq!(
4846 parse_relative_expected(":scope .foo", ParseRelative::ForScope, None).unwrap(),
4847 SelectorList::from_vec(vec![Selector::from_vec(
4848 vec![
4849 Component::Scope,
4850 Component::Combinator(Combinator::Descendant),
4851 Component::Class(DummyAtom::from("foo")),
4852 ],
4853 specificity(0, 2, 0),
4854 SelectorFlags::HAS_SCOPE
4855 )])
4856 );
4857
4858 assert_eq!(
4859 parse_relative_expected("> .foo", ParseRelative::ForScope, Some("> .foo")).unwrap(),
4860 SelectorList::from_vec(vec![Selector::from_vec(
4861 vec![
4862 Component::ImplicitScope,
4863 Component::Combinator(Combinator::Child),
4864 Component::Class(DummyAtom::from("foo")),
4865 ],
4866 specificity(0, 1, 0),
4867 SelectorFlags::HAS_SCOPE
4868 )])
4869 );
4870
4871 assert_eq!(
4872 parse_relative_expected(".foo :scope > .bar", ParseRelative::ForScope, None).unwrap(),
4873 SelectorList::from_vec(vec![Selector::from_vec(
4874 vec![
4875 Component::Class(DummyAtom::from("foo")),
4876 Component::Combinator(Combinator::Descendant),
4877 Component::Scope,
4878 Component::Combinator(Combinator::Child),
4879 Component::Class(DummyAtom::from("bar")),
4880 ],
4881 specificity(0, 3, 0),
4882 SelectorFlags::HAS_SCOPE
4883 )])
4884 );
4885 }
4886
4887 struct TestVisitor {
4888 seen: Vec<String>,
4889 }
4890
4891 impl SelectorVisitor for TestVisitor {
4892 type Impl = DummySelectorImpl;
4893
4894 fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool {
4895 let mut dest = String::new();
4896 s.to_css(&mut dest).unwrap();
4897 self.seen.push(dest);
4898 true
4899 }
4900 }
4901
4902 #[test]
4903 fn visitor() {
4904 let mut test_visitor = TestVisitor { seen: vec![] };
4905 parse(":not(:hover) ~ label").unwrap().slice()[0].visit(&mut test_visitor);
4906 assert!(test_visitor.seen.contains(&":hover".into()));
4907
4908 let mut test_visitor = TestVisitor { seen: vec![] };
4909 parse("::before:hover").unwrap().slice()[0].visit(&mut test_visitor);
4910 assert!(test_visitor.seen.contains(&":hover".into()));
4911 }
4912}