1use crate::attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace};
6use crate::attr::{NamespaceConstraint, ParsedAttrSelectorOperation, ParsedCaseSensitivity};
7use crate::bloom::BLOOM_HASH_MASK;
8use crate::builder::{
9 relative_selector_list_specificity_and_flags, selector_list_specificity_and_flags,
10 SelectorBuilder, SelectorFlags, Specificity, SpecificityAndFlags,
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| byte >= b'A' && byte <= b'Z') {
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: CowRcStr<'i>,
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: CowRcStr<'i>,
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: CowRcStr<'i>,
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: CowRcStr<'i>,
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 pub fn from_iter(mut iter: impl ExactSizeIterator<Item = Selector<Impl>>) -> Self {
410 if iter.len() == 1 {
411 Self::from_one(iter.next().unwrap())
412 } else {
413 Self(ThinArcUnion::from_second(ThinArc::from_header_and_iter(
414 (),
415 iter,
416 )))
417 }
418 }
419
420 #[inline]
421 pub fn slice(&self) -> &[Selector<Impl>] {
422 match self.0.borrow() {
423 ArcUnionBorrow::First(..) => {
424 let selector: &Selector<Impl> = unsafe { std::mem::transmute(self) };
426 std::slice::from_ref(selector)
427 },
428 ArcUnionBorrow::Second(list) => list.get().slice(),
429 }
430 }
431
432 #[inline]
433 pub fn len(&self) -> usize {
434 match self.0.borrow() {
435 ArcUnionBorrow::First(..) => 1,
436 ArcUnionBorrow::Second(list) => list.len(),
437 }
438 }
439
440 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
442 match self.0.borrow() {
443 ArcUnionBorrow::First(s) => s.with_arc(|a| a.heap_ptr()),
444 ArcUnionBorrow::Second(s) => s.with_arc(|a| a.heap_ptr()),
445 }
446 }
447}
448
449#[derive(Clone, Copy, Hash, Eq, PartialEq)]
452pub struct SelectorKey(usize);
453
454impl SelectorKey {
455 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>) -> Self {
457 Self(selector.0.slice().as_ptr() as usize)
458 }
459}
460
461#[derive(PartialEq)]
463enum ForgivingParsing {
464 No,
467 Yes,
471}
472
473#[derive(Copy, Clone, PartialEq)]
475pub enum ParseRelative {
476 ForHas,
478 ForNesting,
481 ForScope,
484 No,
486}
487
488impl<Impl: SelectorImpl> SelectorList<Impl> {
489 pub fn scope() -> Self {
491 Self::from_one(Selector::scope())
492 }
493 pub fn implicit_scope() -> Self {
495 Self::from_one(Selector::implicit_scope())
496 }
497
498 pub fn parse<'i, P>(
503 parser: &P,
504 input: &mut CssParser<'i>,
505 parse_relative: ParseRelative,
506 ) -> Result<Self, ParseError<P::Error>>
507 where
508 P: Parser<'i, Impl = Impl>,
509 {
510 Self::parse_with_state(
511 parser,
512 input,
513 SelectorParsingState::empty(),
514 ForgivingParsing::No,
515 parse_relative,
516 )
517 }
518
519 pub fn parse_disallow_pseudo<'i, P>(
521 parser: &P,
522 input: &mut CssParser<'i>,
523 parse_relative: ParseRelative,
524 ) -> Result<Self, ParseError<P::Error>>
525 where
526 P: Parser<'i, Impl = Impl>,
527 {
528 Self::parse_with_state(
529 parser,
530 input,
531 SelectorParsingState::DISALLOW_PSEUDOS,
532 ForgivingParsing::No,
533 parse_relative,
534 )
535 }
536
537 pub fn parse_forgiving<'i, P>(
538 parser: &P,
539 input: &mut CssParser<'i>,
540 parse_relative: ParseRelative,
541 ) -> Result<Self, ParseError<P::Error>>
542 where
543 P: Parser<'i, Impl = Impl>,
544 {
545 Self::parse_with_state(
546 parser,
547 input,
548 SelectorParsingState::empty(),
549 ForgivingParsing::Yes,
550 parse_relative,
551 )
552 }
553
554 #[inline]
555 fn parse_with_state<'i, P>(
556 parser: &P,
557 input: &mut CssParser<'i>,
558 state: SelectorParsingState,
559 recovery: ForgivingParsing,
560 parse_relative: ParseRelative,
561 ) -> Result<Self, ParseError<P::Error>>
562 where
563 P: Parser<'i, Impl = Impl>,
564 {
565 let mut values = SmallVec::<[_; 4]>::new();
566 let forgiving = recovery == ForgivingParsing::Yes && parser.allow_forgiving_selectors();
567 loop {
568 let selector = input.parse_until_before(Delimiter::Comma, |input| {
569 let start = input.position();
570 let mut selector = parse_selector(parser, input, state, parse_relative);
571 if forgiving && (selector.is_err() || input.expect_exhausted().is_err()) {
572 input.expect_no_error_token()?;
573 selector = Ok(Selector::new_invalid(input.slice_from(start)));
574 }
575 selector
576 })?;
577
578 values.push(selector);
579
580 match input.next() {
581 Ok(&Token::Comma) => {},
582 Ok(_) => unreachable!(),
583 Err(_) => break,
584 }
585 }
586 Ok(Self::from_iter(values.into_iter()))
587 }
588
589 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
591 Self::from_iter(
592 self.slice()
593 .iter()
594 .map(|selector| selector.replace_parent_selector(parent)),
595 )
596 }
597
598 #[allow(dead_code)]
600 pub(crate) fn from_vec(v: Vec<Selector<Impl>>) -> Self {
601 SelectorList::from_iter(v.into_iter())
602 }
603}
604
605fn parse_inner_compound_selector<'i, P, Impl>(
607 parser: &P,
608 input: &mut CssParser<'i>,
609 state: SelectorParsingState,
610) -> Result<Selector<Impl>, ParseError<P::Error>>
611where
612 P: Parser<'i, Impl = Impl>,
613 Impl: SelectorImpl,
614{
615 parse_selector(
616 parser,
617 input,
618 state | SelectorParsingState::DISALLOW_PSEUDOS | SelectorParsingState::DISALLOW_COMBINATORS,
619 ParseRelative::No,
620 )
621}
622
623#[derive(Clone, Debug, Eq, PartialEq)]
639pub struct AncestorHashes {
640 pub packed_hashes: [u32; 3],
641}
642
643pub(crate) fn collect_selector_hashes<'a, Impl: SelectorImpl, Iter>(
644 iter: Iter,
645 quirks_mode: QuirksMode,
646 hashes: &mut [u32; 4],
647 len: &mut usize,
648 create_inner_iterator: fn(&'a Selector<Impl>) -> Iter,
649) -> bool
650where
651 Iter: Iterator<Item = &'a Component<Impl>>,
652{
653 for component in iter {
654 let hash = match *component {
655 Component::LocalName(LocalName {
656 ref name,
657 ref lower_name,
658 }) => {
659 if name != lower_name {
663 continue;
664 }
665 name.precomputed_hash()
666 },
667 Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) => {
668 url.precomputed_hash()
669 },
670 Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => id.precomputed_hash(),
673 Component::Class(ref class) if quirks_mode != QuirksMode::Quirks => {
674 class.precomputed_hash()
675 },
676 Component::AttributeInNoNamespace { ref local_name, .. }
677 if Impl::should_collect_attr_hash(local_name) =>
678 {
679 local_name.precomputed_hash()
682 },
683 Component::AttributeInNoNamespaceExists {
684 ref local_name,
685 ref local_name_lower,
686 ..
687 } => {
688 if local_name != local_name_lower || !Impl::should_collect_attr_hash(local_name) {
692 continue;
693 }
694 local_name.precomputed_hash()
695 },
696 Component::AttributeOther(ref selector) => {
697 if selector.local_name != selector.local_name_lower
698 || !Impl::should_collect_attr_hash(&selector.local_name)
699 {
700 continue;
701 }
702 selector.local_name.precomputed_hash()
703 },
704 Component::Is(ref list) | Component::Where(ref list) => {
705 let slice = list.slice();
709 if slice.len() == 1
710 && !collect_selector_hashes(
711 create_inner_iterator(&slice[0]),
712 quirks_mode,
713 hashes,
714 len,
715 create_inner_iterator,
716 )
717 {
718 return false;
719 }
720 continue;
721 },
722 _ => continue,
723 };
724
725 hashes[*len] = hash & BLOOM_HASH_MASK;
726 *len += 1;
727 if *len == hashes.len() {
728 return false;
729 }
730 }
731 true
732}
733
734fn collect_ancestor_hashes<Impl: SelectorImpl>(
735 mut iter: SelectorIter<Impl>,
736 quirks_mode: QuirksMode,
737 hashes: &mut [u32; 4],
738 len: &mut usize,
739) -> bool {
740 loop {
741 while let Some(item) = iter.next() {
742 if let Component::Is(list) | Component::Where(list) = item {
743 let slice = list.slice();
744 if slice.len() == 1
745 && !collect_ancestor_hashes(slice[0].iter(), quirks_mode, hashes, len)
746 {
747 return false;
748 }
749 }
750 }
751 let Some(c) = iter.next_sequence() else {
752 return true;
753 };
754 match c {
755 Combinator::Child | Combinator::Descendant => break,
757 Combinator::LaterSibling | Combinator::NextSibling => {
758 iter.skip_until_ancestor();
759 break;
760 },
761 Combinator::Part | Combinator::SlotAssignment | Combinator::PseudoElement => {},
766 }
767 }
768
769 collect_selector_hashes(AncestorIter(iter), quirks_mode, hashes, len, |s| {
770 AncestorIter(s.iter())
771 })
772}
773
774impl AncestorHashes {
775 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self {
776 let mut hashes = [0u32; 4];
778 let mut len = 0;
779 collect_ancestor_hashes(selector.iter(), quirks_mode, &mut hashes, &mut len);
780 debug_assert!(len <= 4);
781
782 if len == 4 {
785 let fourth = hashes[3];
786 hashes[0] |= (fourth & 0x000000ff) << 24;
787 hashes[1] |= (fourth & 0x0000ff00) << 16;
788 hashes[2] |= (fourth & 0x00ff0000) << 8;
789 }
790
791 AncestorHashes {
792 packed_hashes: [hashes[0], hashes[1], hashes[2]],
793 }
794 }
795
796 pub fn fourth_hash(&self) -> u32 {
798 ((self.packed_hashes[0] & 0xff000000) >> 24)
799 | ((self.packed_hashes[1] & 0xff000000) >> 16)
800 | ((self.packed_hashes[2] & 0xff000000) >> 8)
801 }
802}
803
804#[inline]
805pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
806 Impl::NamespaceUrl::default()
808}
809
810pub(super) type SelectorData<Impl> = ThinArc<SpecificityAndFlags, Component<Impl>>;
811
812#[derive(Clone, Copy, Debug, Eq, PartialEq)]
815pub enum MatchesFeaturelessHost {
816 Yes,
818 Only,
820 Never,
822}
823
824impl MatchesFeaturelessHost {
825 #[inline]
827 pub fn may_match(self) -> bool {
828 return !matches!(self, Self::Never);
829 }
830}
831
832#[derive(Clone, Eq, PartialEq)]
847#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
848#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
849#[repr(transparent)]
850pub struct Selector<Impl: SelectorImpl>(
851 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] SelectorData<Impl>,
852);
853
854impl<Impl: SelectorImpl> Selector<Impl> {
855 pub fn mark_as_intentionally_leaked(&self) {
857 self.0.mark_as_intentionally_leaked()
858 }
859
860 fn scope() -> Self {
861 Self(ThinArc::from_header_and_iter(
862 SpecificityAndFlags {
863 specificity: Specificity::single_class_like().into(),
864 flags: SelectorFlags::HAS_SCOPE,
865 },
866 std::iter::once(Component::Scope),
867 ))
868 }
869
870 fn implicit_scope() -> Self {
872 Self(ThinArc::from_header_and_iter(
873 SpecificityAndFlags {
874 specificity: 0,
875 flags: SelectorFlags::HAS_SCOPE,
876 },
877 std::iter::once(Component::ImplicitScope),
878 ))
879 }
880
881 #[inline]
882 pub fn specificity(&self) -> u32 {
883 self.0.header.specificity
884 }
885
886 #[inline]
887 pub(crate) fn flags(&self) -> SelectorFlags {
888 self.0.header.flags
889 }
890
891 #[inline]
892 pub fn has_pseudo_element(&self) -> bool {
893 self.flags().intersects(SelectorFlags::HAS_PSEUDO)
894 }
895
896 #[inline]
897 pub fn has_parent_selector(&self) -> bool {
898 self.flags().intersects(SelectorFlags::HAS_PARENT)
899 }
900
901 #[inline]
902 pub fn has_scope_selector(&self) -> bool {
903 self.flags().intersects(SelectorFlags::HAS_SCOPE)
904 }
905
906 #[inline]
907 pub fn is_slotted(&self) -> bool {
908 self.flags().intersects(SelectorFlags::HAS_SLOTTED)
909 }
910
911 #[inline]
912 pub fn is_part(&self) -> bool {
913 self.flags().intersects(SelectorFlags::HAS_PART)
914 }
915
916 #[inline]
917 pub fn parts(&self) -> Option<&[Impl::Identifier]> {
918 if !self.is_part() {
919 return None;
920 }
921
922 let mut iter = self.iter();
923 if self.has_pseudo_element() {
924 for _ in &mut iter {}
926
927 let combinator = iter.next_sequence()?;
928 debug_assert_eq!(combinator, Combinator::PseudoElement);
929 }
930
931 for component in iter {
932 if let Component::Part(ref part) = *component {
933 return Some(part);
934 }
935 }
936
937 debug_assert!(false, "is_part() lied somehow?");
938 None
939 }
940
941 #[inline]
942 pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
943 if !self.has_pseudo_element() {
944 return None;
945 }
946
947 for component in self.iter() {
948 if let Component::PseudoElement(ref pseudo) = *component {
949 return Some(pseudo);
950 }
951 }
952
953 debug_assert!(false, "has_pseudo_element lied!");
954 None
955 }
956
957 #[inline]
958 pub fn pseudo_elements(&self) -> SmallVec<[&Impl::PseudoElement; 3]> {
959 let mut pseudos = SmallVec::new();
960
961 if !self.has_pseudo_element() {
962 return pseudos;
963 }
964
965 let mut iter = self.iter();
966 loop {
967 for component in &mut iter {
968 if let Component::PseudoElement(ref pseudo) = *component {
969 pseudos.push(pseudo);
970 }
971 }
972 match iter.next_sequence() {
973 Some(Combinator::PseudoElement) => {},
974 _ => break,
975 }
976 }
977
978 debug_assert!(!pseudos.is_empty(), "has_pseudo_element lied!");
979
980 pseudos
981 }
982
983 #[inline]
987 pub fn is_universal(&self) -> bool {
988 self.iter_raw_match_order().all(|c| {
989 matches!(
990 *c,
991 Component::ExplicitUniversalType
992 | Component::ExplicitAnyNamespace
993 | Component::Combinator(Combinator::PseudoElement)
994 | Component::PseudoElement(..)
995 )
996 })
997 }
998
999 #[inline]
1002 pub fn matches_featureless_host(
1003 &self,
1004 scope_matches_featureless_host: bool,
1005 ) -> MatchesFeaturelessHost {
1006 let flags = self.flags();
1007 if !flags.intersects(SelectorFlags::HAS_HOST | SelectorFlags::HAS_SCOPE) {
1008 return MatchesFeaturelessHost::Never;
1009 }
1010
1011 let mut iter = self.iter();
1012 if flags.intersects(SelectorFlags::HAS_PSEUDO) {
1013 for _ in &mut iter {
1014 }
1016 match iter.next_sequence() {
1017 Some(c) if c.is_pseudo_element() => {},
1018 _ => {
1019 debug_assert!(false, "Pseudo selector without pseudo combinator?");
1020 return MatchesFeaturelessHost::Never;
1021 },
1022 }
1023 }
1024
1025 let compound_matches = crate::matching::compound_matches_featureless_host(
1026 &mut iter,
1027 scope_matches_featureless_host,
1028 );
1029 if iter.next_sequence().is_some() {
1030 return MatchesFeaturelessHost::Never;
1031 }
1032 return compound_matches;
1033 }
1034
1035 #[inline]
1039 pub fn iter(&self) -> SelectorIter<'_, Impl> {
1040 SelectorIter {
1041 iter: self.iter_raw_match_order(),
1042 next_combinator: None,
1043 }
1044 }
1045
1046 #[inline]
1048 pub fn iter_skip_relative_selector_anchor(&self) -> SelectorIter<'_, Impl> {
1049 if cfg!(debug_assertions) {
1050 let mut selector_iter = self.iter_raw_parse_order_from(0);
1051 assert!(
1052 matches!(
1053 selector_iter.next().unwrap(),
1054 Component::RelativeSelectorAnchor
1055 ),
1056 "Relative selector does not start with RelativeSelectorAnchor"
1057 );
1058 assert!(
1059 selector_iter.next().unwrap().is_combinator(),
1060 "Relative combinator does not exist"
1061 );
1062 }
1063
1064 SelectorIter {
1065 iter: self.0.slice()[..self.len() - 2].iter(),
1066 next_combinator: None,
1067 }
1068 }
1069
1070 #[inline]
1073 pub fn iter_from(&self, offset: usize) -> SelectorIter<'_, Impl> {
1074 let iter = self.0.slice()[offset..].iter();
1075 SelectorIter {
1076 iter,
1077 next_combinator: None,
1078 }
1079 }
1080
1081 #[inline]
1084 pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
1085 match self.0.slice()[index] {
1086 Component::Combinator(c) => c,
1087 ref other => panic!(
1088 "Not a combinator: {:?}, {:?}, index: {}",
1089 other, self, index
1090 ),
1091 }
1092 }
1093
1094 #[inline]
1097 pub fn iter_raw_match_order(&self) -> slice::Iter<'_, Component<Impl>> {
1098 self.0.slice().iter()
1099 }
1100
1101 #[inline]
1104 pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
1105 match self.0.slice()[self.len() - index - 1] {
1106 Component::Combinator(c) => c,
1107 ref other => panic!(
1108 "Not a combinator: {:?}, {:?}, index: {}",
1109 other, self, index
1110 ),
1111 }
1112 }
1113
1114 #[inline]
1118 pub fn iter_raw_parse_order_from(
1119 &self,
1120 offset: usize,
1121 ) -> Rev<slice::Iter<'_, Component<Impl>>> {
1122 self.0.slice()[..self.len() - offset].iter().rev()
1123 }
1124
1125 #[allow(dead_code)]
1127 pub(crate) fn from_vec(
1128 vec: Vec<Component<Impl>>,
1129 specificity: u32,
1130 flags: SelectorFlags,
1131 ) -> Self {
1132 let mut builder = SelectorBuilder::default();
1133 for component in vec.into_iter() {
1134 if let Some(combinator) = component.as_combinator() {
1135 builder.push_combinator(combinator);
1136 } else {
1137 builder.push_simple_selector(component);
1138 }
1139 }
1140 let spec = SpecificityAndFlags { specificity, flags };
1141 Selector(builder.build_with_specificity_and_flags(spec, ParseRelative::No))
1142 }
1143
1144 #[inline]
1145 fn into_data(self) -> SelectorData<Impl> {
1146 self.0
1147 }
1148
1149 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
1150 let parent_specificity_and_flags = selector_list_specificity_and_flags(
1151 parent.slice().iter(),
1152 true,
1153 );
1154
1155 let mut specificity = Specificity::from(self.specificity());
1156 let mut flags = self.flags() - SelectorFlags::HAS_PARENT;
1157 let forbidden_flags = SelectorFlags::forbidden_for_nesting();
1158
1159 fn replace_parent_on_selector_list<Impl: SelectorImpl>(
1160 orig: &[Selector<Impl>],
1161 parent: &SelectorList<Impl>,
1162 specificity: &mut Specificity,
1163 flags: &mut SelectorFlags,
1164 propagate_specificity: bool,
1165 forbidden_flags: SelectorFlags,
1166 ) -> Option<SelectorList<Impl>> {
1167 if !orig.iter().any(|s| s.has_parent_selector()) {
1168 return None;
1169 }
1170
1171 let result =
1172 SelectorList::from_iter(orig.iter().map(|s| s.replace_parent_selector(parent)));
1173
1174 let result_specificity_and_flags = selector_list_specificity_and_flags(
1175 result.slice().iter(),
1176 false,
1177 );
1178 if propagate_specificity {
1179 *specificity += Specificity::from(
1180 result_specificity_and_flags.specificity
1181 - selector_list_specificity_and_flags(
1182 orig.iter(),
1183 false,
1184 )
1185 .specificity,
1186 );
1187 }
1188 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1189 Some(result)
1190 }
1191
1192 fn replace_parent_on_relative_selector_list<Impl: SelectorImpl>(
1193 orig: &[RelativeSelector<Impl>],
1194 parent: &SelectorList<Impl>,
1195 specificity: &mut Specificity,
1196 flags: &mut SelectorFlags,
1197 forbidden_flags: SelectorFlags,
1198 ) -> Box<[RelativeSelector<Impl>]> {
1199 let mut any = false;
1200
1201 let result = orig
1202 .iter()
1203 .map(|s| {
1204 if !s.selector.has_parent_selector() {
1205 return s.clone();
1206 }
1207 any = true;
1208 RelativeSelector {
1209 match_hint: s.match_hint,
1210 selector: s.selector.replace_parent_selector(parent),
1211 }
1212 })
1213 .collect();
1214
1215 if !any {
1216 return result;
1217 }
1218
1219 let result_specificity_and_flags = relative_selector_list_specificity_and_flags(
1220 &result, false,
1221 );
1222 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1223 *specificity += Specificity::from(
1224 result_specificity_and_flags.specificity
1225 - relative_selector_list_specificity_and_flags(
1226 orig, false,
1227 )
1228 .specificity,
1229 );
1230 result
1231 }
1232
1233 fn replace_parent_on_selector<Impl: SelectorImpl>(
1234 orig: &Selector<Impl>,
1235 parent: &SelectorList<Impl>,
1236 specificity: &mut Specificity,
1237 flags: &mut SelectorFlags,
1238 forbidden_flags: SelectorFlags,
1239 ) -> Selector<Impl> {
1240 let new_selector = orig.replace_parent_selector(parent);
1241 *specificity += Specificity::from(new_selector.specificity() - orig.specificity());
1242 flags.insert(new_selector.flags() - forbidden_flags);
1243 new_selector
1244 }
1245
1246 if !self.has_parent_selector() {
1247 return self.clone();
1248 }
1249
1250 let iter = self.iter_raw_match_order().map(|component| {
1251 use self::Component::*;
1252 match *component {
1253 LocalName(..)
1254 | ID(..)
1255 | Class(..)
1256 | AttributeInNoNamespaceExists { .. }
1257 | AttributeInNoNamespace { .. }
1258 | AttributeOther(..)
1259 | ExplicitUniversalType
1260 | ExplicitAnyNamespace
1261 | ExplicitNoNamespace
1262 | DefaultNamespace(..)
1263 | Namespace(..)
1264 | Root
1265 | Empty
1266 | Scope
1267 | ImplicitScope
1268 | Nth(..)
1269 | NonTSPseudoClass(..)
1270 | PseudoElement(..)
1271 | Combinator(..)
1272 | Host(None)
1273 | Part(..)
1274 | Invalid(..)
1275 | RelativeSelectorAnchor => component.clone(),
1276 ParentSelector => {
1277 specificity += Specificity::from(parent_specificity_and_flags.specificity);
1278 flags.insert(parent_specificity_and_flags.flags - forbidden_flags);
1279 Is(parent.clone())
1280 },
1281 Negation(ref selectors) => {
1282 Negation(
1283 replace_parent_on_selector_list(
1284 selectors.slice(),
1285 parent,
1286 &mut specificity,
1287 &mut flags,
1288 true,
1289 forbidden_flags,
1290 )
1291 .unwrap_or_else(|| selectors.clone()),
1292 )
1293 },
1294 Is(ref selectors) => {
1295 Is(replace_parent_on_selector_list(
1296 selectors.slice(),
1297 parent,
1298 &mut specificity,
1299 &mut flags,
1300 true,
1301 forbidden_flags,
1302 )
1303 .unwrap_or_else(|| selectors.clone()))
1304 },
1305 Where(ref selectors) => {
1306 Where(
1307 replace_parent_on_selector_list(
1308 selectors.slice(),
1309 parent,
1310 &mut specificity,
1311 &mut flags,
1312 false,
1313 forbidden_flags,
1314 )
1315 .unwrap_or_else(|| selectors.clone()),
1316 )
1317 },
1318 Has(ref selectors) => Has(replace_parent_on_relative_selector_list(
1319 selectors,
1320 parent,
1321 &mut specificity,
1322 &mut flags,
1323 forbidden_flags,
1324 )),
1325 Host(Some(ref selector)) => Host(Some(replace_parent_on_selector(
1326 selector,
1327 parent,
1328 &mut specificity,
1329 &mut flags,
1330 forbidden_flags,
1331 ))),
1332 NthOf(ref data) => {
1333 let selectors = replace_parent_on_selector_list(
1334 data.selectors(),
1335 parent,
1336 &mut specificity,
1337 &mut flags,
1338 true,
1339 forbidden_flags,
1340 );
1341 NthOf(match selectors {
1342 Some(s) => {
1343 NthOfSelectorData::new(data.nth_data(), s.slice().iter().cloned())
1344 },
1345 None => data.clone(),
1346 })
1347 },
1348 Slotted(ref selector) => Slotted(replace_parent_on_selector(
1349 selector,
1350 parent,
1351 &mut specificity,
1352 &mut flags,
1353 forbidden_flags,
1354 )),
1355 }
1356 });
1357 let mut items = UniqueArc::from_header_and_iter(Default::default(), iter);
1358 *items.header_mut() = SpecificityAndFlags {
1359 specificity: specificity.into(),
1360 flags,
1361 };
1362 Selector(items.shareable())
1363 }
1364
1365 #[inline]
1367 pub fn len(&self) -> usize {
1368 self.0.len()
1369 }
1370
1371 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
1373 self.0.heap_ptr()
1374 }
1375
1376 pub fn visit<V>(&self, visitor: &mut V) -> bool
1395 where
1396 V: SelectorVisitor<Impl = Impl>,
1397 {
1398 let mut current = self.iter();
1399 let mut combinator = None;
1400 loop {
1401 if !visitor.visit_complex_selector(combinator) {
1402 return false;
1403 }
1404
1405 for selector in &mut current {
1406 if !selector.visit(visitor) {
1407 return false;
1408 }
1409 }
1410
1411 combinator = current.next_sequence();
1412 if combinator.is_none() {
1413 break;
1414 }
1415 }
1416
1417 true
1418 }
1419
1420 #[inline]
1422 pub fn parse<'i, P>(parser: &P, input: &mut CssParser<'i>) -> Result<Self, ParseError<P::Error>>
1423 where
1424 P: Parser<'i, Impl = Impl>,
1425 {
1426 parse_selector(
1427 parser,
1428 input,
1429 SelectorParsingState::empty(),
1430 ParseRelative::No,
1431 )
1432 }
1433
1434 pub fn new_invalid(s: &str) -> Self {
1435 fn check_for_parent(input: &mut CssParser, has_parent: &mut bool) {
1436 while let Ok(t) = input.next() {
1437 match *t {
1438 Token::Function(_)
1439 | Token::ParenthesisBlock
1440 | Token::CurlyBracketBlock
1441 | Token::SquareBracketBlock => {
1442 let _ = input.parse_nested_block(
1443 |i| -> Result<(), ParseError<BasicParseError>> {
1444 check_for_parent(i, has_parent);
1445 Ok(())
1446 },
1447 );
1448 },
1449 Token::Delim('&') => {
1450 *has_parent = true;
1451 },
1452 _ => {},
1453 }
1454 if *has_parent {
1455 break;
1456 }
1457 }
1458 }
1459 let mut has_parent = false;
1460 {
1461 let mut parser = CssParser::new(s);
1462 check_for_parent(&mut parser, &mut has_parent);
1463 }
1464 Self(ThinArc::from_header_and_iter(
1465 SpecificityAndFlags {
1466 specificity: 0,
1467 flags: if has_parent {
1468 SelectorFlags::HAS_PARENT
1469 } else {
1470 SelectorFlags::empty()
1471 },
1472 },
1473 std::iter::once(Component::Invalid(Arc::new(String::from(s.trim())))),
1474 ))
1475 }
1476
1477 pub fn is_rightmost(&self, offset: usize) -> bool {
1479 offset == 0
1482 || matches!(
1483 self.combinator_at_match_order(offset - 1),
1484 Combinator::PseudoElement
1485 )
1486 }
1487}
1488
1489#[derive(Clone)]
1490pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
1491 iter: slice::Iter<'a, Component<Impl>>,
1492 next_combinator: Option<Combinator>,
1493}
1494
1495impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
1496 #[inline]
1499 pub fn next_sequence(&mut self) -> Option<Combinator> {
1500 self.next_combinator.take()
1501 }
1502
1503 fn skip_until_ancestor(&mut self) {
1506 loop {
1507 while self.next().is_some() {}
1508 if self.next_sequence().is_none_or(|c| c.is_ancestor()) {
1509 break;
1510 }
1511 }
1512 }
1513
1514 #[inline]
1515 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
1516 let first = match self.next() {
1517 Some(c) => c,
1518 None => return true,
1521 };
1522 self.matches_for_stateless_pseudo_element_internal(first)
1523 }
1524
1525 #[inline(never)]
1526 fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool {
1527 if !first.matches_for_stateless_pseudo_element() {
1528 return false;
1529 }
1530 for component in self {
1531 if !component.matches_for_stateless_pseudo_element() {
1535 return false;
1536 }
1537 }
1538 true
1539 }
1540
1541 #[inline]
1543 pub fn selector_length(&self) -> usize {
1544 self.iter.len()
1545 }
1546}
1547
1548impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
1549 type Item = &'a Component<Impl>;
1550
1551 #[inline]
1552 fn next(&mut self) -> Option<Self::Item> {
1553 debug_assert!(
1554 self.next_combinator.is_none(),
1555 "You should call next_sequence!"
1556 );
1557 match *self.iter.next()? {
1558 Component::Combinator(c) => {
1559 self.next_combinator = Some(c);
1560 None
1561 },
1562 ref x => Some(x),
1563 }
1564 }
1565}
1566
1567impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
1568 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1569 let iter = self.iter.clone().rev();
1570 for component in iter {
1571 component.to_css(f)?
1572 }
1573 Ok(())
1574 }
1575}
1576
1577struct CombinatorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1579impl<'a, Impl: 'a + SelectorImpl> CombinatorIter<'a, Impl> {
1580 fn new(inner: SelectorIter<'a, Impl>) -> Self {
1581 let mut result = CombinatorIter(inner);
1582 result.consume_non_combinators();
1583 result
1584 }
1585
1586 fn consume_non_combinators(&mut self) {
1587 while self.0.next().is_some() {}
1588 }
1589}
1590
1591impl<'a, Impl: SelectorImpl> Iterator for CombinatorIter<'a, Impl> {
1592 type Item = Combinator;
1593 fn next(&mut self) -> Option<Self::Item> {
1594 let result = self.0.next_sequence();
1595 self.consume_non_combinators();
1596 result
1597 }
1598}
1599
1600struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1602impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
1603 type Item = &'a Component<Impl>;
1604 fn next(&mut self) -> Option<Self::Item> {
1605 let next = self.0.next();
1607 if next.is_some() {
1608 return next;
1609 }
1610 if !self.0.next_sequence()?.is_ancestor() {
1612 self.0.skip_until_ancestor();
1613 }
1614 self.0.next()
1615 }
1616}
1617
1618#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1619#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1620pub enum Combinator {
1621 Child, Descendant, NextSibling, LaterSibling, PseudoElement,
1632 SlotAssignment,
1635 Part,
1638}
1639
1640impl Combinator {
1641 #[inline]
1643 pub fn is_pseudo_element(&self) -> bool {
1644 matches!(*self, Combinator::PseudoElement)
1645 }
1646
1647 #[inline]
1649 pub fn is_sibling(&self) -> bool {
1650 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
1651 }
1652
1653 #[inline]
1656 pub fn is_ancestor(&self) -> bool {
1657 !self.is_sibling()
1658 }
1659}
1660
1661#[derive(Copy, Clone, Eq, PartialEq)]
1663#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1664#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1665pub enum NthType {
1666 Child,
1667 LastChild,
1668 OnlyChild,
1669 OfType,
1670 LastOfType,
1671 OnlyOfType,
1672}
1673
1674impl NthType {
1675 pub fn is_only(self) -> bool {
1676 self == Self::OnlyChild || self == Self::OnlyOfType
1677 }
1678
1679 pub fn is_of_type(self) -> bool {
1680 self == Self::OfType || self == Self::LastOfType || self == Self::OnlyOfType
1681 }
1682
1683 pub fn is_from_end(self) -> bool {
1684 self == Self::LastChild || self == Self::LastOfType
1685 }
1686}
1687
1688#[derive(Copy, Clone, Eq, PartialEq, Debug)]
1690#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1691#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1692pub struct AnPlusB(pub i32, pub i32);
1693
1694impl AnPlusB {
1695 #[inline]
1696 pub fn matches_index(&self, i: i32) -> bool {
1697 match i.checked_sub(self.1) {
1699 None => false,
1700 Some(an) => match an.checked_div(self.0) {
1701 Some(n) => n >= 0 && self.0 * n == an,
1702 None => an == 0,
1703 },
1704 }
1705 }
1706}
1707
1708impl ToCss for AnPlusB {
1709 #[inline]
1712 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1713 where
1714 W: fmt::Write,
1715 {
1716 match (self.0, self.1) {
1717 (0, 0) => dest.write_char('0'),
1718
1719 (1, 0) => dest.write_char('n'),
1720 (-1, 0) => dest.write_str("-n"),
1721 (_, 0) => write!(dest, "{}n", self.0),
1722
1723 (0, _) => write!(dest, "{}", self.1),
1724 (1, _) => write!(dest, "n{:+}", self.1),
1725 (-1, _) => write!(dest, "-n{:+}", self.1),
1726 (_, _) => write!(dest, "{}n{:+}", self.0, self.1),
1727 }
1728 }
1729}
1730
1731#[derive(Copy, Clone, Eq, PartialEq)]
1735#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1736#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1737pub struct NthSelectorData {
1738 pub ty: NthType,
1739 pub is_function: bool,
1740 pub an_plus_b: AnPlusB,
1741}
1742
1743impl NthSelectorData {
1744 #[inline]
1746 pub const fn only(of_type: bool) -> Self {
1747 Self {
1748 ty: if of_type {
1749 NthType::OnlyOfType
1750 } else {
1751 NthType::OnlyChild
1752 },
1753 is_function: false,
1754 an_plus_b: AnPlusB(0, 1),
1755 }
1756 }
1757
1758 #[inline]
1760 pub const fn first(of_type: bool) -> Self {
1761 Self {
1762 ty: if of_type {
1763 NthType::OfType
1764 } else {
1765 NthType::Child
1766 },
1767 is_function: false,
1768 an_plus_b: AnPlusB(0, 1),
1769 }
1770 }
1771
1772 #[inline]
1774 pub const fn last(of_type: bool) -> Self {
1775 Self {
1776 ty: if of_type {
1777 NthType::LastOfType
1778 } else {
1779 NthType::LastChild
1780 },
1781 is_function: false,
1782 an_plus_b: AnPlusB(0, 1),
1783 }
1784 }
1785
1786 #[inline]
1788 pub fn is_simple_edge(&self) -> bool {
1789 self.an_plus_b.0 == 0
1790 && self.an_plus_b.1 == 1
1791 && !self.ty.is_of_type()
1792 && !self.ty.is_only()
1793 }
1794
1795 #[inline]
1797 fn write_start<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1798 dest.write_str(match self.ty {
1799 NthType::Child if self.is_function => ":nth-child(",
1800 NthType::Child => ":first-child",
1801 NthType::LastChild if self.is_function => ":nth-last-child(",
1802 NthType::LastChild => ":last-child",
1803 NthType::OfType if self.is_function => ":nth-of-type(",
1804 NthType::OfType => ":first-of-type",
1805 NthType::LastOfType if self.is_function => ":nth-last-of-type(",
1806 NthType::LastOfType => ":last-of-type",
1807 NthType::OnlyChild => ":only-child",
1808 NthType::OnlyOfType => ":only-of-type",
1809 })
1810 }
1811
1812 #[inline]
1813 fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1814 self.an_plus_b.to_css(dest)
1815 }
1816}
1817
1818#[derive(Clone, Eq, PartialEq)]
1822#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1823#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1824pub struct NthOfSelectorData<Impl: SelectorImpl>(
1825 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] ThinArc<NthSelectorData, Selector<Impl>>,
1826);
1827
1828impl<Impl: SelectorImpl> NthOfSelectorData<Impl> {
1829 #[inline]
1831 pub fn new<I>(nth_data: &NthSelectorData, selectors: I) -> Self
1832 where
1833 I: Iterator<Item = Selector<Impl>> + ExactSizeIterator,
1834 {
1835 Self(ThinArc::from_header_and_iter(*nth_data, selectors))
1836 }
1837
1838 #[inline]
1840 pub fn nth_data(&self) -> &NthSelectorData {
1841 &self.0.header
1842 }
1843
1844 #[inline]
1846 pub fn selectors(&self) -> &[Selector<Impl>] {
1847 self.0.slice()
1848 }
1849}
1850
1851#[derive(Clone, Copy, Eq, PartialEq)]
1853#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1854pub enum RelativeSelectorMatchHint {
1855 InSubtree,
1857 InChild,
1859 InNextSibling,
1861 InNextSiblingSubtree,
1863 InSibling,
1865 InSiblingSubtree,
1867}
1868
1869impl RelativeSelectorMatchHint {
1870 pub fn new(
1872 relative_combinator: Combinator,
1873 has_child_or_descendants: bool,
1874 has_adjacent_or_next_siblings: bool,
1875 ) -> Self {
1876 match relative_combinator {
1877 Combinator::Descendant => RelativeSelectorMatchHint::InSubtree,
1878 Combinator::Child => {
1879 if !has_child_or_descendants {
1880 RelativeSelectorMatchHint::InChild
1881 } else {
1882 RelativeSelectorMatchHint::InSubtree
1885 }
1886 },
1887 Combinator::NextSibling => {
1888 if !has_child_or_descendants && !has_adjacent_or_next_siblings {
1889 RelativeSelectorMatchHint::InNextSibling
1890 } else if !has_child_or_descendants && has_adjacent_or_next_siblings {
1891 RelativeSelectorMatchHint::InSibling
1892 } else if has_child_or_descendants && !has_adjacent_or_next_siblings {
1893 RelativeSelectorMatchHint::InNextSiblingSubtree
1895 } else {
1896 RelativeSelectorMatchHint::InSiblingSubtree
1897 }
1898 },
1899 Combinator::LaterSibling => {
1900 if !has_child_or_descendants {
1901 RelativeSelectorMatchHint::InSibling
1902 } else {
1903 RelativeSelectorMatchHint::InSiblingSubtree
1906 }
1907 },
1908 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1909 debug_assert!(false, "Unexpected relative combinator");
1910 RelativeSelectorMatchHint::InSubtree
1911 },
1912 }
1913 }
1914
1915 pub fn is_descendant_direction(&self) -> bool {
1917 matches!(*self, Self::InChild | Self::InSubtree)
1918 }
1919
1920 pub fn is_next_sibling(&self) -> bool {
1922 matches!(*self, Self::InNextSibling | Self::InNextSiblingSubtree)
1923 }
1924
1925 pub fn is_subtree(&self) -> bool {
1927 matches!(
1928 *self,
1929 Self::InSubtree | Self::InSiblingSubtree | Self::InNextSiblingSubtree
1930 )
1931 }
1932}
1933
1934#[derive(Clone, Copy)]
1936pub struct RelativeSelectorCombinatorCount {
1937 relative_combinator: Combinator,
1938 pub child_or_descendants: usize,
1939 pub adjacent_or_next_siblings: usize,
1940}
1941
1942impl RelativeSelectorCombinatorCount {
1943 pub fn new<Impl: SelectorImpl>(relative_selector: &RelativeSelector<Impl>) -> Self {
1945 let mut result = RelativeSelectorCombinatorCount {
1946 relative_combinator: relative_selector.selector.combinator_at_parse_order(1),
1947 child_or_descendants: 0,
1948 adjacent_or_next_siblings: 0,
1949 };
1950
1951 for combinator in CombinatorIter::new(
1952 relative_selector
1953 .selector
1954 .iter_skip_relative_selector_anchor(),
1955 ) {
1956 match combinator {
1957 Combinator::Descendant | Combinator::Child => {
1958 result.child_or_descendants += 1;
1959 },
1960 Combinator::NextSibling | Combinator::LaterSibling => {
1961 result.adjacent_or_next_siblings += 1;
1962 },
1963 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1964 continue;
1965 },
1966 };
1967 }
1968 result
1969 }
1970
1971 pub fn get_match_hint(&self) -> RelativeSelectorMatchHint {
1973 RelativeSelectorMatchHint::new(
1974 self.relative_combinator,
1975 self.child_or_descendants != 0,
1976 self.adjacent_or_next_siblings != 0,
1977 )
1978 }
1979}
1980
1981#[derive(Clone, Eq, PartialEq)]
1983#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1984#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1985pub struct RelativeSelector<Impl: SelectorImpl> {
1986 pub match_hint: RelativeSelectorMatchHint,
1988 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
1990 pub selector: Selector<Impl>,
1991}
1992
1993bitflags! {
1994 #[derive(Clone, Debug, Eq, PartialEq)]
1996 struct CombinatorComposition: u8 {
1997 const DESCENDANTS = 1 << 0;
1998 const SIBLINGS = 1 << 1;
1999 }
2000}
2001
2002impl CombinatorComposition {
2003 fn for_relative_selector<Impl: SelectorImpl>(inner_selector: &Selector<Impl>) -> Self {
2004 let mut result = CombinatorComposition::empty();
2005 for combinator in CombinatorIter::new(inner_selector.iter_skip_relative_selector_anchor()) {
2006 match combinator {
2007 Combinator::Descendant | Combinator::Child => {
2008 result.insert(Self::DESCENDANTS);
2009 },
2010 Combinator::NextSibling | Combinator::LaterSibling => {
2011 result.insert(Self::SIBLINGS);
2012 },
2013 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
2014 continue;
2015 },
2016 };
2017 if result.is_all() {
2018 break;
2019 }
2020 }
2021 return result;
2022 }
2023}
2024
2025impl<Impl: SelectorImpl> RelativeSelector<Impl> {
2026 fn from_selector_list(selector_list: SelectorList<Impl>) -> Box<[Self]> {
2027 selector_list
2028 .slice()
2029 .iter()
2030 .map(|selector| {
2031 if cfg!(debug_assertions) {
2034 let relative_selector_anchor = selector.iter_raw_parse_order_from(0).next();
2035 debug_assert!(
2036 relative_selector_anchor.is_some(),
2037 "Relative selector is empty"
2038 );
2039 debug_assert!(
2040 matches!(
2041 relative_selector_anchor.unwrap(),
2042 Component::RelativeSelectorAnchor
2043 ),
2044 "Relative selector anchor is missing"
2045 );
2046 }
2047 let composition = CombinatorComposition::for_relative_selector(&selector);
2049 let match_hint = RelativeSelectorMatchHint::new(
2050 selector.combinator_at_parse_order(1),
2051 composition.intersects(CombinatorComposition::DESCENDANTS),
2052 composition.intersects(CombinatorComposition::SIBLINGS),
2053 );
2054 RelativeSelector {
2055 match_hint,
2056 selector: selector.clone(),
2057 }
2058 })
2059 .collect()
2060 }
2061}
2062
2063#[derive(Clone, Eq, PartialEq)]
2068#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2069#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2070pub enum Component<Impl: SelectorImpl> {
2071 LocalName(LocalName<Impl>),
2072
2073 ID(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2074 Class(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2075
2076 AttributeInNoNamespaceExists {
2077 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2078 local_name: Impl::LocalName,
2079 local_name_lower: Impl::LocalName,
2080 },
2081 AttributeInNoNamespace {
2083 local_name: Impl::LocalName,
2084 operator: AttrSelectorOperator,
2085 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2086 value: Impl::AttrValue,
2087 case_sensitivity: ParsedCaseSensitivity,
2088 },
2089 AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
2091
2092 ExplicitUniversalType,
2093 ExplicitAnyNamespace,
2094
2095 ExplicitNoNamespace,
2096 DefaultNamespace(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl),
2097 Namespace(
2098 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespacePrefix,
2099 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl,
2100 ),
2101
2102 Negation(SelectorList<Impl>),
2104 Root,
2105 Empty,
2106 Scope,
2107 ImplicitScope,
2115 ParentSelector,
2116 Nth(NthSelectorData),
2117 NthOf(NthOfSelectorData<Impl>),
2118 NonTSPseudoClass(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NonTSPseudoClass),
2119 Slotted(Selector<Impl>),
2131 Part(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Box<[Impl::Identifier]>),
2134 Host(Option<Selector<Impl>>),
2144 Where(SelectorList<Impl>),
2151 Is(SelectorList<Impl>),
2157 Has(Box<[RelativeSelector<Impl>]>),
2163 Invalid(Arc<String>),
2165 PseudoElement(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::PseudoElement),
2167
2168 Combinator(Combinator),
2169
2170 RelativeSelectorAnchor,
2175}
2176
2177impl<Impl: SelectorImpl> Component<Impl> {
2178 #[inline]
2180 pub fn is_combinator(&self) -> bool {
2181 matches!(*self, Component::Combinator(_))
2182 }
2183
2184 #[inline]
2186 pub fn is_host(&self) -> bool {
2187 matches!(*self, Component::Host(..))
2188 }
2189
2190 pub fn as_combinator(&self) -> Option<Combinator> {
2192 match *self {
2193 Component::Combinator(c) => Some(c),
2194 _ => None,
2195 }
2196 }
2197
2198 fn matches_for_stateless_pseudo_element(&self) -> bool {
2202 match *self {
2203 Component::Negation(ref selectors) => !selectors.slice().iter().all(|selector| {
2204 selector
2205 .iter_raw_match_order()
2206 .all(|c| c.matches_for_stateless_pseudo_element())
2207 }),
2208 Component::Is(ref selectors) | Component::Where(ref selectors) => {
2209 selectors.slice().iter().any(|selector| {
2210 selector
2211 .iter_raw_match_order()
2212 .all(|c| c.matches_for_stateless_pseudo_element())
2213 })
2214 },
2215 _ => false,
2216 }
2217 }
2218
2219 pub fn visit<V>(&self, visitor: &mut V) -> bool
2220 where
2221 V: SelectorVisitor<Impl = Impl>,
2222 {
2223 use self::Component::*;
2224 if !visitor.visit_simple_selector(self) {
2225 return false;
2226 }
2227
2228 match *self {
2229 Slotted(ref selector) => {
2230 if !selector.visit(visitor) {
2231 return false;
2232 }
2233 },
2234 Host(Some(ref selector)) => {
2235 if !selector.visit(visitor) {
2236 return false;
2237 }
2238 },
2239 AttributeInNoNamespaceExists {
2240 ref local_name,
2241 ref local_name_lower,
2242 } => {
2243 if !visitor.visit_attribute_selector(
2244 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2245 local_name,
2246 local_name_lower,
2247 ) {
2248 return false;
2249 }
2250 },
2251 AttributeInNoNamespace { ref local_name, .. } => {
2252 if !visitor.visit_attribute_selector(
2253 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2254 local_name,
2255 local_name,
2256 ) {
2257 return false;
2258 }
2259 },
2260 AttributeOther(ref attr_selector) => {
2261 let empty_string;
2262 let namespace = match attr_selector.namespace() {
2263 Some(ns) => ns,
2264 None => {
2265 empty_string = crate::parser::namespace_empty_string::<Impl>();
2266 NamespaceConstraint::Specific(&empty_string)
2267 },
2268 };
2269 if !visitor.visit_attribute_selector(
2270 &namespace,
2271 &attr_selector.local_name,
2272 &attr_selector.local_name_lower,
2273 ) {
2274 return false;
2275 }
2276 },
2277
2278 NonTSPseudoClass(ref pseudo_class) => {
2279 if !pseudo_class.visit(visitor) {
2280 return false;
2281 }
2282 },
2283 Negation(ref list) | Is(ref list) | Where(ref list) => {
2284 let list_kind = SelectorListKind::from_component(self);
2285 debug_assert!(!list_kind.is_empty());
2286 if !visitor.visit_selector_list(list_kind, list.slice()) {
2287 return false;
2288 }
2289 },
2290 NthOf(ref nth_of_data) => {
2291 if !visitor.visit_selector_list(SelectorListKind::NTH_OF, nth_of_data.selectors()) {
2292 return false;
2293 }
2294 },
2295 Has(ref list) => {
2296 if !visitor.visit_relative_selector_list(list) {
2297 return false;
2298 }
2299 },
2300 _ => {},
2301 }
2302
2303 true
2304 }
2305
2306 pub fn has_indexed_selector_in_subject(&self) -> bool {
2310 match *self {
2311 Component::NthOf(..) | Component::Nth(..) => return true,
2312 Component::Is(ref selectors)
2313 | Component::Where(ref selectors)
2314 | Component::Negation(ref selectors) => {
2315 for selector in selectors.slice() {
2317 let mut iter = selector.iter();
2318 while let Some(c) = iter.next() {
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 return 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)]
2953enum QNamePrefix<Impl: SelectorImpl> {
2954 ImplicitNoNamespace, ImplicitAnyNamespace, ImplicitDefaultNamespace(Impl::NamespaceUrl), ExplicitNoNamespace, ExplicitAnyNamespace, ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), }
2961
2962type OptionalQName<'i, Impl> = Option<(QNamePrefix<Impl>, Option<CowRcStr<'i>>)>;
2963
2964fn parse_qualified_name<'i, P, Impl>(
2968 parser: &P,
2969 input: &mut CssParser<'i>,
2970 in_attr_selector: bool,
2971) -> Result<OptionalQName<'i, Impl>, ParseError<P::Error>>
2972where
2973 P: Parser<'i, Impl = Impl>,
2974 Impl: SelectorImpl,
2975{
2976 let default_namespace = |local_name| {
2977 let namespace = match parser.default_namespace() {
2978 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
2979 None => QNamePrefix::ImplicitAnyNamespace,
2980 };
2981 Ok(Some((namespace, local_name)))
2982 };
2983
2984 let explicit_namespace =
2985 |input: &mut CssParser<'i>, namespace| match input.next_including_whitespace() {
2986 Ok(&Token::Delim('*')) if !in_attr_selector => Ok(Some((namespace, None))),
2987 Ok(&Token::Ident(ref local_name)) => Ok(Some((namespace, Some(local_name.clone())))),
2988 Ok(_) => {
2989 let e = if in_attr_selector {
2990 SelectorParseErrorKind::InvalidQualNameInAttr
2991 } else {
2992 SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken
2993 };
2994 Err(ParseError::custom(e))
2995 },
2996 Err(e) => Err(e.into()),
2997 };
2998
2999 let start = input.state();
3000 match input.next_including_whitespace() {
3001 Ok(Token::Ident(value)) => {
3002 let value = value.clone();
3003 let after_ident = input.state();
3004 match input.next_including_whitespace() {
3005 Ok(&Token::Delim('|')) => {
3006 let prefix = value.as_ref().into();
3007 let result = parser.namespace_for_prefix(&prefix);
3008 let url = result.ok_or(ParseError::custom(
3009 SelectorParseErrorKind::ExpectedNamespace,
3010 ))?;
3011 explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
3012 },
3013 _ => {
3014 input.reset(&after_ident);
3015 if in_attr_selector {
3016 Ok(Some((QNamePrefix::ImplicitNoNamespace, Some(value))))
3017 } else {
3018 default_namespace(Some(value))
3019 }
3020 },
3021 }
3022 },
3023 Ok(Token::Delim('*')) => {
3024 let after_star = input.state();
3025 match input.next_including_whitespace() {
3026 Ok(&Token::Delim('|')) => {
3027 explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
3028 },
3029 _ if !in_attr_selector => {
3030 input.reset(&after_star);
3031 default_namespace(None)
3032 },
3033 result => {
3034 result?;
3035 Err(ParseError::custom(
3036 SelectorParseErrorKind::ExpectedBarInAttr,
3037 ))
3038 },
3039 }
3040 },
3041 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
3042 Ok(_) => {
3043 input.reset(&start);
3044 Ok(None)
3045 },
3046 Err(e) => {
3047 input.reset(&start);
3048 Err(e.into())
3049 },
3050 }
3051}
3052
3053fn parse_attribute_selector<'i, P, Impl>(
3054 parser: &P,
3055 input: &mut CssParser<'i>,
3056) -> Result<Component<Impl>, ParseError<P::Error>>
3057where
3058 P: Parser<'i, Impl = Impl>,
3059 Impl: SelectorImpl,
3060{
3061 let namespace;
3062 let local_name;
3063
3064 input.skip_whitespace();
3065
3066 match parse_qualified_name(parser, input, true)? {
3067 None => {
3068 return Err(ParseError::custom(
3069 SelectorParseErrorKind::NoQualifiedNameInAttributeSelector,
3070 ));
3071 },
3072 Some((_, None)) => unreachable!(),
3073 Some((ns, Some(ln))) => {
3074 local_name = ln;
3075 namespace = match ns {
3076 QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
3077 QNamePrefix::ExplicitNamespace(prefix, url) => {
3078 Some(NamespaceConstraint::Specific((prefix, url)))
3079 },
3080 QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
3081 QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
3082 unreachable!() },
3084 }
3085 },
3086 }
3087
3088 let operator = match input.next() {
3089 Err(_) => {
3091 let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
3092 let local_name = local_name.as_ref().into();
3093 if let Some(namespace) = namespace {
3094 return Ok(Component::AttributeOther(Box::new(
3095 AttrSelectorWithOptionalNamespace {
3096 namespace: Some(namespace),
3097 local_name,
3098 local_name_lower,
3099 operation: ParsedAttrSelectorOperation::Exists,
3100 },
3101 )));
3102 } else {
3103 return Ok(Component::AttributeInNoNamespaceExists {
3104 local_name,
3105 local_name_lower,
3106 });
3107 }
3108 },
3109
3110 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
3112 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
3114 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
3116 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
3118 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
3120 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
3122 Ok(_) => {
3123 return Err(ParseError::custom(
3124 SelectorParseErrorKind::UnexpectedTokenInAttributeSelector,
3125 ));
3126 },
3127 };
3128
3129 let value = match input.expect_ident_or_string() {
3130 Ok(t) => t.clone(),
3131 Err(BasicParseError {
3132 kind: BasicParseErrorKind::UnexpectedToken,
3133 }) => return Err(ParseError::custom(SelectorParseErrorKind::BadValueInAttr)),
3134 Err(e) => return Err(e.into()),
3135 };
3136
3137 let attribute_flags = parse_attribute_flags(input)?;
3138 let value = value.as_ref().into();
3139 let local_name_lower: Impl::LocalName;
3140 let local_name_is_ascii_lowercase;
3141 let case_sensitivity;
3142 {
3143 let local_name_lower_cow = to_ascii_lowercase(&local_name);
3144 case_sensitivity =
3145 attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
3146 local_name_lower = local_name_lower_cow.as_ref().into();
3147 local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
3148 }
3149 if namespace.is_some() || !local_name_is_ascii_lowercase {
3150 let local_name = if local_name_is_ascii_lowercase {
3151 local_name_lower.clone()
3152 } else {
3153 local_name.as_ref().into()
3154 };
3155 Ok(Component::AttributeOther(Box::new(
3156 AttrSelectorWithOptionalNamespace {
3157 namespace,
3158 local_name,
3159 local_name_lower,
3160 operation: ParsedAttrSelectorOperation::WithValue {
3161 operator,
3162 case_sensitivity,
3163 value,
3164 },
3165 },
3166 )))
3167 } else {
3168 Ok(Component::AttributeInNoNamespace {
3169 local_name: local_name_lower,
3170 operator,
3171 value,
3172 case_sensitivity,
3173 })
3174 }
3175}
3176
3177enum AttributeFlags {
3179 CaseSensitive,
3181 AsciiCaseInsensitive,
3183 CaseSensitivityDependsOnName,
3185}
3186
3187fn is_ascii_case_insensitive_html_attribute(name: &str) -> bool {
3198 matches!(
3199 name,
3200 "accept"
3201 | "accept-charset"
3202 | "align"
3203 | "alink"
3204 | "axis"
3205 | "bgcolor"
3206 | "charset"
3207 | "checked"
3208 | "clear"
3209 | "codetype"
3210 | "color"
3211 | "compact"
3212 | "declare"
3213 | "defer"
3214 | "dir"
3215 | "direction"
3216 | "disabled"
3217 | "enctype"
3218 | "face"
3219 | "frame"
3220 | "hreflang"
3221 | "http-equiv"
3222 | "lang"
3223 | "language"
3224 | "link"
3225 | "media"
3226 | "method"
3227 | "multiple"
3228 | "nohref"
3229 | "noresize"
3230 | "noshade"
3231 | "nowrap"
3232 | "readonly"
3233 | "rel"
3234 | "rev"
3235 | "rules"
3236 | "scope"
3237 | "scrolling"
3238 | "selected"
3239 | "shape"
3240 | "target"
3241 | "text"
3242 | "type"
3243 | "valign"
3244 | "valuetype"
3245 | "vlink"
3246 )
3247}
3248
3249impl AttributeFlags {
3250 fn to_case_sensitivity(
3251 self,
3252 local_name_lower: &str,
3253 have_namespace: bool,
3254 ) -> ParsedCaseSensitivity {
3255 match self {
3256 AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
3257 AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
3258 AttributeFlags::CaseSensitivityDependsOnName => {
3259 if !have_namespace && is_ascii_case_insensitive_html_attribute(local_name_lower) {
3260 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
3261 } else {
3262 ParsedCaseSensitivity::CaseSensitive
3263 }
3264 },
3265 }
3266 }
3267}
3268
3269fn parse_attribute_flags(input: &mut CssParser) -> Result<AttributeFlags, BasicParseError> {
3270 let token = match input.next() {
3271 Ok(t) => t,
3272 Err(..) => {
3273 return Ok(AttributeFlags::CaseSensitivityDependsOnName);
3276 },
3277 };
3278
3279 let ident = match *token {
3280 Token::Ident(ref i) => i,
3281 _ => return Err(BasicParseError::unexpected_token()),
3282 };
3283
3284 Ok(match_ignore_ascii_case! {
3285 ident,
3286 "i" => AttributeFlags::AsciiCaseInsensitive,
3287 "s" => AttributeFlags::CaseSensitive,
3288 _ => return Err(BasicParseError::unexpected_token()),
3289 })
3290}
3291
3292fn parse_negation<'i, P, Impl>(
3295 parser: &P,
3296 input: &mut CssParser<'i>,
3297 state: SelectorParsingState,
3298) -> Result<Component<Impl>, ParseError<P::Error>>
3299where
3300 P: Parser<'i, Impl = Impl>,
3301 Impl: SelectorImpl,
3302{
3303 let list = SelectorList::parse_with_state(
3304 parser,
3305 input,
3306 state
3307 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3308 | SelectorParsingState::DISALLOW_PSEUDOS,
3309 ForgivingParsing::No,
3310 ParseRelative::No,
3311 )?;
3312
3313 Ok(Component::Negation(list))
3314}
3315
3316fn parse_compound_selector<'i, P, Impl>(
3323 parser: &P,
3324 state: &mut SelectorParsingState,
3325 input: &mut CssParser<'i>,
3326 builder: &mut SelectorBuilder<Impl>,
3327) -> Result<bool, ParseError<P::Error>>
3328where
3329 P: Parser<'i, Impl = Impl>,
3330 Impl: SelectorImpl,
3331{
3332 input.skip_whitespace();
3333
3334 let mut empty = true;
3335 if parse_type_selector(parser, input, *state, builder)? {
3336 empty = false;
3337 }
3338
3339 loop {
3340 let result = match parse_one_simple_selector(parser, input, *state)? {
3341 None => break,
3342 Some(result) => result,
3343 };
3344
3345 if empty {
3346 if let Some(url) = parser.default_namespace() {
3347 let ignore_default_ns = state
3375 .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
3386 empty = false;
3387
3388 match result {
3389 SimpleSelectorParseResult::SimpleSelector(s) => {
3390 builder.push_simple_selector(s);
3391 },
3392 SimpleSelectorParseResult::PartPseudo(part_names) => {
3393 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3394 builder.push_combinator(Combinator::Part);
3395 builder.push_simple_selector(Component::Part(part_names));
3396 },
3397 SimpleSelectorParseResult::SlottedPseudo(selector) => {
3398 state.insert(SelectorParsingState::AFTER_SLOTTED);
3399 builder.push_combinator(Combinator::SlotAssignment);
3400 builder.push_simple_selector(Component::Slotted(selector));
3401 },
3402 SimpleSelectorParseResult::PseudoElement(p) => {
3403 if p.parses_as_element_backed() {
3404 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3405 } else {
3406 state.insert(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO);
3407 if p.is_before_or_after() {
3408 state.insert(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO);
3409 }
3410 }
3411 if !p.accepts_state_pseudo_classes() {
3412 state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
3413 }
3414 if p.is_in_pseudo_element_tree() {
3415 state.insert(SelectorParsingState::IN_PSEUDO_ELEMENT_TREE);
3416 }
3417 builder.push_combinator(Combinator::PseudoElement);
3418 builder.push_simple_selector(Component::PseudoElement(p));
3419 },
3420 }
3421 }
3422 Ok(empty)
3423}
3424
3425fn parse_is_where<'i, P, Impl>(
3426 parser: &P,
3427 input: &mut CssParser<'i>,
3428 state: SelectorParsingState,
3429 component: impl FnOnce(SelectorList<Impl>) -> Component<Impl>,
3430) -> Result<Component<Impl>, ParseError<P::Error>>
3431where
3432 P: Parser<'i, Impl = Impl>,
3433 Impl: SelectorImpl,
3434{
3435 debug_assert!(parser.parse_is_and_where());
3436 let inner = SelectorList::parse_with_state(
3442 parser,
3443 input,
3444 state
3445 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3446 | SelectorParsingState::DISALLOW_PSEUDOS,
3447 ForgivingParsing::Yes,
3448 ParseRelative::No,
3449 )?;
3450 Ok(component(inner))
3451}
3452
3453fn parse_has<'i, P, Impl>(
3454 parser: &P,
3455 input: &mut CssParser<'i>,
3456 state: SelectorParsingState,
3457) -> Result<Component<Impl>, ParseError<P::Error>>
3458where
3459 P: Parser<'i, Impl = Impl>,
3460 Impl: SelectorImpl,
3461{
3462 debug_assert!(parser.parse_has());
3463 if state.intersects(
3464 SelectorParsingState::DISALLOW_RELATIVE_SELECTOR | SelectorParsingState::AFTER_PSEUDO,
3465 ) {
3466 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3467 }
3468 let inner = SelectorList::parse_with_state(
3473 parser,
3474 input,
3475 state
3476 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3477 | SelectorParsingState::DISALLOW_PSEUDOS
3478 | SelectorParsingState::DISALLOW_RELATIVE_SELECTOR,
3479 ForgivingParsing::No,
3480 ParseRelative::ForHas,
3481 )?;
3482 Ok(Component::Has(RelativeSelector::from_selector_list(inner)))
3483}
3484
3485fn parse_functional_pseudo_class<'i, P, Impl>(
3486 parser: &P,
3487 input: &mut CssParser<'i>,
3488 name: CowRcStr<'i>,
3489 state: SelectorParsingState,
3490) -> Result<Component<Impl>, ParseError<P::Error>>
3491where
3492 P: Parser<'i, Impl = Impl>,
3493 Impl: SelectorImpl,
3494{
3495 match_ignore_ascii_case! { &name,
3496 "nth-child" => return parse_nth_pseudo_class(parser, input, state, NthType::Child),
3497 "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::OfType),
3498 "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, NthType::LastChild),
3499 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::LastOfType),
3500 "is" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Is),
3501 "where" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Where),
3502 "has" if parser.parse_has() => return parse_has(parser, input, state),
3503 "host" => {
3504 if !state.allows_tree_structural_pseudo_classes() {
3505 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3506 }
3507 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
3508 },
3509 "not" => {
3510 return parse_negation(parser, input, state)
3511 },
3512 _ => {}
3513 }
3514
3515 if parser.parse_is_and_where() && parser.is_is_alias(&name) {
3516 return parse_is_where(parser, input, state, Component::Is);
3517 }
3518
3519 if state.intersects(
3520 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO | SelectorParsingState::AFTER_SLOTTED,
3521 ) {
3522 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3523 }
3524
3525 let after_part = state.intersects(SelectorParsingState::AFTER_PART_LIKE);
3526 P::parse_non_ts_functional_pseudo_class(parser, name, input, after_part)
3527 .map(Component::NonTSPseudoClass)
3528}
3529
3530fn parse_nth_pseudo_class<'i, P, Impl>(
3531 parser: &P,
3532 input: &mut CssParser<'i>,
3533 state: SelectorParsingState,
3534 ty: NthType,
3535) -> Result<Component<Impl>, ParseError<P::Error>>
3536where
3537 P: Parser<'i, Impl = Impl>,
3538 Impl: SelectorImpl,
3539{
3540 if !state.allows_tree_structural_pseudo_classes() {
3541 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3542 }
3543 let (a, b) = parse_nth(input)?;
3544 let nth_data = NthSelectorData {
3545 ty,
3546 is_function: true,
3547 an_plus_b: AnPlusB(a, b),
3548 };
3549 if !parser.parse_nth_child_of() || ty.is_of_type() {
3550 return Ok(Component::Nth(nth_data));
3551 }
3552
3553 if input.try_parse(|i| i.expect_ident_matching("of")).is_err() {
3555 return Ok(Component::Nth(nth_data));
3556 }
3557 let selectors = SelectorList::parse_with_state(
3560 parser,
3561 input,
3562 state
3563 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3564 | SelectorParsingState::DISALLOW_PSEUDOS,
3565 ForgivingParsing::No,
3566 ParseRelative::No,
3567 )?;
3568 Ok(Component::NthOf(NthOfSelectorData::new(
3569 &nth_data,
3570 selectors.slice().iter().cloned(),
3571 )))
3572}
3573
3574pub fn is_css2_pseudo_element(name: &str) -> bool {
3578 match_ignore_ascii_case! { name,
3580 "before" | "after" | "first-line" | "first-letter" => true,
3581 _ => false,
3582 }
3583}
3584
3585fn parse_one_simple_selector<'i, P, Impl>(
3591 parser: &P,
3592 input: &mut CssParser<'i>,
3593 state: SelectorParsingState,
3594) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<P::Error>>
3595where
3596 P: Parser<'i, Impl = Impl>,
3597 Impl: SelectorImpl,
3598{
3599 let start = input.state();
3600 let token = match input.next_including_whitespace().map(|t| t.clone()) {
3601 Ok(t) => t,
3602 Err(..) => {
3603 input.reset(&start);
3604 return Ok(None);
3605 },
3606 };
3607
3608 Ok(Some(match token {
3609 Token::IDHash(id) => {
3610 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3611 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3612 }
3613 let id = Component::ID(id.as_ref().into());
3614 SimpleSelectorParseResult::SimpleSelector(id)
3615 },
3616 Token::Delim(delim) if delim == '.' || (delim == '&' && parser.parse_parent_selector()) => {
3617 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3618 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3619 }
3620 SimpleSelectorParseResult::SimpleSelector(if delim == '&' {
3621 Component::ParentSelector
3622 } else {
3623 let class = match *input.next_including_whitespace()? {
3624 Token::Ident(ref class) => class,
3625 _ => {
3626 let e = SelectorParseErrorKind::ClassNeedsIdent;
3627 return Err(ParseError::custom(e));
3628 },
3629 };
3630 Component::Class(class.as_ref().into())
3631 })
3632 },
3633 Token::SquareBracketBlock => {
3634 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3635 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3636 }
3637 let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
3638 SimpleSelectorParseResult::SimpleSelector(attr)
3639 },
3640 Token::Colon => {
3641 let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
3642 Token::Colon => (false, input.next_including_whitespace()?.clone()),
3643 t => (true, t),
3644 };
3645 let (name, is_functional) = match next_token {
3646 Token::Ident(name) => (name, false),
3647 Token::Function(name) => (name, true),
3648 _ => {
3649 let e = SelectorParseErrorKind::PseudoElementExpectedIdent;
3650 return Err(ParseError::custom(e));
3651 },
3652 };
3653 let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name);
3654 if is_pseudo_element {
3655 if state.intersects(SelectorParsingState::DISALLOW_PSEUDOS)
3661 || (state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3662 && !state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO))
3663 {
3664 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3665 }
3666 let pseudo_element = if is_functional {
3667 if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
3668 if !state.allows_part() {
3669 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3670 }
3671 let names = input.parse_nested_block(|input| {
3672 let mut result = Vec::with_capacity(1);
3673 result.push(input.expect_ident()?.as_ref().into());
3674 while !input.is_exhausted() {
3675 result.push(input.expect_ident()?.as_ref().into());
3676 }
3677 Ok(result.into_boxed_slice())
3678 })?;
3679 return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
3680 }
3681 if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
3682 if !state.allows_slotted() {
3683 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3684 }
3685 let selector = input.parse_nested_block(|input| {
3686 parse_inner_compound_selector(parser, input, state)
3687 })?;
3688 return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
3689 }
3690 input.parse_nested_block(|input| {
3691 P::parse_functional_pseudo_element(parser, name, input)
3692 })?
3693 } else {
3694 P::parse_pseudo_element(parser, name)?
3695 };
3696
3697 if state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO)
3698 && !pseudo_element.valid_after_before_or_after()
3699 {
3700 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3701 }
3702
3703 if state.intersects(SelectorParsingState::AFTER_SLOTTED)
3704 && !pseudo_element.valid_after_slotted()
3705 {
3706 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3707 }
3708 SimpleSelectorParseResult::PseudoElement(pseudo_element)
3709 } else {
3710 let pseudo_class = if is_functional {
3711 input.parse_nested_block(|input| {
3712 parse_functional_pseudo_class(parser, input, name, state)
3713 })?
3714 } else {
3715 parse_simple_pseudo_class(parser, name, state)?
3716 };
3717 SimpleSelectorParseResult::SimpleSelector(pseudo_class)
3718 }
3719 },
3720 _ => {
3721 input.reset(&start);
3722 return Ok(None);
3723 },
3724 }))
3725}
3726
3727fn parse_simple_pseudo_class<'i, P, Impl>(
3728 parser: &P,
3729 name: CowRcStr<'i>,
3730 state: SelectorParsingState,
3731) -> Result<Component<Impl>, ParseError<P::Error>>
3732where
3733 P: Parser<'i, Impl = Impl>,
3734 Impl: SelectorImpl,
3735{
3736 if !state.allows_non_functional_pseudo_classes() {
3737 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3738 }
3739
3740 if state.allows_tree_structural_pseudo_classes() {
3741 if state.allows_only_child_pseudo_class_only() {
3746 if name.eq_ignore_ascii_case("only-child") {
3747 return Ok(Component::Nth(NthSelectorData::only(
3748 false,
3749 )));
3750 }
3751 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3755 }
3756
3757 match_ignore_ascii_case! { &name,
3758 "first-child" => return Ok(Component::Nth(NthSelectorData::first(false))),
3759 "last-child" => return Ok(Component::Nth(NthSelectorData::last(false))),
3760 "only-child" => return Ok(Component::Nth(NthSelectorData::only(false))),
3761 "root" => return Ok(Component::Root),
3762 "empty" => return Ok(Component::Empty),
3763 "scope" => return Ok(Component::Scope),
3764 "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
3765 "first-of-type" => return Ok(Component::Nth(NthSelectorData::first(true))),
3766 "last-of-type" => return Ok(Component::Nth(NthSelectorData::last(true))),
3767 "only-of-type" => return Ok(Component::Nth(NthSelectorData::only(true))),
3768 _ => {},
3769 }
3770 }
3771
3772 let pseudo_class = P::parse_non_ts_pseudo_class(parser, name)?;
3773 if state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3774 && !pseudo_class.is_user_action_state()
3775 {
3776 return Err(ParseError::custom(SelectorParseErrorKind::InvalidState));
3777 }
3778 Ok(Component::NonTSPseudoClass(pseudo_class))
3779}
3780
3781#[cfg(test)]
3783pub mod tests {
3784 use super::*;
3785 use crate::builder::SelectorFlags;
3786 use crate::parser;
3787 use cssparser::{serialize_identifier, Parser as CssParser, ToCss};
3788 use std::collections::HashMap;
3789 use std::fmt;
3790
3791 #[derive(Clone, Debug, Eq, PartialEq)]
3792 pub enum PseudoClass {
3793 Hover,
3794 Active,
3795 Lang(String),
3796 }
3797
3798 #[derive(Clone, Debug, Eq, PartialEq)]
3799 pub enum PseudoElement {
3800 Before,
3801 After,
3802 Marker,
3803 DetailsContent,
3804 Highlight(String),
3805 }
3806
3807 impl parser::PseudoElement for PseudoElement {
3808 fn accepts_state_pseudo_classes(&self) -> bool {
3809 true
3810 }
3811
3812 fn valid_after_slotted(&self) -> bool {
3813 true
3814 }
3815
3816 fn valid_after_before_or_after(&self) -> bool {
3817 matches!(self, Self::Marker)
3818 }
3819
3820 fn is_before_or_after(&self) -> bool {
3821 matches!(self, Self::Before | Self::After)
3822 }
3823
3824 fn parses_as_element_backed(&self) -> bool {
3825 matches!(self, Self::DetailsContent)
3826 }
3827 }
3828
3829 impl parser::NonTSPseudoClass for PseudoClass {
3830 #[inline]
3831 fn is_active_or_hover(&self) -> bool {
3832 matches!(*self, PseudoClass::Active | PseudoClass::Hover)
3833 }
3834
3835 #[inline]
3836 fn is_user_action_state(&self) -> bool {
3837 self.is_active_or_hover()
3838 }
3839 }
3840
3841 impl ToCss for PseudoClass {
3842 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3843 where
3844 W: fmt::Write,
3845 {
3846 match *self {
3847 PseudoClass::Hover => dest.write_str(":hover"),
3848 PseudoClass::Active => dest.write_str(":active"),
3849 PseudoClass::Lang(ref lang) => {
3850 dest.write_str(":lang(")?;
3851 serialize_identifier(lang, dest)?;
3852 dest.write_char(')')
3853 },
3854 }
3855 }
3856 }
3857
3858 impl ToCss for PseudoElement {
3859 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3860 where
3861 W: fmt::Write,
3862 {
3863 match *self {
3864 PseudoElement::Before => dest.write_str("::before"),
3865 PseudoElement::After => dest.write_str("::after"),
3866 PseudoElement::Marker => dest.write_str("::marker"),
3867 PseudoElement::DetailsContent => dest.write_str("::details-content"),
3868 PseudoElement::Highlight(ref name) => {
3869 dest.write_str("::highlight(")?;
3870 serialize_identifier(&name, dest)?;
3871 dest.write_char(')')
3872 },
3873 }
3874 }
3875 }
3876
3877 #[derive(Clone, Debug, PartialEq)]
3878 pub struct DummySelectorImpl;
3879
3880 #[derive(Default)]
3881 pub struct DummyParser {
3882 default_ns: Option<DummyAtom>,
3883 ns_prefixes: HashMap<DummyAtom, DummyAtom>,
3884 }
3885
3886 impl DummyParser {
3887 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
3888 DummyParser {
3889 default_ns: Some(default_ns),
3890 ns_prefixes: Default::default(),
3891 }
3892 }
3893 }
3894
3895 impl SelectorImpl for DummySelectorImpl {
3896 type ExtraMatchingData<'a> = std::marker::PhantomData<&'a ()>;
3897 type AttrValue = DummyAttrValue;
3898 type Identifier = DummyAtom;
3899 type LocalName = DummyAtom;
3900 type NamespaceUrl = DummyAtom;
3901 type NamespacePrefix = DummyAtom;
3902 type BorrowedLocalName = DummyAtom;
3903 type BorrowedNamespaceUrl = DummyAtom;
3904 type NonTSPseudoClass = PseudoClass;
3905 type PseudoElement = PseudoElement;
3906 }
3907
3908 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3909 pub struct DummyAttrValue(String);
3910
3911 impl ToCss for DummyAttrValue {
3912 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3913 where
3914 W: fmt::Write,
3915 {
3916 use std::fmt::Write;
3917
3918 dest.write_char('"')?;
3919 write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)?;
3920 dest.write_char('"')
3921 }
3922 }
3923
3924 impl<'a> From<&'a str> for DummyAttrValue {
3925 fn from(string: &'a str) -> Self {
3926 Self(string.into())
3927 }
3928 }
3929
3930 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3931 pub struct DummyAtom(String);
3932
3933 impl ToCss for DummyAtom {
3934 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3935 where
3936 W: fmt::Write,
3937 {
3938 serialize_identifier(&self.0, dest)
3939 }
3940 }
3941
3942 impl From<String> for DummyAtom {
3943 fn from(string: String) -> Self {
3944 DummyAtom(string)
3945 }
3946 }
3947
3948 impl<'a> From<&'a str> for DummyAtom {
3949 fn from(string: &'a str) -> Self {
3950 DummyAtom(string.into())
3951 }
3952 }
3953
3954 impl PrecomputedHash for DummyAtom {
3955 fn precomputed_hash(&self) -> u32 {
3956 self.0.as_ptr() as u32
3957 }
3958 }
3959
3960 impl<'i> Parser<'i> for DummyParser {
3961 type Impl = DummySelectorImpl;
3962 type Error = SelectorParseErrorKind;
3963
3964 fn parse_slotted(&self) -> bool {
3965 true
3966 }
3967
3968 fn parse_nth_child_of(&self) -> bool {
3969 true
3970 }
3971
3972 fn parse_is_and_where(&self) -> bool {
3973 true
3974 }
3975
3976 fn parse_has(&self) -> bool {
3977 true
3978 }
3979
3980 fn parse_parent_selector(&self) -> bool {
3981 true
3982 }
3983
3984 fn parse_part(&self) -> bool {
3985 true
3986 }
3987
3988 fn parse_host(&self) -> bool {
3989 true
3990 }
3991
3992 fn parse_non_ts_pseudo_class(
3993 &self,
3994 name: CowRcStr<'i>,
3995 ) -> 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: CowRcStr<'i>,
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(
4025 &self,
4026 name: CowRcStr<'i>,
4027 ) -> Result<PseudoElement, SelectorParseError> {
4028 match_ignore_ascii_case! { &name,
4029 "before" => return Ok(PseudoElement::Before),
4030 "after" => return Ok(PseudoElement::After),
4031 "marker" => return Ok(PseudoElement::Marker),
4032 "details-content" => return Ok(PseudoElement::DetailsContent),
4033 _ => {}
4034 }
4035 Err(ParseError::custom(
4036 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
4037 ))
4038 }
4039
4040 fn parse_functional_pseudo_element(
4041 &self,
4042 name: CowRcStr<'i>,
4043 parser: &mut CssParser<'i>,
4044 ) -> Result<PseudoElement, SelectorParseError> {
4045 match_ignore_ascii_case! { &name,
4046 "highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())),
4047 _ => {}
4048 }
4049 Err(ParseError::custom(
4050 SelectorParseErrorKind::UnsupportedPseudoClassOrElement,
4051 ))
4052 }
4053
4054 fn default_namespace(&self) -> Option<DummyAtom> {
4055 self.default_ns.clone()
4056 }
4057
4058 fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
4059 self.ns_prefixes.get(prefix).cloned()
4060 }
4061 }
4062
4063 fn parse<'i>(input: &'i str) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4064 parse_relative(input, ParseRelative::No)
4065 }
4066
4067 fn parse_relative<'i>(
4068 input: &'i str,
4069 parse_relative: ParseRelative,
4070 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4071 parse_ns_relative(input, &DummyParser::default(), parse_relative)
4072 }
4073
4074 fn parse_expected<'i, 'a>(
4075 input: &'i str,
4076 expected: Option<&'a str>,
4077 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4078 parse_ns_expected(input, &DummyParser::default(), expected)
4079 }
4080
4081 fn parse_relative_expected<'i, 'a>(
4082 input: &'i str,
4083 parse_relative: ParseRelative,
4084 expected: Option<&'a str>,
4085 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4086 parse_ns_relative_expected(input, &DummyParser::default(), parse_relative, expected)
4087 }
4088
4089 fn parse_ns<'i>(
4090 input: &'i str,
4091 parser: &DummyParser,
4092 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4093 parse_ns_relative(input, parser, ParseRelative::No)
4094 }
4095
4096 fn parse_ns_relative<'i>(
4097 input: &'i str,
4098 parser: &DummyParser,
4099 parse_relative: ParseRelative,
4100 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4101 parse_ns_relative_expected(input, parser, parse_relative, None)
4102 }
4103
4104 fn parse_ns_expected<'i, 'a>(
4105 input: &'i str,
4106 parser: &DummyParser,
4107 expected: Option<&'a str>,
4108 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4109 parse_ns_relative_expected(input, parser, ParseRelative::No, expected)
4110 }
4111
4112 fn parse_ns_relative_expected<'i, 'a>(
4113 input: &'i str,
4114 parser: &DummyParser,
4115 parse_relative: ParseRelative,
4116 expected: Option<&'a str>,
4117 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError> {
4118 let result = SelectorList::parse(parser, &mut CssParser::new(input), parse_relative);
4119 if let Ok(ref selectors) = result {
4120 assert_eq!(
4124 selectors.to_css_string(),
4125 match expected {
4126 Some(x) => x,
4127 None => input,
4128 }
4129 );
4130 }
4131 result
4132 }
4133
4134 fn specificity(a: u32, b: u32, c: u32) -> u32 {
4135 a << 20 | b << 10 | c
4136 }
4137
4138 #[test]
4139 fn test_ancestor_hashes_in_subject_position() {
4140 fn ancestor_hash_count(selector: &str) -> usize {
4141 let list = parse(selector).unwrap();
4142 assert_eq!(list.slice().len(), 1);
4143 let mut hashes = [0u32; 4];
4144 let mut len = 0;
4145 collect_ancestor_hashes(
4146 list.slice()[0].iter(),
4147 QuirksMode::NoQuirks,
4148 &mut hashes,
4149 &mut len,
4150 );
4151 len
4152 }
4153
4154 assert_eq!(ancestor_hash_count(".subject"), 0);
4156 assert_eq!(ancestor_hash_count(":where(.subject)"), 0);
4157
4158 assert_eq!(ancestor_hash_count(":where(.ancestor > .subject)"), 1);
4161 assert_eq!(ancestor_hash_count(":is(.ancestor .subject)"), 1);
4162 assert_eq!(
4163 ancestor_hash_count(":where(.ancestor > :not(:last-child))"),
4164 1
4165 );
4166
4167 assert_eq!(
4170 ancestor_hash_count(".real-ancestor :where(.inner-ancestor > .subject)"),
4171 2
4172 );
4173
4174 assert_eq!(ancestor_hash_count(":is(.a, .b) .subject"), 0);
4178 assert_eq!(
4179 ancestor_hash_count(":where(.ancestor > .subject, .other)"),
4180 0
4181 );
4182 assert_eq!(ancestor_hash_count(".real-ancestor :where(.a > .b, .c)"), 1);
4185
4186 assert_eq!(ancestor_hash_count(".subject::before"), 0);
4190 assert_eq!(ancestor_hash_count(".real-ancestor .subject::before"), 1);
4191 assert_eq!(
4194 ancestor_hash_count(":where(.ancestor > .subject)::before"),
4195 1
4196 );
4197 }
4198
4199 #[test]
4200 fn test_empty() {
4201 let list = SelectorList::parse(
4202 &DummyParser::default(),
4203 &mut CssParser::new(":empty"),
4204 ParseRelative::No,
4205 );
4206 assert!(list.is_ok());
4207 }
4208
4209 const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
4210 const SVG: &str = "http://www.w3.org/2000/svg";
4211
4212 #[test]
4213 fn test_parsing() {
4214 assert!(parse("").is_err());
4215 assert!(parse(":lang(4)").is_err());
4216 assert!(parse(":lang(en US)").is_err());
4217 assert_eq!(
4218 parse("EeÉ"),
4219 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4220 vec![Component::LocalName(LocalName {
4221 name: DummyAtom::from("EeÉ"),
4222 lower_name: DummyAtom::from("eeÉ"),
4223 })],
4224 specificity(0, 0, 1),
4225 SelectorFlags::empty(),
4226 )]))
4227 );
4228 assert_eq!(
4229 parse("|e"),
4230 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4231 vec![
4232 Component::ExplicitNoNamespace,
4233 Component::LocalName(LocalName {
4234 name: DummyAtom::from("e"),
4235 lower_name: DummyAtom::from("e"),
4236 }),
4237 ],
4238 specificity(0, 0, 1),
4239 SelectorFlags::empty(),
4240 )]))
4241 );
4242 assert_eq!(
4245 parse_expected("*|e", Some("e")),
4246 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4247 vec![Component::LocalName(LocalName {
4248 name: DummyAtom::from("e"),
4249 lower_name: DummyAtom::from("e"),
4250 })],
4251 specificity(0, 0, 1),
4252 SelectorFlags::empty(),
4253 )]))
4254 );
4255 assert_eq!(
4260 parse_ns(
4261 "*|e",
4262 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4263 ),
4264 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4265 vec![
4266 Component::ExplicitAnyNamespace,
4267 Component::LocalName(LocalName {
4268 name: DummyAtom::from("e"),
4269 lower_name: DummyAtom::from("e"),
4270 }),
4271 ],
4272 specificity(0, 0, 1),
4273 SelectorFlags::empty(),
4274 )]))
4275 );
4276 assert_eq!(
4277 parse("*"),
4278 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4279 vec![Component::ExplicitUniversalType],
4280 specificity(0, 0, 0),
4281 SelectorFlags::empty(),
4282 )]))
4283 );
4284 assert_eq!(
4285 parse("|*"),
4286 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4287 vec![
4288 Component::ExplicitNoNamespace,
4289 Component::ExplicitUniversalType,
4290 ],
4291 specificity(0, 0, 0),
4292 SelectorFlags::empty(),
4293 )]))
4294 );
4295 assert_eq!(
4296 parse_expected("*|*", Some("*")),
4297 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4298 vec![Component::ExplicitUniversalType],
4299 specificity(0, 0, 0),
4300 SelectorFlags::empty(),
4301 )]))
4302 );
4303 assert_eq!(
4304 parse_ns(
4305 "*|*",
4306 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4307 ),
4308 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4309 vec![
4310 Component::ExplicitAnyNamespace,
4311 Component::ExplicitUniversalType,
4312 ],
4313 specificity(0, 0, 0),
4314 SelectorFlags::empty(),
4315 )]))
4316 );
4317 assert_eq!(
4318 parse(".foo:lang(en-US)"),
4319 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4320 vec![
4321 Component::Class(DummyAtom::from("foo")),
4322 Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
4323 ],
4324 specificity(0, 2, 0),
4325 SelectorFlags::empty(),
4326 )]))
4327 );
4328 assert_eq!(
4329 parse("#bar"),
4330 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4331 vec![Component::ID(DummyAtom::from("bar"))],
4332 specificity(1, 0, 0),
4333 SelectorFlags::empty(),
4334 )]))
4335 );
4336 assert_eq!(
4337 parse("e.foo#bar"),
4338 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4339 vec![
4340 Component::LocalName(LocalName {
4341 name: DummyAtom::from("e"),
4342 lower_name: DummyAtom::from("e"),
4343 }),
4344 Component::Class(DummyAtom::from("foo")),
4345 Component::ID(DummyAtom::from("bar")),
4346 ],
4347 specificity(1, 1, 1),
4348 SelectorFlags::empty(),
4349 )]))
4350 );
4351 assert_eq!(
4352 parse("e.foo #bar"),
4353 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4354 vec![
4355 Component::LocalName(LocalName {
4356 name: DummyAtom::from("e"),
4357 lower_name: DummyAtom::from("e"),
4358 }),
4359 Component::Class(DummyAtom::from("foo")),
4360 Component::Combinator(Combinator::Descendant),
4361 Component::ID(DummyAtom::from("bar")),
4362 ],
4363 specificity(1, 1, 1),
4364 SelectorFlags::empty(),
4365 )]))
4366 );
4367 let mut parser = DummyParser::default();
4370 assert_eq!(
4371 parse_ns("[Foo]", &parser),
4372 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4373 vec![Component::AttributeInNoNamespaceExists {
4374 local_name: DummyAtom::from("Foo"),
4375 local_name_lower: DummyAtom::from("foo"),
4376 }],
4377 specificity(0, 1, 0),
4378 SelectorFlags::empty(),
4379 )]))
4380 );
4381 assert!(parse_ns("svg|circle", &parser).is_err());
4382 parser
4383 .ns_prefixes
4384 .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
4385 assert_eq!(
4386 parse_ns("svg|circle", &parser),
4387 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4388 vec![
4389 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4390 Component::LocalName(LocalName {
4391 name: DummyAtom::from("circle"),
4392 lower_name: DummyAtom::from("circle"),
4393 }),
4394 ],
4395 specificity(0, 0, 1),
4396 SelectorFlags::empty(),
4397 )]))
4398 );
4399 assert_eq!(
4400 parse_ns("svg|*", &parser),
4401 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4402 vec![
4403 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4404 Component::ExplicitUniversalType,
4405 ],
4406 specificity(0, 0, 0),
4407 SelectorFlags::empty(),
4408 )]))
4409 );
4410 parser.default_ns = Some(MATHML.into());
4415 assert_eq!(
4416 parse_ns("[Foo]", &parser),
4417 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4418 vec![
4419 Component::DefaultNamespace(MATHML.into()),
4420 Component::AttributeInNoNamespaceExists {
4421 local_name: DummyAtom::from("Foo"),
4422 local_name_lower: DummyAtom::from("foo"),
4423 },
4424 ],
4425 specificity(0, 1, 0),
4426 SelectorFlags::empty(),
4427 )]))
4428 );
4429 assert_eq!(
4431 parse_ns("e", &parser),
4432 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4433 vec![
4434 Component::DefaultNamespace(MATHML.into()),
4435 Component::LocalName(LocalName {
4436 name: DummyAtom::from("e"),
4437 lower_name: DummyAtom::from("e"),
4438 }),
4439 ],
4440 specificity(0, 0, 1),
4441 SelectorFlags::empty(),
4442 )]))
4443 );
4444 assert_eq!(
4445 parse_ns("*", &parser),
4446 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4447 vec![
4448 Component::DefaultNamespace(MATHML.into()),
4449 Component::ExplicitUniversalType,
4450 ],
4451 specificity(0, 0, 0),
4452 SelectorFlags::empty(),
4453 )]))
4454 );
4455 assert_eq!(
4456 parse_ns("*|*", &parser),
4457 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4458 vec![
4459 Component::ExplicitAnyNamespace,
4460 Component::ExplicitUniversalType,
4461 ],
4462 specificity(0, 0, 0),
4463 SelectorFlags::empty(),
4464 )]))
4465 );
4466 assert_eq!(
4469 parse_ns(":not(.cl)", &parser),
4470 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4471 vec![
4472 Component::DefaultNamespace(MATHML.into()),
4473 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4474 vec![Component::Class(DummyAtom::from("cl"))],
4475 specificity(0, 1, 0),
4476 SelectorFlags::empty(),
4477 )])),
4478 ],
4479 specificity(0, 1, 0),
4480 SelectorFlags::empty(),
4481 )]))
4482 );
4483 assert_eq!(
4484 parse_ns(":not(*)", &parser),
4485 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4486 vec![
4487 Component::DefaultNamespace(MATHML.into()),
4488 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4489 vec![
4490 Component::DefaultNamespace(MATHML.into()),
4491 Component::ExplicitUniversalType,
4492 ],
4493 specificity(0, 0, 0),
4494 SelectorFlags::empty(),
4495 )]),),
4496 ],
4497 specificity(0, 0, 0),
4498 SelectorFlags::empty(),
4499 )]))
4500 );
4501 assert_eq!(
4502 parse_ns(":not(e)", &parser),
4503 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4504 vec![
4505 Component::DefaultNamespace(MATHML.into()),
4506 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4507 vec![
4508 Component::DefaultNamespace(MATHML.into()),
4509 Component::LocalName(LocalName {
4510 name: DummyAtom::from("e"),
4511 lower_name: DummyAtom::from("e"),
4512 }),
4513 ],
4514 specificity(0, 0, 1),
4515 SelectorFlags::empty(),
4516 )])),
4517 ],
4518 specificity(0, 0, 1),
4519 SelectorFlags::empty(),
4520 )]))
4521 );
4522 assert_eq!(
4523 parse("[attr|=\"foo\"]"),
4524 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4525 vec![Component::AttributeInNoNamespace {
4526 local_name: DummyAtom::from("attr"),
4527 operator: AttrSelectorOperator::DashMatch,
4528 value: DummyAttrValue::from("foo"),
4529 case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
4530 }],
4531 specificity(0, 1, 0),
4532 SelectorFlags::empty(),
4533 )]))
4534 );
4535 assert_eq!(
4537 parse("::before"),
4538 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4539 vec![
4540 Component::Combinator(Combinator::PseudoElement),
4541 Component::PseudoElement(PseudoElement::Before),
4542 ],
4543 specificity(0, 0, 1),
4544 SelectorFlags::HAS_PSEUDO,
4545 )]))
4546 );
4547 assert_eq!(
4548 parse("::before:hover"),
4549 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4550 vec![
4551 Component::Combinator(Combinator::PseudoElement),
4552 Component::PseudoElement(PseudoElement::Before),
4553 Component::NonTSPseudoClass(PseudoClass::Hover),
4554 ],
4555 specificity(0, 1, 1),
4556 SelectorFlags::HAS_PSEUDO,
4557 )]))
4558 );
4559 assert_eq!(
4560 parse("::before:hover:hover"),
4561 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4562 vec![
4563 Component::Combinator(Combinator::PseudoElement),
4564 Component::PseudoElement(PseudoElement::Before),
4565 Component::NonTSPseudoClass(PseudoClass::Hover),
4566 Component::NonTSPseudoClass(PseudoClass::Hover),
4567 ],
4568 specificity(0, 2, 1),
4569 SelectorFlags::HAS_PSEUDO,
4570 )]))
4571 );
4572 assert!(parse("::before:hover:lang(foo)").is_err());
4573 assert!(parse("::before:hover .foo").is_err());
4574 assert!(parse("::before .foo").is_err());
4575 assert!(parse("::before ~ bar").is_err());
4576 assert!(parse("::before:active").is_ok());
4577
4578 assert!(parse(":: before").is_err());
4580 assert_eq!(
4581 parse("div ::after"),
4582 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4583 vec![
4584 Component::LocalName(LocalName {
4585 name: DummyAtom::from("div"),
4586 lower_name: DummyAtom::from("div"),
4587 }),
4588 Component::Combinator(Combinator::Descendant),
4589 Component::Combinator(Combinator::PseudoElement),
4590 Component::PseudoElement(PseudoElement::After),
4591 ],
4592 specificity(0, 0, 2),
4593 SelectorFlags::HAS_PSEUDO,
4594 )]))
4595 );
4596 assert_eq!(
4597 parse("#d1 > .ok"),
4598 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4599 vec![
4600 Component::ID(DummyAtom::from("d1")),
4601 Component::Combinator(Combinator::Child),
4602 Component::Class(DummyAtom::from("ok")),
4603 ],
4604 specificity(1, 1, 0),
4605 SelectorFlags::empty(),
4606 )]))
4607 );
4608 parser.default_ns = None;
4609 assert!(parse(":not(#provel.old)").is_ok());
4610 assert!(parse(":not(#provel > old)").is_ok());
4611 assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
4612 assert_eq!(
4614 parse_ns(":not(*)", &parser),
4615 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4616 vec![Component::Negation(SelectorList::from_vec(vec![
4617 Selector::from_vec(
4618 vec![Component::ExplicitUniversalType],
4619 specificity(0, 0, 0),
4620 SelectorFlags::empty(),
4621 )
4622 ]))],
4623 specificity(0, 0, 0),
4624 SelectorFlags::empty(),
4625 )]))
4626 );
4627 assert_eq!(
4628 parse_ns(":not(|*)", &parser),
4629 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4630 vec![Component::Negation(SelectorList::from_vec(vec![
4631 Selector::from_vec(
4632 vec![
4633 Component::ExplicitNoNamespace,
4634 Component::ExplicitUniversalType,
4635 ],
4636 specificity(0, 0, 0),
4637 SelectorFlags::empty(),
4638 )
4639 ]))],
4640 specificity(0, 0, 0),
4641 SelectorFlags::empty(),
4642 )]))
4643 );
4644 assert_eq!(
4647 parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
4648 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4649 vec![Component::Negation(SelectorList::from_vec(vec![
4650 Selector::from_vec(
4651 vec![Component::ExplicitUniversalType],
4652 specificity(0, 0, 0),
4653 SelectorFlags::empty(),
4654 )
4655 ]))],
4656 specificity(0, 0, 0),
4657 SelectorFlags::empty(),
4658 )]))
4659 );
4660
4661 assert!(parse("::highlight(foo)").is_ok());
4662
4663 assert!(parse("::slotted()").is_err());
4664 assert!(parse("::slotted(div)").is_ok());
4665 assert!(parse("::slotted(div).foo").is_err());
4666 assert!(parse("::slotted(div + bar)").is_err());
4667 assert!(parse("::slotted(div) + foo").is_err());
4668
4669 assert!(parse("::part()").is_err());
4670 assert!(parse("::part(42)").is_err());
4671 assert!(parse("::part(foo bar)").is_ok());
4672 assert!(parse("::part(foo):hover").is_ok());
4673 assert!(parse("::part(foo) + bar").is_err());
4674
4675 assert!(parse("div ::slotted(div)").is_ok());
4676 assert!(parse("div + slot::slotted(div)").is_ok());
4677 assert!(parse("div + slot::slotted(div.foo)").is_ok());
4678 assert!(parse("slot::slotted(div,foo)::first-line").is_err());
4679 assert!(parse("::slotted(div)::before").is_ok());
4680 assert!(parse("slot::slotted(div,foo)").is_err());
4681
4682 assert!(parse("foo:where()").is_ok());
4683 assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
4684 assert!(parse("foo:where(::before)").is_ok());
4685 }
4686
4687 #[test]
4688 fn parent_selector() {
4689 assert!(parse("foo &").is_ok());
4690 assert_eq!(
4691 parse("#foo &.bar"),
4692 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4693 vec![
4694 Component::ID(DummyAtom::from("foo")),
4695 Component::Combinator(Combinator::Descendant),
4696 Component::ParentSelector,
4697 Component::Class(DummyAtom::from("bar")),
4698 ],
4699 specificity(1, 1, 0),
4700 SelectorFlags::HAS_PARENT
4701 )]))
4702 );
4703
4704 let parent = parse(".bar, div .baz").unwrap();
4705 let child = parse("#foo &.bar").unwrap();
4706 assert_eq!(
4707 child.replace_parent_selector(&parent),
4708 parse("#foo :is(.bar, div .baz).bar").unwrap()
4709 );
4710
4711 let has_child = parse("#foo:has(&.bar)").unwrap();
4712 assert_eq!(
4713 has_child.replace_parent_selector(&parent),
4714 parse("#foo:has(:is(.bar, div .baz).bar)").unwrap()
4715 );
4716
4717 let child =
4718 parse_relative_expected("#foo", ParseRelative::ForNesting, Some("& #foo")).unwrap();
4719 assert_eq!(
4720 child.replace_parent_selector(&parent),
4721 parse(":is(.bar, div .baz) #foo").unwrap()
4722 );
4723
4724 let child =
4725 parse_relative_expected("+ #foo", ParseRelative::ForNesting, Some("& + #foo")).unwrap();
4726 assert_eq!(child, parse("& + #foo").unwrap());
4727 }
4728
4729 #[test]
4730 fn test_pseudo_iter() {
4731 let list = parse("q::before").unwrap();
4732 let selector = &list.slice()[0];
4733 assert!(!selector.is_universal());
4734 let mut iter = selector.iter();
4735 assert_eq!(
4736 iter.next(),
4737 Some(&Component::PseudoElement(PseudoElement::Before))
4738 );
4739 assert_eq!(iter.next(), None);
4740 let combinator = iter.next_sequence();
4741 assert_eq!(combinator, Some(Combinator::PseudoElement));
4742 assert_eq!(
4743 iter.next(),
4744 Some(&Component::LocalName(LocalName {
4745 name: DummyAtom::from("q"),
4746 lower_name: DummyAtom::from("q"),
4747 }))
4748 );
4749 assert_eq!(iter.next(), None);
4750 assert_eq!(iter.next_sequence(), None);
4751 }
4752
4753 #[test]
4754 fn test_pseudo_before_marker() {
4755 let list = parse("::before::marker").unwrap();
4756 let selector = &list.slice()[0];
4757 let mut iter = selector.iter();
4758 assert_eq!(
4759 iter.next(),
4760 Some(&Component::PseudoElement(PseudoElement::Marker))
4761 );
4762 assert_eq!(iter.next(), None);
4763 let combinator = iter.next_sequence();
4764 assert_eq!(combinator, Some(Combinator::PseudoElement));
4765 assert_eq!(
4766 iter.next(),
4767 Some(&Component::PseudoElement(PseudoElement::Before))
4768 );
4769 assert_eq!(iter.next(), None);
4770 let combinator = iter.next_sequence();
4771 assert_eq!(combinator, Some(Combinator::PseudoElement));
4772 assert_eq!(iter.next(), None);
4773 assert_eq!(iter.next_sequence(), None);
4774 }
4775
4776 #[test]
4777 fn test_pseudo_duplicate_before_after_or_marker() {
4778 assert!(parse("::before::before").is_err());
4779 assert!(parse("::after::after").is_err());
4780 assert!(parse("::marker::marker").is_err());
4781 }
4782
4783 #[test]
4784 fn test_pseudo_on_element_backed_pseudo() {
4785 let list = parse("::details-content::before").unwrap();
4786 let selector = &list.slice()[0];
4787 let mut iter = selector.iter();
4788 assert_eq!(
4789 iter.next(),
4790 Some(&Component::PseudoElement(PseudoElement::Before))
4791 );
4792 assert_eq!(iter.next(), None);
4793 let combinator = iter.next_sequence();
4794 assert_eq!(combinator, Some(Combinator::PseudoElement));
4795 assert_eq!(
4796 iter.next(),
4797 Some(&Component::PseudoElement(PseudoElement::DetailsContent))
4798 );
4799 assert_eq!(iter.next(), None);
4800 let combinator = iter.next_sequence();
4801 assert_eq!(combinator, Some(Combinator::PseudoElement));
4802 assert_eq!(iter.next(), None);
4803 assert_eq!(iter.next_sequence(), None);
4804 }
4805
4806 #[test]
4807 fn test_universal() {
4808 let list = parse_ns(
4809 "*|*::before",
4810 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
4811 )
4812 .unwrap();
4813 let selector = &list.slice()[0];
4814 assert!(selector.is_universal());
4815 }
4816
4817 #[test]
4818 fn test_empty_pseudo_iter() {
4819 let list = parse("::before").unwrap();
4820 let selector = &list.slice()[0];
4821 assert!(selector.is_universal());
4822 let mut iter = selector.iter();
4823 assert_eq!(
4824 iter.next(),
4825 Some(&Component::PseudoElement(PseudoElement::Before))
4826 );
4827 assert_eq!(iter.next(), None);
4828 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
4829 assert_eq!(iter.next(), None);
4830 assert_eq!(iter.next_sequence(), None);
4831 }
4832
4833 #[test]
4834 fn test_parse_implicit_scope() {
4835 assert_eq!(
4836 parse_relative_expected(".foo", ParseRelative::ForScope, None).unwrap(),
4837 SelectorList::from_vec(vec![Selector::from_vec(
4838 vec![
4839 Component::ImplicitScope,
4840 Component::Combinator(Combinator::Descendant),
4841 Component::Class(DummyAtom::from("foo")),
4842 ],
4843 specificity(0, 1, 0),
4844 SelectorFlags::HAS_SCOPE,
4845 )])
4846 );
4847
4848 assert_eq!(
4849 parse_relative_expected(":scope .foo", ParseRelative::ForScope, None).unwrap(),
4850 SelectorList::from_vec(vec![Selector::from_vec(
4851 vec![
4852 Component::Scope,
4853 Component::Combinator(Combinator::Descendant),
4854 Component::Class(DummyAtom::from("foo")),
4855 ],
4856 specificity(0, 2, 0),
4857 SelectorFlags::HAS_SCOPE
4858 )])
4859 );
4860
4861 assert_eq!(
4862 parse_relative_expected("> .foo", ParseRelative::ForScope, Some("> .foo")).unwrap(),
4863 SelectorList::from_vec(vec![Selector::from_vec(
4864 vec![
4865 Component::ImplicitScope,
4866 Component::Combinator(Combinator::Child),
4867 Component::Class(DummyAtom::from("foo")),
4868 ],
4869 specificity(0, 1, 0),
4870 SelectorFlags::HAS_SCOPE
4871 )])
4872 );
4873
4874 assert_eq!(
4875 parse_relative_expected(".foo :scope > .bar", ParseRelative::ForScope, None).unwrap(),
4876 SelectorList::from_vec(vec![Selector::from_vec(
4877 vec![
4878 Component::Class(DummyAtom::from("foo")),
4879 Component::Combinator(Combinator::Descendant),
4880 Component::Scope,
4881 Component::Combinator(Combinator::Child),
4882 Component::Class(DummyAtom::from("bar")),
4883 ],
4884 specificity(0, 3, 0),
4885 SelectorFlags::HAS_SCOPE
4886 )])
4887 );
4888 }
4889
4890 struct TestVisitor {
4891 seen: Vec<String>,
4892 }
4893
4894 impl SelectorVisitor for TestVisitor {
4895 type Impl = DummySelectorImpl;
4896
4897 fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool {
4898 let mut dest = String::new();
4899 s.to_css(&mut dest).unwrap();
4900 self.seen.push(dest);
4901 true
4902 }
4903 }
4904
4905 #[test]
4906 fn visitor() {
4907 let mut test_visitor = TestVisitor { seen: vec![] };
4908 parse(":not(:hover) ~ label").unwrap().slice()[0].visit(&mut test_visitor);
4909 assert!(test_visitor.seen.contains(&":hover".into()));
4910
4911 let mut test_visitor = TestVisitor { seen: vec![] };
4912 parse("::before:hover").unwrap().slice()[0].visit(&mut test_visitor);
4913 assert!(test_visitor.seen.contains(&":hover".into()));
4914 }
4915}