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