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