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(&self, offset: usize) -> Rev<slice::Iter<Component<Impl>>> {
1105 self.0.slice()[..self.len() - offset].iter().rev()
1106 }
1107
1108 #[allow(dead_code)]
1110 pub(crate) fn from_vec(
1111 vec: Vec<Component<Impl>>,
1112 specificity: u32,
1113 flags: SelectorFlags,
1114 ) -> Self {
1115 let mut builder = SelectorBuilder::default();
1116 for component in vec.into_iter() {
1117 if let Some(combinator) = component.as_combinator() {
1118 builder.push_combinator(combinator);
1119 } else {
1120 builder.push_simple_selector(component);
1121 }
1122 }
1123 let spec = SpecificityAndFlags { specificity, flags };
1124 Selector(builder.build_with_specificity_and_flags(spec, ParseRelative::No))
1125 }
1126
1127 #[inline]
1128 fn into_data(self) -> SelectorData<Impl> {
1129 self.0
1130 }
1131
1132 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
1133 let parent_specificity_and_flags = selector_list_specificity_and_flags(
1134 parent.slice().iter(),
1135 true,
1136 );
1137
1138 let mut specificity = Specificity::from(self.specificity());
1139 let mut flags = self.flags() - SelectorFlags::HAS_PARENT;
1140 let forbidden_flags = SelectorFlags::forbidden_for_nesting();
1141
1142 fn replace_parent_on_selector_list<Impl: SelectorImpl>(
1143 orig: &[Selector<Impl>],
1144 parent: &SelectorList<Impl>,
1145 specificity: &mut Specificity,
1146 flags: &mut SelectorFlags,
1147 propagate_specificity: bool,
1148 forbidden_flags: SelectorFlags,
1149 ) -> Option<SelectorList<Impl>> {
1150 if !orig.iter().any(|s| s.has_parent_selector()) {
1151 return None;
1152 }
1153
1154 let result =
1155 SelectorList::from_iter(orig.iter().map(|s| s.replace_parent_selector(parent)));
1156
1157 let result_specificity_and_flags = selector_list_specificity_and_flags(
1158 result.slice().iter(),
1159 false,
1160 );
1161 if propagate_specificity {
1162 *specificity += Specificity::from(
1163 result_specificity_and_flags.specificity
1164 - selector_list_specificity_and_flags(
1165 orig.iter(),
1166 false,
1167 )
1168 .specificity,
1169 );
1170 }
1171 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1172 Some(result)
1173 }
1174
1175 fn replace_parent_on_relative_selector_list<Impl: SelectorImpl>(
1176 orig: &[RelativeSelector<Impl>],
1177 parent: &SelectorList<Impl>,
1178 specificity: &mut Specificity,
1179 flags: &mut SelectorFlags,
1180 forbidden_flags: SelectorFlags,
1181 ) -> Vec<RelativeSelector<Impl>> {
1182 let mut any = false;
1183
1184 let result = orig
1185 .iter()
1186 .map(|s| {
1187 if !s.selector.has_parent_selector() {
1188 return s.clone();
1189 }
1190 any = true;
1191 RelativeSelector {
1192 match_hint: s.match_hint,
1193 selector: s.selector.replace_parent_selector(parent),
1194 }
1195 })
1196 .collect();
1197
1198 if !any {
1199 return result;
1200 }
1201
1202 let result_specificity_and_flags = relative_selector_list_specificity_and_flags(
1203 &result, false,
1204 );
1205 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1206 *specificity += Specificity::from(
1207 result_specificity_and_flags.specificity
1208 - relative_selector_list_specificity_and_flags(
1209 orig, false,
1210 )
1211 .specificity,
1212 );
1213 result
1214 }
1215
1216 fn replace_parent_on_selector<Impl: SelectorImpl>(
1217 orig: &Selector<Impl>,
1218 parent: &SelectorList<Impl>,
1219 specificity: &mut Specificity,
1220 flags: &mut SelectorFlags,
1221 forbidden_flags: SelectorFlags,
1222 ) -> Selector<Impl> {
1223 let new_selector = orig.replace_parent_selector(parent);
1224 *specificity += Specificity::from(new_selector.specificity() - orig.specificity());
1225 flags.insert(new_selector.flags() - forbidden_flags);
1226 new_selector
1227 }
1228
1229 if !self.has_parent_selector() {
1230 return self.clone();
1231 }
1232
1233 let iter = self.iter_raw_match_order().map(|component| {
1234 use self::Component::*;
1235 match *component {
1236 LocalName(..)
1237 | ID(..)
1238 | Class(..)
1239 | AttributeInNoNamespaceExists { .. }
1240 | AttributeInNoNamespace { .. }
1241 | AttributeOther(..)
1242 | ExplicitUniversalType
1243 | ExplicitAnyNamespace
1244 | ExplicitNoNamespace
1245 | DefaultNamespace(..)
1246 | Namespace(..)
1247 | Root
1248 | Empty
1249 | Scope
1250 | ImplicitScope
1251 | Nth(..)
1252 | NonTSPseudoClass(..)
1253 | PseudoElement(..)
1254 | Combinator(..)
1255 | Host(None)
1256 | Part(..)
1257 | Invalid(..)
1258 | RelativeSelectorAnchor => component.clone(),
1259 ParentSelector => {
1260 specificity += Specificity::from(parent_specificity_and_flags.specificity);
1261 flags.insert(parent_specificity_and_flags.flags - forbidden_flags);
1262 Is(parent.clone())
1263 },
1264 Negation(ref selectors) => {
1265 Negation(
1266 replace_parent_on_selector_list(
1267 selectors.slice(),
1268 parent,
1269 &mut specificity,
1270 &mut flags,
1271 true,
1272 forbidden_flags,
1273 )
1274 .unwrap_or_else(|| selectors.clone()),
1275 )
1276 },
1277 Is(ref selectors) => {
1278 Is(replace_parent_on_selector_list(
1279 selectors.slice(),
1280 parent,
1281 &mut specificity,
1282 &mut flags,
1283 true,
1284 forbidden_flags,
1285 )
1286 .unwrap_or_else(|| selectors.clone()))
1287 },
1288 Where(ref selectors) => {
1289 Where(
1290 replace_parent_on_selector_list(
1291 selectors.slice(),
1292 parent,
1293 &mut specificity,
1294 &mut flags,
1295 false,
1296 forbidden_flags,
1297 )
1298 .unwrap_or_else(|| selectors.clone()),
1299 )
1300 },
1301 Has(ref selectors) => Has(replace_parent_on_relative_selector_list(
1302 selectors,
1303 parent,
1304 &mut specificity,
1305 &mut flags,
1306 forbidden_flags,
1307 )
1308 .into_boxed_slice()),
1309
1310 Host(Some(ref selector)) => Host(Some(replace_parent_on_selector(
1311 selector,
1312 parent,
1313 &mut specificity,
1314 &mut flags,
1315 forbidden_flags,
1316 ))),
1317 NthOf(ref data) => {
1318 let selectors = replace_parent_on_selector_list(
1319 data.selectors(),
1320 parent,
1321 &mut specificity,
1322 &mut flags,
1323 true,
1324 forbidden_flags,
1325 );
1326 NthOf(match selectors {
1327 Some(s) => {
1328 NthOfSelectorData::new(data.nth_data(), s.slice().iter().cloned())
1329 },
1330 None => data.clone(),
1331 })
1332 },
1333 Slotted(ref selector) => Slotted(replace_parent_on_selector(
1334 selector,
1335 parent,
1336 &mut specificity,
1337 &mut flags,
1338 forbidden_flags,
1339 )),
1340 }
1341 });
1342 let mut items = UniqueArc::from_header_and_iter(Default::default(), iter);
1343 *items.header_mut() = SpecificityAndFlags {
1344 specificity: specificity.into(),
1345 flags,
1346 };
1347 Selector(items.shareable())
1348 }
1349
1350 #[inline]
1352 pub fn len(&self) -> usize {
1353 self.0.len()
1354 }
1355
1356 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
1358 self.0.heap_ptr()
1359 }
1360
1361 pub fn visit<V>(&self, visitor: &mut V) -> bool
1380 where
1381 V: SelectorVisitor<Impl = Impl>,
1382 {
1383 let mut current = self.iter();
1384 let mut combinator = None;
1385 loop {
1386 if !visitor.visit_complex_selector(combinator) {
1387 return false;
1388 }
1389
1390 for selector in &mut current {
1391 if !selector.visit(visitor) {
1392 return false;
1393 }
1394 }
1395
1396 combinator = current.next_sequence();
1397 if combinator.is_none() {
1398 break;
1399 }
1400 }
1401
1402 true
1403 }
1404
1405 #[inline]
1407 pub fn parse<'i, 't, P>(
1408 parser: &P,
1409 input: &mut CssParser<'i, 't>,
1410 ) -> Result<Self, ParseError<'i, P::Error>>
1411 where
1412 P: Parser<'i, Impl = Impl>,
1413 {
1414 parse_selector(
1415 parser,
1416 input,
1417 SelectorParsingState::empty(),
1418 ParseRelative::No,
1419 )
1420 }
1421
1422 pub fn new_invalid(s: &str) -> Self {
1423 fn check_for_parent(input: &mut CssParser, has_parent: &mut bool) {
1424 while let Ok(t) = input.next() {
1425 match *t {
1426 Token::Function(_)
1427 | Token::ParenthesisBlock
1428 | Token::CurlyBracketBlock
1429 | Token::SquareBracketBlock => {
1430 let _ = input.parse_nested_block(
1431 |i| -> Result<(), ParseError<'_, BasicParseError>> {
1432 check_for_parent(i, has_parent);
1433 Ok(())
1434 },
1435 );
1436 },
1437 Token::Delim('&') => {
1438 *has_parent = true;
1439 },
1440 _ => {},
1441 }
1442 if *has_parent {
1443 break;
1444 }
1445 }
1446 }
1447 let mut has_parent = false;
1448 {
1449 let mut parser = cssparser::ParserInput::new(s);
1450 let mut parser = CssParser::new(&mut parser);
1451 check_for_parent(&mut parser, &mut has_parent);
1452 }
1453 Self(ThinArc::from_header_and_iter(
1454 SpecificityAndFlags {
1455 specificity: 0,
1456 flags: if has_parent {
1457 SelectorFlags::HAS_PARENT
1458 } else {
1459 SelectorFlags::empty()
1460 },
1461 },
1462 std::iter::once(Component::Invalid(Arc::new(String::from(s.trim())))),
1463 ))
1464 }
1465
1466 pub fn is_rightmost(&self, offset: usize) -> bool {
1468 offset == 0
1471 || matches!(
1472 self.combinator_at_match_order(offset - 1),
1473 Combinator::PseudoElement
1474 )
1475 }
1476}
1477
1478#[derive(Clone)]
1479pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
1480 iter: slice::Iter<'a, Component<Impl>>,
1481 next_combinator: Option<Combinator>,
1482}
1483
1484impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
1485 #[inline]
1488 pub fn next_sequence(&mut self) -> Option<Combinator> {
1489 self.next_combinator.take()
1490 }
1491
1492 #[inline]
1493 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
1494 let first = match self.next() {
1495 Some(c) => c,
1496 None => return true,
1499 };
1500 self.matches_for_stateless_pseudo_element_internal(first)
1501 }
1502
1503 #[inline(never)]
1504 fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool {
1505 if !first.matches_for_stateless_pseudo_element() {
1506 return false;
1507 }
1508 for component in self {
1509 if !component.matches_for_stateless_pseudo_element() {
1513 return false;
1514 }
1515 }
1516 true
1517 }
1518
1519 #[inline]
1521 pub fn selector_length(&self) -> usize {
1522 self.iter.len()
1523 }
1524}
1525
1526impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
1527 type Item = &'a Component<Impl>;
1528
1529 #[inline]
1530 fn next(&mut self) -> Option<Self::Item> {
1531 debug_assert!(
1532 self.next_combinator.is_none(),
1533 "You should call next_sequence!"
1534 );
1535 match *self.iter.next()? {
1536 Component::Combinator(c) => {
1537 self.next_combinator = Some(c);
1538 None
1539 },
1540 ref x => Some(x),
1541 }
1542 }
1543}
1544
1545impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
1546 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1547 let iter = self.iter.clone().rev();
1548 for component in iter {
1549 component.to_css(f)?
1550 }
1551 Ok(())
1552 }
1553}
1554
1555struct CombinatorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1557impl<'a, Impl: 'a + SelectorImpl> CombinatorIter<'a, Impl> {
1558 fn new(inner: SelectorIter<'a, Impl>) -> Self {
1559 let mut result = CombinatorIter(inner);
1560 result.consume_non_combinators();
1561 result
1562 }
1563
1564 fn consume_non_combinators(&mut self) {
1565 while self.0.next().is_some() {}
1566 }
1567}
1568
1569impl<'a, Impl: SelectorImpl> Iterator for CombinatorIter<'a, Impl> {
1570 type Item = Combinator;
1571 fn next(&mut self) -> Option<Self::Item> {
1572 let result = self.0.next_sequence();
1573 self.consume_non_combinators();
1574 result
1575 }
1576}
1577
1578struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1580impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> {
1581 fn new(inner: SelectorIter<'a, Impl>) -> Self {
1584 let mut result = AncestorIter(inner);
1585 result.skip_until_ancestor();
1586 result
1587 }
1588
1589 fn skip_until_ancestor(&mut self) {
1592 loop {
1593 while self.0.next().is_some() {}
1594 if self.0.next_sequence().map_or(true, |x| {
1598 matches!(x, Combinator::Child | Combinator::Descendant)
1599 }) {
1600 break;
1601 }
1602 }
1603 }
1604}
1605
1606impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
1607 type Item = &'a Component<Impl>;
1608 fn next(&mut self) -> Option<Self::Item> {
1609 let next = self.0.next();
1611 if next.is_some() {
1612 return next;
1613 }
1614
1615 if let Some(combinator) = self.0.next_sequence() {
1617 if !matches!(combinator, Combinator::Child | Combinator::Descendant) {
1618 self.skip_until_ancestor();
1619 }
1620 }
1621
1622 self.0.next()
1623 }
1624}
1625
1626#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1627#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1628pub enum Combinator {
1629 Child, Descendant, NextSibling, LaterSibling, PseudoElement,
1640 SlotAssignment,
1643 Part,
1646}
1647
1648impl Combinator {
1649 #[inline]
1651 pub fn is_ancestor(&self) -> bool {
1652 matches!(
1653 *self,
1654 Combinator::Child
1655 | Combinator::Descendant
1656 | Combinator::PseudoElement
1657 | Combinator::SlotAssignment
1658 )
1659 }
1660
1661 #[inline]
1663 pub fn is_pseudo_element(&self) -> bool {
1664 matches!(*self, Combinator::PseudoElement)
1665 }
1666
1667 #[inline]
1669 pub fn is_sibling(&self) -> bool {
1670 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
1671 }
1672}
1673
1674#[derive(Copy, Clone, Eq, PartialEq)]
1676#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1677#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1678pub enum NthType {
1679 Child,
1680 LastChild,
1681 OnlyChild,
1682 OfType,
1683 LastOfType,
1684 OnlyOfType,
1685}
1686
1687impl NthType {
1688 pub fn is_only(self) -> bool {
1689 self == Self::OnlyChild || self == Self::OnlyOfType
1690 }
1691
1692 pub fn is_of_type(self) -> bool {
1693 self == Self::OfType || self == Self::LastOfType || self == Self::OnlyOfType
1694 }
1695
1696 pub fn is_from_end(self) -> bool {
1697 self == Self::LastChild || self == Self::LastOfType
1698 }
1699}
1700
1701#[derive(Copy, Clone, Eq, PartialEq, Debug)]
1703#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1704#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1705pub struct AnPlusB(pub i32, pub i32);
1706
1707impl AnPlusB {
1708 #[inline]
1709 pub fn matches_index(&self, i: i32) -> bool {
1710 match i.checked_sub(self.1) {
1712 None => false,
1713 Some(an) => match an.checked_div(self.0) {
1714 Some(n) => n >= 0 && self.0 * n == an,
1715 None => an == 0,
1716 },
1717 }
1718 }
1719}
1720
1721impl ToCss for AnPlusB {
1722 #[inline]
1725 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1726 where
1727 W: fmt::Write,
1728 {
1729 match (self.0, self.1) {
1730 (0, 0) => dest.write_char('0'),
1731
1732 (1, 0) => dest.write_char('n'),
1733 (-1, 0) => dest.write_str("-n"),
1734 (_, 0) => write!(dest, "{}n", self.0),
1735
1736 (0, _) => write!(dest, "{}", self.1),
1737 (1, _) => write!(dest, "n{:+}", self.1),
1738 (-1, _) => write!(dest, "-n{:+}", self.1),
1739 (_, _) => write!(dest, "{}n{:+}", self.0, self.1),
1740 }
1741 }
1742}
1743
1744#[derive(Copy, Clone, Eq, PartialEq)]
1748#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1749#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1750pub struct NthSelectorData {
1751 pub ty: NthType,
1752 pub is_function: bool,
1753 pub an_plus_b: AnPlusB,
1754}
1755
1756impl NthSelectorData {
1757 #[inline]
1759 pub const fn only(of_type: bool) -> Self {
1760 Self {
1761 ty: if of_type {
1762 NthType::OnlyOfType
1763 } else {
1764 NthType::OnlyChild
1765 },
1766 is_function: false,
1767 an_plus_b: AnPlusB(0, 1),
1768 }
1769 }
1770
1771 #[inline]
1773 pub const fn first(of_type: bool) -> Self {
1774 Self {
1775 ty: if of_type {
1776 NthType::OfType
1777 } else {
1778 NthType::Child
1779 },
1780 is_function: false,
1781 an_plus_b: AnPlusB(0, 1),
1782 }
1783 }
1784
1785 #[inline]
1787 pub const fn last(of_type: bool) -> Self {
1788 Self {
1789 ty: if of_type {
1790 NthType::LastOfType
1791 } else {
1792 NthType::LastChild
1793 },
1794 is_function: false,
1795 an_plus_b: AnPlusB(0, 1),
1796 }
1797 }
1798
1799 #[inline]
1801 pub fn is_simple_edge(&self) -> bool {
1802 self.an_plus_b.0 == 0
1803 && self.an_plus_b.1 == 1
1804 && !self.ty.is_of_type()
1805 && !self.ty.is_only()
1806 }
1807
1808 #[inline]
1810 fn write_start<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1811 dest.write_str(match self.ty {
1812 NthType::Child if self.is_function => ":nth-child(",
1813 NthType::Child => ":first-child",
1814 NthType::LastChild if self.is_function => ":nth-last-child(",
1815 NthType::LastChild => ":last-child",
1816 NthType::OfType if self.is_function => ":nth-of-type(",
1817 NthType::OfType => ":first-of-type",
1818 NthType::LastOfType if self.is_function => ":nth-last-of-type(",
1819 NthType::LastOfType => ":last-of-type",
1820 NthType::OnlyChild => ":only-child",
1821 NthType::OnlyOfType => ":only-of-type",
1822 })
1823 }
1824
1825 #[inline]
1826 fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1827 self.an_plus_b.to_css(dest)
1828 }
1829}
1830
1831#[derive(Clone, Eq, PartialEq)]
1835#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1836#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1837pub struct NthOfSelectorData<Impl: SelectorImpl>(
1838 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] ThinArc<NthSelectorData, Selector<Impl>>,
1839);
1840
1841impl<Impl: SelectorImpl> NthOfSelectorData<Impl> {
1842 #[inline]
1844 pub fn new<I>(nth_data: &NthSelectorData, selectors: I) -> Self
1845 where
1846 I: Iterator<Item = Selector<Impl>> + ExactSizeIterator,
1847 {
1848 Self(ThinArc::from_header_and_iter(*nth_data, selectors))
1849 }
1850
1851 #[inline]
1853 pub fn nth_data(&self) -> &NthSelectorData {
1854 &self.0.header
1855 }
1856
1857 #[inline]
1859 pub fn selectors(&self) -> &[Selector<Impl>] {
1860 self.0.slice()
1861 }
1862}
1863
1864#[derive(Clone, Copy, Eq, PartialEq)]
1866#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1867pub enum RelativeSelectorMatchHint {
1868 InSubtree,
1870 InChild,
1872 InNextSibling,
1874 InNextSiblingSubtree,
1876 InSibling,
1878 InSiblingSubtree,
1880}
1881
1882impl RelativeSelectorMatchHint {
1883 pub fn new(
1885 relative_combinator: Combinator,
1886 has_child_or_descendants: bool,
1887 has_adjacent_or_next_siblings: bool,
1888 ) -> Self {
1889 match relative_combinator {
1890 Combinator::Descendant => RelativeSelectorMatchHint::InSubtree,
1891 Combinator::Child => {
1892 if !has_child_or_descendants {
1893 RelativeSelectorMatchHint::InChild
1894 } else {
1895 RelativeSelectorMatchHint::InSubtree
1898 }
1899 },
1900 Combinator::NextSibling => {
1901 if !has_child_or_descendants && !has_adjacent_or_next_siblings {
1902 RelativeSelectorMatchHint::InNextSibling
1903 } else if !has_child_or_descendants && has_adjacent_or_next_siblings {
1904 RelativeSelectorMatchHint::InSibling
1905 } else if has_child_or_descendants && !has_adjacent_or_next_siblings {
1906 RelativeSelectorMatchHint::InNextSiblingSubtree
1908 } else {
1909 RelativeSelectorMatchHint::InSiblingSubtree
1910 }
1911 },
1912 Combinator::LaterSibling => {
1913 if !has_child_or_descendants {
1914 RelativeSelectorMatchHint::InSibling
1915 } else {
1916 RelativeSelectorMatchHint::InSiblingSubtree
1919 }
1920 },
1921 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1922 debug_assert!(false, "Unexpected relative combinator");
1923 RelativeSelectorMatchHint::InSubtree
1924 },
1925 }
1926 }
1927
1928 pub fn is_descendant_direction(&self) -> bool {
1930 matches!(*self, Self::InChild | Self::InSubtree)
1931 }
1932
1933 pub fn is_next_sibling(&self) -> bool {
1935 matches!(*self, Self::InNextSibling | Self::InNextSiblingSubtree)
1936 }
1937
1938 pub fn is_subtree(&self) -> bool {
1940 matches!(
1941 *self,
1942 Self::InSubtree | Self::InSiblingSubtree | Self::InNextSiblingSubtree
1943 )
1944 }
1945}
1946
1947#[derive(Clone, Copy)]
1949pub struct RelativeSelectorCombinatorCount {
1950 relative_combinator: Combinator,
1951 pub child_or_descendants: usize,
1952 pub adjacent_or_next_siblings: usize,
1953}
1954
1955impl RelativeSelectorCombinatorCount {
1956 pub fn new<Impl: SelectorImpl>(relative_selector: &RelativeSelector<Impl>) -> Self {
1958 let mut result = RelativeSelectorCombinatorCount {
1959 relative_combinator: relative_selector.selector.combinator_at_parse_order(1),
1960 child_or_descendants: 0,
1961 adjacent_or_next_siblings: 0,
1962 };
1963
1964 for combinator in CombinatorIter::new(
1965 relative_selector
1966 .selector
1967 .iter_skip_relative_selector_anchor(),
1968 ) {
1969 match combinator {
1970 Combinator::Descendant | Combinator::Child => {
1971 result.child_or_descendants += 1;
1972 },
1973 Combinator::NextSibling | Combinator::LaterSibling => {
1974 result.adjacent_or_next_siblings += 1;
1975 },
1976 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1977 continue
1978 },
1979 };
1980 }
1981 result
1982 }
1983
1984 pub fn get_match_hint(&self) -> RelativeSelectorMatchHint {
1986 RelativeSelectorMatchHint::new(
1987 self.relative_combinator,
1988 self.child_or_descendants != 0,
1989 self.adjacent_or_next_siblings != 0,
1990 )
1991 }
1992}
1993
1994#[derive(Clone, Eq, PartialEq)]
1996#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1997#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1998pub struct RelativeSelector<Impl: SelectorImpl> {
1999 pub match_hint: RelativeSelectorMatchHint,
2001 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2003 pub selector: Selector<Impl>,
2004}
2005
2006bitflags! {
2007 #[derive(Clone, Debug, Eq, PartialEq)]
2009 struct CombinatorComposition: u8 {
2010 const DESCENDANTS = 1 << 0;
2011 const SIBLINGS = 1 << 1;
2012 }
2013}
2014
2015impl CombinatorComposition {
2016 fn for_relative_selector<Impl: SelectorImpl>(inner_selector: &Selector<Impl>) -> Self {
2017 let mut result = CombinatorComposition::empty();
2018 for combinator in CombinatorIter::new(inner_selector.iter_skip_relative_selector_anchor()) {
2019 match combinator {
2020 Combinator::Descendant | Combinator::Child => {
2021 result.insert(Self::DESCENDANTS);
2022 },
2023 Combinator::NextSibling | Combinator::LaterSibling => {
2024 result.insert(Self::SIBLINGS);
2025 },
2026 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
2027 continue
2028 },
2029 };
2030 if result.is_all() {
2031 break;
2032 }
2033 }
2034 return result;
2035 }
2036}
2037
2038impl<Impl: SelectorImpl> RelativeSelector<Impl> {
2039 fn from_selector_list(selector_list: SelectorList<Impl>) -> Box<[Self]> {
2040 selector_list
2041 .slice()
2042 .iter()
2043 .map(|selector| {
2044 if cfg!(debug_assertions) {
2047 let relative_selector_anchor = selector.iter_raw_parse_order_from(0).next();
2048 debug_assert!(
2049 relative_selector_anchor.is_some(),
2050 "Relative selector is empty"
2051 );
2052 debug_assert!(
2053 matches!(
2054 relative_selector_anchor.unwrap(),
2055 Component::RelativeSelectorAnchor
2056 ),
2057 "Relative selector anchor is missing"
2058 );
2059 }
2060 let composition = CombinatorComposition::for_relative_selector(&selector);
2062 let match_hint = RelativeSelectorMatchHint::new(
2063 selector.combinator_at_parse_order(1),
2064 composition.intersects(CombinatorComposition::DESCENDANTS),
2065 composition.intersects(CombinatorComposition::SIBLINGS),
2066 );
2067 RelativeSelector {
2068 match_hint,
2069 selector: selector.clone(),
2070 }
2071 })
2072 .collect()
2073 }
2074}
2075
2076#[derive(Clone, Eq, PartialEq)]
2081#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2082#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2083pub enum Component<Impl: SelectorImpl> {
2084 LocalName(LocalName<Impl>),
2085
2086 ID(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2087 Class(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2088
2089 AttributeInNoNamespaceExists {
2090 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2091 local_name: Impl::LocalName,
2092 local_name_lower: Impl::LocalName,
2093 },
2094 AttributeInNoNamespace {
2096 local_name: Impl::LocalName,
2097 operator: AttrSelectorOperator,
2098 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2099 value: Impl::AttrValue,
2100 case_sensitivity: ParsedCaseSensitivity,
2101 },
2102 AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
2104
2105 ExplicitUniversalType,
2106 ExplicitAnyNamespace,
2107
2108 ExplicitNoNamespace,
2109 DefaultNamespace(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl),
2110 Namespace(
2111 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespacePrefix,
2112 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl,
2113 ),
2114
2115 Negation(SelectorList<Impl>),
2117 Root,
2118 Empty,
2119 Scope,
2120 ImplicitScope,
2128 ParentSelector,
2129 Nth(NthSelectorData),
2130 NthOf(NthOfSelectorData<Impl>),
2131 NonTSPseudoClass(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NonTSPseudoClass),
2132 Slotted(Selector<Impl>),
2144 Part(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Box<[Impl::Identifier]>),
2147 Host(Option<Selector<Impl>>),
2157 Where(SelectorList<Impl>),
2164 Is(SelectorList<Impl>),
2170 Has(Box<[RelativeSelector<Impl>]>),
2176 Invalid(Arc<String>),
2178 PseudoElement(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::PseudoElement),
2180
2181 Combinator(Combinator),
2182
2183 RelativeSelectorAnchor,
2188}
2189
2190impl<Impl: SelectorImpl> Component<Impl> {
2191 #[inline]
2193 pub fn is_combinator(&self) -> bool {
2194 matches!(*self, Component::Combinator(_))
2195 }
2196
2197 #[inline]
2199 pub fn is_host(&self) -> bool {
2200 matches!(*self, Component::Host(..))
2201 }
2202
2203 pub fn as_combinator(&self) -> Option<Combinator> {
2205 match *self {
2206 Component::Combinator(c) => Some(c),
2207 _ => None,
2208 }
2209 }
2210
2211 fn matches_for_stateless_pseudo_element(&self) -> bool {
2215 match *self {
2216 Component::Negation(ref selectors) => !selectors.slice().iter().all(|selector| {
2217 selector
2218 .iter_raw_match_order()
2219 .all(|c| c.matches_for_stateless_pseudo_element())
2220 }),
2221 Component::Is(ref selectors) | Component::Where(ref selectors) => {
2222 selectors.slice().iter().any(|selector| {
2223 selector
2224 .iter_raw_match_order()
2225 .all(|c| c.matches_for_stateless_pseudo_element())
2226 })
2227 },
2228 _ => false,
2229 }
2230 }
2231
2232 pub fn visit<V>(&self, visitor: &mut V) -> bool
2233 where
2234 V: SelectorVisitor<Impl = Impl>,
2235 {
2236 use self::Component::*;
2237 if !visitor.visit_simple_selector(self) {
2238 return false;
2239 }
2240
2241 match *self {
2242 Slotted(ref selector) => {
2243 if !selector.visit(visitor) {
2244 return false;
2245 }
2246 },
2247 Host(Some(ref selector)) => {
2248 if !selector.visit(visitor) {
2249 return false;
2250 }
2251 },
2252 AttributeInNoNamespaceExists {
2253 ref local_name,
2254 ref local_name_lower,
2255 } => {
2256 if !visitor.visit_attribute_selector(
2257 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2258 local_name,
2259 local_name_lower,
2260 ) {
2261 return false;
2262 }
2263 },
2264 AttributeInNoNamespace { ref local_name, .. } => {
2265 if !visitor.visit_attribute_selector(
2266 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2267 local_name,
2268 local_name,
2269 ) {
2270 return false;
2271 }
2272 },
2273 AttributeOther(ref attr_selector) => {
2274 let empty_string;
2275 let namespace = match attr_selector.namespace() {
2276 Some(ns) => ns,
2277 None => {
2278 empty_string = crate::parser::namespace_empty_string::<Impl>();
2279 NamespaceConstraint::Specific(&empty_string)
2280 },
2281 };
2282 if !visitor.visit_attribute_selector(
2283 &namespace,
2284 &attr_selector.local_name,
2285 &attr_selector.local_name_lower,
2286 ) {
2287 return false;
2288 }
2289 },
2290
2291 NonTSPseudoClass(ref pseudo_class) => {
2292 if !pseudo_class.visit(visitor) {
2293 return false;
2294 }
2295 },
2296 Negation(ref list) | Is(ref list) | Where(ref list) => {
2297 let list_kind = SelectorListKind::from_component(self);
2298 debug_assert!(!list_kind.is_empty());
2299 if !visitor.visit_selector_list(list_kind, list.slice()) {
2300 return false;
2301 }
2302 },
2303 NthOf(ref nth_of_data) => {
2304 if !visitor.visit_selector_list(SelectorListKind::NTH_OF, nth_of_data.selectors()) {
2305 return false;
2306 }
2307 },
2308 Has(ref list) => {
2309 if !visitor.visit_relative_selector_list(list) {
2310 return false;
2311 }
2312 },
2313 _ => {},
2314 }
2315
2316 true
2317 }
2318
2319 pub fn has_indexed_selector_in_subject(&self) -> bool {
2323 match *self {
2324 Component::NthOf(..) | Component::Nth(..) => return true,
2325 Component::Is(ref selectors)
2326 | Component::Where(ref selectors)
2327 | Component::Negation(ref selectors) => {
2328 for selector in selectors.slice() {
2330 let mut iter = selector.iter();
2331 while let Some(c) = iter.next() {
2332 if c.has_indexed_selector_in_subject() {
2333 return true;
2334 }
2335 }
2336 }
2337 },
2338 _ => (),
2339 };
2340 false
2341 }
2342}
2343
2344#[derive(Clone, Eq, PartialEq)]
2345#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2346#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2347pub struct LocalName<Impl: SelectorImpl> {
2348 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2349 pub name: Impl::LocalName,
2350 pub lower_name: Impl::LocalName,
2351}
2352
2353impl<Impl: SelectorImpl> Debug for Selector<Impl> {
2354 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2355 f.write_str("Selector(")?;
2356 self.to_css(f)?;
2357 write!(
2358 f,
2359 ", specificity = {:#x}, flags = {:?})",
2360 self.specificity(),
2361 self.flags()
2362 )
2363 }
2364}
2365
2366impl<Impl: SelectorImpl> Debug for Component<Impl> {
2367 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2368 self.to_css(f)
2369 }
2370}
2371impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
2372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2373 self.to_css(f)
2374 }
2375}
2376impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
2377 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2378 self.to_css(f)
2379 }
2380}
2381
2382fn serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result
2383where
2384 Impl: SelectorImpl,
2385 I: Iterator<Item = &'a Selector<Impl>>,
2386 W: fmt::Write,
2387{
2388 let mut first = true;
2389 for selector in iter {
2390 if !first {
2391 dest.write_str(", ")?;
2392 }
2393 first = false;
2394 selector.to_css(dest)?;
2395 }
2396 Ok(())
2397}
2398
2399impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
2400 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2401 where
2402 W: fmt::Write,
2403 {
2404 serialize_selector_list(self.slice().iter(), dest)
2405 }
2406}
2407
2408impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
2409 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2410 where
2411 W: fmt::Write,
2412 {
2413 let mut combinators = self
2426 .iter_raw_match_order()
2427 .rev()
2428 .filter_map(|x| x.as_combinator());
2429 let compound_selectors = self
2430 .iter_raw_match_order()
2431 .as_slice()
2432 .split(|x| x.is_combinator())
2433 .rev();
2434
2435 let mut combinators_exhausted = false;
2436 for compound in compound_selectors {
2437 debug_assert!(!combinators_exhausted);
2438
2439 let first_compound = match compound.first() {
2441 None => continue,
2442 Some(c) => c,
2443 };
2444 if matches!(
2445 first_compound,
2446 Component::RelativeSelectorAnchor | Component::ImplicitScope
2447 ) {
2448 debug_assert!(
2449 compound.len() == 1,
2450 "RelativeSelectorAnchor/ImplicitScope should only be a simple selector"
2451 );
2452 if let Some(c) = combinators.next() {
2453 c.to_css_relative(dest)?;
2454 } else {
2455 debug_assert!(
2458 matches!(first_compound, Component::ImplicitScope),
2459 "Only implicit :scope may not have any combinator"
2460 );
2461 }
2462 continue;
2463 }
2464
2465 let (can_elide_namespace, first_non_namespace) = match compound[0] {
2476 Component::ExplicitAnyNamespace
2477 | Component::ExplicitNoNamespace
2478 | Component::Namespace(..) => (false, 1),
2479 Component::DefaultNamespace(..) => (true, 1),
2480 _ => (true, 0),
2481 };
2482 let mut perform_step_2 = true;
2483 let next_combinator = combinators.next();
2484 if first_non_namespace == compound.len() - 1 {
2485 match (next_combinator, &compound[first_non_namespace]) {
2486 (Some(Combinator::PseudoElement), _)
2494 | (Some(Combinator::SlotAssignment), _) => (),
2495 (_, &Component::ExplicitUniversalType) => {
2496 for simple in compound.iter() {
2499 simple.to_css(dest)?;
2500 }
2501 perform_step_2 = false;
2503 },
2504 _ => (),
2505 }
2506 }
2507
2508 if perform_step_2 {
2518 for simple in compound.iter() {
2519 if let Component::ExplicitUniversalType = *simple {
2520 if can_elide_namespace {
2525 continue;
2526 }
2527 }
2528 simple.to_css(dest)?;
2529 }
2530 }
2531
2532 match next_combinator {
2538 Some(c) => c.to_css(dest)?,
2539 None => combinators_exhausted = true,
2540 };
2541
2542 }
2548
2549 Ok(())
2550 }
2551}
2552
2553impl Combinator {
2554 fn to_css_internal<W>(&self, dest: &mut W, prefix_space: bool) -> fmt::Result
2555 where
2556 W: fmt::Write,
2557 {
2558 if matches!(
2559 *self,
2560 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment
2561 ) {
2562 return Ok(());
2563 }
2564 if prefix_space {
2565 dest.write_char(' ')?;
2566 }
2567 match *self {
2568 Combinator::Child => dest.write_str("> "),
2569 Combinator::Descendant => Ok(()),
2570 Combinator::NextSibling => dest.write_str("+ "),
2571 Combinator::LaterSibling => dest.write_str("~ "),
2572 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => unsafe {
2573 debug_unreachable!("Already handled")
2574 },
2575 }
2576 }
2577
2578 fn to_css_relative<W>(&self, dest: &mut W) -> fmt::Result
2579 where
2580 W: fmt::Write,
2581 {
2582 self.to_css_internal(dest, false)
2583 }
2584}
2585
2586impl ToCss for Combinator {
2587 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2588 where
2589 W: fmt::Write,
2590 {
2591 self.to_css_internal(dest, true)
2592 }
2593}
2594
2595impl<Impl: SelectorImpl> ToCss for Component<Impl> {
2596 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2597 where
2598 W: fmt::Write,
2599 {
2600 use self::Component::*;
2601
2602 match *self {
2603 Combinator(ref c) => c.to_css(dest),
2604 Slotted(ref selector) => {
2605 dest.write_str("::slotted(")?;
2606 selector.to_css(dest)?;
2607 dest.write_char(')')
2608 },
2609 Part(ref part_names) => {
2610 dest.write_str("::part(")?;
2611 for (i, name) in part_names.iter().enumerate() {
2612 if i != 0 {
2613 dest.write_char(' ')?;
2614 }
2615 name.to_css(dest)?;
2616 }
2617 dest.write_char(')')
2618 },
2619 PseudoElement(ref p) => p.to_css(dest),
2620 ID(ref s) => {
2621 dest.write_char('#')?;
2622 s.to_css(dest)
2623 },
2624 Class(ref s) => {
2625 dest.write_char('.')?;
2626 s.to_css(dest)
2627 },
2628 LocalName(ref s) => s.to_css(dest),
2629 ExplicitUniversalType => dest.write_char('*'),
2630
2631 DefaultNamespace(_) => Ok(()),
2632 ExplicitNoNamespace => dest.write_char('|'),
2633 ExplicitAnyNamespace => dest.write_str("*|"),
2634 Namespace(ref prefix, _) => {
2635 prefix.to_css(dest)?;
2636 dest.write_char('|')
2637 },
2638
2639 AttributeInNoNamespaceExists { ref local_name, .. } => {
2640 dest.write_char('[')?;
2641 local_name.to_css(dest)?;
2642 dest.write_char(']')
2643 },
2644 AttributeInNoNamespace {
2645 ref local_name,
2646 operator,
2647 ref value,
2648 case_sensitivity,
2649 ..
2650 } => {
2651 dest.write_char('[')?;
2652 local_name.to_css(dest)?;
2653 operator.to_css(dest)?;
2654 value.to_css(dest)?;
2655 match case_sensitivity {
2656 ParsedCaseSensitivity::CaseSensitive
2657 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2658 },
2659 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2660 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2661 }
2662 dest.write_char(']')
2663 },
2664 AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
2665
2666 Root => dest.write_str(":root"),
2668 Empty => dest.write_str(":empty"),
2669 Scope => dest.write_str(":scope"),
2670 ParentSelector => dest.write_char('&'),
2671 Host(ref selector) => {
2672 dest.write_str(":host")?;
2673 if let Some(ref selector) = *selector {
2674 dest.write_char('(')?;
2675 selector.to_css(dest)?;
2676 dest.write_char(')')?;
2677 }
2678 Ok(())
2679 },
2680 Nth(ref nth_data) => {
2681 nth_data.write_start(dest)?;
2682 if nth_data.is_function {
2683 nth_data.write_affine(dest)?;
2684 dest.write_char(')')?;
2685 }
2686 Ok(())
2687 },
2688 NthOf(ref nth_of_data) => {
2689 let nth_data = nth_of_data.nth_data();
2690 nth_data.write_start(dest)?;
2691 debug_assert!(
2692 nth_data.is_function,
2693 "A selector must be a function to hold An+B notation"
2694 );
2695 nth_data.write_affine(dest)?;
2696 debug_assert!(
2697 matches!(nth_data.ty, NthType::Child | NthType::LastChild),
2698 "Only :nth-child or :nth-last-child can be of a selector list"
2699 );
2700 debug_assert!(
2701 !nth_of_data.selectors().is_empty(),
2702 "The selector list should not be empty"
2703 );
2704 dest.write_str(" of ")?;
2705 serialize_selector_list(nth_of_data.selectors().iter(), dest)?;
2706 dest.write_char(')')
2707 },
2708 Is(ref list) | Where(ref list) | Negation(ref list) => {
2709 match *self {
2710 Where(..) => dest.write_str(":where(")?,
2711 Is(..) => dest.write_str(":is(")?,
2712 Negation(..) => dest.write_str(":not(")?,
2713 _ => unreachable!(),
2714 }
2715 serialize_selector_list(list.slice().iter(), dest)?;
2716 dest.write_str(")")
2717 },
2718 Has(ref list) => {
2719 dest.write_str(":has(")?;
2720 let mut first = true;
2721 for RelativeSelector { ref selector, .. } in list.iter() {
2722 if !first {
2723 dest.write_str(", ")?;
2724 }
2725 first = false;
2726 selector.to_css(dest)?;
2727 }
2728 dest.write_str(")")
2729 },
2730 NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
2731 Invalid(ref css) => dest.write_str(css),
2732 RelativeSelectorAnchor | ImplicitScope => Ok(()),
2733 }
2734 }
2735}
2736
2737impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
2738 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2739 where
2740 W: fmt::Write,
2741 {
2742 dest.write_char('[')?;
2743 match self.namespace {
2744 Some(NamespaceConstraint::Specific((ref prefix, _))) => {
2745 prefix.to_css(dest)?;
2746 dest.write_char('|')?
2747 },
2748 Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
2749 None => {},
2750 }
2751 self.local_name.to_css(dest)?;
2752 match self.operation {
2753 ParsedAttrSelectorOperation::Exists => {},
2754 ParsedAttrSelectorOperation::WithValue {
2755 operator,
2756 case_sensitivity,
2757 ref value,
2758 } => {
2759 operator.to_css(dest)?;
2760 value.to_css(dest)?;
2761 match case_sensitivity {
2762 ParsedCaseSensitivity::CaseSensitive
2763 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2764 },
2765 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2766 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2767 }
2768 },
2769 }
2770 dest.write_char(']')
2771 }
2772}
2773
2774impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
2775 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2776 where
2777 W: fmt::Write,
2778 {
2779 self.name.to_css(dest)
2780 }
2781}
2782
2783fn parse_selector<'i, 't, P, Impl>(
2788 parser: &P,
2789 input: &mut CssParser<'i, 't>,
2790 mut state: SelectorParsingState,
2791 parse_relative: ParseRelative,
2792) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
2793where
2794 P: Parser<'i, Impl = Impl>,
2795 Impl: SelectorImpl,
2796{
2797 let mut builder = SelectorBuilder::default();
2798
2799 input.skip_whitespace();
2801
2802 if parse_relative != ParseRelative::No {
2803 let combinator = try_parse_combinator::<P, Impl>(input);
2804 match parse_relative {
2805 ParseRelative::ForHas => {
2806 builder.push_simple_selector(Component::RelativeSelectorAnchor);
2807 builder.push_combinator(combinator.unwrap_or(Combinator::Descendant));
2810 },
2811 ParseRelative::ForNesting | ParseRelative::ForScope => {
2812 if let Ok(combinator) = combinator {
2813 let selector = match parse_relative {
2814 ParseRelative::ForHas | ParseRelative::No => unreachable!(),
2815 ParseRelative::ForNesting => Component::ParentSelector,
2816 ParseRelative::ForScope => Component::ImplicitScope,
2820 };
2821 builder.push_simple_selector(selector);
2822 builder.push_combinator(combinator);
2823 }
2824 },
2825 ParseRelative::No => unreachable!(),
2826 }
2827 }
2828 'outer_loop: loop {
2829 let empty = parse_compound_selector(parser, &mut state, input, &mut builder)?;
2831 if empty {
2832 return Err(input.new_custom_error(if builder.has_combinators() {
2833 SelectorParseErrorKind::DanglingCombinator
2834 } else {
2835 SelectorParseErrorKind::EmptySelector
2836 }));
2837 }
2838
2839 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2840 debug_assert!(state.intersects(
2841 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO
2842 | SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO
2843 | SelectorParsingState::AFTER_SLOTTED
2844 | SelectorParsingState::AFTER_PART_LIKE
2845 ));
2846 break;
2847 }
2848
2849 let combinator = if let Ok(c) = try_parse_combinator::<P, Impl>(input) {
2850 c
2851 } else {
2852 break 'outer_loop;
2853 };
2854
2855 if !state.allows_combinators() {
2856 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2857 }
2858
2859 builder.push_combinator(combinator);
2860 }
2861 return Ok(Selector(builder.build(parse_relative)));
2862}
2863
2864fn try_parse_combinator<'i, 't, P, Impl>(input: &mut CssParser<'i, 't>) -> Result<Combinator, ()> {
2865 let mut any_whitespace = false;
2866 loop {
2867 let before_this_token = input.state();
2868 match input.next_including_whitespace() {
2869 Err(_e) => return Err(()),
2870 Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
2871 Ok(&Token::Delim('>')) => {
2872 return Ok(Combinator::Child);
2873 },
2874 Ok(&Token::Delim('+')) => {
2875 return Ok(Combinator::NextSibling);
2876 },
2877 Ok(&Token::Delim('~')) => {
2878 return Ok(Combinator::LaterSibling);
2879 },
2880 Ok(_) => {
2881 input.reset(&before_this_token);
2882 if any_whitespace {
2883 return Ok(Combinator::Descendant);
2884 } else {
2885 return Err(());
2886 }
2887 },
2888 }
2889 }
2890}
2891
2892fn parse_type_selector<'i, 't, P, Impl, S>(
2896 parser: &P,
2897 input: &mut CssParser<'i, 't>,
2898 state: SelectorParsingState,
2899 sink: &mut S,
2900) -> Result<bool, ParseError<'i, P::Error>>
2901where
2902 P: Parser<'i, Impl = Impl>,
2903 Impl: SelectorImpl,
2904 S: Push<Component<Impl>>,
2905{
2906 match parse_qualified_name(parser, input, false) {
2907 Err(ParseError {
2908 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
2909 ..
2910 })
2911 | Ok(OptionalQName::None(_)) => Ok(false),
2912 Ok(OptionalQName::Some(namespace, local_name)) => {
2913 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2914 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2915 }
2916 match namespace {
2917 QNamePrefix::ImplicitAnyNamespace => {},
2918 QNamePrefix::ImplicitDefaultNamespace(url) => {
2919 sink.push(Component::DefaultNamespace(url))
2920 },
2921 QNamePrefix::ExplicitNamespace(prefix, url) => {
2922 sink.push(match parser.default_namespace() {
2923 Some(ref default_url) if url == *default_url => {
2924 Component::DefaultNamespace(url)
2925 },
2926 _ => Component::Namespace(prefix, url),
2927 })
2928 },
2929 QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
2930 QNamePrefix::ExplicitAnyNamespace => {
2931 match parser.default_namespace() {
2932 None => {},
2944 Some(_) => sink.push(Component::ExplicitAnyNamespace),
2945 }
2946 },
2947 QNamePrefix::ImplicitNoNamespace => {
2948 unreachable!() },
2950 }
2951 match local_name {
2952 Some(name) => sink.push(Component::LocalName(LocalName {
2953 lower_name: to_ascii_lowercase(&name).as_ref().into(),
2954 name: name.as_ref().into(),
2955 })),
2956 None => sink.push(Component::ExplicitUniversalType),
2957 }
2958 Ok(true)
2959 },
2960 Err(e) => Err(e),
2961 }
2962}
2963
2964#[derive(Debug)]
2965enum SimpleSelectorParseResult<Impl: SelectorImpl> {
2966 SimpleSelector(Component<Impl>),
2967 PseudoElement(Impl::PseudoElement),
2968 SlottedPseudo(Selector<Impl>),
2969 PartPseudo(Box<[Impl::Identifier]>),
2970}
2971
2972#[derive(Debug)]
2973enum QNamePrefix<Impl: SelectorImpl> {
2974 ImplicitNoNamespace, ImplicitAnyNamespace, ImplicitDefaultNamespace(Impl::NamespaceUrl), ExplicitNoNamespace, ExplicitAnyNamespace, ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), }
2981
2982enum OptionalQName<'i, Impl: SelectorImpl> {
2983 Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
2984 None(Token<'i>),
2985}
2986
2987fn parse_qualified_name<'i, 't, P, Impl>(
2992 parser: &P,
2993 input: &mut CssParser<'i, 't>,
2994 in_attr_selector: bool,
2995) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
2996where
2997 P: Parser<'i, Impl = Impl>,
2998 Impl: SelectorImpl,
2999{
3000 let default_namespace = |local_name| {
3001 let namespace = match parser.default_namespace() {
3002 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
3003 None => QNamePrefix::ImplicitAnyNamespace,
3004 };
3005 Ok(OptionalQName::Some(namespace, local_name))
3006 };
3007
3008 let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
3009 let location = input.current_source_location();
3010 match input.next_including_whitespace() {
3011 Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)),
3012 Ok(&Token::Ident(ref local_name)) => {
3013 Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
3014 },
3015 Ok(t) if in_attr_selector => {
3016 let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
3017 Err(location.new_custom_error(e))
3018 },
3019 Ok(t) => Err(location.new_custom_error(
3020 SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()),
3021 )),
3022 Err(e) => Err(e.into()),
3023 }
3024 };
3025
3026 let start = input.state();
3027 match input.next_including_whitespace() {
3028 Ok(Token::Ident(value)) => {
3029 let value = value.clone();
3030 let after_ident = input.state();
3031 match input.next_including_whitespace() {
3032 Ok(&Token::Delim('|')) => {
3033 let prefix = value.as_ref().into();
3034 let result = parser.namespace_for_prefix(&prefix);
3035 let url = result.ok_or(
3036 after_ident
3037 .source_location()
3038 .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)),
3039 )?;
3040 explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
3041 },
3042 _ => {
3043 input.reset(&after_ident);
3044 if in_attr_selector {
3045 Ok(OptionalQName::Some(
3046 QNamePrefix::ImplicitNoNamespace,
3047 Some(value),
3048 ))
3049 } else {
3050 default_namespace(Some(value))
3051 }
3052 },
3053 }
3054 },
3055 Ok(Token::Delim('*')) => {
3056 let after_star = input.state();
3057 match input.next_including_whitespace() {
3058 Ok(&Token::Delim('|')) => {
3059 explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
3060 },
3061 _ if !in_attr_selector => {
3062 input.reset(&after_star);
3063 default_namespace(None)
3064 },
3065 result => {
3066 let t = result?;
3067 Err(after_star
3068 .source_location()
3069 .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t.clone())))
3070 },
3071 }
3072 },
3073 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
3074 Ok(t) => {
3075 let t = t.clone();
3076 input.reset(&start);
3077 Ok(OptionalQName::None(t))
3078 },
3079 Err(e) => {
3080 input.reset(&start);
3081 Err(e.into())
3082 },
3083 }
3084}
3085
3086fn parse_attribute_selector<'i, 't, P, Impl>(
3087 parser: &P,
3088 input: &mut CssParser<'i, 't>,
3089) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3090where
3091 P: Parser<'i, Impl = Impl>,
3092 Impl: SelectorImpl,
3093{
3094 let namespace;
3095 let local_name;
3096
3097 input.skip_whitespace();
3098
3099 match parse_qualified_name(parser, input, true)? {
3100 OptionalQName::None(t) => {
3101 return Err(input.new_custom_error(
3102 SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t),
3103 ));
3104 },
3105 OptionalQName::Some(_, None) => unreachable!(),
3106 OptionalQName::Some(ns, Some(ln)) => {
3107 local_name = ln;
3108 namespace = match ns {
3109 QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
3110 QNamePrefix::ExplicitNamespace(prefix, url) => {
3111 Some(NamespaceConstraint::Specific((prefix, url)))
3112 },
3113 QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
3114 QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
3115 unreachable!() },
3117 }
3118 },
3119 }
3120
3121 let location = input.current_source_location();
3122 let operator = match input.next() {
3123 Err(_) => {
3125 let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
3126 let local_name = local_name.as_ref().into();
3127 if let Some(namespace) = namespace {
3128 return Ok(Component::AttributeOther(Box::new(
3129 AttrSelectorWithOptionalNamespace {
3130 namespace: Some(namespace),
3131 local_name,
3132 local_name_lower,
3133 operation: ParsedAttrSelectorOperation::Exists,
3134 },
3135 )));
3136 } else {
3137 return Ok(Component::AttributeInNoNamespaceExists {
3138 local_name,
3139 local_name_lower,
3140 });
3141 }
3142 },
3143
3144 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
3146 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
3148 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
3150 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
3152 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
3154 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
3156 Ok(t) => {
3157 return Err(location.new_custom_error(
3158 SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()),
3159 ));
3160 },
3161 };
3162
3163 let value = match input.expect_ident_or_string() {
3164 Ok(t) => t.clone(),
3165 Err(BasicParseError {
3166 kind: BasicParseErrorKind::UnexpectedToken(t),
3167 location,
3168 }) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))),
3169 Err(e) => return Err(e.into()),
3170 };
3171
3172 let attribute_flags = parse_attribute_flags(input)?;
3173 let value = value.as_ref().into();
3174 let local_name_lower;
3175 let local_name_is_ascii_lowercase;
3176 let case_sensitivity;
3177 {
3178 let local_name_lower_cow = to_ascii_lowercase(&local_name);
3179 case_sensitivity =
3180 attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
3181 local_name_lower = local_name_lower_cow.as_ref().into();
3182 local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
3183 }
3184 let local_name = local_name.as_ref().into();
3185 if namespace.is_some() || !local_name_is_ascii_lowercase {
3186 Ok(Component::AttributeOther(Box::new(
3187 AttrSelectorWithOptionalNamespace {
3188 namespace,
3189 local_name,
3190 local_name_lower,
3191 operation: ParsedAttrSelectorOperation::WithValue {
3192 operator,
3193 case_sensitivity,
3194 value,
3195 },
3196 },
3197 )))
3198 } else {
3199 Ok(Component::AttributeInNoNamespace {
3200 local_name,
3201 operator,
3202 value,
3203 case_sensitivity,
3204 })
3205 }
3206}
3207
3208enum AttributeFlags {
3210 CaseSensitive,
3212 AsciiCaseInsensitive,
3214 CaseSensitivityDependsOnName,
3216}
3217
3218impl AttributeFlags {
3219 fn to_case_sensitivity(self, local_name: &str, have_namespace: bool) -> ParsedCaseSensitivity {
3220 match self {
3221 AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
3222 AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
3223 AttributeFlags::CaseSensitivityDependsOnName => {
3224 if !have_namespace
3225 && include!(concat!(
3226 env!("OUT_DIR"),
3227 "/ascii_case_insensitive_html_attributes.rs"
3228 ))
3229 .contains(local_name)
3230 {
3231 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
3232 } else {
3233 ParsedCaseSensitivity::CaseSensitive
3234 }
3235 },
3236 }
3237 }
3238}
3239
3240fn parse_attribute_flags<'i, 't>(
3241 input: &mut CssParser<'i, 't>,
3242) -> Result<AttributeFlags, BasicParseError<'i>> {
3243 let location = input.current_source_location();
3244 let token = match input.next() {
3245 Ok(t) => t,
3246 Err(..) => {
3247 return Ok(AttributeFlags::CaseSensitivityDependsOnName);
3250 },
3251 };
3252
3253 let ident = match *token {
3254 Token::Ident(ref i) => i,
3255 ref other => return Err(location.new_basic_unexpected_token_error(other.clone())),
3256 };
3257
3258 Ok(match_ignore_ascii_case! {
3259 ident,
3260 "i" => AttributeFlags::AsciiCaseInsensitive,
3261 "s" => AttributeFlags::CaseSensitive,
3262 _ => return Err(location.new_basic_unexpected_token_error(token.clone())),
3263 })
3264}
3265
3266fn parse_negation<'i, 't, P, Impl>(
3269 parser: &P,
3270 input: &mut CssParser<'i, 't>,
3271 state: SelectorParsingState,
3272) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3273where
3274 P: Parser<'i, Impl = Impl>,
3275 Impl: SelectorImpl,
3276{
3277 let list = SelectorList::parse_with_state(
3278 parser,
3279 input,
3280 state
3281 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3282 | SelectorParsingState::DISALLOW_PSEUDOS,
3283 ForgivingParsing::No,
3284 ParseRelative::No,
3285 )?;
3286
3287 Ok(Component::Negation(list))
3288}
3289
3290fn parse_compound_selector<'i, 't, P, Impl>(
3297 parser: &P,
3298 state: &mut SelectorParsingState,
3299 input: &mut CssParser<'i, 't>,
3300 builder: &mut SelectorBuilder<Impl>,
3301) -> Result<bool, ParseError<'i, P::Error>>
3302where
3303 P: Parser<'i, Impl = Impl>,
3304 Impl: SelectorImpl,
3305{
3306 input.skip_whitespace();
3307
3308 let mut empty = true;
3309 if parse_type_selector(parser, input, *state, builder)? {
3310 empty = false;
3311 }
3312
3313 loop {
3314 let result = match parse_one_simple_selector(parser, input, *state)? {
3315 None => break,
3316 Some(result) => result,
3317 };
3318
3319 if empty {
3320 if let Some(url) = parser.default_namespace() {
3321 let ignore_default_ns = state
3349 .intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE)
3350 || matches!(
3351 result,
3352 SimpleSelectorParseResult::SimpleSelector(Component::Host(..))
3353 );
3354 if !ignore_default_ns {
3355 builder.push_simple_selector(Component::DefaultNamespace(url));
3356 }
3357 }
3358 }
3359
3360 empty = false;
3361
3362 match result {
3363 SimpleSelectorParseResult::SimpleSelector(s) => {
3364 builder.push_simple_selector(s);
3365 },
3366 SimpleSelectorParseResult::PartPseudo(part_names) => {
3367 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3368 builder.push_combinator(Combinator::Part);
3369 builder.push_simple_selector(Component::Part(part_names));
3370 },
3371 SimpleSelectorParseResult::SlottedPseudo(selector) => {
3372 state.insert(SelectorParsingState::AFTER_SLOTTED);
3373 builder.push_combinator(Combinator::SlotAssignment);
3374 builder.push_simple_selector(Component::Slotted(selector));
3375 },
3376 SimpleSelectorParseResult::PseudoElement(p) => {
3377 if p.is_element_backed() {
3378 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3379 } else {
3380 state.insert(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO);
3381 if p.is_before_or_after() {
3382 state.insert(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO);
3383 }
3384 }
3385 if !p.accepts_state_pseudo_classes() {
3386 state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
3387 }
3388 if p.is_in_pseudo_element_tree() {
3389 state.insert(SelectorParsingState::IN_PSEUDO_ELEMENT_TREE);
3390 }
3391 builder.push_combinator(Combinator::PseudoElement);
3392 builder.push_simple_selector(Component::PseudoElement(p));
3393 },
3394 }
3395 }
3396 Ok(empty)
3397}
3398
3399fn parse_is_where<'i, 't, P, Impl>(
3400 parser: &P,
3401 input: &mut CssParser<'i, 't>,
3402 state: SelectorParsingState,
3403 component: impl FnOnce(SelectorList<Impl>) -> Component<Impl>,
3404) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3405where
3406 P: Parser<'i, Impl = Impl>,
3407 Impl: SelectorImpl,
3408{
3409 debug_assert!(parser.parse_is_and_where());
3410 let inner = SelectorList::parse_with_state(
3416 parser,
3417 input,
3418 state
3419 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3420 | SelectorParsingState::DISALLOW_PSEUDOS,
3421 ForgivingParsing::Yes,
3422 ParseRelative::No,
3423 )?;
3424 Ok(component(inner))
3425}
3426
3427fn parse_has<'i, 't, P, Impl>(
3428 parser: &P,
3429 input: &mut CssParser<'i, 't>,
3430 state: SelectorParsingState,
3431) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3432where
3433 P: Parser<'i, Impl = Impl>,
3434 Impl: SelectorImpl,
3435{
3436 debug_assert!(parser.parse_has());
3437 if state.intersects(SelectorParsingState::DISALLOW_RELATIVE_SELECTOR) {
3438 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3439 }
3440 let inner = SelectorList::parse_with_state(
3445 parser,
3446 input,
3447 state
3448 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3449 | SelectorParsingState::DISALLOW_PSEUDOS
3450 | SelectorParsingState::DISALLOW_RELATIVE_SELECTOR,
3451 ForgivingParsing::No,
3452 ParseRelative::ForHas,
3453 )?;
3454 Ok(Component::Has(RelativeSelector::from_selector_list(inner)))
3455}
3456
3457fn parse_functional_pseudo_class<'i, 't, P, Impl>(
3458 parser: &P,
3459 input: &mut CssParser<'i, 't>,
3460 name: CowRcStr<'i>,
3461 state: SelectorParsingState,
3462) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3463where
3464 P: Parser<'i, Impl = Impl>,
3465 Impl: SelectorImpl,
3466{
3467 match_ignore_ascii_case! { &name,
3468 "nth-child" => return parse_nth_pseudo_class(parser, input, state, NthType::Child),
3469 "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::OfType),
3470 "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, NthType::LastChild),
3471 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::LastOfType),
3472 "is" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Is),
3473 "where" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Where),
3474 "has" if parser.parse_has() => return parse_has(parser, input, state),
3475 "host" => {
3476 if !state.allows_tree_structural_pseudo_classes() {
3477 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3478 }
3479 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
3480 },
3481 "not" => {
3482 return parse_negation(parser, input, state)
3483 },
3484 _ => {}
3485 }
3486
3487 if parser.parse_is_and_where() && parser.is_is_alias(&name) {
3488 return parse_is_where(parser, input, state, Component::Is);
3489 }
3490
3491 if state.intersects(
3492 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO | SelectorParsingState::AFTER_SLOTTED,
3493 ) {
3494 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3495 }
3496
3497 let after_part = state.intersects(SelectorParsingState::AFTER_PART_LIKE);
3498 P::parse_non_ts_functional_pseudo_class(parser, name, input, after_part)
3499 .map(Component::NonTSPseudoClass)
3500}
3501
3502fn parse_nth_pseudo_class<'i, 't, P, Impl>(
3503 parser: &P,
3504 input: &mut CssParser<'i, 't>,
3505 state: SelectorParsingState,
3506 ty: NthType,
3507) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3508where
3509 P: Parser<'i, Impl = Impl>,
3510 Impl: SelectorImpl,
3511{
3512 if !state.allows_tree_structural_pseudo_classes() {
3513 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3514 }
3515 let (a, b) = parse_nth(input)?;
3516 let nth_data = NthSelectorData {
3517 ty,
3518 is_function: true,
3519 an_plus_b: AnPlusB(a, b),
3520 };
3521 if !parser.parse_nth_child_of() || ty.is_of_type() {
3522 return Ok(Component::Nth(nth_data));
3523 }
3524
3525 if input.try_parse(|i| i.expect_ident_matching("of")).is_err() {
3527 return Ok(Component::Nth(nth_data));
3528 }
3529 let selectors = SelectorList::parse_with_state(
3532 parser,
3533 input,
3534 state
3535 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3536 | SelectorParsingState::DISALLOW_PSEUDOS,
3537 ForgivingParsing::No,
3538 ParseRelative::No,
3539 )?;
3540 Ok(Component::NthOf(NthOfSelectorData::new(
3541 &nth_data,
3542 selectors.slice().iter().cloned(),
3543 )))
3544}
3545
3546pub fn is_css2_pseudo_element(name: &str) -> bool {
3550 match_ignore_ascii_case! { name,
3552 "before" | "after" | "first-line" | "first-letter" => true,
3553 _ => false,
3554 }
3555}
3556
3557fn parse_one_simple_selector<'i, 't, P, Impl>(
3563 parser: &P,
3564 input: &mut CssParser<'i, 't>,
3565 state: SelectorParsingState,
3566) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>>
3567where
3568 P: Parser<'i, Impl = Impl>,
3569 Impl: SelectorImpl,
3570{
3571 let start = input.state();
3572 let token = match input.next_including_whitespace().map(|t| t.clone()) {
3573 Ok(t) => t,
3574 Err(..) => {
3575 input.reset(&start);
3576 return Ok(None);
3577 },
3578 };
3579
3580 Ok(Some(match token {
3581 Token::IDHash(id) => {
3582 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3583 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3584 }
3585 let id = Component::ID(id.as_ref().into());
3586 SimpleSelectorParseResult::SimpleSelector(id)
3587 },
3588 Token::Delim(delim) if delim == '.' || (delim == '&' && parser.parse_parent_selector()) => {
3589 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3590 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3591 }
3592 let location = input.current_source_location();
3593 SimpleSelectorParseResult::SimpleSelector(if delim == '&' {
3594 Component::ParentSelector
3595 } else {
3596 let class = match *input.next_including_whitespace()? {
3597 Token::Ident(ref class) => class,
3598 ref t => {
3599 let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
3600 return Err(location.new_custom_error(e));
3601 },
3602 };
3603 Component::Class(class.as_ref().into())
3604 })
3605 },
3606 Token::SquareBracketBlock => {
3607 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3608 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3609 }
3610 let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
3611 SimpleSelectorParseResult::SimpleSelector(attr)
3612 },
3613 Token::Colon => {
3614 let location = input.current_source_location();
3615 let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
3616 Token::Colon => (false, input.next_including_whitespace()?.clone()),
3617 t => (true, t),
3618 };
3619 let (name, is_functional) = match next_token {
3620 Token::Ident(name) => (name, false),
3621 Token::Function(name) => (name, true),
3622 t => {
3623 let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t);
3624 return Err(input.new_custom_error(e));
3625 },
3626 };
3627 let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name);
3628 if is_pseudo_element {
3629 if state.intersects(SelectorParsingState::DISALLOW_PSEUDOS)
3635 || (state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3636 && !state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO))
3637 {
3638 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3639 }
3640 let pseudo_element = if is_functional {
3641 if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
3642 if !state.allows_part() {
3643 return Err(
3644 input.new_custom_error(SelectorParseErrorKind::InvalidState)
3645 );
3646 }
3647 let names = input.parse_nested_block(|input| {
3648 let mut result = Vec::with_capacity(1);
3649 result.push(input.expect_ident()?.as_ref().into());
3650 while !input.is_exhausted() {
3651 result.push(input.expect_ident()?.as_ref().into());
3652 }
3653 Ok(result.into_boxed_slice())
3654 })?;
3655 return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
3656 }
3657 if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
3658 if !state.allows_slotted() {
3659 return Err(
3660 input.new_custom_error(SelectorParseErrorKind::InvalidState)
3661 );
3662 }
3663 let selector = input.parse_nested_block(|input| {
3664 parse_inner_compound_selector(parser, input, state)
3665 })?;
3666 return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
3667 }
3668 input.parse_nested_block(|input| {
3669 P::parse_functional_pseudo_element(parser, name, input)
3670 })?
3671 } else {
3672 P::parse_pseudo_element(parser, location, name)?
3673 };
3674
3675 if state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO)
3676 && !pseudo_element.valid_after_before_or_after()
3677 {
3678 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3679 }
3680
3681 if state.intersects(SelectorParsingState::AFTER_SLOTTED)
3682 && !pseudo_element.valid_after_slotted()
3683 {
3684 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3685 }
3686 SimpleSelectorParseResult::PseudoElement(pseudo_element)
3687 } else {
3688 let pseudo_class = if is_functional {
3689 input.parse_nested_block(|input| {
3690 parse_functional_pseudo_class(parser, input, name, state)
3691 })?
3692 } else {
3693 parse_simple_pseudo_class(parser, location, name, state)?
3694 };
3695 SimpleSelectorParseResult::SimpleSelector(pseudo_class)
3696 }
3697 },
3698 _ => {
3699 input.reset(&start);
3700 return Ok(None);
3701 },
3702 }))
3703}
3704
3705fn parse_simple_pseudo_class<'i, P, Impl>(
3706 parser: &P,
3707 location: SourceLocation,
3708 name: CowRcStr<'i>,
3709 state: SelectorParsingState,
3710) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3711where
3712 P: Parser<'i, Impl = Impl>,
3713 Impl: SelectorImpl,
3714{
3715 if !state.allows_non_functional_pseudo_classes() {
3716 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3717 }
3718
3719 if state.allows_tree_structural_pseudo_classes() {
3720 if state.allows_only_child_pseudo_class_only() {
3725 if name.eq_ignore_ascii_case("only-child") {
3726 return Ok(Component::Nth(NthSelectorData::only(
3727 false,
3728 )));
3729 }
3730 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3734 }
3735
3736 match_ignore_ascii_case! { &name,
3737 "first-child" => return Ok(Component::Nth(NthSelectorData::first(false))),
3738 "last-child" => return Ok(Component::Nth(NthSelectorData::last(false))),
3739 "only-child" => return Ok(Component::Nth(NthSelectorData::only(false))),
3740 "root" => return Ok(Component::Root),
3741 "empty" => return Ok(Component::Empty),
3742 "scope" => return Ok(Component::Scope),
3743 "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
3744 "first-of-type" => return Ok(Component::Nth(NthSelectorData::first(true))),
3745 "last-of-type" => return Ok(Component::Nth(NthSelectorData::last(true))),
3746 "only-of-type" => return Ok(Component::Nth(NthSelectorData::only(true))),
3747 _ => {},
3748 }
3749 }
3750
3751 let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?;
3752 if state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3753 && !pseudo_class.is_user_action_state()
3754 {
3755 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3756 }
3757 Ok(Component::NonTSPseudoClass(pseudo_class))
3758}
3759
3760#[cfg(test)]
3762pub mod tests {
3763 use super::*;
3764 use crate::builder::SelectorFlags;
3765 use crate::parser;
3766 use cssparser::{serialize_identifier, Parser as CssParser, ParserInput, ToCss};
3767 use std::collections::HashMap;
3768 use std::fmt;
3769
3770 #[derive(Clone, Debug, Eq, PartialEq)]
3771 pub enum PseudoClass {
3772 Hover,
3773 Active,
3774 Lang(String),
3775 }
3776
3777 #[derive(Clone, Debug, Eq, PartialEq)]
3778 pub enum PseudoElement {
3779 Before,
3780 After,
3781 Marker,
3782 DetailsContent,
3783 Highlight(String),
3784 }
3785
3786 impl parser::PseudoElement for PseudoElement {
3787 type Impl = DummySelectorImpl;
3788
3789 fn accepts_state_pseudo_classes(&self) -> bool {
3790 true
3791 }
3792
3793 fn valid_after_slotted(&self) -> bool {
3794 true
3795 }
3796
3797 fn valid_after_before_or_after(&self) -> bool {
3798 matches!(self, Self::Marker)
3799 }
3800
3801 fn is_before_or_after(&self) -> bool {
3802 matches!(self, Self::Before | Self::After)
3803 }
3804
3805 fn is_element_backed(&self) -> bool {
3806 matches!(self, Self::DetailsContent)
3807 }
3808 }
3809
3810 impl parser::NonTSPseudoClass for PseudoClass {
3811 type Impl = DummySelectorImpl;
3812
3813 #[inline]
3814 fn is_active_or_hover(&self) -> bool {
3815 matches!(*self, PseudoClass::Active | PseudoClass::Hover)
3816 }
3817
3818 #[inline]
3819 fn is_user_action_state(&self) -> bool {
3820 self.is_active_or_hover()
3821 }
3822 }
3823
3824 impl ToCss for PseudoClass {
3825 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3826 where
3827 W: fmt::Write,
3828 {
3829 match *self {
3830 PseudoClass::Hover => dest.write_str(":hover"),
3831 PseudoClass::Active => dest.write_str(":active"),
3832 PseudoClass::Lang(ref lang) => {
3833 dest.write_str(":lang(")?;
3834 serialize_identifier(lang, dest)?;
3835 dest.write_char(')')
3836 },
3837 }
3838 }
3839 }
3840
3841 impl ToCss for PseudoElement {
3842 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3843 where
3844 W: fmt::Write,
3845 {
3846 match *self {
3847 PseudoElement::Before => dest.write_str("::before"),
3848 PseudoElement::After => dest.write_str("::after"),
3849 PseudoElement::Marker => dest.write_str("::marker"),
3850 PseudoElement::DetailsContent => dest.write_str("::details-content"),
3851 PseudoElement::Highlight(ref name) => {
3852 dest.write_str("::highlight(")?;
3853 serialize_identifier(&name, dest)?;
3854 dest.write_char(')')
3855 },
3856 }
3857 }
3858 }
3859
3860 #[derive(Clone, Debug, PartialEq)]
3861 pub struct DummySelectorImpl;
3862
3863 #[derive(Default)]
3864 pub struct DummyParser {
3865 default_ns: Option<DummyAtom>,
3866 ns_prefixes: HashMap<DummyAtom, DummyAtom>,
3867 }
3868
3869 impl DummyParser {
3870 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
3871 DummyParser {
3872 default_ns: Some(default_ns),
3873 ns_prefixes: Default::default(),
3874 }
3875 }
3876 }
3877
3878 impl SelectorImpl for DummySelectorImpl {
3879 type ExtraMatchingData<'a> = std::marker::PhantomData<&'a ()>;
3880 type AttrValue = DummyAttrValue;
3881 type Identifier = DummyAtom;
3882 type LocalName = DummyAtom;
3883 type NamespaceUrl = DummyAtom;
3884 type NamespacePrefix = DummyAtom;
3885 type BorrowedLocalName = DummyAtom;
3886 type BorrowedNamespaceUrl = DummyAtom;
3887 type NonTSPseudoClass = PseudoClass;
3888 type PseudoElement = PseudoElement;
3889 }
3890
3891 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3892 pub struct DummyAttrValue(String);
3893
3894 impl ToCss for DummyAttrValue {
3895 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3896 where
3897 W: fmt::Write,
3898 {
3899 use std::fmt::Write;
3900
3901 dest.write_char('"')?;
3902 write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)?;
3903 dest.write_char('"')
3904 }
3905 }
3906
3907 impl<'a> From<&'a str> for DummyAttrValue {
3908 fn from(string: &'a str) -> Self {
3909 Self(string.into())
3910 }
3911 }
3912
3913 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3914 pub struct DummyAtom(String);
3915
3916 impl ToCss for DummyAtom {
3917 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3918 where
3919 W: fmt::Write,
3920 {
3921 serialize_identifier(&self.0, dest)
3922 }
3923 }
3924
3925 impl From<String> for DummyAtom {
3926 fn from(string: String) -> Self {
3927 DummyAtom(string)
3928 }
3929 }
3930
3931 impl<'a> From<&'a str> for DummyAtom {
3932 fn from(string: &'a str) -> Self {
3933 DummyAtom(string.into())
3934 }
3935 }
3936
3937 impl PrecomputedHash for DummyAtom {
3938 fn precomputed_hash(&self) -> u32 {
3939 self.0.as_ptr() as u32
3940 }
3941 }
3942
3943 impl<'i> Parser<'i> for DummyParser {
3944 type Impl = DummySelectorImpl;
3945 type Error = SelectorParseErrorKind<'i>;
3946
3947 fn parse_slotted(&self) -> bool {
3948 true
3949 }
3950
3951 fn parse_nth_child_of(&self) -> bool {
3952 true
3953 }
3954
3955 fn parse_is_and_where(&self) -> bool {
3956 true
3957 }
3958
3959 fn parse_has(&self) -> bool {
3960 true
3961 }
3962
3963 fn parse_parent_selector(&self) -> bool {
3964 true
3965 }
3966
3967 fn parse_part(&self) -> bool {
3968 true
3969 }
3970
3971 fn parse_host(&self) -> bool {
3972 true
3973 }
3974
3975 fn parse_non_ts_pseudo_class(
3976 &self,
3977 location: SourceLocation,
3978 name: CowRcStr<'i>,
3979 ) -> Result<PseudoClass, SelectorParseError<'i>> {
3980 match_ignore_ascii_case! { &name,
3981 "hover" => return Ok(PseudoClass::Hover),
3982 "active" => return Ok(PseudoClass::Active),
3983 _ => {}
3984 }
3985 Err(
3986 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
3987 name,
3988 )),
3989 )
3990 }
3991
3992 fn parse_non_ts_functional_pseudo_class<'t>(
3993 &self,
3994 name: CowRcStr<'i>,
3995 parser: &mut CssParser<'i, 't>,
3996 after_part: bool,
3997 ) -> Result<PseudoClass, SelectorParseError<'i>> {
3998 match_ignore_ascii_case! { &name,
3999 "lang" if !after_part => {
4000 let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
4001 return Ok(PseudoClass::Lang(lang));
4002 },
4003 _ => {}
4004 }
4005 Err(
4006 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4007 name,
4008 )),
4009 )
4010 }
4011
4012 fn parse_pseudo_element(
4013 &self,
4014 location: SourceLocation,
4015 name: CowRcStr<'i>,
4016 ) -> Result<PseudoElement, SelectorParseError<'i>> {
4017 match_ignore_ascii_case! { &name,
4018 "before" => return Ok(PseudoElement::Before),
4019 "after" => return Ok(PseudoElement::After),
4020 "marker" => return Ok(PseudoElement::Marker),
4021 "details-content" => return Ok(PseudoElement::DetailsContent),
4022 _ => {}
4023 }
4024 Err(
4025 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4026 name,
4027 )),
4028 )
4029 }
4030
4031 fn parse_functional_pseudo_element<'t>(
4032 &self,
4033 name: CowRcStr<'i>,
4034 parser: &mut CssParser<'i, 't>,
4035 ) -> Result<PseudoElement, SelectorParseError<'i>> {
4036 match_ignore_ascii_case! {&name,
4037 "highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())),
4038 _ => {}
4039 }
4040 Err(
4041 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4042 name,
4043 )),
4044 )
4045 }
4046
4047 fn default_namespace(&self) -> Option<DummyAtom> {
4048 self.default_ns.clone()
4049 }
4050
4051 fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
4052 self.ns_prefixes.get(prefix).cloned()
4053 }
4054 }
4055
4056 fn parse<'i>(
4057 input: &'i str,
4058 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4059 parse_relative(input, ParseRelative::No)
4060 }
4061
4062 fn parse_relative<'i>(
4063 input: &'i str,
4064 parse_relative: ParseRelative,
4065 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4066 parse_ns_relative(input, &DummyParser::default(), parse_relative)
4067 }
4068
4069 fn parse_expected<'i, 'a>(
4070 input: &'i str,
4071 expected: Option<&'a str>,
4072 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4073 parse_ns_expected(input, &DummyParser::default(), expected)
4074 }
4075
4076 fn parse_relative_expected<'i, 'a>(
4077 input: &'i str,
4078 parse_relative: ParseRelative,
4079 expected: Option<&'a str>,
4080 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4081 parse_ns_relative_expected(input, &DummyParser::default(), parse_relative, expected)
4082 }
4083
4084 fn parse_ns<'i>(
4085 input: &'i str,
4086 parser: &DummyParser,
4087 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4088 parse_ns_relative(input, parser, ParseRelative::No)
4089 }
4090
4091 fn parse_ns_relative<'i>(
4092 input: &'i str,
4093 parser: &DummyParser,
4094 parse_relative: ParseRelative,
4095 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4096 parse_ns_relative_expected(input, parser, parse_relative, None)
4097 }
4098
4099 fn parse_ns_expected<'i, 'a>(
4100 input: &'i str,
4101 parser: &DummyParser,
4102 expected: Option<&'a str>,
4103 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4104 parse_ns_relative_expected(input, parser, ParseRelative::No, expected)
4105 }
4106
4107 fn parse_ns_relative_expected<'i, 'a>(
4108 input: &'i str,
4109 parser: &DummyParser,
4110 parse_relative: ParseRelative,
4111 expected: Option<&'a str>,
4112 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4113 let mut parser_input = ParserInput::new(input);
4114 let result = SelectorList::parse(
4115 parser,
4116 &mut CssParser::new(&mut parser_input),
4117 parse_relative,
4118 );
4119 if let Ok(ref selectors) = result {
4120 assert_eq!(
4124 selectors.to_css_string(),
4125 match expected {
4126 Some(x) => x,
4127 None => input,
4128 }
4129 );
4130 }
4131 result
4132 }
4133
4134 fn specificity(a: u32, b: u32, c: u32) -> u32 {
4135 a << 20 | b << 10 | c
4136 }
4137
4138 #[test]
4139 fn test_empty() {
4140 let mut input = ParserInput::new(":empty");
4141 let list = SelectorList::parse(
4142 &DummyParser::default(),
4143 &mut CssParser::new(&mut input),
4144 ParseRelative::No,
4145 );
4146 assert!(list.is_ok());
4147 }
4148
4149 const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
4150 const SVG: &str = "http://www.w3.org/2000/svg";
4151
4152 #[test]
4153 fn test_parsing() {
4154 assert!(parse("").is_err());
4155 assert!(parse(":lang(4)").is_err());
4156 assert!(parse(":lang(en US)").is_err());
4157 assert_eq!(
4158 parse("EeÉ"),
4159 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4160 vec![Component::LocalName(LocalName {
4161 name: DummyAtom::from("EeÉ"),
4162 lower_name: DummyAtom::from("eeÉ"),
4163 })],
4164 specificity(0, 0, 1),
4165 SelectorFlags::empty(),
4166 )]))
4167 );
4168 assert_eq!(
4169 parse("|e"),
4170 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4171 vec![
4172 Component::ExplicitNoNamespace,
4173 Component::LocalName(LocalName {
4174 name: DummyAtom::from("e"),
4175 lower_name: DummyAtom::from("e"),
4176 }),
4177 ],
4178 specificity(0, 0, 1),
4179 SelectorFlags::empty(),
4180 )]))
4181 );
4182 assert_eq!(
4185 parse_expected("*|e", Some("e")),
4186 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4187 vec![Component::LocalName(LocalName {
4188 name: DummyAtom::from("e"),
4189 lower_name: DummyAtom::from("e"),
4190 })],
4191 specificity(0, 0, 1),
4192 SelectorFlags::empty(),
4193 )]))
4194 );
4195 assert_eq!(
4200 parse_ns(
4201 "*|e",
4202 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4203 ),
4204 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4205 vec![
4206 Component::ExplicitAnyNamespace,
4207 Component::LocalName(LocalName {
4208 name: DummyAtom::from("e"),
4209 lower_name: DummyAtom::from("e"),
4210 }),
4211 ],
4212 specificity(0, 0, 1),
4213 SelectorFlags::empty(),
4214 )]))
4215 );
4216 assert_eq!(
4217 parse("*"),
4218 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4219 vec![Component::ExplicitUniversalType],
4220 specificity(0, 0, 0),
4221 SelectorFlags::empty(),
4222 )]))
4223 );
4224 assert_eq!(
4225 parse("|*"),
4226 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4227 vec![
4228 Component::ExplicitNoNamespace,
4229 Component::ExplicitUniversalType,
4230 ],
4231 specificity(0, 0, 0),
4232 SelectorFlags::empty(),
4233 )]))
4234 );
4235 assert_eq!(
4236 parse_expected("*|*", Some("*")),
4237 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4238 vec![Component::ExplicitUniversalType],
4239 specificity(0, 0, 0),
4240 SelectorFlags::empty(),
4241 )]))
4242 );
4243 assert_eq!(
4244 parse_ns(
4245 "*|*",
4246 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4247 ),
4248 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4249 vec![
4250 Component::ExplicitAnyNamespace,
4251 Component::ExplicitUniversalType,
4252 ],
4253 specificity(0, 0, 0),
4254 SelectorFlags::empty(),
4255 )]))
4256 );
4257 assert_eq!(
4258 parse(".foo:lang(en-US)"),
4259 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4260 vec![
4261 Component::Class(DummyAtom::from("foo")),
4262 Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
4263 ],
4264 specificity(0, 2, 0),
4265 SelectorFlags::empty(),
4266 )]))
4267 );
4268 assert_eq!(
4269 parse("#bar"),
4270 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4271 vec![Component::ID(DummyAtom::from("bar"))],
4272 specificity(1, 0, 0),
4273 SelectorFlags::empty(),
4274 )]))
4275 );
4276 assert_eq!(
4277 parse("e.foo#bar"),
4278 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4279 vec![
4280 Component::LocalName(LocalName {
4281 name: DummyAtom::from("e"),
4282 lower_name: DummyAtom::from("e"),
4283 }),
4284 Component::Class(DummyAtom::from("foo")),
4285 Component::ID(DummyAtom::from("bar")),
4286 ],
4287 specificity(1, 1, 1),
4288 SelectorFlags::empty(),
4289 )]))
4290 );
4291 assert_eq!(
4292 parse("e.foo #bar"),
4293 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4294 vec![
4295 Component::LocalName(LocalName {
4296 name: DummyAtom::from("e"),
4297 lower_name: DummyAtom::from("e"),
4298 }),
4299 Component::Class(DummyAtom::from("foo")),
4300 Component::Combinator(Combinator::Descendant),
4301 Component::ID(DummyAtom::from("bar")),
4302 ],
4303 specificity(1, 1, 1),
4304 SelectorFlags::empty(),
4305 )]))
4306 );
4307 let mut parser = DummyParser::default();
4310 assert_eq!(
4311 parse_ns("[Foo]", &parser),
4312 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4313 vec![Component::AttributeInNoNamespaceExists {
4314 local_name: DummyAtom::from("Foo"),
4315 local_name_lower: DummyAtom::from("foo"),
4316 }],
4317 specificity(0, 1, 0),
4318 SelectorFlags::empty(),
4319 )]))
4320 );
4321 assert!(parse_ns("svg|circle", &parser).is_err());
4322 parser
4323 .ns_prefixes
4324 .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
4325 assert_eq!(
4326 parse_ns("svg|circle", &parser),
4327 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4328 vec![
4329 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4330 Component::LocalName(LocalName {
4331 name: DummyAtom::from("circle"),
4332 lower_name: DummyAtom::from("circle"),
4333 }),
4334 ],
4335 specificity(0, 0, 1),
4336 SelectorFlags::empty(),
4337 )]))
4338 );
4339 assert_eq!(
4340 parse_ns("svg|*", &parser),
4341 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4342 vec![
4343 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4344 Component::ExplicitUniversalType,
4345 ],
4346 specificity(0, 0, 0),
4347 SelectorFlags::empty(),
4348 )]))
4349 );
4350 parser.default_ns = Some(MATHML.into());
4355 assert_eq!(
4356 parse_ns("[Foo]", &parser),
4357 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4358 vec![
4359 Component::DefaultNamespace(MATHML.into()),
4360 Component::AttributeInNoNamespaceExists {
4361 local_name: DummyAtom::from("Foo"),
4362 local_name_lower: DummyAtom::from("foo"),
4363 },
4364 ],
4365 specificity(0, 1, 0),
4366 SelectorFlags::empty(),
4367 )]))
4368 );
4369 assert_eq!(
4371 parse_ns("e", &parser),
4372 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4373 vec![
4374 Component::DefaultNamespace(MATHML.into()),
4375 Component::LocalName(LocalName {
4376 name: DummyAtom::from("e"),
4377 lower_name: DummyAtom::from("e"),
4378 }),
4379 ],
4380 specificity(0, 0, 1),
4381 SelectorFlags::empty(),
4382 )]))
4383 );
4384 assert_eq!(
4385 parse_ns("*", &parser),
4386 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4387 vec![
4388 Component::DefaultNamespace(MATHML.into()),
4389 Component::ExplicitUniversalType,
4390 ],
4391 specificity(0, 0, 0),
4392 SelectorFlags::empty(),
4393 )]))
4394 );
4395 assert_eq!(
4396 parse_ns("*|*", &parser),
4397 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4398 vec![
4399 Component::ExplicitAnyNamespace,
4400 Component::ExplicitUniversalType,
4401 ],
4402 specificity(0, 0, 0),
4403 SelectorFlags::empty(),
4404 )]))
4405 );
4406 assert_eq!(
4409 parse_ns(":not(.cl)", &parser),
4410 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4411 vec![
4412 Component::DefaultNamespace(MATHML.into()),
4413 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4414 vec![Component::Class(DummyAtom::from("cl"))],
4415 specificity(0, 1, 0),
4416 SelectorFlags::empty(),
4417 )])),
4418 ],
4419 specificity(0, 1, 0),
4420 SelectorFlags::empty(),
4421 )]))
4422 );
4423 assert_eq!(
4424 parse_ns(":not(*)", &parser),
4425 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4426 vec![
4427 Component::DefaultNamespace(MATHML.into()),
4428 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4429 vec![
4430 Component::DefaultNamespace(MATHML.into()),
4431 Component::ExplicitUniversalType,
4432 ],
4433 specificity(0, 0, 0),
4434 SelectorFlags::empty(),
4435 )]),),
4436 ],
4437 specificity(0, 0, 0),
4438 SelectorFlags::empty(),
4439 )]))
4440 );
4441 assert_eq!(
4442 parse_ns(":not(e)", &parser),
4443 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4444 vec![
4445 Component::DefaultNamespace(MATHML.into()),
4446 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4447 vec![
4448 Component::DefaultNamespace(MATHML.into()),
4449 Component::LocalName(LocalName {
4450 name: DummyAtom::from("e"),
4451 lower_name: DummyAtom::from("e"),
4452 }),
4453 ],
4454 specificity(0, 0, 1),
4455 SelectorFlags::empty(),
4456 )])),
4457 ],
4458 specificity(0, 0, 1),
4459 SelectorFlags::empty(),
4460 )]))
4461 );
4462 assert_eq!(
4463 parse("[attr|=\"foo\"]"),
4464 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4465 vec![Component::AttributeInNoNamespace {
4466 local_name: DummyAtom::from("attr"),
4467 operator: AttrSelectorOperator::DashMatch,
4468 value: DummyAttrValue::from("foo"),
4469 case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
4470 }],
4471 specificity(0, 1, 0),
4472 SelectorFlags::empty(),
4473 )]))
4474 );
4475 assert_eq!(
4477 parse("::before"),
4478 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4479 vec![
4480 Component::Combinator(Combinator::PseudoElement),
4481 Component::PseudoElement(PseudoElement::Before),
4482 ],
4483 specificity(0, 0, 1),
4484 SelectorFlags::HAS_PSEUDO,
4485 )]))
4486 );
4487 assert_eq!(
4488 parse("::before:hover"),
4489 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4490 vec![
4491 Component::Combinator(Combinator::PseudoElement),
4492 Component::PseudoElement(PseudoElement::Before),
4493 Component::NonTSPseudoClass(PseudoClass::Hover),
4494 ],
4495 specificity(0, 1, 1),
4496 SelectorFlags::HAS_PSEUDO,
4497 )]))
4498 );
4499 assert_eq!(
4500 parse("::before:hover:hover"),
4501 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4502 vec![
4503 Component::Combinator(Combinator::PseudoElement),
4504 Component::PseudoElement(PseudoElement::Before),
4505 Component::NonTSPseudoClass(PseudoClass::Hover),
4506 Component::NonTSPseudoClass(PseudoClass::Hover),
4507 ],
4508 specificity(0, 2, 1),
4509 SelectorFlags::HAS_PSEUDO,
4510 )]))
4511 );
4512 assert!(parse("::before:hover:lang(foo)").is_err());
4513 assert!(parse("::before:hover .foo").is_err());
4514 assert!(parse("::before .foo").is_err());
4515 assert!(parse("::before ~ bar").is_err());
4516 assert!(parse("::before:active").is_ok());
4517
4518 assert!(parse(":: before").is_err());
4520 assert_eq!(
4521 parse("div ::after"),
4522 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4523 vec![
4524 Component::LocalName(LocalName {
4525 name: DummyAtom::from("div"),
4526 lower_name: DummyAtom::from("div"),
4527 }),
4528 Component::Combinator(Combinator::Descendant),
4529 Component::Combinator(Combinator::PseudoElement),
4530 Component::PseudoElement(PseudoElement::After),
4531 ],
4532 specificity(0, 0, 2),
4533 SelectorFlags::HAS_PSEUDO,
4534 )]))
4535 );
4536 assert_eq!(
4537 parse("#d1 > .ok"),
4538 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4539 vec![
4540 Component::ID(DummyAtom::from("d1")),
4541 Component::Combinator(Combinator::Child),
4542 Component::Class(DummyAtom::from("ok")),
4543 ],
4544 (1 << 20) + (1 << 10) + (0 << 0),
4545 SelectorFlags::empty(),
4546 )]))
4547 );
4548 parser.default_ns = None;
4549 assert!(parse(":not(#provel.old)").is_ok());
4550 assert!(parse(":not(#provel > old)").is_ok());
4551 assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
4552 assert_eq!(
4554 parse_ns(":not(*)", &parser),
4555 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4556 vec![Component::Negation(SelectorList::from_vec(vec![
4557 Selector::from_vec(
4558 vec![Component::ExplicitUniversalType],
4559 specificity(0, 0, 0),
4560 SelectorFlags::empty(),
4561 )
4562 ]))],
4563 specificity(0, 0, 0),
4564 SelectorFlags::empty(),
4565 )]))
4566 );
4567 assert_eq!(
4568 parse_ns(":not(|*)", &parser),
4569 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4570 vec![Component::Negation(SelectorList::from_vec(vec![
4571 Selector::from_vec(
4572 vec![
4573 Component::ExplicitNoNamespace,
4574 Component::ExplicitUniversalType,
4575 ],
4576 specificity(0, 0, 0),
4577 SelectorFlags::empty(),
4578 )
4579 ]))],
4580 specificity(0, 0, 0),
4581 SelectorFlags::empty(),
4582 )]))
4583 );
4584 assert_eq!(
4587 parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
4588 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4589 vec![Component::Negation(SelectorList::from_vec(vec![
4590 Selector::from_vec(
4591 vec![Component::ExplicitUniversalType],
4592 specificity(0, 0, 0),
4593 SelectorFlags::empty(),
4594 )
4595 ]))],
4596 specificity(0, 0, 0),
4597 SelectorFlags::empty(),
4598 )]))
4599 );
4600
4601 assert!(parse("::highlight(foo)").is_ok());
4602
4603 assert!(parse("::slotted()").is_err());
4604 assert!(parse("::slotted(div)").is_ok());
4605 assert!(parse("::slotted(div).foo").is_err());
4606 assert!(parse("::slotted(div + bar)").is_err());
4607 assert!(parse("::slotted(div) + foo").is_err());
4608
4609 assert!(parse("::part()").is_err());
4610 assert!(parse("::part(42)").is_err());
4611 assert!(parse("::part(foo bar)").is_ok());
4612 assert!(parse("::part(foo):hover").is_ok());
4613 assert!(parse("::part(foo) + bar").is_err());
4614
4615 assert!(parse("div ::slotted(div)").is_ok());
4616 assert!(parse("div + slot::slotted(div)").is_ok());
4617 assert!(parse("div + slot::slotted(div.foo)").is_ok());
4618 assert!(parse("slot::slotted(div,foo)::first-line").is_err());
4619 assert!(parse("::slotted(div)::before").is_ok());
4620 assert!(parse("slot::slotted(div,foo)").is_err());
4621
4622 assert!(parse("foo:where()").is_ok());
4623 assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
4624 assert!(parse("foo:where(::before)").is_ok());
4625 }
4626
4627 #[test]
4628 fn parent_selector() {
4629 assert!(parse("foo &").is_ok());
4630 assert_eq!(
4631 parse("#foo &.bar"),
4632 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4633 vec![
4634 Component::ID(DummyAtom::from("foo")),
4635 Component::Combinator(Combinator::Descendant),
4636 Component::ParentSelector,
4637 Component::Class(DummyAtom::from("bar")),
4638 ],
4639 (1 << 20) + (1 << 10) + (0 << 0),
4640 SelectorFlags::HAS_PARENT
4641 )]))
4642 );
4643
4644 let parent = parse(".bar, div .baz").unwrap();
4645 let child = parse("#foo &.bar").unwrap();
4646 assert_eq!(
4647 child.replace_parent_selector(&parent),
4648 parse("#foo :is(.bar, div .baz).bar").unwrap()
4649 );
4650
4651 let has_child = parse("#foo:has(&.bar)").unwrap();
4652 assert_eq!(
4653 has_child.replace_parent_selector(&parent),
4654 parse("#foo:has(:is(.bar, div .baz).bar)").unwrap()
4655 );
4656
4657 let child =
4658 parse_relative_expected("#foo", ParseRelative::ForNesting, Some("& #foo")).unwrap();
4659 assert_eq!(
4660 child.replace_parent_selector(&parent),
4661 parse(":is(.bar, div .baz) #foo").unwrap()
4662 );
4663
4664 let child =
4665 parse_relative_expected("+ #foo", ParseRelative::ForNesting, Some("& + #foo")).unwrap();
4666 assert_eq!(child, parse("& + #foo").unwrap());
4667 }
4668
4669 #[test]
4670 fn test_pseudo_iter() {
4671 let list = parse("q::before").unwrap();
4672 let selector = &list.slice()[0];
4673 assert!(!selector.is_universal());
4674 let mut iter = selector.iter();
4675 assert_eq!(
4676 iter.next(),
4677 Some(&Component::PseudoElement(PseudoElement::Before))
4678 );
4679 assert_eq!(iter.next(), None);
4680 let combinator = iter.next_sequence();
4681 assert_eq!(combinator, Some(Combinator::PseudoElement));
4682 assert!(matches!(iter.next(), Some(&Component::LocalName(..))));
4683 assert_eq!(iter.next(), None);
4684 assert_eq!(iter.next_sequence(), None);
4685 }
4686
4687 #[test]
4688 fn test_pseudo_before_marker() {
4689 let list = parse("::before::marker").unwrap();
4690 let selector = &list.slice()[0];
4691 let mut iter = selector.iter();
4692 assert_eq!(
4693 iter.next(),
4694 Some(&Component::PseudoElement(PseudoElement::Marker))
4695 );
4696 assert_eq!(iter.next(), None);
4697 let combinator = iter.next_sequence();
4698 assert_eq!(combinator, Some(Combinator::PseudoElement));
4699 assert!(matches!(
4700 iter.next(),
4701 Some(&Component::PseudoElement(PseudoElement::Before))
4702 ));
4703 assert_eq!(iter.next(), None);
4704 let combinator = iter.next_sequence();
4705 assert_eq!(combinator, Some(Combinator::PseudoElement));
4706 assert_eq!(iter.next(), None);
4707 assert_eq!(iter.next_sequence(), None);
4708 }
4709
4710 #[test]
4711 fn test_pseudo_duplicate_before_after_or_marker() {
4712 assert!(parse("::before::before").is_err());
4713 assert!(parse("::after::after").is_err());
4714 assert!(parse("::marker::marker").is_err());
4715 }
4716
4717 #[test]
4718 fn test_pseudo_on_element_backed_pseudo() {
4719 let list = parse("::details-content::before").unwrap();
4720 let selector = &list.slice()[0];
4721 let mut iter = selector.iter();
4722 assert_eq!(
4723 iter.next(),
4724 Some(&Component::PseudoElement(PseudoElement::Before))
4725 );
4726 assert_eq!(iter.next(), None);
4727 let combinator = iter.next_sequence();
4728 assert_eq!(combinator, Some(Combinator::PseudoElement));
4729 assert!(matches!(
4730 iter.next(),
4731 Some(&Component::PseudoElement(PseudoElement::DetailsContent))
4732 ));
4733 assert_eq!(iter.next(), None);
4734 let combinator = iter.next_sequence();
4735 assert_eq!(combinator, Some(Combinator::PseudoElement));
4736 assert_eq!(iter.next(), None);
4737 assert_eq!(iter.next_sequence(), None);
4738 }
4739
4740 #[test]
4741 fn test_universal() {
4742 let list = parse_ns(
4743 "*|*::before",
4744 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
4745 )
4746 .unwrap();
4747 let selector = &list.slice()[0];
4748 assert!(selector.is_universal());
4749 }
4750
4751 #[test]
4752 fn test_empty_pseudo_iter() {
4753 let list = parse("::before").unwrap();
4754 let selector = &list.slice()[0];
4755 assert!(selector.is_universal());
4756 let mut iter = selector.iter();
4757 assert_eq!(
4758 iter.next(),
4759 Some(&Component::PseudoElement(PseudoElement::Before))
4760 );
4761 assert_eq!(iter.next(), None);
4762 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
4763 assert_eq!(iter.next(), None);
4764 assert_eq!(iter.next_sequence(), None);
4765 }
4766
4767 #[test]
4768 fn test_parse_implicit_scope() {
4769 assert_eq!(
4770 parse_relative_expected(".foo", ParseRelative::ForScope, None).unwrap(),
4771 SelectorList::from_vec(vec![Selector::from_vec(
4772 vec![
4773 Component::ImplicitScope,
4774 Component::Combinator(Combinator::Descendant),
4775 Component::Class(DummyAtom::from("foo")),
4776 ],
4777 specificity(0, 1, 0),
4778 SelectorFlags::HAS_SCOPE,
4779 )])
4780 );
4781
4782 assert_eq!(
4783 parse_relative_expected(":scope .foo", ParseRelative::ForScope, None).unwrap(),
4784 SelectorList::from_vec(vec![Selector::from_vec(
4785 vec![
4786 Component::Scope,
4787 Component::Combinator(Combinator::Descendant),
4788 Component::Class(DummyAtom::from("foo")),
4789 ],
4790 specificity(0, 2, 0),
4791 SelectorFlags::HAS_SCOPE
4792 )])
4793 );
4794
4795 assert_eq!(
4796 parse_relative_expected("> .foo", ParseRelative::ForScope, Some("> .foo")).unwrap(),
4797 SelectorList::from_vec(vec![Selector::from_vec(
4798 vec![
4799 Component::ImplicitScope,
4800 Component::Combinator(Combinator::Child),
4801 Component::Class(DummyAtom::from("foo")),
4802 ],
4803 specificity(0, 1, 0),
4804 SelectorFlags::HAS_SCOPE
4805 )])
4806 );
4807
4808 assert_eq!(
4809 parse_relative_expected(".foo :scope > .bar", ParseRelative::ForScope, None).unwrap(),
4810 SelectorList::from_vec(vec![Selector::from_vec(
4811 vec![
4812 Component::Class(DummyAtom::from("foo")),
4813 Component::Combinator(Combinator::Descendant),
4814 Component::Scope,
4815 Component::Combinator(Combinator::Child),
4816 Component::Class(DummyAtom::from("bar")),
4817 ],
4818 specificity(0, 3, 0),
4819 SelectorFlags::HAS_SCOPE
4820 )])
4821 );
4822 }
4823
4824 struct TestVisitor {
4825 seen: Vec<String>,
4826 }
4827
4828 impl SelectorVisitor for TestVisitor {
4829 type Impl = DummySelectorImpl;
4830
4831 fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool {
4832 let mut dest = String::new();
4833 s.to_css(&mut dest).unwrap();
4834 self.seen.push(dest);
4835 true
4836 }
4837 }
4838
4839 #[test]
4840 fn visitor() {
4841 let mut test_visitor = TestVisitor { seen: vec![] };
4842 parse(":not(:hover) ~ label").unwrap().slice()[0].visit(&mut test_visitor);
4843 assert!(test_visitor.seen.contains(&":hover".into()));
4844
4845 let mut test_visitor = TestVisitor { seen: vec![] };
4846 parse("::before:hover").unwrap().slice()[0].visit(&mut test_visitor);
4847 assert!(test_visitor.seen.contains(&":hover".into()));
4848 }
4849}