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 parses_as_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 mut iter: SelectorIter<Impl>,
751 quirks_mode: QuirksMode,
752 hashes: &mut [u32; 4],
753 len: &mut usize,
754) -> bool {
755 loop {
756 while let Some(item) = iter.next() {
757 if let Component::Is(ref list) | Component::Where(ref list) = item {
758 let slice = list.slice();
759 if slice.len() == 1
760 && !collect_ancestor_hashes(slice[0].iter(), quirks_mode, hashes, len)
761 {
762 return false;
763 }
764 }
765 }
766 let Some(c) = iter.next_sequence() else {
767 return true;
768 };
769 match c {
770 Combinator::Child | Combinator::Descendant => break,
772 Combinator::LaterSibling | Combinator::NextSibling => {
773 iter.skip_until_ancestor();
774 break;
775 },
776 Combinator::Part | Combinator::SlotAssignment | Combinator::PseudoElement => {},
781 }
782 }
783
784 collect_selector_hashes(AncestorIter(iter), quirks_mode, hashes, len, |s| {
785 AncestorIter(s.iter())
786 })
787}
788
789impl AncestorHashes {
790 pub fn new<Impl: SelectorImpl>(selector: &Selector<Impl>, quirks_mode: QuirksMode) -> Self {
791 let mut hashes = [0u32; 4];
793 let mut len = 0;
794 collect_ancestor_hashes(selector.iter(), quirks_mode, &mut hashes, &mut len);
795 debug_assert!(len <= 4);
796
797 if len == 4 {
800 let fourth = hashes[3];
801 hashes[0] |= (fourth & 0x000000ff) << 24;
802 hashes[1] |= (fourth & 0x0000ff00) << 16;
803 hashes[2] |= (fourth & 0x00ff0000) << 8;
804 }
805
806 AncestorHashes {
807 packed_hashes: [hashes[0], hashes[1], hashes[2]],
808 }
809 }
810
811 pub fn fourth_hash(&self) -> u32 {
813 ((self.packed_hashes[0] & 0xff000000) >> 24)
814 | ((self.packed_hashes[1] & 0xff000000) >> 16)
815 | ((self.packed_hashes[2] & 0xff000000) >> 8)
816 }
817}
818
819#[inline]
820pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
821 Impl::NamespaceUrl::default()
823}
824
825pub(super) type SelectorData<Impl> = ThinArc<SpecificityAndFlags, Component<Impl>>;
826
827#[derive(Clone, Copy, Debug, Eq, PartialEq)]
830pub enum MatchesFeaturelessHost {
831 Yes,
833 Only,
835 Never,
837}
838
839impl MatchesFeaturelessHost {
840 #[inline]
842 pub fn may_match(self) -> bool {
843 return !matches!(self, Self::Never);
844 }
845}
846
847#[derive(Clone, Eq, PartialEq)]
862#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
863#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
864#[repr(transparent)]
865pub struct Selector<Impl: SelectorImpl>(
866 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] SelectorData<Impl>,
867);
868
869impl<Impl: SelectorImpl> Selector<Impl> {
870 pub fn mark_as_intentionally_leaked(&self) {
872 self.0.mark_as_intentionally_leaked()
873 }
874
875 fn scope() -> Self {
876 Self(ThinArc::from_header_and_iter(
877 SpecificityAndFlags {
878 specificity: Specificity::single_class_like().into(),
879 flags: SelectorFlags::HAS_SCOPE,
880 },
881 std::iter::once(Component::Scope),
882 ))
883 }
884
885 fn implicit_scope() -> Self {
887 Self(ThinArc::from_header_and_iter(
888 SpecificityAndFlags {
889 specificity: 0,
890 flags: SelectorFlags::HAS_SCOPE,
891 },
892 std::iter::once(Component::ImplicitScope),
893 ))
894 }
895
896 #[inline]
897 pub fn specificity(&self) -> u32 {
898 self.0.header.specificity
899 }
900
901 #[inline]
902 pub(crate) fn flags(&self) -> SelectorFlags {
903 self.0.header.flags
904 }
905
906 #[inline]
907 pub fn has_pseudo_element(&self) -> bool {
908 self.flags().intersects(SelectorFlags::HAS_PSEUDO)
909 }
910
911 #[inline]
912 pub fn has_parent_selector(&self) -> bool {
913 self.flags().intersects(SelectorFlags::HAS_PARENT)
914 }
915
916 #[inline]
917 pub fn has_scope_selector(&self) -> bool {
918 self.flags().intersects(SelectorFlags::HAS_SCOPE)
919 }
920
921 #[inline]
922 pub fn is_slotted(&self) -> bool {
923 self.flags().intersects(SelectorFlags::HAS_SLOTTED)
924 }
925
926 #[inline]
927 pub fn is_part(&self) -> bool {
928 self.flags().intersects(SelectorFlags::HAS_PART)
929 }
930
931 #[inline]
932 pub fn parts(&self) -> Option<&[Impl::Identifier]> {
933 if !self.is_part() {
934 return None;
935 }
936
937 let mut iter = self.iter();
938 if self.has_pseudo_element() {
939 for _ in &mut iter {}
941
942 let combinator = iter.next_sequence()?;
943 debug_assert_eq!(combinator, Combinator::PseudoElement);
944 }
945
946 for component in iter {
947 if let Component::Part(ref part) = *component {
948 return Some(part);
949 }
950 }
951
952 debug_assert!(false, "is_part() lied somehow?");
953 None
954 }
955
956 #[inline]
957 pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
958 if !self.has_pseudo_element() {
959 return None;
960 }
961
962 for component in self.iter() {
963 if let Component::PseudoElement(ref pseudo) = *component {
964 return Some(pseudo);
965 }
966 }
967
968 debug_assert!(false, "has_pseudo_element lied!");
969 None
970 }
971
972 #[inline]
973 pub fn pseudo_elements(&self) -> SmallVec<[&Impl::PseudoElement; 3]> {
974 let mut pseudos = SmallVec::new();
975
976 if !self.has_pseudo_element() {
977 return pseudos;
978 }
979
980 let mut iter = self.iter();
981 loop {
982 for component in &mut iter {
983 if let Component::PseudoElement(ref pseudo) = *component {
984 pseudos.push(pseudo);
985 }
986 }
987 match iter.next_sequence() {
988 Some(Combinator::PseudoElement) => {},
989 _ => break,
990 }
991 }
992
993 debug_assert!(!pseudos.is_empty(), "has_pseudo_element lied!");
994
995 pseudos
996 }
997
998 #[inline]
1002 pub fn is_universal(&self) -> bool {
1003 self.iter_raw_match_order().all(|c| {
1004 matches!(
1005 *c,
1006 Component::ExplicitUniversalType
1007 | Component::ExplicitAnyNamespace
1008 | Component::Combinator(Combinator::PseudoElement)
1009 | Component::PseudoElement(..)
1010 )
1011 })
1012 }
1013
1014 #[inline]
1017 pub fn matches_featureless_host(
1018 &self,
1019 scope_matches_featureless_host: bool,
1020 ) -> MatchesFeaturelessHost {
1021 let flags = self.flags();
1022 if !flags.intersects(SelectorFlags::HAS_HOST | SelectorFlags::HAS_SCOPE) {
1023 return MatchesFeaturelessHost::Never;
1024 }
1025
1026 let mut iter = self.iter();
1027 if flags.intersects(SelectorFlags::HAS_PSEUDO) {
1028 for _ in &mut iter {
1029 }
1031 match iter.next_sequence() {
1032 Some(c) if c.is_pseudo_element() => {},
1033 _ => {
1034 debug_assert!(false, "Pseudo selector without pseudo combinator?");
1035 return MatchesFeaturelessHost::Never;
1036 },
1037 }
1038 }
1039
1040 let compound_matches = crate::matching::compound_matches_featureless_host(
1041 &mut iter,
1042 scope_matches_featureless_host,
1043 );
1044 if iter.next_sequence().is_some() {
1045 return MatchesFeaturelessHost::Never;
1046 }
1047 return compound_matches;
1048 }
1049
1050 #[inline]
1054 pub fn iter(&self) -> SelectorIter<'_, Impl> {
1055 SelectorIter {
1056 iter: self.iter_raw_match_order(),
1057 next_combinator: None,
1058 }
1059 }
1060
1061 #[inline]
1063 pub fn iter_skip_relative_selector_anchor(&self) -> SelectorIter<'_, Impl> {
1064 if cfg!(debug_assertions) {
1065 let mut selector_iter = self.iter_raw_parse_order_from(0);
1066 assert!(
1067 matches!(
1068 selector_iter.next().unwrap(),
1069 Component::RelativeSelectorAnchor
1070 ),
1071 "Relative selector does not start with RelativeSelectorAnchor"
1072 );
1073 assert!(
1074 selector_iter.next().unwrap().is_combinator(),
1075 "Relative combinator does not exist"
1076 );
1077 }
1078
1079 SelectorIter {
1080 iter: self.0.slice()[..self.len() - 2].iter(),
1081 next_combinator: None,
1082 }
1083 }
1084
1085 #[inline]
1088 pub fn iter_from(&self, offset: usize) -> SelectorIter<'_, Impl> {
1089 let iter = self.0.slice()[offset..].iter();
1090 SelectorIter {
1091 iter,
1092 next_combinator: None,
1093 }
1094 }
1095
1096 #[inline]
1099 pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
1100 match self.0.slice()[index] {
1101 Component::Combinator(c) => c,
1102 ref other => panic!(
1103 "Not a combinator: {:?}, {:?}, index: {}",
1104 other, self, index
1105 ),
1106 }
1107 }
1108
1109 #[inline]
1112 pub fn iter_raw_match_order(&self) -> slice::Iter<'_, Component<Impl>> {
1113 self.0.slice().iter()
1114 }
1115
1116 #[inline]
1119 pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
1120 match self.0.slice()[self.len() - index - 1] {
1121 Component::Combinator(c) => c,
1122 ref other => panic!(
1123 "Not a combinator: {:?}, {:?}, index: {}",
1124 other, self, index
1125 ),
1126 }
1127 }
1128
1129 #[inline]
1133 pub fn iter_raw_parse_order_from(
1134 &self,
1135 offset: usize,
1136 ) -> Rev<slice::Iter<'_, Component<Impl>>> {
1137 self.0.slice()[..self.len() - offset].iter().rev()
1138 }
1139
1140 #[allow(dead_code)]
1142 pub(crate) fn from_vec(
1143 vec: Vec<Component<Impl>>,
1144 specificity: u32,
1145 flags: SelectorFlags,
1146 ) -> Self {
1147 let mut builder = SelectorBuilder::default();
1148 for component in vec.into_iter() {
1149 if let Some(combinator) = component.as_combinator() {
1150 builder.push_combinator(combinator);
1151 } else {
1152 builder.push_simple_selector(component);
1153 }
1154 }
1155 let spec = SpecificityAndFlags { specificity, flags };
1156 Selector(builder.build_with_specificity_and_flags(spec, ParseRelative::No))
1157 }
1158
1159 #[inline]
1160 fn into_data(self) -> SelectorData<Impl> {
1161 self.0
1162 }
1163
1164 pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
1165 let parent_specificity_and_flags = selector_list_specificity_and_flags(
1166 parent.slice().iter(),
1167 true,
1168 );
1169
1170 let mut specificity = Specificity::from(self.specificity());
1171 let mut flags = self.flags() - SelectorFlags::HAS_PARENT;
1172 let forbidden_flags = SelectorFlags::forbidden_for_nesting();
1173
1174 fn replace_parent_on_selector_list<Impl: SelectorImpl>(
1175 orig: &[Selector<Impl>],
1176 parent: &SelectorList<Impl>,
1177 specificity: &mut Specificity,
1178 flags: &mut SelectorFlags,
1179 propagate_specificity: bool,
1180 forbidden_flags: SelectorFlags,
1181 ) -> Option<SelectorList<Impl>> {
1182 if !orig.iter().any(|s| s.has_parent_selector()) {
1183 return None;
1184 }
1185
1186 let result =
1187 SelectorList::from_iter(orig.iter().map(|s| s.replace_parent_selector(parent)));
1188
1189 let result_specificity_and_flags = selector_list_specificity_and_flags(
1190 result.slice().iter(),
1191 false,
1192 );
1193 if propagate_specificity {
1194 *specificity += Specificity::from(
1195 result_specificity_and_flags.specificity
1196 - selector_list_specificity_and_flags(
1197 orig.iter(),
1198 false,
1199 )
1200 .specificity,
1201 );
1202 }
1203 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1204 Some(result)
1205 }
1206
1207 fn replace_parent_on_relative_selector_list<Impl: SelectorImpl>(
1208 orig: &[RelativeSelector<Impl>],
1209 parent: &SelectorList<Impl>,
1210 specificity: &mut Specificity,
1211 flags: &mut SelectorFlags,
1212 forbidden_flags: SelectorFlags,
1213 ) -> Vec<RelativeSelector<Impl>> {
1214 let mut any = false;
1215
1216 let result = orig
1217 .iter()
1218 .map(|s| {
1219 if !s.selector.has_parent_selector() {
1220 return s.clone();
1221 }
1222 any = true;
1223 RelativeSelector {
1224 match_hint: s.match_hint,
1225 selector: s.selector.replace_parent_selector(parent),
1226 }
1227 })
1228 .collect();
1229
1230 if !any {
1231 return result;
1232 }
1233
1234 let result_specificity_and_flags = relative_selector_list_specificity_and_flags(
1235 &result, false,
1236 );
1237 flags.insert(result_specificity_and_flags.flags - forbidden_flags);
1238 *specificity += Specificity::from(
1239 result_specificity_and_flags.specificity
1240 - relative_selector_list_specificity_and_flags(
1241 orig, false,
1242 )
1243 .specificity,
1244 );
1245 result
1246 }
1247
1248 fn replace_parent_on_selector<Impl: SelectorImpl>(
1249 orig: &Selector<Impl>,
1250 parent: &SelectorList<Impl>,
1251 specificity: &mut Specificity,
1252 flags: &mut SelectorFlags,
1253 forbidden_flags: SelectorFlags,
1254 ) -> Selector<Impl> {
1255 let new_selector = orig.replace_parent_selector(parent);
1256 *specificity += Specificity::from(new_selector.specificity() - orig.specificity());
1257 flags.insert(new_selector.flags() - forbidden_flags);
1258 new_selector
1259 }
1260
1261 if !self.has_parent_selector() {
1262 return self.clone();
1263 }
1264
1265 let iter = self.iter_raw_match_order().map(|component| {
1266 use self::Component::*;
1267 match *component {
1268 LocalName(..)
1269 | ID(..)
1270 | Class(..)
1271 | AttributeInNoNamespaceExists { .. }
1272 | AttributeInNoNamespace { .. }
1273 | AttributeOther(..)
1274 | ExplicitUniversalType
1275 | ExplicitAnyNamespace
1276 | ExplicitNoNamespace
1277 | DefaultNamespace(..)
1278 | Namespace(..)
1279 | Root
1280 | Empty
1281 | Scope
1282 | ImplicitScope
1283 | Nth(..)
1284 | NonTSPseudoClass(..)
1285 | PseudoElement(..)
1286 | Combinator(..)
1287 | Host(None)
1288 | Part(..)
1289 | Invalid(..)
1290 | RelativeSelectorAnchor => component.clone(),
1291 ParentSelector => {
1292 specificity += Specificity::from(parent_specificity_and_flags.specificity);
1293 flags.insert(parent_specificity_and_flags.flags - forbidden_flags);
1294 Is(parent.clone())
1295 },
1296 Negation(ref selectors) => {
1297 Negation(
1298 replace_parent_on_selector_list(
1299 selectors.slice(),
1300 parent,
1301 &mut specificity,
1302 &mut flags,
1303 true,
1304 forbidden_flags,
1305 )
1306 .unwrap_or_else(|| selectors.clone()),
1307 )
1308 },
1309 Is(ref selectors) => {
1310 Is(replace_parent_on_selector_list(
1311 selectors.slice(),
1312 parent,
1313 &mut specificity,
1314 &mut flags,
1315 true,
1316 forbidden_flags,
1317 )
1318 .unwrap_or_else(|| selectors.clone()))
1319 },
1320 Where(ref selectors) => {
1321 Where(
1322 replace_parent_on_selector_list(
1323 selectors.slice(),
1324 parent,
1325 &mut specificity,
1326 &mut flags,
1327 false,
1328 forbidden_flags,
1329 )
1330 .unwrap_or_else(|| selectors.clone()),
1331 )
1332 },
1333 Has(ref selectors) => Has(replace_parent_on_relative_selector_list(
1334 selectors,
1335 parent,
1336 &mut specificity,
1337 &mut flags,
1338 forbidden_flags,
1339 )
1340 .into_boxed_slice()),
1341
1342 Host(Some(ref selector)) => Host(Some(replace_parent_on_selector(
1343 selector,
1344 parent,
1345 &mut specificity,
1346 &mut flags,
1347 forbidden_flags,
1348 ))),
1349 NthOf(ref data) => {
1350 let selectors = replace_parent_on_selector_list(
1351 data.selectors(),
1352 parent,
1353 &mut specificity,
1354 &mut flags,
1355 true,
1356 forbidden_flags,
1357 );
1358 NthOf(match selectors {
1359 Some(s) => {
1360 NthOfSelectorData::new(data.nth_data(), s.slice().iter().cloned())
1361 },
1362 None => data.clone(),
1363 })
1364 },
1365 Slotted(ref selector) => Slotted(replace_parent_on_selector(
1366 selector,
1367 parent,
1368 &mut specificity,
1369 &mut flags,
1370 forbidden_flags,
1371 )),
1372 }
1373 });
1374 let mut items = UniqueArc::from_header_and_iter(Default::default(), iter);
1375 *items.header_mut() = SpecificityAndFlags {
1376 specificity: specificity.into(),
1377 flags,
1378 };
1379 Selector(items.shareable())
1380 }
1381
1382 #[inline]
1384 pub fn len(&self) -> usize {
1385 self.0.len()
1386 }
1387
1388 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
1390 self.0.heap_ptr()
1391 }
1392
1393 pub fn visit<V>(&self, visitor: &mut V) -> bool
1412 where
1413 V: SelectorVisitor<Impl = Impl>,
1414 {
1415 let mut current = self.iter();
1416 let mut combinator = None;
1417 loop {
1418 if !visitor.visit_complex_selector(combinator) {
1419 return false;
1420 }
1421
1422 for selector in &mut current {
1423 if !selector.visit(visitor) {
1424 return false;
1425 }
1426 }
1427
1428 combinator = current.next_sequence();
1429 if combinator.is_none() {
1430 break;
1431 }
1432 }
1433
1434 true
1435 }
1436
1437 #[inline]
1439 pub fn parse<'i, 't, P>(
1440 parser: &P,
1441 input: &mut CssParser<'i, 't>,
1442 ) -> Result<Self, ParseError<'i, P::Error>>
1443 where
1444 P: Parser<'i, Impl = Impl>,
1445 {
1446 parse_selector(
1447 parser,
1448 input,
1449 SelectorParsingState::empty(),
1450 ParseRelative::No,
1451 )
1452 }
1453
1454 pub fn new_invalid(s: &str) -> Self {
1455 fn check_for_parent(input: &mut CssParser, has_parent: &mut bool) {
1456 while let Ok(t) = input.next() {
1457 match *t {
1458 Token::Function(_)
1459 | Token::ParenthesisBlock
1460 | Token::CurlyBracketBlock
1461 | Token::SquareBracketBlock => {
1462 let _ = input.parse_nested_block(
1463 |i| -> Result<(), ParseError<'_, BasicParseError>> {
1464 check_for_parent(i, has_parent);
1465 Ok(())
1466 },
1467 );
1468 },
1469 Token::Delim('&') => {
1470 *has_parent = true;
1471 },
1472 _ => {},
1473 }
1474 if *has_parent {
1475 break;
1476 }
1477 }
1478 }
1479 let mut has_parent = false;
1480 {
1481 let mut parser = cssparser::ParserInput::new(s);
1482 let mut parser = CssParser::new(&mut parser);
1483 check_for_parent(&mut parser, &mut has_parent);
1484 }
1485 Self(ThinArc::from_header_and_iter(
1486 SpecificityAndFlags {
1487 specificity: 0,
1488 flags: if has_parent {
1489 SelectorFlags::HAS_PARENT
1490 } else {
1491 SelectorFlags::empty()
1492 },
1493 },
1494 std::iter::once(Component::Invalid(Arc::new(String::from(s.trim())))),
1495 ))
1496 }
1497
1498 pub fn is_rightmost(&self, offset: usize) -> bool {
1500 offset == 0
1503 || matches!(
1504 self.combinator_at_match_order(offset - 1),
1505 Combinator::PseudoElement
1506 )
1507 }
1508}
1509
1510#[derive(Clone)]
1511pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
1512 iter: slice::Iter<'a, Component<Impl>>,
1513 next_combinator: Option<Combinator>,
1514}
1515
1516impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
1517 #[inline]
1520 pub fn next_sequence(&mut self) -> Option<Combinator> {
1521 self.next_combinator.take()
1522 }
1523
1524 fn skip_until_ancestor(&mut self) {
1527 loop {
1528 while self.next().is_some() {}
1529 if self.next_sequence().is_none_or(|c| c.is_ancestor()) {
1530 break;
1531 }
1532 }
1533 }
1534
1535 #[inline]
1536 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
1537 let first = match self.next() {
1538 Some(c) => c,
1539 None => return true,
1542 };
1543 self.matches_for_stateless_pseudo_element_internal(first)
1544 }
1545
1546 #[inline(never)]
1547 fn matches_for_stateless_pseudo_element_internal(&mut self, first: &Component<Impl>) -> bool {
1548 if !first.matches_for_stateless_pseudo_element() {
1549 return false;
1550 }
1551 for component in self {
1552 if !component.matches_for_stateless_pseudo_element() {
1556 return false;
1557 }
1558 }
1559 true
1560 }
1561
1562 #[inline]
1564 pub fn selector_length(&self) -> usize {
1565 self.iter.len()
1566 }
1567}
1568
1569impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
1570 type Item = &'a Component<Impl>;
1571
1572 #[inline]
1573 fn next(&mut self) -> Option<Self::Item> {
1574 debug_assert!(
1575 self.next_combinator.is_none(),
1576 "You should call next_sequence!"
1577 );
1578 match *self.iter.next()? {
1579 Component::Combinator(c) => {
1580 self.next_combinator = Some(c);
1581 None
1582 },
1583 ref x => Some(x),
1584 }
1585 }
1586}
1587
1588impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
1589 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1590 let iter = self.iter.clone().rev();
1591 for component in iter {
1592 component.to_css(f)?
1593 }
1594 Ok(())
1595 }
1596}
1597
1598struct CombinatorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1600impl<'a, Impl: 'a + SelectorImpl> CombinatorIter<'a, Impl> {
1601 fn new(inner: SelectorIter<'a, Impl>) -> Self {
1602 let mut result = CombinatorIter(inner);
1603 result.consume_non_combinators();
1604 result
1605 }
1606
1607 fn consume_non_combinators(&mut self) {
1608 while self.0.next().is_some() {}
1609 }
1610}
1611
1612impl<'a, Impl: SelectorImpl> Iterator for CombinatorIter<'a, Impl> {
1613 type Item = Combinator;
1614 fn next(&mut self) -> Option<Self::Item> {
1615 let result = self.0.next_sequence();
1616 self.consume_non_combinators();
1617 result
1618 }
1619}
1620
1621struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
1623impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
1624 type Item = &'a Component<Impl>;
1625 fn next(&mut self) -> Option<Self::Item> {
1626 let next = self.0.next();
1628 if next.is_some() {
1629 return next;
1630 }
1631 if !self.0.next_sequence()?.is_ancestor() {
1633 self.0.skip_until_ancestor();
1634 }
1635 self.0.next()
1636 }
1637}
1638
1639#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1640#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1641pub enum Combinator {
1642 Child, Descendant, NextSibling, LaterSibling, PseudoElement,
1653 SlotAssignment,
1656 Part,
1659}
1660
1661impl Combinator {
1662 #[inline]
1664 pub fn is_pseudo_element(&self) -> bool {
1665 matches!(*self, Combinator::PseudoElement)
1666 }
1667
1668 #[inline]
1670 pub fn is_sibling(&self) -> bool {
1671 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
1672 }
1673
1674 #[inline]
1677 pub fn is_ancestor(&self) -> bool {
1678 !self.is_sibling()
1679 }
1680}
1681
1682#[derive(Copy, Clone, Eq, PartialEq)]
1684#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1685#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1686pub enum NthType {
1687 Child,
1688 LastChild,
1689 OnlyChild,
1690 OfType,
1691 LastOfType,
1692 OnlyOfType,
1693}
1694
1695impl NthType {
1696 pub fn is_only(self) -> bool {
1697 self == Self::OnlyChild || self == Self::OnlyOfType
1698 }
1699
1700 pub fn is_of_type(self) -> bool {
1701 self == Self::OfType || self == Self::LastOfType || self == Self::OnlyOfType
1702 }
1703
1704 pub fn is_from_end(self) -> bool {
1705 self == Self::LastChild || self == Self::LastOfType
1706 }
1707}
1708
1709#[derive(Copy, Clone, Eq, PartialEq, Debug)]
1711#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1712#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1713pub struct AnPlusB(pub i32, pub i32);
1714
1715impl AnPlusB {
1716 #[inline]
1717 pub fn matches_index(&self, i: i32) -> bool {
1718 match i.checked_sub(self.1) {
1720 None => false,
1721 Some(an) => match an.checked_div(self.0) {
1722 Some(n) => n >= 0 && self.0 * n == an,
1723 None => an == 0,
1724 },
1725 }
1726 }
1727}
1728
1729impl ToCss for AnPlusB {
1730 #[inline]
1733 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1734 where
1735 W: fmt::Write,
1736 {
1737 match (self.0, self.1) {
1738 (0, 0) => dest.write_char('0'),
1739
1740 (1, 0) => dest.write_char('n'),
1741 (-1, 0) => dest.write_str("-n"),
1742 (_, 0) => write!(dest, "{}n", self.0),
1743
1744 (0, _) => write!(dest, "{}", self.1),
1745 (1, _) => write!(dest, "n{:+}", self.1),
1746 (-1, _) => write!(dest, "-n{:+}", self.1),
1747 (_, _) => write!(dest, "{}n{:+}", self.0, self.1),
1748 }
1749 }
1750}
1751
1752#[derive(Copy, Clone, Eq, PartialEq)]
1756#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1757#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1758pub struct NthSelectorData {
1759 pub ty: NthType,
1760 pub is_function: bool,
1761 pub an_plus_b: AnPlusB,
1762}
1763
1764impl NthSelectorData {
1765 #[inline]
1767 pub const fn only(of_type: bool) -> Self {
1768 Self {
1769 ty: if of_type {
1770 NthType::OnlyOfType
1771 } else {
1772 NthType::OnlyChild
1773 },
1774 is_function: false,
1775 an_plus_b: AnPlusB(0, 1),
1776 }
1777 }
1778
1779 #[inline]
1781 pub const fn first(of_type: bool) -> Self {
1782 Self {
1783 ty: if of_type {
1784 NthType::OfType
1785 } else {
1786 NthType::Child
1787 },
1788 is_function: false,
1789 an_plus_b: AnPlusB(0, 1),
1790 }
1791 }
1792
1793 #[inline]
1795 pub const fn last(of_type: bool) -> Self {
1796 Self {
1797 ty: if of_type {
1798 NthType::LastOfType
1799 } else {
1800 NthType::LastChild
1801 },
1802 is_function: false,
1803 an_plus_b: AnPlusB(0, 1),
1804 }
1805 }
1806
1807 #[inline]
1809 pub fn is_simple_edge(&self) -> bool {
1810 self.an_plus_b.0 == 0
1811 && self.an_plus_b.1 == 1
1812 && !self.ty.is_of_type()
1813 && !self.ty.is_only()
1814 }
1815
1816 #[inline]
1818 fn write_start<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1819 dest.write_str(match self.ty {
1820 NthType::Child if self.is_function => ":nth-child(",
1821 NthType::Child => ":first-child",
1822 NthType::LastChild if self.is_function => ":nth-last-child(",
1823 NthType::LastChild => ":last-child",
1824 NthType::OfType if self.is_function => ":nth-of-type(",
1825 NthType::OfType => ":first-of-type",
1826 NthType::LastOfType if self.is_function => ":nth-last-of-type(",
1827 NthType::LastOfType => ":last-of-type",
1828 NthType::OnlyChild => ":only-child",
1829 NthType::OnlyOfType => ":only-of-type",
1830 })
1831 }
1832
1833 #[inline]
1834 fn write_affine<W: fmt::Write>(&self, dest: &mut W) -> fmt::Result {
1835 self.an_plus_b.to_css(dest)
1836 }
1837}
1838
1839#[derive(Clone, Eq, PartialEq)]
1843#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1844#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
1845pub struct NthOfSelectorData<Impl: SelectorImpl>(
1846 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] ThinArc<NthSelectorData, Selector<Impl>>,
1847);
1848
1849impl<Impl: SelectorImpl> NthOfSelectorData<Impl> {
1850 #[inline]
1852 pub fn new<I>(nth_data: &NthSelectorData, selectors: I) -> Self
1853 where
1854 I: Iterator<Item = Selector<Impl>> + ExactSizeIterator,
1855 {
1856 Self(ThinArc::from_header_and_iter(*nth_data, selectors))
1857 }
1858
1859 #[inline]
1861 pub fn nth_data(&self) -> &NthSelectorData {
1862 &self.0.header
1863 }
1864
1865 #[inline]
1867 pub fn selectors(&self) -> &[Selector<Impl>] {
1868 self.0.slice()
1869 }
1870}
1871
1872#[derive(Clone, Copy, Eq, PartialEq)]
1874#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
1875pub enum RelativeSelectorMatchHint {
1876 InSubtree,
1878 InChild,
1880 InNextSibling,
1882 InNextSiblingSubtree,
1884 InSibling,
1886 InSiblingSubtree,
1888}
1889
1890impl RelativeSelectorMatchHint {
1891 pub fn new(
1893 relative_combinator: Combinator,
1894 has_child_or_descendants: bool,
1895 has_adjacent_or_next_siblings: bool,
1896 ) -> Self {
1897 match relative_combinator {
1898 Combinator::Descendant => RelativeSelectorMatchHint::InSubtree,
1899 Combinator::Child => {
1900 if !has_child_or_descendants {
1901 RelativeSelectorMatchHint::InChild
1902 } else {
1903 RelativeSelectorMatchHint::InSubtree
1906 }
1907 },
1908 Combinator::NextSibling => {
1909 if !has_child_or_descendants && !has_adjacent_or_next_siblings {
1910 RelativeSelectorMatchHint::InNextSibling
1911 } else if !has_child_or_descendants && has_adjacent_or_next_siblings {
1912 RelativeSelectorMatchHint::InSibling
1913 } else if has_child_or_descendants && !has_adjacent_or_next_siblings {
1914 RelativeSelectorMatchHint::InNextSiblingSubtree
1916 } else {
1917 RelativeSelectorMatchHint::InSiblingSubtree
1918 }
1919 },
1920 Combinator::LaterSibling => {
1921 if !has_child_or_descendants {
1922 RelativeSelectorMatchHint::InSibling
1923 } else {
1924 RelativeSelectorMatchHint::InSiblingSubtree
1927 }
1928 },
1929 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1930 debug_assert!(false, "Unexpected relative combinator");
1931 RelativeSelectorMatchHint::InSubtree
1932 },
1933 }
1934 }
1935
1936 pub fn is_descendant_direction(&self) -> bool {
1938 matches!(*self, Self::InChild | Self::InSubtree)
1939 }
1940
1941 pub fn is_next_sibling(&self) -> bool {
1943 matches!(*self, Self::InNextSibling | Self::InNextSiblingSubtree)
1944 }
1945
1946 pub fn is_subtree(&self) -> bool {
1948 matches!(
1949 *self,
1950 Self::InSubtree | Self::InSiblingSubtree | Self::InNextSiblingSubtree
1951 )
1952 }
1953}
1954
1955#[derive(Clone, Copy)]
1957pub struct RelativeSelectorCombinatorCount {
1958 relative_combinator: Combinator,
1959 pub child_or_descendants: usize,
1960 pub adjacent_or_next_siblings: usize,
1961}
1962
1963impl RelativeSelectorCombinatorCount {
1964 pub fn new<Impl: SelectorImpl>(relative_selector: &RelativeSelector<Impl>) -> Self {
1966 let mut result = RelativeSelectorCombinatorCount {
1967 relative_combinator: relative_selector.selector.combinator_at_parse_order(1),
1968 child_or_descendants: 0,
1969 adjacent_or_next_siblings: 0,
1970 };
1971
1972 for combinator in CombinatorIter::new(
1973 relative_selector
1974 .selector
1975 .iter_skip_relative_selector_anchor(),
1976 ) {
1977 match combinator {
1978 Combinator::Descendant | Combinator::Child => {
1979 result.child_or_descendants += 1;
1980 },
1981 Combinator::NextSibling | Combinator::LaterSibling => {
1982 result.adjacent_or_next_siblings += 1;
1983 },
1984 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
1985 continue;
1986 },
1987 };
1988 }
1989 result
1990 }
1991
1992 pub fn get_match_hint(&self) -> RelativeSelectorMatchHint {
1994 RelativeSelectorMatchHint::new(
1995 self.relative_combinator,
1996 self.child_or_descendants != 0,
1997 self.adjacent_or_next_siblings != 0,
1998 )
1999 }
2000}
2001
2002#[derive(Clone, Eq, PartialEq)]
2004#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2005#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2006pub struct RelativeSelector<Impl: SelectorImpl> {
2007 pub match_hint: RelativeSelectorMatchHint,
2009 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2011 pub selector: Selector<Impl>,
2012}
2013
2014bitflags! {
2015 #[derive(Clone, Debug, Eq, PartialEq)]
2017 struct CombinatorComposition: u8 {
2018 const DESCENDANTS = 1 << 0;
2019 const SIBLINGS = 1 << 1;
2020 }
2021}
2022
2023impl CombinatorComposition {
2024 fn for_relative_selector<Impl: SelectorImpl>(inner_selector: &Selector<Impl>) -> Self {
2025 let mut result = CombinatorComposition::empty();
2026 for combinator in CombinatorIter::new(inner_selector.iter_skip_relative_selector_anchor()) {
2027 match combinator {
2028 Combinator::Descendant | Combinator::Child => {
2029 result.insert(Self::DESCENDANTS);
2030 },
2031 Combinator::NextSibling | Combinator::LaterSibling => {
2032 result.insert(Self::SIBLINGS);
2033 },
2034 Combinator::Part | Combinator::PseudoElement | Combinator::SlotAssignment => {
2035 continue;
2036 },
2037 };
2038 if result.is_all() {
2039 break;
2040 }
2041 }
2042 return result;
2043 }
2044}
2045
2046impl<Impl: SelectorImpl> RelativeSelector<Impl> {
2047 fn from_selector_list(selector_list: SelectorList<Impl>) -> Box<[Self]> {
2048 selector_list
2049 .slice()
2050 .iter()
2051 .map(|selector| {
2052 if cfg!(debug_assertions) {
2055 let relative_selector_anchor = selector.iter_raw_parse_order_from(0).next();
2056 debug_assert!(
2057 relative_selector_anchor.is_some(),
2058 "Relative selector is empty"
2059 );
2060 debug_assert!(
2061 matches!(
2062 relative_selector_anchor.unwrap(),
2063 Component::RelativeSelectorAnchor
2064 ),
2065 "Relative selector anchor is missing"
2066 );
2067 }
2068 let composition = CombinatorComposition::for_relative_selector(&selector);
2070 let match_hint = RelativeSelectorMatchHint::new(
2071 selector.combinator_at_parse_order(1),
2072 composition.intersects(CombinatorComposition::DESCENDANTS),
2073 composition.intersects(CombinatorComposition::SIBLINGS),
2074 );
2075 RelativeSelector {
2076 match_hint,
2077 selector: selector.clone(),
2078 }
2079 })
2080 .collect()
2081 }
2082}
2083
2084#[derive(Clone, Eq, PartialEq)]
2089#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2090#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2091pub enum Component<Impl: SelectorImpl> {
2092 LocalName(LocalName<Impl>),
2093
2094 ID(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2095 Class(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::Identifier),
2096
2097 AttributeInNoNamespaceExists {
2098 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2099 local_name: Impl::LocalName,
2100 local_name_lower: Impl::LocalName,
2101 },
2102 AttributeInNoNamespace {
2104 local_name: Impl::LocalName,
2105 operator: AttrSelectorOperator,
2106 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2107 value: Impl::AttrValue,
2108 case_sensitivity: ParsedCaseSensitivity,
2109 },
2110 AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
2112
2113 ExplicitUniversalType,
2114 ExplicitAnyNamespace,
2115
2116 ExplicitNoNamespace,
2117 DefaultNamespace(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl),
2118 Namespace(
2119 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespacePrefix,
2120 #[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NamespaceUrl,
2121 ),
2122
2123 Negation(SelectorList<Impl>),
2125 Root,
2126 Empty,
2127 Scope,
2128 ImplicitScope,
2136 ParentSelector,
2137 Nth(NthSelectorData),
2138 NthOf(NthOfSelectorData<Impl>),
2139 NonTSPseudoClass(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::NonTSPseudoClass),
2140 Slotted(Selector<Impl>),
2152 Part(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Box<[Impl::Identifier]>),
2155 Host(Option<Selector<Impl>>),
2165 Where(SelectorList<Impl>),
2172 Is(SelectorList<Impl>),
2178 Has(Box<[RelativeSelector<Impl>]>),
2184 Invalid(Arc<String>),
2186 PseudoElement(#[cfg_attr(feature = "to_shmem", shmem(field_bound))] Impl::PseudoElement),
2188
2189 Combinator(Combinator),
2190
2191 RelativeSelectorAnchor,
2196}
2197
2198impl<Impl: SelectorImpl> Component<Impl> {
2199 #[inline]
2201 pub fn is_combinator(&self) -> bool {
2202 matches!(*self, Component::Combinator(_))
2203 }
2204
2205 #[inline]
2207 pub fn is_host(&self) -> bool {
2208 matches!(*self, Component::Host(..))
2209 }
2210
2211 pub fn as_combinator(&self) -> Option<Combinator> {
2213 match *self {
2214 Component::Combinator(c) => Some(c),
2215 _ => None,
2216 }
2217 }
2218
2219 fn matches_for_stateless_pseudo_element(&self) -> bool {
2223 match *self {
2224 Component::Negation(ref selectors) => !selectors.slice().iter().all(|selector| {
2225 selector
2226 .iter_raw_match_order()
2227 .all(|c| c.matches_for_stateless_pseudo_element())
2228 }),
2229 Component::Is(ref selectors) | Component::Where(ref selectors) => {
2230 selectors.slice().iter().any(|selector| {
2231 selector
2232 .iter_raw_match_order()
2233 .all(|c| c.matches_for_stateless_pseudo_element())
2234 })
2235 },
2236 _ => false,
2237 }
2238 }
2239
2240 pub fn visit<V>(&self, visitor: &mut V) -> bool
2241 where
2242 V: SelectorVisitor<Impl = Impl>,
2243 {
2244 use self::Component::*;
2245 if !visitor.visit_simple_selector(self) {
2246 return false;
2247 }
2248
2249 match *self {
2250 Slotted(ref selector) => {
2251 if !selector.visit(visitor) {
2252 return false;
2253 }
2254 },
2255 Host(Some(ref selector)) => {
2256 if !selector.visit(visitor) {
2257 return false;
2258 }
2259 },
2260 AttributeInNoNamespaceExists {
2261 ref local_name,
2262 ref local_name_lower,
2263 } => {
2264 if !visitor.visit_attribute_selector(
2265 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2266 local_name,
2267 local_name_lower,
2268 ) {
2269 return false;
2270 }
2271 },
2272 AttributeInNoNamespace { ref local_name, .. } => {
2273 if !visitor.visit_attribute_selector(
2274 &NamespaceConstraint::Specific(&namespace_empty_string::<Impl>()),
2275 local_name,
2276 local_name,
2277 ) {
2278 return false;
2279 }
2280 },
2281 AttributeOther(ref attr_selector) => {
2282 let empty_string;
2283 let namespace = match attr_selector.namespace() {
2284 Some(ns) => ns,
2285 None => {
2286 empty_string = crate::parser::namespace_empty_string::<Impl>();
2287 NamespaceConstraint::Specific(&empty_string)
2288 },
2289 };
2290 if !visitor.visit_attribute_selector(
2291 &namespace,
2292 &attr_selector.local_name,
2293 &attr_selector.local_name_lower,
2294 ) {
2295 return false;
2296 }
2297 },
2298
2299 NonTSPseudoClass(ref pseudo_class) => {
2300 if !pseudo_class.visit(visitor) {
2301 return false;
2302 }
2303 },
2304 Negation(ref list) | Is(ref list) | Where(ref list) => {
2305 let list_kind = SelectorListKind::from_component(self);
2306 debug_assert!(!list_kind.is_empty());
2307 if !visitor.visit_selector_list(list_kind, list.slice()) {
2308 return false;
2309 }
2310 },
2311 NthOf(ref nth_of_data) => {
2312 if !visitor.visit_selector_list(SelectorListKind::NTH_OF, nth_of_data.selectors()) {
2313 return false;
2314 }
2315 },
2316 Has(ref list) => {
2317 if !visitor.visit_relative_selector_list(list) {
2318 return false;
2319 }
2320 },
2321 _ => {},
2322 }
2323
2324 true
2325 }
2326
2327 pub fn has_indexed_selector_in_subject(&self) -> bool {
2331 match *self {
2332 Component::NthOf(..) | Component::Nth(..) => return true,
2333 Component::Is(ref selectors)
2334 | Component::Where(ref selectors)
2335 | Component::Negation(ref selectors) => {
2336 for selector in selectors.slice() {
2338 let mut iter = selector.iter();
2339 while let Some(c) = iter.next() {
2340 if c.has_indexed_selector_in_subject() {
2341 return true;
2342 }
2343 }
2344 }
2345 },
2346 _ => (),
2347 };
2348 false
2349 }
2350}
2351
2352#[derive(Clone, Eq, PartialEq)]
2353#[cfg_attr(feature = "to_shmem", derive(ToShmem))]
2354#[cfg_attr(feature = "to_shmem", shmem(no_bounds))]
2355pub struct LocalName<Impl: SelectorImpl> {
2356 #[cfg_attr(feature = "to_shmem", shmem(field_bound))]
2357 pub name: Impl::LocalName,
2358 pub lower_name: Impl::LocalName,
2359}
2360
2361impl<Impl: SelectorImpl> Debug for Selector<Impl> {
2362 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2363 f.write_str("Selector(")?;
2364 self.to_css(f)?;
2365 write!(
2366 f,
2367 ", specificity = {:#x}, flags = {:?})",
2368 self.specificity(),
2369 self.flags()
2370 )
2371 }
2372}
2373
2374impl<Impl: SelectorImpl> Debug for Component<Impl> {
2375 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2376 self.to_css(f)
2377 }
2378}
2379impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
2380 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2381 self.to_css(f)
2382 }
2383}
2384impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
2385 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2386 self.to_css(f)
2387 }
2388}
2389
2390fn serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result
2391where
2392 Impl: SelectorImpl,
2393 I: Iterator<Item = &'a Selector<Impl>>,
2394 W: fmt::Write,
2395{
2396 let mut first = true;
2397 for selector in iter {
2398 if !first {
2399 dest.write_str(", ")?;
2400 }
2401 first = false;
2402 selector.to_css(dest)?;
2403 }
2404 Ok(())
2405}
2406
2407impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
2408 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2409 where
2410 W: fmt::Write,
2411 {
2412 serialize_selector_list(self.slice().iter(), dest)
2413 }
2414}
2415
2416impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
2417 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2418 where
2419 W: fmt::Write,
2420 {
2421 let mut combinators = self
2434 .iter_raw_match_order()
2435 .rev()
2436 .filter_map(|x| x.as_combinator());
2437 let compound_selectors = self
2438 .iter_raw_match_order()
2439 .as_slice()
2440 .split(|x| x.is_combinator())
2441 .rev();
2442
2443 let mut combinators_exhausted = false;
2444 for compound in compound_selectors {
2445 debug_assert!(!combinators_exhausted);
2446
2447 let first_compound = match compound.first() {
2449 None => continue,
2450 Some(c) => c,
2451 };
2452 if matches!(
2453 first_compound,
2454 Component::RelativeSelectorAnchor | Component::ImplicitScope
2455 ) {
2456 debug_assert!(
2457 compound.len() == 1,
2458 "RelativeSelectorAnchor/ImplicitScope should only be a simple selector"
2459 );
2460 if let Some(c) = combinators.next() {
2461 c.to_css_relative(dest)?;
2462 } else {
2463 debug_assert!(
2466 matches!(first_compound, Component::ImplicitScope),
2467 "Only implicit :scope may not have any combinator"
2468 );
2469 }
2470 continue;
2471 }
2472
2473 let (can_elide_namespace, first_non_namespace) = match compound[0] {
2484 Component::ExplicitAnyNamespace
2485 | Component::ExplicitNoNamespace
2486 | Component::Namespace(..) => (false, 1),
2487 Component::DefaultNamespace(..) => (true, 1),
2488 _ => (true, 0),
2489 };
2490 let mut perform_step_2 = true;
2491 let next_combinator = combinators.next();
2492 if first_non_namespace == compound.len() - 1 {
2493 match (next_combinator, &compound[first_non_namespace]) {
2494 (Some(Combinator::PseudoElement), _)
2502 | (Some(Combinator::SlotAssignment), _) => (),
2503 (_, &Component::ExplicitUniversalType) => {
2504 for simple in compound.iter() {
2507 simple.to_css(dest)?;
2508 }
2509 perform_step_2 = false;
2511 },
2512 _ => (),
2513 }
2514 }
2515
2516 if perform_step_2 {
2526 for simple in compound.iter() {
2527 if let Component::ExplicitUniversalType = *simple {
2528 if can_elide_namespace {
2533 continue;
2534 }
2535 }
2536 simple.to_css(dest)?;
2537 }
2538 }
2539
2540 match next_combinator {
2546 Some(c) => c.to_css(dest)?,
2547 None => combinators_exhausted = true,
2548 };
2549
2550 }
2556
2557 Ok(())
2558 }
2559}
2560
2561impl Combinator {
2562 fn to_css_internal<W>(&self, dest: &mut W, prefix_space: bool) -> fmt::Result
2563 where
2564 W: fmt::Write,
2565 {
2566 if matches!(
2567 *self,
2568 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment
2569 ) {
2570 return Ok(());
2571 }
2572 if prefix_space {
2573 dest.write_char(' ')?;
2574 }
2575 match *self {
2576 Combinator::Child => dest.write_str("> "),
2577 Combinator::Descendant => Ok(()),
2578 Combinator::NextSibling => dest.write_str("+ "),
2579 Combinator::LaterSibling => dest.write_str("~ "),
2580 Combinator::PseudoElement | Combinator::Part | Combinator::SlotAssignment => unsafe {
2581 debug_unreachable!("Already handled")
2582 },
2583 }
2584 }
2585
2586 fn to_css_relative<W>(&self, dest: &mut W) -> fmt::Result
2587 where
2588 W: fmt::Write,
2589 {
2590 self.to_css_internal(dest, false)
2591 }
2592}
2593
2594impl ToCss for Combinator {
2595 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2596 where
2597 W: fmt::Write,
2598 {
2599 self.to_css_internal(dest, true)
2600 }
2601}
2602
2603impl<Impl: SelectorImpl> ToCss for Component<Impl> {
2604 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2605 where
2606 W: fmt::Write,
2607 {
2608 use self::Component::*;
2609
2610 match *self {
2611 Combinator(ref c) => c.to_css(dest),
2612 Slotted(ref selector) => {
2613 dest.write_str("::slotted(")?;
2614 selector.to_css(dest)?;
2615 dest.write_char(')')
2616 },
2617 Part(ref part_names) => {
2618 dest.write_str("::part(")?;
2619 for (i, name) in part_names.iter().enumerate() {
2620 if i != 0 {
2621 dest.write_char(' ')?;
2622 }
2623 name.to_css(dest)?;
2624 }
2625 dest.write_char(')')
2626 },
2627 PseudoElement(ref p) => p.to_css(dest),
2628 ID(ref s) => {
2629 dest.write_char('#')?;
2630 s.to_css(dest)
2631 },
2632 Class(ref s) => {
2633 dest.write_char('.')?;
2634 s.to_css(dest)
2635 },
2636 LocalName(ref s) => s.to_css(dest),
2637 ExplicitUniversalType => dest.write_char('*'),
2638
2639 DefaultNamespace(_) => Ok(()),
2640 ExplicitNoNamespace => dest.write_char('|'),
2641 ExplicitAnyNamespace => dest.write_str("*|"),
2642 Namespace(ref prefix, _) => {
2643 prefix.to_css(dest)?;
2644 dest.write_char('|')
2645 },
2646
2647 AttributeInNoNamespaceExists { ref local_name, .. } => {
2648 dest.write_char('[')?;
2649 local_name.to_css(dest)?;
2650 dest.write_char(']')
2651 },
2652 AttributeInNoNamespace {
2653 ref local_name,
2654 operator,
2655 ref value,
2656 case_sensitivity,
2657 ..
2658 } => {
2659 dest.write_char('[')?;
2660 local_name.to_css(dest)?;
2661 operator.to_css(dest)?;
2662 value.to_css(dest)?;
2663 match case_sensitivity {
2664 ParsedCaseSensitivity::CaseSensitive
2665 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2666 },
2667 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2668 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2669 }
2670 dest.write_char(']')
2671 },
2672 AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
2673
2674 Root => dest.write_str(":root"),
2676 Empty => dest.write_str(":empty"),
2677 Scope => dest.write_str(":scope"),
2678 ParentSelector => dest.write_char('&'),
2679 Host(ref selector) => {
2680 dest.write_str(":host")?;
2681 if let Some(ref selector) = *selector {
2682 dest.write_char('(')?;
2683 selector.to_css(dest)?;
2684 dest.write_char(')')?;
2685 }
2686 Ok(())
2687 },
2688 Nth(ref nth_data) => {
2689 nth_data.write_start(dest)?;
2690 if nth_data.is_function {
2691 nth_data.write_affine(dest)?;
2692 dest.write_char(')')?;
2693 }
2694 Ok(())
2695 },
2696 NthOf(ref nth_of_data) => {
2697 let nth_data = nth_of_data.nth_data();
2698 nth_data.write_start(dest)?;
2699 debug_assert!(
2700 nth_data.is_function,
2701 "A selector must be a function to hold An+B notation"
2702 );
2703 nth_data.write_affine(dest)?;
2704 debug_assert!(
2705 matches!(nth_data.ty, NthType::Child | NthType::LastChild),
2706 "Only :nth-child or :nth-last-child can be of a selector list"
2707 );
2708 debug_assert!(
2709 !nth_of_data.selectors().is_empty(),
2710 "The selector list should not be empty"
2711 );
2712 dest.write_str(" of ")?;
2713 serialize_selector_list(nth_of_data.selectors().iter(), dest)?;
2714 dest.write_char(')')
2715 },
2716 Is(ref list) | Where(ref list) | Negation(ref list) => {
2717 match *self {
2718 Where(..) => dest.write_str(":where(")?,
2719 Is(..) => dest.write_str(":is(")?,
2720 Negation(..) => dest.write_str(":not(")?,
2721 _ => unreachable!(),
2722 }
2723 serialize_selector_list(list.slice().iter(), dest)?;
2724 dest.write_str(")")
2725 },
2726 Has(ref list) => {
2727 dest.write_str(":has(")?;
2728 serialize_selector_list(list.iter().map(|rel| &rel.selector), dest)?;
2729 dest.write_str(")")
2730 },
2731 NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
2732 Invalid(ref css) => dest.write_str(css),
2733 RelativeSelectorAnchor | ImplicitScope => Ok(()),
2734 }
2735 }
2736}
2737
2738impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
2739 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2740 where
2741 W: fmt::Write,
2742 {
2743 dest.write_char('[')?;
2744 match self.namespace {
2745 Some(NamespaceConstraint::Specific((ref prefix, _))) => {
2746 prefix.to_css(dest)?;
2747 dest.write_char('|')?
2748 },
2749 Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
2750 None => {},
2751 }
2752 self.local_name.to_css(dest)?;
2753 match self.operation {
2754 ParsedAttrSelectorOperation::Exists => {},
2755 ParsedAttrSelectorOperation::WithValue {
2756 operator,
2757 case_sensitivity,
2758 ref value,
2759 } => {
2760 operator.to_css(dest)?;
2761 value.to_css(dest)?;
2762 match case_sensitivity {
2763 ParsedCaseSensitivity::CaseSensitive
2764 | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
2765 },
2766 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
2767 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
2768 }
2769 },
2770 }
2771 dest.write_char(']')
2772 }
2773}
2774
2775impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
2776 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2777 where
2778 W: fmt::Write,
2779 {
2780 self.name.to_css(dest)
2781 }
2782}
2783
2784fn parse_selector<'i, 't, P, Impl>(
2789 parser: &P,
2790 input: &mut CssParser<'i, 't>,
2791 mut state: SelectorParsingState,
2792 parse_relative: ParseRelative,
2793) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
2794where
2795 P: Parser<'i, Impl = Impl>,
2796 Impl: SelectorImpl,
2797{
2798 let mut builder = SelectorBuilder::default();
2799
2800 input.skip_whitespace();
2802
2803 if parse_relative != ParseRelative::No {
2804 let combinator = try_parse_combinator(input);
2805 match parse_relative {
2806 ParseRelative::ForHas => {
2807 builder.push_simple_selector(Component::RelativeSelectorAnchor);
2808 builder.push_combinator(combinator.unwrap_or(Combinator::Descendant));
2811 },
2812 ParseRelative::ForNesting | ParseRelative::ForScope => {
2813 if let Ok(combinator) = combinator {
2814 let selector = match parse_relative {
2815 ParseRelative::ForHas | ParseRelative::No => unreachable!(),
2816 ParseRelative::ForNesting => Component::ParentSelector,
2817 ParseRelative::ForScope => Component::ImplicitScope,
2821 };
2822 builder.push_simple_selector(selector);
2823 builder.push_combinator(combinator);
2824 }
2825 },
2826 ParseRelative::No => unreachable!(),
2827 }
2828 }
2829 loop {
2830 let empty = parse_compound_selector(parser, &mut state, input, &mut builder)?;
2832 if empty {
2833 return Err(input.new_custom_error(if builder.has_combinators() {
2834 SelectorParseErrorKind::DanglingCombinator
2835 } else {
2836 SelectorParseErrorKind::EmptySelector
2837 }));
2838 }
2839
2840 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2841 debug_assert!(state.intersects(
2842 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO
2843 | SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO
2844 | SelectorParsingState::AFTER_SLOTTED
2845 | SelectorParsingState::AFTER_PART_LIKE
2846 ));
2847 break;
2848 }
2849
2850 let combinator = if let Ok(c) = try_parse_combinator(input) {
2851 c
2852 } else {
2853 break;
2854 };
2855
2856 if !state.allows_combinators() {
2857 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2858 }
2859
2860 builder.push_combinator(combinator);
2861 }
2862 return Ok(Selector(builder.build(parse_relative)));
2863}
2864
2865fn try_parse_combinator<'i, 't>(input: &mut CssParser<'i, 't>) -> Result<Combinator, ()> {
2866 let mut any_whitespace = false;
2867 loop {
2868 let before_this_token = input.state();
2869 match input.next_including_whitespace() {
2870 Err(_e) => return Err(()),
2871 Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
2872 Ok(&Token::Delim('>')) => {
2873 return Ok(Combinator::Child);
2874 },
2875 Ok(&Token::Delim('+')) => {
2876 return Ok(Combinator::NextSibling);
2877 },
2878 Ok(&Token::Delim('~')) => {
2879 return Ok(Combinator::LaterSibling);
2880 },
2881 Ok(_) => {
2882 input.reset(&before_this_token);
2883 if any_whitespace {
2884 return Ok(Combinator::Descendant);
2885 } else {
2886 return Err(());
2887 }
2888 },
2889 }
2890 }
2891}
2892
2893fn parse_type_selector<'i, 't, P, Impl, S>(
2897 parser: &P,
2898 input: &mut CssParser<'i, 't>,
2899 state: SelectorParsingState,
2900 sink: &mut S,
2901) -> Result<bool, ParseError<'i, P::Error>>
2902where
2903 P: Parser<'i, Impl = Impl>,
2904 Impl: SelectorImpl,
2905 S: Push<Component<Impl>>,
2906{
2907 match parse_qualified_name(parser, input, false) {
2908 Err(ParseError {
2909 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
2910 ..
2911 })
2912 | Ok(OptionalQName::None(_)) => Ok(false),
2913 Ok(OptionalQName::Some(namespace, local_name)) => {
2914 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2915 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2916 }
2917 match namespace {
2918 QNamePrefix::ImplicitAnyNamespace => {},
2919 QNamePrefix::ImplicitDefaultNamespace(url) => {
2920 sink.push(Component::DefaultNamespace(url))
2921 },
2922 QNamePrefix::ExplicitNamespace(prefix, url) => {
2923 sink.push(match parser.default_namespace() {
2924 Some(ref default_url) if url == *default_url => {
2925 Component::DefaultNamespace(url)
2926 },
2927 _ => Component::Namespace(prefix, url),
2928 })
2929 },
2930 QNamePrefix::ExplicitNoNamespace => sink.push(Component::ExplicitNoNamespace),
2931 QNamePrefix::ExplicitAnyNamespace => {
2932 match parser.default_namespace() {
2933 None => {},
2945 Some(_) => sink.push(Component::ExplicitAnyNamespace),
2946 }
2947 },
2948 QNamePrefix::ImplicitNoNamespace => {
2949 unreachable!() },
2951 }
2952 match local_name {
2953 Some(name) => sink.push(Component::LocalName(LocalName {
2954 lower_name: to_ascii_lowercase(&name).as_ref().into(),
2955 name: name.as_ref().into(),
2956 })),
2957 None => sink.push(Component::ExplicitUniversalType),
2958 }
2959 Ok(true)
2960 },
2961 Err(e) => Err(e),
2962 }
2963}
2964
2965#[derive(Debug)]
2966enum SimpleSelectorParseResult<Impl: SelectorImpl> {
2967 SimpleSelector(Component<Impl>),
2968 PseudoElement(Impl::PseudoElement),
2969 SlottedPseudo(Selector<Impl>),
2970 PartPseudo(Box<[Impl::Identifier]>),
2971}
2972
2973#[derive(Debug)]
2974enum QNamePrefix<Impl: SelectorImpl> {
2975 ImplicitNoNamespace, ImplicitAnyNamespace, ImplicitDefaultNamespace(Impl::NamespaceUrl), ExplicitNoNamespace, ExplicitAnyNamespace, ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), }
2982
2983enum OptionalQName<'i, Impl: SelectorImpl> {
2984 Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
2985 None(Token<'i>),
2986}
2987
2988fn parse_qualified_name<'i, 't, P, Impl>(
2993 parser: &P,
2994 input: &mut CssParser<'i, 't>,
2995 in_attr_selector: bool,
2996) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
2997where
2998 P: Parser<'i, Impl = Impl>,
2999 Impl: SelectorImpl,
3000{
3001 let default_namespace = |local_name| {
3002 let namespace = match parser.default_namespace() {
3003 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
3004 None => QNamePrefix::ImplicitAnyNamespace,
3005 };
3006 Ok(OptionalQName::Some(namespace, local_name))
3007 };
3008
3009 let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
3010 let location = input.current_source_location();
3011 match input.next_including_whitespace() {
3012 Ok(&Token::Delim('*')) if !in_attr_selector => Ok(OptionalQName::Some(namespace, None)),
3013 Ok(&Token::Ident(ref local_name)) => {
3014 Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
3015 },
3016 Ok(t) if in_attr_selector => {
3017 let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
3018 Err(location.new_custom_error(e))
3019 },
3020 Ok(t) => Err(location.new_custom_error(
3021 SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()),
3022 )),
3023 Err(e) => Err(e.into()),
3024 }
3025 };
3026
3027 let start = input.state();
3028 match input.next_including_whitespace() {
3029 Ok(Token::Ident(value)) => {
3030 let value = value.clone();
3031 let after_ident = input.state();
3032 match input.next_including_whitespace() {
3033 Ok(&Token::Delim('|')) => {
3034 let prefix = value.as_ref().into();
3035 let result = parser.namespace_for_prefix(&prefix);
3036 let url = result.ok_or(
3037 after_ident
3038 .source_location()
3039 .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)),
3040 )?;
3041 explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url))
3042 },
3043 _ => {
3044 input.reset(&after_ident);
3045 if in_attr_selector {
3046 Ok(OptionalQName::Some(
3047 QNamePrefix::ImplicitNoNamespace,
3048 Some(value),
3049 ))
3050 } else {
3051 default_namespace(Some(value))
3052 }
3053 },
3054 }
3055 },
3056 Ok(Token::Delim('*')) => {
3057 let after_star = input.state();
3058 match input.next_including_whitespace() {
3059 Ok(&Token::Delim('|')) => {
3060 explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
3061 },
3062 _ if !in_attr_selector => {
3063 input.reset(&after_star);
3064 default_namespace(None)
3065 },
3066 result => {
3067 let t = result?;
3068 Err(after_star
3069 .source_location()
3070 .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t.clone())))
3071 },
3072 }
3073 },
3074 Ok(Token::Delim('|')) => explicit_namespace(input, QNamePrefix::ExplicitNoNamespace),
3075 Ok(t) => {
3076 let t = t.clone();
3077 input.reset(&start);
3078 Ok(OptionalQName::None(t))
3079 },
3080 Err(e) => {
3081 input.reset(&start);
3082 Err(e.into())
3083 },
3084 }
3085}
3086
3087fn parse_attribute_selector<'i, 't, P, Impl>(
3088 parser: &P,
3089 input: &mut CssParser<'i, 't>,
3090) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3091where
3092 P: Parser<'i, Impl = Impl>,
3093 Impl: SelectorImpl,
3094{
3095 let namespace;
3096 let local_name;
3097
3098 input.skip_whitespace();
3099
3100 match parse_qualified_name(parser, input, true)? {
3101 OptionalQName::None(t) => {
3102 return Err(input.new_custom_error(
3103 SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t),
3104 ));
3105 },
3106 OptionalQName::Some(_, None) => unreachable!(),
3107 OptionalQName::Some(ns, Some(ln)) => {
3108 local_name = ln;
3109 namespace = match ns {
3110 QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace => None,
3111 QNamePrefix::ExplicitNamespace(prefix, url) => {
3112 Some(NamespaceConstraint::Specific((prefix, url)))
3113 },
3114 QNamePrefix::ExplicitAnyNamespace => Some(NamespaceConstraint::Any),
3115 QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) => {
3116 unreachable!() },
3118 }
3119 },
3120 }
3121
3122 let location = input.current_source_location();
3123 let operator = match input.next() {
3124 Err(_) => {
3126 let local_name_lower = to_ascii_lowercase(&local_name).as_ref().into();
3127 let local_name = local_name.as_ref().into();
3128 if let Some(namespace) = namespace {
3129 return Ok(Component::AttributeOther(Box::new(
3130 AttrSelectorWithOptionalNamespace {
3131 namespace: Some(namespace),
3132 local_name,
3133 local_name_lower,
3134 operation: ParsedAttrSelectorOperation::Exists,
3135 },
3136 )));
3137 } else {
3138 return Ok(Component::AttributeInNoNamespaceExists {
3139 local_name,
3140 local_name_lower,
3141 });
3142 }
3143 },
3144
3145 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
3147 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
3149 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
3151 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
3153 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
3155 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
3157 Ok(t) => {
3158 return Err(location.new_custom_error(
3159 SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()),
3160 ));
3161 },
3162 };
3163
3164 let value = match input.expect_ident_or_string() {
3165 Ok(t) => t.clone(),
3166 Err(BasicParseError {
3167 kind: BasicParseErrorKind::UnexpectedToken(t),
3168 location,
3169 }) => return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))),
3170 Err(e) => return Err(e.into()),
3171 };
3172
3173 let attribute_flags = parse_attribute_flags(input)?;
3174 let value = value.as_ref().into();
3175 let local_name_lower;
3176 let local_name_is_ascii_lowercase;
3177 let case_sensitivity;
3178 {
3179 let local_name_lower_cow = to_ascii_lowercase(&local_name);
3180 case_sensitivity =
3181 attribute_flags.to_case_sensitivity(local_name_lower_cow.as_ref(), namespace.is_some());
3182 local_name_lower = local_name_lower_cow.as_ref().into();
3183 local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..));
3184 }
3185 let local_name = local_name.as_ref().into();
3186 if namespace.is_some() || !local_name_is_ascii_lowercase {
3187 Ok(Component::AttributeOther(Box::new(
3188 AttrSelectorWithOptionalNamespace {
3189 namespace,
3190 local_name,
3191 local_name_lower,
3192 operation: ParsedAttrSelectorOperation::WithValue {
3193 operator,
3194 case_sensitivity,
3195 value,
3196 },
3197 },
3198 )))
3199 } else {
3200 Ok(Component::AttributeInNoNamespace {
3201 local_name,
3202 operator,
3203 value,
3204 case_sensitivity,
3205 })
3206 }
3207}
3208
3209enum AttributeFlags {
3211 CaseSensitive,
3213 AsciiCaseInsensitive,
3215 CaseSensitivityDependsOnName,
3217}
3218
3219impl AttributeFlags {
3220 fn to_case_sensitivity(
3221 self,
3222 local_name_lower: &str,
3223 have_namespace: bool,
3224 ) -> ParsedCaseSensitivity {
3225 match self {
3226 AttributeFlags::CaseSensitive => ParsedCaseSensitivity::ExplicitCaseSensitive,
3227 AttributeFlags::AsciiCaseInsensitive => ParsedCaseSensitivity::AsciiCaseInsensitive,
3228 AttributeFlags::CaseSensitivityDependsOnName => {
3229 if !have_namespace
3230 && include!(concat!(
3231 env!("OUT_DIR"),
3232 "/ascii_case_insensitive_html_attributes.rs"
3233 ))
3234 .contains(local_name_lower)
3235 {
3236 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
3237 } else {
3238 ParsedCaseSensitivity::CaseSensitive
3239 }
3240 },
3241 }
3242 }
3243}
3244
3245fn parse_attribute_flags<'i, 't>(
3246 input: &mut CssParser<'i, 't>,
3247) -> Result<AttributeFlags, BasicParseError<'i>> {
3248 let location = input.current_source_location();
3249 let token = match input.next() {
3250 Ok(t) => t,
3251 Err(..) => {
3252 return Ok(AttributeFlags::CaseSensitivityDependsOnName);
3255 },
3256 };
3257
3258 let ident = match *token {
3259 Token::Ident(ref i) => i,
3260 ref other => return Err(location.new_basic_unexpected_token_error(other.clone())),
3261 };
3262
3263 Ok(match_ignore_ascii_case! {
3264 ident,
3265 "i" => AttributeFlags::AsciiCaseInsensitive,
3266 "s" => AttributeFlags::CaseSensitive,
3267 _ => return Err(location.new_basic_unexpected_token_error(token.clone())),
3268 })
3269}
3270
3271fn parse_negation<'i, 't, P, Impl>(
3274 parser: &P,
3275 input: &mut CssParser<'i, 't>,
3276 state: SelectorParsingState,
3277) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3278where
3279 P: Parser<'i, Impl = Impl>,
3280 Impl: SelectorImpl,
3281{
3282 let list = SelectorList::parse_with_state(
3283 parser,
3284 input,
3285 state
3286 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3287 | SelectorParsingState::DISALLOW_PSEUDOS,
3288 ForgivingParsing::No,
3289 ParseRelative::No,
3290 )?;
3291
3292 Ok(Component::Negation(list))
3293}
3294
3295fn parse_compound_selector<'i, 't, P, Impl>(
3302 parser: &P,
3303 state: &mut SelectorParsingState,
3304 input: &mut CssParser<'i, 't>,
3305 builder: &mut SelectorBuilder<Impl>,
3306) -> Result<bool, ParseError<'i, P::Error>>
3307where
3308 P: Parser<'i, Impl = Impl>,
3309 Impl: SelectorImpl,
3310{
3311 input.skip_whitespace();
3312
3313 let mut empty = true;
3314 if parse_type_selector(parser, input, *state, builder)? {
3315 empty = false;
3316 }
3317
3318 loop {
3319 let result = match parse_one_simple_selector(parser, input, *state)? {
3320 None => break,
3321 Some(result) => result,
3322 };
3323
3324 if empty {
3325 if let Some(url) = parser.default_namespace() {
3326 let ignore_default_ns = state
3354 .intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE)
3355 || matches!(
3356 result,
3357 SimpleSelectorParseResult::SimpleSelector(Component::Host(..))
3358 );
3359 if !ignore_default_ns {
3360 builder.push_simple_selector(Component::DefaultNamespace(url));
3361 }
3362 }
3363 }
3364
3365 empty = false;
3366
3367 match result {
3368 SimpleSelectorParseResult::SimpleSelector(s) => {
3369 builder.push_simple_selector(s);
3370 },
3371 SimpleSelectorParseResult::PartPseudo(part_names) => {
3372 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3373 builder.push_combinator(Combinator::Part);
3374 builder.push_simple_selector(Component::Part(part_names));
3375 },
3376 SimpleSelectorParseResult::SlottedPseudo(selector) => {
3377 state.insert(SelectorParsingState::AFTER_SLOTTED);
3378 builder.push_combinator(Combinator::SlotAssignment);
3379 builder.push_simple_selector(Component::Slotted(selector));
3380 },
3381 SimpleSelectorParseResult::PseudoElement(p) => {
3382 if p.parses_as_element_backed() {
3383 state.insert(SelectorParsingState::AFTER_PART_LIKE);
3384 } else {
3385 state.insert(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO);
3386 if p.is_before_or_after() {
3387 state.insert(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO);
3388 }
3389 }
3390 if !p.accepts_state_pseudo_classes() {
3391 state.insert(SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT);
3392 }
3393 if p.is_in_pseudo_element_tree() {
3394 state.insert(SelectorParsingState::IN_PSEUDO_ELEMENT_TREE);
3395 }
3396 builder.push_combinator(Combinator::PseudoElement);
3397 builder.push_simple_selector(Component::PseudoElement(p));
3398 },
3399 }
3400 }
3401 Ok(empty)
3402}
3403
3404fn parse_is_where<'i, 't, P, Impl>(
3405 parser: &P,
3406 input: &mut CssParser<'i, 't>,
3407 state: SelectorParsingState,
3408 component: impl FnOnce(SelectorList<Impl>) -> Component<Impl>,
3409) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3410where
3411 P: Parser<'i, Impl = Impl>,
3412 Impl: SelectorImpl,
3413{
3414 debug_assert!(parser.parse_is_and_where());
3415 let inner = SelectorList::parse_with_state(
3421 parser,
3422 input,
3423 state
3424 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3425 | SelectorParsingState::DISALLOW_PSEUDOS,
3426 ForgivingParsing::Yes,
3427 ParseRelative::No,
3428 )?;
3429 Ok(component(inner))
3430}
3431
3432fn parse_has<'i, 't, P, Impl>(
3433 parser: &P,
3434 input: &mut CssParser<'i, 't>,
3435 state: SelectorParsingState,
3436) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3437where
3438 P: Parser<'i, Impl = Impl>,
3439 Impl: SelectorImpl,
3440{
3441 debug_assert!(parser.parse_has());
3442 if state.intersects(
3443 SelectorParsingState::DISALLOW_RELATIVE_SELECTOR | SelectorParsingState::AFTER_PSEUDO,
3444 ) {
3445 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3446 }
3447 let inner = SelectorList::parse_with_state(
3452 parser,
3453 input,
3454 state
3455 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3456 | SelectorParsingState::DISALLOW_PSEUDOS
3457 | SelectorParsingState::DISALLOW_RELATIVE_SELECTOR,
3458 ForgivingParsing::No,
3459 ParseRelative::ForHas,
3460 )?;
3461 Ok(Component::Has(RelativeSelector::from_selector_list(inner)))
3462}
3463
3464fn parse_functional_pseudo_class<'i, 't, P, Impl>(
3465 parser: &P,
3466 input: &mut CssParser<'i, 't>,
3467 name: CowRcStr<'i>,
3468 state: SelectorParsingState,
3469) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3470where
3471 P: Parser<'i, Impl = Impl>,
3472 Impl: SelectorImpl,
3473{
3474 match_ignore_ascii_case! { &name,
3475 "nth-child" => return parse_nth_pseudo_class(parser, input, state, NthType::Child),
3476 "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::OfType),
3477 "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, NthType::LastChild),
3478 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, NthType::LastOfType),
3479 "is" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Is),
3480 "where" if parser.parse_is_and_where() => return parse_is_where(parser, input, state, Component::Where),
3481 "has" if parser.parse_has() => return parse_has(parser, input, state),
3482 "host" => {
3483 if !state.allows_tree_structural_pseudo_classes() {
3484 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3485 }
3486 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
3487 },
3488 "not" => {
3489 return parse_negation(parser, input, state)
3490 },
3491 _ => {}
3492 }
3493
3494 if parser.parse_is_and_where() && parser.is_is_alias(&name) {
3495 return parse_is_where(parser, input, state, Component::Is);
3496 }
3497
3498 if state.intersects(
3499 SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO | SelectorParsingState::AFTER_SLOTTED,
3500 ) {
3501 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3502 }
3503
3504 let after_part = state.intersects(SelectorParsingState::AFTER_PART_LIKE);
3505 P::parse_non_ts_functional_pseudo_class(parser, name, input, after_part)
3506 .map(Component::NonTSPseudoClass)
3507}
3508
3509fn parse_nth_pseudo_class<'i, 't, P, Impl>(
3510 parser: &P,
3511 input: &mut CssParser<'i, 't>,
3512 state: SelectorParsingState,
3513 ty: NthType,
3514) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3515where
3516 P: Parser<'i, Impl = Impl>,
3517 Impl: SelectorImpl,
3518{
3519 if !state.allows_tree_structural_pseudo_classes() {
3520 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3521 }
3522 let (a, b) = parse_nth(input)?;
3523 let nth_data = NthSelectorData {
3524 ty,
3525 is_function: true,
3526 an_plus_b: AnPlusB(a, b),
3527 };
3528 if !parser.parse_nth_child_of() || ty.is_of_type() {
3529 return Ok(Component::Nth(nth_data));
3530 }
3531
3532 if input.try_parse(|i| i.expect_ident_matching("of")).is_err() {
3534 return Ok(Component::Nth(nth_data));
3535 }
3536 let selectors = SelectorList::parse_with_state(
3539 parser,
3540 input,
3541 state
3542 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
3543 | SelectorParsingState::DISALLOW_PSEUDOS,
3544 ForgivingParsing::No,
3545 ParseRelative::No,
3546 )?;
3547 Ok(Component::NthOf(NthOfSelectorData::new(
3548 &nth_data,
3549 selectors.slice().iter().cloned(),
3550 )))
3551}
3552
3553pub fn is_css2_pseudo_element(name: &str) -> bool {
3557 match_ignore_ascii_case! { name,
3559 "before" | "after" | "first-line" | "first-letter" => true,
3560 _ => false,
3561 }
3562}
3563
3564fn parse_one_simple_selector<'i, 't, P, Impl>(
3570 parser: &P,
3571 input: &mut CssParser<'i, 't>,
3572 state: SelectorParsingState,
3573) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>>
3574where
3575 P: Parser<'i, Impl = Impl>,
3576 Impl: SelectorImpl,
3577{
3578 let start = input.state();
3579 let token = match input.next_including_whitespace().map(|t| t.clone()) {
3580 Ok(t) => t,
3581 Err(..) => {
3582 input.reset(&start);
3583 return Ok(None);
3584 },
3585 };
3586
3587 Ok(Some(match token {
3588 Token::IDHash(id) => {
3589 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3590 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3591 }
3592 let id = Component::ID(id.as_ref().into());
3593 SimpleSelectorParseResult::SimpleSelector(id)
3594 },
3595 Token::Delim(delim) if delim == '.' || (delim == '&' && parser.parse_parent_selector()) => {
3596 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3597 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3598 }
3599 let location = input.current_source_location();
3600 SimpleSelectorParseResult::SimpleSelector(if delim == '&' {
3601 Component::ParentSelector
3602 } else {
3603 let class = match *input.next_including_whitespace()? {
3604 Token::Ident(ref class) => class,
3605 ref t => {
3606 let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
3607 return Err(location.new_custom_error(e));
3608 },
3609 };
3610 Component::Class(class.as_ref().into())
3611 })
3612 },
3613 Token::SquareBracketBlock => {
3614 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
3615 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3616 }
3617 let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?;
3618 SimpleSelectorParseResult::SimpleSelector(attr)
3619 },
3620 Token::Colon => {
3621 let location = input.current_source_location();
3622 let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() {
3623 Token::Colon => (false, input.next_including_whitespace()?.clone()),
3624 t => (true, t),
3625 };
3626 let (name, is_functional) = match next_token {
3627 Token::Ident(name) => (name, false),
3628 Token::Function(name) => (name, true),
3629 t => {
3630 let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t);
3631 return Err(input.new_custom_error(e));
3632 },
3633 };
3634 let is_pseudo_element = !is_single_colon || is_css2_pseudo_element(&name);
3635 if is_pseudo_element {
3636 if state.intersects(SelectorParsingState::DISALLOW_PSEUDOS)
3642 || (state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3643 && !state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO))
3644 {
3645 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3646 }
3647 let pseudo_element = if is_functional {
3648 if P::parse_part(parser) && name.eq_ignore_ascii_case("part") {
3649 if !state.allows_part() {
3650 return Err(
3651 input.new_custom_error(SelectorParseErrorKind::InvalidState)
3652 );
3653 }
3654 let names = input.parse_nested_block(|input| {
3655 let mut result = Vec::with_capacity(1);
3656 result.push(input.expect_ident()?.as_ref().into());
3657 while !input.is_exhausted() {
3658 result.push(input.expect_ident()?.as_ref().into());
3659 }
3660 Ok(result.into_boxed_slice())
3661 })?;
3662 return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
3663 }
3664 if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
3665 if !state.allows_slotted() {
3666 return Err(
3667 input.new_custom_error(SelectorParseErrorKind::InvalidState)
3668 );
3669 }
3670 let selector = input.parse_nested_block(|input| {
3671 parse_inner_compound_selector(parser, input, state)
3672 })?;
3673 return Ok(Some(SimpleSelectorParseResult::SlottedPseudo(selector)));
3674 }
3675 input.parse_nested_block(|input| {
3676 P::parse_functional_pseudo_element(parser, name, input)
3677 })?
3678 } else {
3679 P::parse_pseudo_element(parser, location, name)?
3680 };
3681
3682 if state.intersects(SelectorParsingState::AFTER_BEFORE_OR_AFTER_PSEUDO)
3683 && !pseudo_element.valid_after_before_or_after()
3684 {
3685 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3686 }
3687
3688 if state.intersects(SelectorParsingState::AFTER_SLOTTED)
3689 && !pseudo_element.valid_after_slotted()
3690 {
3691 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
3692 }
3693 SimpleSelectorParseResult::PseudoElement(pseudo_element)
3694 } else {
3695 let pseudo_class = if is_functional {
3696 input.parse_nested_block(|input| {
3697 parse_functional_pseudo_class(parser, input, name, state)
3698 })?
3699 } else {
3700 parse_simple_pseudo_class(parser, location, name, state)?
3701 };
3702 SimpleSelectorParseResult::SimpleSelector(pseudo_class)
3703 }
3704 },
3705 _ => {
3706 input.reset(&start);
3707 return Ok(None);
3708 },
3709 }))
3710}
3711
3712fn parse_simple_pseudo_class<'i, P, Impl>(
3713 parser: &P,
3714 location: SourceLocation,
3715 name: CowRcStr<'i>,
3716 state: SelectorParsingState,
3717) -> Result<Component<Impl>, ParseError<'i, P::Error>>
3718where
3719 P: Parser<'i, Impl = Impl>,
3720 Impl: SelectorImpl,
3721{
3722 if !state.allows_non_functional_pseudo_classes() {
3723 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3724 }
3725
3726 if state.allows_tree_structural_pseudo_classes() {
3727 if state.allows_only_child_pseudo_class_only() {
3732 if name.eq_ignore_ascii_case("only-child") {
3733 return Ok(Component::Nth(NthSelectorData::only(
3734 false,
3735 )));
3736 }
3737 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3741 }
3742
3743 match_ignore_ascii_case! { &name,
3744 "first-child" => return Ok(Component::Nth(NthSelectorData::first(false))),
3745 "last-child" => return Ok(Component::Nth(NthSelectorData::last(false))),
3746 "only-child" => return Ok(Component::Nth(NthSelectorData::only(false))),
3747 "root" => return Ok(Component::Root),
3748 "empty" => return Ok(Component::Empty),
3749 "scope" => return Ok(Component::Scope),
3750 "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
3751 "first-of-type" => return Ok(Component::Nth(NthSelectorData::first(true))),
3752 "last-of-type" => return Ok(Component::Nth(NthSelectorData::last(true))),
3753 "only-of-type" => return Ok(Component::Nth(NthSelectorData::only(true))),
3754 _ => {},
3755 }
3756 }
3757
3758 let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?;
3759 if state.intersects(SelectorParsingState::AFTER_NON_ELEMENT_BACKED_PSEUDO)
3760 && !pseudo_class.is_user_action_state()
3761 {
3762 return Err(location.new_custom_error(SelectorParseErrorKind::InvalidState));
3763 }
3764 Ok(Component::NonTSPseudoClass(pseudo_class))
3765}
3766
3767#[cfg(test)]
3769pub mod tests {
3770 use super::*;
3771 use crate::builder::SelectorFlags;
3772 use crate::parser;
3773 use cssparser::{serialize_identifier, Parser as CssParser, ParserInput, ToCss};
3774 use std::collections::HashMap;
3775 use std::fmt;
3776
3777 #[derive(Clone, Debug, Eq, PartialEq)]
3778 pub enum PseudoClass {
3779 Hover,
3780 Active,
3781 Lang(String),
3782 }
3783
3784 #[derive(Clone, Debug, Eq, PartialEq)]
3785 pub enum PseudoElement {
3786 Before,
3787 After,
3788 Marker,
3789 DetailsContent,
3790 Highlight(String),
3791 }
3792
3793 impl parser::PseudoElement for PseudoElement {
3794 type Impl = DummySelectorImpl;
3795
3796 fn accepts_state_pseudo_classes(&self) -> bool {
3797 true
3798 }
3799
3800 fn valid_after_slotted(&self) -> bool {
3801 true
3802 }
3803
3804 fn valid_after_before_or_after(&self) -> bool {
3805 matches!(self, Self::Marker)
3806 }
3807
3808 fn is_before_or_after(&self) -> bool {
3809 matches!(self, Self::Before | Self::After)
3810 }
3811
3812 fn parses_as_element_backed(&self) -> bool {
3813 matches!(self, Self::DetailsContent)
3814 }
3815 }
3816
3817 impl parser::NonTSPseudoClass for PseudoClass {
3818 type Impl = DummySelectorImpl;
3819
3820 #[inline]
3821 fn is_active_or_hover(&self) -> bool {
3822 matches!(*self, PseudoClass::Active | PseudoClass::Hover)
3823 }
3824
3825 #[inline]
3826 fn is_user_action_state(&self) -> bool {
3827 self.is_active_or_hover()
3828 }
3829 }
3830
3831 impl ToCss for PseudoClass {
3832 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3833 where
3834 W: fmt::Write,
3835 {
3836 match *self {
3837 PseudoClass::Hover => dest.write_str(":hover"),
3838 PseudoClass::Active => dest.write_str(":active"),
3839 PseudoClass::Lang(ref lang) => {
3840 dest.write_str(":lang(")?;
3841 serialize_identifier(lang, dest)?;
3842 dest.write_char(')')
3843 },
3844 }
3845 }
3846 }
3847
3848 impl ToCss for PseudoElement {
3849 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3850 where
3851 W: fmt::Write,
3852 {
3853 match *self {
3854 PseudoElement::Before => dest.write_str("::before"),
3855 PseudoElement::After => dest.write_str("::after"),
3856 PseudoElement::Marker => dest.write_str("::marker"),
3857 PseudoElement::DetailsContent => dest.write_str("::details-content"),
3858 PseudoElement::Highlight(ref name) => {
3859 dest.write_str("::highlight(")?;
3860 serialize_identifier(&name, dest)?;
3861 dest.write_char(')')
3862 },
3863 }
3864 }
3865 }
3866
3867 #[derive(Clone, Debug, PartialEq)]
3868 pub struct DummySelectorImpl;
3869
3870 #[derive(Default)]
3871 pub struct DummyParser {
3872 default_ns: Option<DummyAtom>,
3873 ns_prefixes: HashMap<DummyAtom, DummyAtom>,
3874 }
3875
3876 impl DummyParser {
3877 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
3878 DummyParser {
3879 default_ns: Some(default_ns),
3880 ns_prefixes: Default::default(),
3881 }
3882 }
3883 }
3884
3885 impl SelectorImpl for DummySelectorImpl {
3886 type ExtraMatchingData<'a> = std::marker::PhantomData<&'a ()>;
3887 type AttrValue = DummyAttrValue;
3888 type Identifier = DummyAtom;
3889 type LocalName = DummyAtom;
3890 type NamespaceUrl = DummyAtom;
3891 type NamespacePrefix = DummyAtom;
3892 type BorrowedLocalName = DummyAtom;
3893 type BorrowedNamespaceUrl = DummyAtom;
3894 type NonTSPseudoClass = PseudoClass;
3895 type PseudoElement = PseudoElement;
3896 }
3897
3898 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3899 pub struct DummyAttrValue(String);
3900
3901 impl ToCss for DummyAttrValue {
3902 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3903 where
3904 W: fmt::Write,
3905 {
3906 use std::fmt::Write;
3907
3908 dest.write_char('"')?;
3909 write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)?;
3910 dest.write_char('"')
3911 }
3912 }
3913
3914 impl<'a> From<&'a str> for DummyAttrValue {
3915 fn from(string: &'a str) -> Self {
3916 Self(string.into())
3917 }
3918 }
3919
3920 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
3921 pub struct DummyAtom(String);
3922
3923 impl ToCss for DummyAtom {
3924 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
3925 where
3926 W: fmt::Write,
3927 {
3928 serialize_identifier(&self.0, dest)
3929 }
3930 }
3931
3932 impl From<String> for DummyAtom {
3933 fn from(string: String) -> Self {
3934 DummyAtom(string)
3935 }
3936 }
3937
3938 impl<'a> From<&'a str> for DummyAtom {
3939 fn from(string: &'a str) -> Self {
3940 DummyAtom(string.into())
3941 }
3942 }
3943
3944 impl PrecomputedHash for DummyAtom {
3945 fn precomputed_hash(&self) -> u32 {
3946 self.0.as_ptr() as u32
3947 }
3948 }
3949
3950 impl<'i> Parser<'i> for DummyParser {
3951 type Impl = DummySelectorImpl;
3952 type Error = SelectorParseErrorKind<'i>;
3953
3954 fn parse_slotted(&self) -> bool {
3955 true
3956 }
3957
3958 fn parse_nth_child_of(&self) -> bool {
3959 true
3960 }
3961
3962 fn parse_is_and_where(&self) -> bool {
3963 true
3964 }
3965
3966 fn parse_has(&self) -> bool {
3967 true
3968 }
3969
3970 fn parse_parent_selector(&self) -> bool {
3971 true
3972 }
3973
3974 fn parse_part(&self) -> bool {
3975 true
3976 }
3977
3978 fn parse_host(&self) -> bool {
3979 true
3980 }
3981
3982 fn parse_non_ts_pseudo_class(
3983 &self,
3984 location: SourceLocation,
3985 name: CowRcStr<'i>,
3986 ) -> Result<PseudoClass, SelectorParseError<'i>> {
3987 match_ignore_ascii_case! { &name,
3988 "hover" => return Ok(PseudoClass::Hover),
3989 "active" => return Ok(PseudoClass::Active),
3990 _ => {}
3991 }
3992 Err(
3993 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
3994 name,
3995 )),
3996 )
3997 }
3998
3999 fn parse_non_ts_functional_pseudo_class<'t>(
4000 &self,
4001 name: CowRcStr<'i>,
4002 parser: &mut CssParser<'i, 't>,
4003 after_part: bool,
4004 ) -> Result<PseudoClass, SelectorParseError<'i>> {
4005 match_ignore_ascii_case! { &name,
4006 "lang" if !after_part => {
4007 let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
4008 return Ok(PseudoClass::Lang(lang));
4009 },
4010 _ => {}
4011 }
4012 Err(
4013 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4014 name,
4015 )),
4016 )
4017 }
4018
4019 fn parse_pseudo_element(
4020 &self,
4021 location: SourceLocation,
4022 name: CowRcStr<'i>,
4023 ) -> Result<PseudoElement, SelectorParseError<'i>> {
4024 match_ignore_ascii_case! { &name,
4025 "before" => return Ok(PseudoElement::Before),
4026 "after" => return Ok(PseudoElement::After),
4027 "marker" => return Ok(PseudoElement::Marker),
4028 "details-content" => return Ok(PseudoElement::DetailsContent),
4029 _ => {}
4030 }
4031 Err(
4032 location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4033 name,
4034 )),
4035 )
4036 }
4037
4038 fn parse_functional_pseudo_element<'t>(
4039 &self,
4040 name: CowRcStr<'i>,
4041 parser: &mut CssParser<'i, 't>,
4042 ) -> Result<PseudoElement, SelectorParseError<'i>> {
4043 match_ignore_ascii_case! { &name,
4044 "highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())),
4045 _ => {}
4046 }
4047 Err(
4048 parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
4049 name,
4050 )),
4051 )
4052 }
4053
4054 fn default_namespace(&self) -> Option<DummyAtom> {
4055 self.default_ns.clone()
4056 }
4057
4058 fn namespace_for_prefix(&self, prefix: &DummyAtom) -> Option<DummyAtom> {
4059 self.ns_prefixes.get(prefix).cloned()
4060 }
4061 }
4062
4063 fn parse<'i>(
4064 input: &'i str,
4065 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4066 parse_relative(input, ParseRelative::No)
4067 }
4068
4069 fn parse_relative<'i>(
4070 input: &'i str,
4071 parse_relative: ParseRelative,
4072 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4073 parse_ns_relative(input, &DummyParser::default(), parse_relative)
4074 }
4075
4076 fn parse_expected<'i, 'a>(
4077 input: &'i str,
4078 expected: Option<&'a str>,
4079 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4080 parse_ns_expected(input, &DummyParser::default(), expected)
4081 }
4082
4083 fn parse_relative_expected<'i, 'a>(
4084 input: &'i str,
4085 parse_relative: ParseRelative,
4086 expected: Option<&'a str>,
4087 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4088 parse_ns_relative_expected(input, &DummyParser::default(), parse_relative, expected)
4089 }
4090
4091 fn parse_ns<'i>(
4092 input: &'i str,
4093 parser: &DummyParser,
4094 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4095 parse_ns_relative(input, parser, ParseRelative::No)
4096 }
4097
4098 fn parse_ns_relative<'i>(
4099 input: &'i str,
4100 parser: &DummyParser,
4101 parse_relative: ParseRelative,
4102 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4103 parse_ns_relative_expected(input, parser, parse_relative, None)
4104 }
4105
4106 fn parse_ns_expected<'i, 'a>(
4107 input: &'i str,
4108 parser: &DummyParser,
4109 expected: Option<&'a str>,
4110 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4111 parse_ns_relative_expected(input, parser, ParseRelative::No, expected)
4112 }
4113
4114 fn parse_ns_relative_expected<'i, 'a>(
4115 input: &'i str,
4116 parser: &DummyParser,
4117 parse_relative: ParseRelative,
4118 expected: Option<&'a str>,
4119 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
4120 let mut parser_input = ParserInput::new(input);
4121 let result = SelectorList::parse(
4122 parser,
4123 &mut CssParser::new(&mut parser_input),
4124 parse_relative,
4125 );
4126 if let Ok(ref selectors) = result {
4127 assert_eq!(
4131 selectors.to_css_string(),
4132 match expected {
4133 Some(x) => x,
4134 None => input,
4135 }
4136 );
4137 }
4138 result
4139 }
4140
4141 fn specificity(a: u32, b: u32, c: u32) -> u32 {
4142 a << 20 | b << 10 | c
4143 }
4144
4145 #[test]
4146 fn test_ancestor_hashes_in_subject_position() {
4147 fn ancestor_hash_count(selector: &str) -> usize {
4148 let list = parse(selector).unwrap();
4149 assert_eq!(list.slice().len(), 1);
4150 let mut hashes = [0u32; 4];
4151 let mut len = 0;
4152 collect_ancestor_hashes(
4153 list.slice()[0].iter(),
4154 QuirksMode::NoQuirks,
4155 &mut hashes,
4156 &mut len,
4157 );
4158 len
4159 }
4160
4161 assert_eq!(ancestor_hash_count(".subject"), 0);
4163 assert_eq!(ancestor_hash_count(":where(.subject)"), 0);
4164
4165 assert_eq!(ancestor_hash_count(":where(.ancestor > .subject)"), 1);
4168 assert_eq!(ancestor_hash_count(":is(.ancestor .subject)"), 1);
4169 assert_eq!(
4170 ancestor_hash_count(":where(.ancestor > :not(:last-child))"),
4171 1
4172 );
4173
4174 assert_eq!(
4177 ancestor_hash_count(".real-ancestor :where(.inner-ancestor > .subject)"),
4178 2
4179 );
4180
4181 assert_eq!(ancestor_hash_count(":is(.a, .b) .subject"), 0);
4185 assert_eq!(
4186 ancestor_hash_count(":where(.ancestor > .subject, .other)"),
4187 0
4188 );
4189 assert_eq!(ancestor_hash_count(".real-ancestor :where(.a > .b, .c)"), 1);
4192
4193 assert_eq!(ancestor_hash_count(".subject::before"), 0);
4197 assert_eq!(ancestor_hash_count(".real-ancestor .subject::before"), 1);
4198 assert_eq!(
4201 ancestor_hash_count(":where(.ancestor > .subject)::before"),
4202 1
4203 );
4204 }
4205
4206 #[test]
4207 fn test_empty() {
4208 let mut input = ParserInput::new(":empty");
4209 let list = SelectorList::parse(
4210 &DummyParser::default(),
4211 &mut CssParser::new(&mut input),
4212 ParseRelative::No,
4213 );
4214 assert!(list.is_ok());
4215 }
4216
4217 const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
4218 const SVG: &str = "http://www.w3.org/2000/svg";
4219
4220 #[test]
4221 fn test_parsing() {
4222 assert!(parse("").is_err());
4223 assert!(parse(":lang(4)").is_err());
4224 assert!(parse(":lang(en US)").is_err());
4225 assert_eq!(
4226 parse("EeÉ"),
4227 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4228 vec![Component::LocalName(LocalName {
4229 name: DummyAtom::from("EeÉ"),
4230 lower_name: DummyAtom::from("eeÉ"),
4231 })],
4232 specificity(0, 0, 1),
4233 SelectorFlags::empty(),
4234 )]))
4235 );
4236 assert_eq!(
4237 parse("|e"),
4238 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4239 vec![
4240 Component::ExplicitNoNamespace,
4241 Component::LocalName(LocalName {
4242 name: DummyAtom::from("e"),
4243 lower_name: DummyAtom::from("e"),
4244 }),
4245 ],
4246 specificity(0, 0, 1),
4247 SelectorFlags::empty(),
4248 )]))
4249 );
4250 assert_eq!(
4253 parse_expected("*|e", Some("e")),
4254 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4255 vec![Component::LocalName(LocalName {
4256 name: DummyAtom::from("e"),
4257 lower_name: DummyAtom::from("e"),
4258 })],
4259 specificity(0, 0, 1),
4260 SelectorFlags::empty(),
4261 )]))
4262 );
4263 assert_eq!(
4268 parse_ns(
4269 "*|e",
4270 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4271 ),
4272 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4273 vec![
4274 Component::ExplicitAnyNamespace,
4275 Component::LocalName(LocalName {
4276 name: DummyAtom::from("e"),
4277 lower_name: DummyAtom::from("e"),
4278 }),
4279 ],
4280 specificity(0, 0, 1),
4281 SelectorFlags::empty(),
4282 )]))
4283 );
4284 assert_eq!(
4285 parse("*"),
4286 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4287 vec![Component::ExplicitUniversalType],
4288 specificity(0, 0, 0),
4289 SelectorFlags::empty(),
4290 )]))
4291 );
4292 assert_eq!(
4293 parse("|*"),
4294 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4295 vec![
4296 Component::ExplicitNoNamespace,
4297 Component::ExplicitUniversalType,
4298 ],
4299 specificity(0, 0, 0),
4300 SelectorFlags::empty(),
4301 )]))
4302 );
4303 assert_eq!(
4304 parse_expected("*|*", Some("*")),
4305 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4306 vec![Component::ExplicitUniversalType],
4307 specificity(0, 0, 0),
4308 SelectorFlags::empty(),
4309 )]))
4310 );
4311 assert_eq!(
4312 parse_ns(
4313 "*|*",
4314 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org"))
4315 ),
4316 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4317 vec![
4318 Component::ExplicitAnyNamespace,
4319 Component::ExplicitUniversalType,
4320 ],
4321 specificity(0, 0, 0),
4322 SelectorFlags::empty(),
4323 )]))
4324 );
4325 assert_eq!(
4326 parse(".foo:lang(en-US)"),
4327 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4328 vec![
4329 Component::Class(DummyAtom::from("foo")),
4330 Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())),
4331 ],
4332 specificity(0, 2, 0),
4333 SelectorFlags::empty(),
4334 )]))
4335 );
4336 assert_eq!(
4337 parse("#bar"),
4338 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4339 vec![Component::ID(DummyAtom::from("bar"))],
4340 specificity(1, 0, 0),
4341 SelectorFlags::empty(),
4342 )]))
4343 );
4344 assert_eq!(
4345 parse("e.foo#bar"),
4346 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4347 vec![
4348 Component::LocalName(LocalName {
4349 name: DummyAtom::from("e"),
4350 lower_name: DummyAtom::from("e"),
4351 }),
4352 Component::Class(DummyAtom::from("foo")),
4353 Component::ID(DummyAtom::from("bar")),
4354 ],
4355 specificity(1, 1, 1),
4356 SelectorFlags::empty(),
4357 )]))
4358 );
4359 assert_eq!(
4360 parse("e.foo #bar"),
4361 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4362 vec![
4363 Component::LocalName(LocalName {
4364 name: DummyAtom::from("e"),
4365 lower_name: DummyAtom::from("e"),
4366 }),
4367 Component::Class(DummyAtom::from("foo")),
4368 Component::Combinator(Combinator::Descendant),
4369 Component::ID(DummyAtom::from("bar")),
4370 ],
4371 specificity(1, 1, 1),
4372 SelectorFlags::empty(),
4373 )]))
4374 );
4375 let mut parser = DummyParser::default();
4378 assert_eq!(
4379 parse_ns("[Foo]", &parser),
4380 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4381 vec![Component::AttributeInNoNamespaceExists {
4382 local_name: DummyAtom::from("Foo"),
4383 local_name_lower: DummyAtom::from("foo"),
4384 }],
4385 specificity(0, 1, 0),
4386 SelectorFlags::empty(),
4387 )]))
4388 );
4389 assert!(parse_ns("svg|circle", &parser).is_err());
4390 parser
4391 .ns_prefixes
4392 .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
4393 assert_eq!(
4394 parse_ns("svg|circle", &parser),
4395 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4396 vec![
4397 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4398 Component::LocalName(LocalName {
4399 name: DummyAtom::from("circle"),
4400 lower_name: DummyAtom::from("circle"),
4401 }),
4402 ],
4403 specificity(0, 0, 1),
4404 SelectorFlags::empty(),
4405 )]))
4406 );
4407 assert_eq!(
4408 parse_ns("svg|*", &parser),
4409 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4410 vec![
4411 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
4412 Component::ExplicitUniversalType,
4413 ],
4414 specificity(0, 0, 0),
4415 SelectorFlags::empty(),
4416 )]))
4417 );
4418 parser.default_ns = Some(MATHML.into());
4423 assert_eq!(
4424 parse_ns("[Foo]", &parser),
4425 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4426 vec![
4427 Component::DefaultNamespace(MATHML.into()),
4428 Component::AttributeInNoNamespaceExists {
4429 local_name: DummyAtom::from("Foo"),
4430 local_name_lower: DummyAtom::from("foo"),
4431 },
4432 ],
4433 specificity(0, 1, 0),
4434 SelectorFlags::empty(),
4435 )]))
4436 );
4437 assert_eq!(
4439 parse_ns("e", &parser),
4440 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4441 vec![
4442 Component::DefaultNamespace(MATHML.into()),
4443 Component::LocalName(LocalName {
4444 name: DummyAtom::from("e"),
4445 lower_name: DummyAtom::from("e"),
4446 }),
4447 ],
4448 specificity(0, 0, 1),
4449 SelectorFlags::empty(),
4450 )]))
4451 );
4452 assert_eq!(
4453 parse_ns("*", &parser),
4454 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4455 vec![
4456 Component::DefaultNamespace(MATHML.into()),
4457 Component::ExplicitUniversalType,
4458 ],
4459 specificity(0, 0, 0),
4460 SelectorFlags::empty(),
4461 )]))
4462 );
4463 assert_eq!(
4464 parse_ns("*|*", &parser),
4465 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4466 vec![
4467 Component::ExplicitAnyNamespace,
4468 Component::ExplicitUniversalType,
4469 ],
4470 specificity(0, 0, 0),
4471 SelectorFlags::empty(),
4472 )]))
4473 );
4474 assert_eq!(
4477 parse_ns(":not(.cl)", &parser),
4478 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4479 vec![
4480 Component::DefaultNamespace(MATHML.into()),
4481 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4482 vec![Component::Class(DummyAtom::from("cl"))],
4483 specificity(0, 1, 0),
4484 SelectorFlags::empty(),
4485 )])),
4486 ],
4487 specificity(0, 1, 0),
4488 SelectorFlags::empty(),
4489 )]))
4490 );
4491 assert_eq!(
4492 parse_ns(":not(*)", &parser),
4493 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4494 vec![
4495 Component::DefaultNamespace(MATHML.into()),
4496 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4497 vec![
4498 Component::DefaultNamespace(MATHML.into()),
4499 Component::ExplicitUniversalType,
4500 ],
4501 specificity(0, 0, 0),
4502 SelectorFlags::empty(),
4503 )]),),
4504 ],
4505 specificity(0, 0, 0),
4506 SelectorFlags::empty(),
4507 )]))
4508 );
4509 assert_eq!(
4510 parse_ns(":not(e)", &parser),
4511 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4512 vec![
4513 Component::DefaultNamespace(MATHML.into()),
4514 Component::Negation(SelectorList::from_vec(vec![Selector::from_vec(
4515 vec![
4516 Component::DefaultNamespace(MATHML.into()),
4517 Component::LocalName(LocalName {
4518 name: DummyAtom::from("e"),
4519 lower_name: DummyAtom::from("e"),
4520 }),
4521 ],
4522 specificity(0, 0, 1),
4523 SelectorFlags::empty(),
4524 )])),
4525 ],
4526 specificity(0, 0, 1),
4527 SelectorFlags::empty(),
4528 )]))
4529 );
4530 assert_eq!(
4531 parse("[attr|=\"foo\"]"),
4532 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4533 vec![Component::AttributeInNoNamespace {
4534 local_name: DummyAtom::from("attr"),
4535 operator: AttrSelectorOperator::DashMatch,
4536 value: DummyAttrValue::from("foo"),
4537 case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
4538 }],
4539 specificity(0, 1, 0),
4540 SelectorFlags::empty(),
4541 )]))
4542 );
4543 assert_eq!(
4545 parse("::before"),
4546 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4547 vec![
4548 Component::Combinator(Combinator::PseudoElement),
4549 Component::PseudoElement(PseudoElement::Before),
4550 ],
4551 specificity(0, 0, 1),
4552 SelectorFlags::HAS_PSEUDO,
4553 )]))
4554 );
4555 assert_eq!(
4556 parse("::before:hover"),
4557 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4558 vec![
4559 Component::Combinator(Combinator::PseudoElement),
4560 Component::PseudoElement(PseudoElement::Before),
4561 Component::NonTSPseudoClass(PseudoClass::Hover),
4562 ],
4563 specificity(0, 1, 1),
4564 SelectorFlags::HAS_PSEUDO,
4565 )]))
4566 );
4567 assert_eq!(
4568 parse("::before:hover:hover"),
4569 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4570 vec![
4571 Component::Combinator(Combinator::PseudoElement),
4572 Component::PseudoElement(PseudoElement::Before),
4573 Component::NonTSPseudoClass(PseudoClass::Hover),
4574 Component::NonTSPseudoClass(PseudoClass::Hover),
4575 ],
4576 specificity(0, 2, 1),
4577 SelectorFlags::HAS_PSEUDO,
4578 )]))
4579 );
4580 assert!(parse("::before:hover:lang(foo)").is_err());
4581 assert!(parse("::before:hover .foo").is_err());
4582 assert!(parse("::before .foo").is_err());
4583 assert!(parse("::before ~ bar").is_err());
4584 assert!(parse("::before:active").is_ok());
4585
4586 assert!(parse(":: before").is_err());
4588 assert_eq!(
4589 parse("div ::after"),
4590 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4591 vec![
4592 Component::LocalName(LocalName {
4593 name: DummyAtom::from("div"),
4594 lower_name: DummyAtom::from("div"),
4595 }),
4596 Component::Combinator(Combinator::Descendant),
4597 Component::Combinator(Combinator::PseudoElement),
4598 Component::PseudoElement(PseudoElement::After),
4599 ],
4600 specificity(0, 0, 2),
4601 SelectorFlags::HAS_PSEUDO,
4602 )]))
4603 );
4604 assert_eq!(
4605 parse("#d1 > .ok"),
4606 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4607 vec![
4608 Component::ID(DummyAtom::from("d1")),
4609 Component::Combinator(Combinator::Child),
4610 Component::Class(DummyAtom::from("ok")),
4611 ],
4612 specificity(1, 1, 0),
4613 SelectorFlags::empty(),
4614 )]))
4615 );
4616 parser.default_ns = None;
4617 assert!(parse(":not(#provel.old)").is_ok());
4618 assert!(parse(":not(#provel > old)").is_ok());
4619 assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok());
4620 assert_eq!(
4622 parse_ns(":not(*)", &parser),
4623 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4624 vec![Component::Negation(SelectorList::from_vec(vec![
4625 Selector::from_vec(
4626 vec![Component::ExplicitUniversalType],
4627 specificity(0, 0, 0),
4628 SelectorFlags::empty(),
4629 )
4630 ]))],
4631 specificity(0, 0, 0),
4632 SelectorFlags::empty(),
4633 )]))
4634 );
4635 assert_eq!(
4636 parse_ns(":not(|*)", &parser),
4637 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4638 vec![Component::Negation(SelectorList::from_vec(vec![
4639 Selector::from_vec(
4640 vec![
4641 Component::ExplicitNoNamespace,
4642 Component::ExplicitUniversalType,
4643 ],
4644 specificity(0, 0, 0),
4645 SelectorFlags::empty(),
4646 )
4647 ]))],
4648 specificity(0, 0, 0),
4649 SelectorFlags::empty(),
4650 )]))
4651 );
4652 assert_eq!(
4655 parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
4656 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4657 vec![Component::Negation(SelectorList::from_vec(vec![
4658 Selector::from_vec(
4659 vec![Component::ExplicitUniversalType],
4660 specificity(0, 0, 0),
4661 SelectorFlags::empty(),
4662 )
4663 ]))],
4664 specificity(0, 0, 0),
4665 SelectorFlags::empty(),
4666 )]))
4667 );
4668
4669 assert!(parse("::highlight(foo)").is_ok());
4670
4671 assert!(parse("::slotted()").is_err());
4672 assert!(parse("::slotted(div)").is_ok());
4673 assert!(parse("::slotted(div).foo").is_err());
4674 assert!(parse("::slotted(div + bar)").is_err());
4675 assert!(parse("::slotted(div) + foo").is_err());
4676
4677 assert!(parse("::part()").is_err());
4678 assert!(parse("::part(42)").is_err());
4679 assert!(parse("::part(foo bar)").is_ok());
4680 assert!(parse("::part(foo):hover").is_ok());
4681 assert!(parse("::part(foo) + bar").is_err());
4682
4683 assert!(parse("div ::slotted(div)").is_ok());
4684 assert!(parse("div + slot::slotted(div)").is_ok());
4685 assert!(parse("div + slot::slotted(div.foo)").is_ok());
4686 assert!(parse("slot::slotted(div,foo)::first-line").is_err());
4687 assert!(parse("::slotted(div)::before").is_ok());
4688 assert!(parse("slot::slotted(div,foo)").is_err());
4689
4690 assert!(parse("foo:where()").is_ok());
4691 assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
4692 assert!(parse("foo:where(::before)").is_ok());
4693 }
4694
4695 #[test]
4696 fn parent_selector() {
4697 assert!(parse("foo &").is_ok());
4698 assert_eq!(
4699 parse("#foo &.bar"),
4700 Ok(SelectorList::from_vec(vec![Selector::from_vec(
4701 vec![
4702 Component::ID(DummyAtom::from("foo")),
4703 Component::Combinator(Combinator::Descendant),
4704 Component::ParentSelector,
4705 Component::Class(DummyAtom::from("bar")),
4706 ],
4707 specificity(1, 1, 0),
4708 SelectorFlags::HAS_PARENT
4709 )]))
4710 );
4711
4712 let parent = parse(".bar, div .baz").unwrap();
4713 let child = parse("#foo &.bar").unwrap();
4714 assert_eq!(
4715 child.replace_parent_selector(&parent),
4716 parse("#foo :is(.bar, div .baz).bar").unwrap()
4717 );
4718
4719 let has_child = parse("#foo:has(&.bar)").unwrap();
4720 assert_eq!(
4721 has_child.replace_parent_selector(&parent),
4722 parse("#foo:has(:is(.bar, div .baz).bar)").unwrap()
4723 );
4724
4725 let child =
4726 parse_relative_expected("#foo", ParseRelative::ForNesting, Some("& #foo")).unwrap();
4727 assert_eq!(
4728 child.replace_parent_selector(&parent),
4729 parse(":is(.bar, div .baz) #foo").unwrap()
4730 );
4731
4732 let child =
4733 parse_relative_expected("+ #foo", ParseRelative::ForNesting, Some("& + #foo")).unwrap();
4734 assert_eq!(child, parse("& + #foo").unwrap());
4735 }
4736
4737 #[test]
4738 fn test_pseudo_iter() {
4739 let list = parse("q::before").unwrap();
4740 let selector = &list.slice()[0];
4741 assert!(!selector.is_universal());
4742 let mut iter = selector.iter();
4743 assert_eq!(
4744 iter.next(),
4745 Some(&Component::PseudoElement(PseudoElement::Before))
4746 );
4747 assert_eq!(iter.next(), None);
4748 let combinator = iter.next_sequence();
4749 assert_eq!(combinator, Some(Combinator::PseudoElement));
4750 assert_eq!(
4751 iter.next(),
4752 Some(&Component::LocalName(LocalName {
4753 name: DummyAtom::from("q"),
4754 lower_name: DummyAtom::from("q"),
4755 }))
4756 );
4757 assert_eq!(iter.next(), None);
4758 assert_eq!(iter.next_sequence(), None);
4759 }
4760
4761 #[test]
4762 fn test_pseudo_before_marker() {
4763 let list = parse("::before::marker").unwrap();
4764 let selector = &list.slice()[0];
4765 let mut iter = selector.iter();
4766 assert_eq!(
4767 iter.next(),
4768 Some(&Component::PseudoElement(PseudoElement::Marker))
4769 );
4770 assert_eq!(iter.next(), None);
4771 let combinator = iter.next_sequence();
4772 assert_eq!(combinator, Some(Combinator::PseudoElement));
4773 assert_eq!(
4774 iter.next(),
4775 Some(&Component::PseudoElement(PseudoElement::Before))
4776 );
4777 assert_eq!(iter.next(), None);
4778 let combinator = iter.next_sequence();
4779 assert_eq!(combinator, Some(Combinator::PseudoElement));
4780 assert_eq!(iter.next(), None);
4781 assert_eq!(iter.next_sequence(), None);
4782 }
4783
4784 #[test]
4785 fn test_pseudo_duplicate_before_after_or_marker() {
4786 assert!(parse("::before::before").is_err());
4787 assert!(parse("::after::after").is_err());
4788 assert!(parse("::marker::marker").is_err());
4789 }
4790
4791 #[test]
4792 fn test_pseudo_on_element_backed_pseudo() {
4793 let list = parse("::details-content::before").unwrap();
4794 let selector = &list.slice()[0];
4795 let mut iter = selector.iter();
4796 assert_eq!(
4797 iter.next(),
4798 Some(&Component::PseudoElement(PseudoElement::Before))
4799 );
4800 assert_eq!(iter.next(), None);
4801 let combinator = iter.next_sequence();
4802 assert_eq!(combinator, Some(Combinator::PseudoElement));
4803 assert_eq!(
4804 iter.next(),
4805 Some(&Component::PseudoElement(PseudoElement::DetailsContent))
4806 );
4807 assert_eq!(iter.next(), None);
4808 let combinator = iter.next_sequence();
4809 assert_eq!(combinator, Some(Combinator::PseudoElement));
4810 assert_eq!(iter.next(), None);
4811 assert_eq!(iter.next_sequence(), None);
4812 }
4813
4814 #[test]
4815 fn test_universal() {
4816 let list = parse_ns(
4817 "*|*::before",
4818 &DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")),
4819 )
4820 .unwrap();
4821 let selector = &list.slice()[0];
4822 assert!(selector.is_universal());
4823 }
4824
4825 #[test]
4826 fn test_empty_pseudo_iter() {
4827 let list = parse("::before").unwrap();
4828 let selector = &list.slice()[0];
4829 assert!(selector.is_universal());
4830 let mut iter = selector.iter();
4831 assert_eq!(
4832 iter.next(),
4833 Some(&Component::PseudoElement(PseudoElement::Before))
4834 );
4835 assert_eq!(iter.next(), None);
4836 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
4837 assert_eq!(iter.next(), None);
4838 assert_eq!(iter.next_sequence(), None);
4839 }
4840
4841 #[test]
4842 fn test_parse_implicit_scope() {
4843 assert_eq!(
4844 parse_relative_expected(".foo", ParseRelative::ForScope, None).unwrap(),
4845 SelectorList::from_vec(vec![Selector::from_vec(
4846 vec![
4847 Component::ImplicitScope,
4848 Component::Combinator(Combinator::Descendant),
4849 Component::Class(DummyAtom::from("foo")),
4850 ],
4851 specificity(0, 1, 0),
4852 SelectorFlags::HAS_SCOPE,
4853 )])
4854 );
4855
4856 assert_eq!(
4857 parse_relative_expected(":scope .foo", ParseRelative::ForScope, None).unwrap(),
4858 SelectorList::from_vec(vec![Selector::from_vec(
4859 vec![
4860 Component::Scope,
4861 Component::Combinator(Combinator::Descendant),
4862 Component::Class(DummyAtom::from("foo")),
4863 ],
4864 specificity(0, 2, 0),
4865 SelectorFlags::HAS_SCOPE
4866 )])
4867 );
4868
4869 assert_eq!(
4870 parse_relative_expected("> .foo", ParseRelative::ForScope, Some("> .foo")).unwrap(),
4871 SelectorList::from_vec(vec![Selector::from_vec(
4872 vec![
4873 Component::ImplicitScope,
4874 Component::Combinator(Combinator::Child),
4875 Component::Class(DummyAtom::from("foo")),
4876 ],
4877 specificity(0, 1, 0),
4878 SelectorFlags::HAS_SCOPE
4879 )])
4880 );
4881
4882 assert_eq!(
4883 parse_relative_expected(".foo :scope > .bar", ParseRelative::ForScope, None).unwrap(),
4884 SelectorList::from_vec(vec![Selector::from_vec(
4885 vec![
4886 Component::Class(DummyAtom::from("foo")),
4887 Component::Combinator(Combinator::Descendant),
4888 Component::Scope,
4889 Component::Combinator(Combinator::Child),
4890 Component::Class(DummyAtom::from("bar")),
4891 ],
4892 specificity(0, 3, 0),
4893 SelectorFlags::HAS_SCOPE
4894 )])
4895 );
4896 }
4897
4898 struct TestVisitor {
4899 seen: Vec<String>,
4900 }
4901
4902 impl SelectorVisitor for TestVisitor {
4903 type Impl = DummySelectorImpl;
4904
4905 fn visit_simple_selector(&mut self, s: &Component<DummySelectorImpl>) -> bool {
4906 let mut dest = String::new();
4907 s.to_css(&mut dest).unwrap();
4908 self.seen.push(dest);
4909 true
4910 }
4911 }
4912
4913 #[test]
4914 fn visitor() {
4915 let mut test_visitor = TestVisitor { seen: vec![] };
4916 parse(":not(:hover) ~ label").unwrap().slice()[0].visit(&mut test_visitor);
4917 assert!(test_visitor.seen.contains(&":hover".into()));
4918
4919 let mut test_visitor = TestVisitor { seen: vec![] };
4920 parse("::before:hover").unwrap().slice()[0].visit(&mut test_visitor);
4921 assert!(test_visitor.seen.contains(&":hover".into()));
4922 }
4923}