1pub use crate::visitor::SelectorVisitor;
6use {
7 crate::{
8 attr::{
9 AttrSelectorOperator,
10 AttrSelectorWithOptionalNamespace,
11 NamespaceConstraint,
12 ParsedAttrSelectorOperation,
13 ParsedCaseSensitivity,
14 SELECTOR_WHITESPACE,
15 },
16 bloom::BLOOM_HASH_MASK,
17 builder::{SelectorBuilder, SelectorFlags, SpecificityAndFlags},
18 context::QuirksMode,
19 sink::Push,
20 },
21 cssparser::{
22 parse_nth,
23 BasicParseError,
24 BasicParseErrorKind,
25 CowRcStr,
26 Delimiter,
27 ParseError,
28 ParseErrorKind,
29 Parser as CssParser,
30 SourceLocation,
31 ToCss,
32 Token,
33 },
34 precomputed_hash::PrecomputedHash,
35 servo_arc::ThinArc,
36 smallvec::SmallVec,
37 std::{
38 borrow::{Borrow, Cow},
39 fmt::{self, Debug},
40 iter::Rev,
41 slice,
42 },
43};
44
45pub trait PseudoElement: Sized + ToCss {
47 type Impl: SelectorImpl;
49
50 fn accepts_state_pseudo_classes(&self) -> bool {
53 false
54 }
55
56 fn valid_after_slotted(&self) -> bool {
58 false
59 }
60}
61
62pub trait NonTSPseudoClass: Sized + ToCss {
64 type Impl: SelectorImpl;
66
67 fn is_active_or_hover(&self) -> bool;
69
70 fn is_user_action_state(&self) -> bool;
74
75 fn visit<V>(&self, _visitor: &mut V) -> bool
76 where
77 V: SelectorVisitor<Impl = Self::Impl>,
78 {
79 true
80 }
81}
82
83fn to_ascii_lowercase(s: &str) -> Cow<str> {
86 if let Some(first_uppercase) =
87 s.bytes().position(|byte| byte >= b'A' && byte <= b'Z')
88 {
89 let mut string = s.to_owned();
90 string[first_uppercase..].make_ascii_lowercase();
91 string.into()
92 } else {
93 s.into()
94 }
95}
96
97bitflags! {
98 struct SelectorParsingState: u8 {
100 const SKIP_DEFAULT_NAMESPACE = 1 << 0;
103
104 const AFTER_SLOTTED = 1 << 1;
109 const AFTER_PART = 1 << 2;
114 const AFTER_PSEUDO_ELEMENT = 1 << 3;
121 const AFTER_NON_STATEFUL_PSEUDO_ELEMENT = 1 << 4;
126
127 const AFTER_PSEUDO = Self::AFTER_PART.bits | Self::AFTER_SLOTTED.bits | Self::AFTER_PSEUDO_ELEMENT.bits;
129
130 const DISALLOW_COMBINATORS = 1 << 5;
132
133 const DISALLOW_PSEUDOS = 1 << 6;
135 }
136}
137
138impl SelectorParsingState {
139 #[inline]
140 fn allows_pseudos(self) -> bool {
141 !self.intersects(Self::AFTER_PSEUDO_ELEMENT | Self::DISALLOW_PSEUDOS)
143 }
144
145 #[inline]
146 fn allows_slotted(self) -> bool {
147 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
148 }
149
150 #[inline]
151 fn allows_part(self) -> bool {
152 !self.intersects(Self::AFTER_PSEUDO | Self::DISALLOW_PSEUDOS)
153 }
154
155 #[inline]
160 fn allows_custom_functional_pseudo_classes(self) -> bool {
161 !self.intersects(Self::AFTER_PSEUDO)
162 }
163
164 #[inline]
165 fn allows_non_functional_pseudo_classes(self) -> bool {
166 !self.intersects(
167 Self::AFTER_SLOTTED | Self::AFTER_NON_STATEFUL_PSEUDO_ELEMENT,
168 )
169 }
170
171 #[inline]
172 fn allows_tree_structural_pseudo_classes(self) -> bool {
173 !self.intersects(Self::AFTER_PSEUDO)
174 }
175
176 #[inline]
177 fn allows_combinators(self) -> bool {
178 !self.intersects(Self::DISALLOW_COMBINATORS)
179 }
180}
181
182pub type SelectorParseError<'i> = ParseError<'i, SelectorParseErrorKind<'i>>;
183
184#[derive(Clone, Debug, PartialEq)]
185pub enum SelectorParseErrorKind<'i> {
186 NoQualifiedNameInAttributeSelector(Token<'i>),
187 EmptySelector,
188 DanglingCombinator,
189 NonCompoundSelector,
190 NonPseudoElementAfterSlotted,
191 InvalidPseudoElementAfterSlotted,
192 InvalidPseudoElementInsideWhere,
193 InvalidState,
194 UnexpectedTokenInAttributeSelector(Token<'i>),
195 PseudoElementExpectedColon(Token<'i>),
196 PseudoElementExpectedIdent(Token<'i>),
197 NoIdentForPseudo(Token<'i>),
198 UnsupportedPseudoClassOrElement(CowRcStr<'i>),
199 UnexpectedIdent(CowRcStr<'i>),
200 ExpectedNamespace(CowRcStr<'i>),
201 ExpectedBarInAttr(Token<'i>),
202 BadValueInAttr(Token<'i>),
203 InvalidQualNameInAttr(Token<'i>),
204 ExplicitNamespaceUnexpectedToken(Token<'i>),
205 ClassNeedsIdent(Token<'i>),
206}
207
208macro_rules! with_all_bounds {
209 (
210 [ $( $InSelector: tt )* ]
211 [ $( $CommonBounds: tt )* ]
212 [ $( $FromStr: tt )* ]
213 ) => {
214 pub trait SelectorImpl: Clone + Debug + Sized + 'static {
221 type ExtraMatchingData: Sized + Default + 'static;
222 type AttrValue: $($InSelector)*;
223 type Identifier: $($InSelector)*;
224 type LocalName: $($InSelector)* + Borrow<Self::BorrowedLocalName>;
225 type NamespaceUrl: $($CommonBounds)* + Default + Borrow<Self::BorrowedNamespaceUrl>;
226 type NamespacePrefix: $($InSelector)* + Default;
227 type BorrowedNamespaceUrl: ?Sized + Eq;
228 type BorrowedLocalName: ?Sized + Eq;
229
230 type NonTSPseudoClass: $($CommonBounds)* + NonTSPseudoClass<Impl = Self>;
233
234 type PseudoElement: $($CommonBounds)* + PseudoElement<Impl = Self>;
236 }
237 }
238}
239
240macro_rules! with_bounds {
241 ( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
242 with_all_bounds! {
243 [$($CommonBounds)* + $($FromStr)* + ToCss]
244 [$($CommonBounds)*]
245 [$($FromStr)*]
246 }
247 }
248}
249
250with_bounds! {
251 [Clone + Eq]
252 [for<'a> From<&'a str>]
253}
254
255pub trait Parser<'i> {
256 type Impl: SelectorImpl;
257 type Error: 'i + From<SelectorParseErrorKind<'i>>;
258
259 fn parse_slotted(&self) -> bool {
261 false
262 }
263
264 fn parse_part(&self) -> bool {
266 false
267 }
268
269 fn parse_is_and_where(&self) -> bool {
271 true
272 }
273
274 fn is_and_where_error_recovery(&self) -> ParseErrorRecovery {
276 ParseErrorRecovery::IgnoreInvalidSelector
277 }
278
279 fn is_is_alias(&self, _name: &str) -> bool {
281 false
282 }
283
284 fn parse_host(&self) -> bool {
286 false
287 }
288
289 fn parse_non_ts_pseudo_class(
295 &self,
296 location: SourceLocation,
297 name: CowRcStr<'i>,
298 ) -> Result<
299 <Self::Impl as SelectorImpl>::NonTSPseudoClass,
300 ParseError<'i, Self::Error>,
301 > {
302 Err(location.new_custom_error(
303 SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
304 ))
305 }
306
307 fn parse_non_ts_functional_pseudo_class<'t>(
308 &self,
309 name: CowRcStr<'i>,
310 arguments: &mut CssParser<'i, 't>,
311 ) -> Result<
312 <Self::Impl as SelectorImpl>::NonTSPseudoClass,
313 ParseError<'i, Self::Error>,
314 > {
315 Err(arguments.new_custom_error(
316 SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
317 ))
318 }
319
320 fn parse_pseudo_element(
321 &self,
322 location: SourceLocation,
323 name: CowRcStr<'i>,
324 ) -> Result<
325 <Self::Impl as SelectorImpl>::PseudoElement,
326 ParseError<'i, Self::Error>,
327 > {
328 Err(location.new_custom_error(
329 SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
330 ))
331 }
332
333 fn parse_functional_pseudo_element<'t>(
334 &self,
335 name: CowRcStr<'i>,
336 arguments: &mut CssParser<'i, 't>,
337 ) -> Result<
338 <Self::Impl as SelectorImpl>::PseudoElement,
339 ParseError<'i, Self::Error>,
340 > {
341 Err(arguments.new_custom_error(
342 SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
343 ))
344 }
345
346 fn default_namespace(
347 &self,
348 ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
349 None
350 }
351
352 fn namespace_for_prefix(
353 &self,
354 _prefix: &<Self::Impl as SelectorImpl>::NamespacePrefix,
355 ) -> Option<<Self::Impl as SelectorImpl>::NamespaceUrl> {
356 None
357 }
358}
359
360#[derive(Clone, Debug, Eq, PartialEq)]
361pub struct SelectorList<Impl: SelectorImpl>(pub SmallVec<[Selector<Impl>; 1]>);
362
363pub enum ParseErrorRecovery {
365 DiscardList,
368 IgnoreInvalidSelector,
372}
373
374impl<Impl: SelectorImpl> SelectorList<Impl> {
375 pub fn parse<'i, 't, P>(
380 parser: &P,
381 input: &mut CssParser<'i, 't>,
382 ) -> Result<Self, ParseError<'i, P::Error>>
383 where
384 P: Parser<'i, Impl = Impl>,
385 {
386 Self::parse_with_state(
387 parser,
388 input,
389 SelectorParsingState::empty(),
390 ParseErrorRecovery::DiscardList,
391 )
392 }
393
394 #[inline]
395 fn parse_with_state<'i, 't, P>(
396 parser: &P,
397 input: &mut CssParser<'i, 't>,
398 state: SelectorParsingState,
399 recovery: ParseErrorRecovery,
400 ) -> Result<Self, ParseError<'i, P::Error>>
401 where
402 P: Parser<'i, Impl = Impl>,
403 {
404 let mut values = SmallVec::new();
405 loop {
406 let selector = input
407 .parse_until_before(Delimiter::Comma, |input| {
408 parse_selector(parser, input, state)
409 });
410
411 let was_ok = selector.is_ok();
412 match selector {
413 Ok(selector) => values.push(selector),
414 Err(err) => match recovery {
415 ParseErrorRecovery::DiscardList => return Err(err),
416 ParseErrorRecovery::IgnoreInvalidSelector => {}
417 },
418 }
419
420 loop {
421 match input.next() {
422 Err(_) => return Ok(SelectorList(values)),
423 Ok(&Token::Comma) => break,
424 Ok(_) => {
425 debug_assert!(
426 !was_ok,
427 "Shouldn't have got a selector if getting here"
428 );
429 }
430 }
431 }
432 }
433 }
434
435 pub fn from_vec(v: Vec<Selector<Impl>>) -> Self {
437 SelectorList(SmallVec::from_vec(v))
438 }
439}
440
441fn parse_inner_compound_selector<'i, 't, P, Impl>(
443 parser: &P,
444 input: &mut CssParser<'i, 't>,
445 state: SelectorParsingState,
446) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
447where
448 P: Parser<'i, Impl = Impl>,
449 Impl: SelectorImpl,
450{
451 parse_selector(
452 parser,
453 input,
454 state
455 | SelectorParsingState::DISALLOW_PSEUDOS
456 | SelectorParsingState::DISALLOW_COMBINATORS,
457 )
458}
459
460#[derive(Clone, Debug, Eq, PartialEq)]
476pub struct AncestorHashes {
477 pub packed_hashes: [u32; 3],
478}
479
480fn collect_ancestor_hashes<Impl: SelectorImpl>(
481 iter: SelectorIter<Impl>,
482 quirks_mode: QuirksMode,
483 hashes: &mut [u32; 4],
484 len: &mut usize,
485) -> bool
486where
487 Impl::Identifier: PrecomputedHash,
488 Impl::LocalName: PrecomputedHash,
489 Impl::NamespaceUrl: PrecomputedHash,
490{
491 for component in AncestorIter::new(iter) {
492 let hash = match *component {
493 Component::LocalName(LocalName {
494 ref name,
495 ref lower_name,
496 }) => {
497 if name != lower_name {
501 continue;
502 }
503 name.precomputed_hash()
504 }
505 Component::DefaultNamespace(ref url)
506 | Component::Namespace(_, ref url) => url.precomputed_hash(),
507 Component::ID(ref id) if quirks_mode != QuirksMode::Quirks => {
510 id.precomputed_hash()
511 }
512 Component::Class(ref class)
513 if quirks_mode != QuirksMode::Quirks =>
514 {
515 class.precomputed_hash()
516 }
517 Component::Is(ref list) | Component::Where(ref list) => {
518 if list.len() == 1
522 && !collect_ancestor_hashes(
523 list[0].iter(),
524 quirks_mode,
525 hashes,
526 len,
527 )
528 {
529 return false;
530 }
531 continue;
532 }
533 _ => continue,
534 };
535
536 hashes[*len] = hash & BLOOM_HASH_MASK;
537 *len += 1;
538 if *len == hashes.len() {
539 return false;
540 }
541 }
542 true
543}
544
545impl AncestorHashes {
546 pub fn new<Impl: SelectorImpl>(
547 selector: &Selector<Impl>,
548 quirks_mode: QuirksMode,
549 ) -> Self
550 where
551 Impl::Identifier: PrecomputedHash,
552 Impl::LocalName: PrecomputedHash,
553 Impl::NamespaceUrl: PrecomputedHash,
554 {
555 let mut hashes = [0u32; 4];
557 let mut len = 0;
558 collect_ancestor_hashes(
559 selector.iter(),
560 quirks_mode,
561 &mut hashes,
562 &mut len,
563 );
564 debug_assert!(len <= 4);
565
566 if len == 4 {
569 let fourth = hashes[3];
570 hashes[0] |= (fourth & 0x000000ff) << 24;
571 hashes[1] |= (fourth & 0x0000ff00) << 16;
572 hashes[2] |= (fourth & 0x00ff0000) << 8;
573 }
574
575 AncestorHashes {
576 packed_hashes: [hashes[0], hashes[1], hashes[2]],
577 }
578 }
579
580 pub fn fourth_hash(&self) -> u32 {
582 ((self.packed_hashes[0] & 0xff000000) >> 24)
583 | ((self.packed_hashes[1] & 0xff000000) >> 16)
584 | ((self.packed_hashes[2] & 0xff000000) >> 8)
585 }
586}
587
588pub fn namespace_empty_string<Impl: SelectorImpl>() -> Impl::NamespaceUrl {
589 Impl::NamespaceUrl::default()
591}
592
593#[derive(Clone, Eq, PartialEq)]
608pub struct Selector<Impl: SelectorImpl>(
609 ThinArc<SpecificityAndFlags, Component<Impl>>,
610);
611
612impl<Impl: SelectorImpl> Selector<Impl> {
613 #[inline]
614 pub fn specificity(&self) -> u32 {
615 self.0.header.header.specificity()
616 }
617
618 #[inline]
619 pub fn has_pseudo_element(&self) -> bool {
620 self.0.header.header.has_pseudo_element()
621 }
622
623 #[inline]
624 pub fn is_slotted(&self) -> bool {
625 self.0.header.header.is_slotted()
626 }
627
628 #[inline]
629 pub fn is_part(&self) -> bool {
630 self.0.header.header.is_part()
631 }
632
633 #[inline]
634 pub fn parts(&self) -> Option<&[Impl::Identifier]> {
635 if !self.is_part() {
636 return None;
637 }
638
639 let mut iter = self.iter();
640 if self.has_pseudo_element() {
641 for _ in &mut iter {}
643
644 let combinator = iter.next_sequence()?;
645 debug_assert_eq!(combinator, Combinator::PseudoElement);
646 }
647
648 for component in iter {
649 if let Component::Part(ref part) = *component {
650 return Some(part);
651 }
652 }
653
654 debug_assert!(false, "is_part() lied somehow?");
655 None
656 }
657
658 #[inline]
659 pub fn pseudo_element(&self) -> Option<&Impl::PseudoElement> {
660 if !self.has_pseudo_element() {
661 return None;
662 }
663
664 for component in self.iter() {
665 if let Component::PseudoElement(ref pseudo) = *component {
666 return Some(pseudo);
667 }
668 }
669
670 debug_assert!(false, "has_pseudo_element lied!");
671 None
672 }
673
674 #[inline]
678 pub fn is_universal(&self) -> bool {
679 self.iter_raw_match_order().all(|c| {
680 matches!(
681 *c,
682 Component::ExplicitUniversalType
683 | Component::ExplicitAnyNamespace
684 | Component::Combinator(Combinator::PseudoElement)
685 | Component::PseudoElement(..)
686 )
687 })
688 }
689
690 #[inline]
694 pub fn iter(&self) -> SelectorIter<Impl> {
695 SelectorIter {
696 iter: self.iter_raw_match_order(),
697 next_combinator: None,
698 }
699 }
700
701 #[inline]
705 pub fn is_featureless_host_selector_or_pseudo_element(&self) -> bool {
706 let mut iter = self.iter();
707 if !self.has_pseudo_element() {
708 return iter.is_featureless_host_selector();
709 }
710
711 for _ in &mut iter {}
713
714 match iter.next_sequence() {
715 None => return false,
716 Some(combinator) => {
717 debug_assert_eq!(combinator, Combinator::PseudoElement);
718 }
719 }
720
721 iter.is_featureless_host_selector()
722 }
723
724 #[inline]
727 pub fn iter_from(&self, offset: usize) -> SelectorIter<Impl> {
728 let iter = self.0.slice[offset..].iter();
729 SelectorIter {
730 iter,
731 next_combinator: None,
732 }
733 }
734
735 #[inline]
738 pub fn combinator_at_match_order(&self, index: usize) -> Combinator {
739 match self.0.slice[index] {
740 Component::Combinator(c) => c,
741 ref other => panic!(
742 "Not a combinator: {:?}, {:?}, index: {}",
743 other, self, index
744 ),
745 }
746 }
747
748 #[inline]
751 pub fn iter_raw_match_order(&self) -> slice::Iter<Component<Impl>> {
752 self.0.slice.iter()
753 }
754
755 #[inline]
758 pub fn combinator_at_parse_order(&self, index: usize) -> Combinator {
759 match self.0.slice[self.len() - index - 1] {
760 Component::Combinator(c) => c,
761 ref other => panic!(
762 "Not a combinator: {:?}, {:?}, index: {}",
763 other, self, index
764 ),
765 }
766 }
767
768 #[inline]
772 pub fn iter_raw_parse_order_from(
773 &self,
774 offset: usize,
775 ) -> Rev<slice::Iter<Component<Impl>>> {
776 self.0.slice[..self.len() - offset].iter().rev()
777 }
778
779 #[allow(unused)]
781 pub(crate) fn from_vec(
782 vec: Vec<Component<Impl>>,
783 specificity: u32,
784 flags: SelectorFlags,
785 ) -> Self {
786 let mut builder = SelectorBuilder::default();
787 for component in vec.into_iter() {
788 if let Some(combinator) = component.as_combinator() {
789 builder.push_combinator(combinator);
790 } else {
791 builder.push_simple_selector(component);
792 }
793 }
794 let spec = SpecificityAndFlags { specificity, flags };
795 Selector(builder.build_with_specificity_and_flags(spec))
796 }
797
798 #[inline]
800 pub fn len(&self) -> usize {
801 self.0.slice.len()
802 }
803
804 pub fn thin_arc_heap_ptr(&self) -> *const ::std::os::raw::c_void {
806 self.0.heap_ptr()
807 }
808
809 pub fn visit<V>(&self, visitor: &mut V) -> bool
828 where
829 V: SelectorVisitor<Impl = Impl>,
830 {
831 let mut current = self.iter();
832 let mut combinator = None;
833 loop {
834 if !visitor.visit_complex_selector(combinator) {
835 return false;
836 }
837
838 for selector in &mut current {
839 if !selector.visit(visitor) {
840 return false;
841 }
842 }
843
844 combinator = current.next_sequence();
845 if combinator.is_none() {
846 break;
847 }
848 }
849
850 true
851 }
852}
853
854#[derive(Clone)]
855pub struct SelectorIter<'a, Impl: 'a + SelectorImpl> {
856 iter: slice::Iter<'a, Component<Impl>>,
857 next_combinator: Option<Combinator>,
858}
859
860impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
861 #[inline]
864 pub fn next_sequence(&mut self) -> Option<Combinator> {
865 self.next_combinator.take()
866 }
867
868 #[inline]
871 pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
872 self.selector_length() > 0
873 && self.all(|component| matches!(*component, Component::Host(..)))
874 && self.next_sequence().is_none()
875 }
876
877 #[inline]
878 pub(crate) fn matches_for_stateless_pseudo_element(&mut self) -> bool {
879 let first = match self.next() {
880 Some(c) => c,
881 None => return true,
884 };
885 self.matches_for_stateless_pseudo_element_internal(first)
886 }
887
888 #[inline(never)]
889 fn matches_for_stateless_pseudo_element_internal(
890 &mut self,
891 first: &Component<Impl>,
892 ) -> bool {
893 if !first.matches_for_stateless_pseudo_element() {
894 return false;
895 }
896 for component in self {
897 if !component.matches_for_stateless_pseudo_element() {
901 return false;
902 }
903 }
904 true
905 }
906
907 #[inline]
909 pub fn selector_length(&self) -> usize {
910 self.iter.len()
911 }
912}
913
914impl<'a, Impl: SelectorImpl> Iterator for SelectorIter<'a, Impl> {
915 type Item = &'a Component<Impl>;
916
917 #[inline]
918 fn next(&mut self) -> Option<Self::Item> {
919 debug_assert!(
920 self.next_combinator.is_none(),
921 "You should call next_sequence!"
922 );
923 match *self.iter.next()? {
924 Component::Combinator(c) => {
925 self.next_combinator = Some(c);
926 None
927 }
928 ref x => Some(x),
929 }
930 }
931}
932
933impl<'a, Impl: SelectorImpl> fmt::Debug for SelectorIter<'a, Impl> {
934 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
935 let iter = self.iter.clone().rev();
936 for component in iter {
937 component.to_css(f)?
938 }
939 Ok(())
940 }
941}
942
943struct AncestorIter<'a, Impl: 'a + SelectorImpl>(SelectorIter<'a, Impl>);
945impl<'a, Impl: 'a + SelectorImpl> AncestorIter<'a, Impl> {
946 fn new(inner: SelectorIter<'a, Impl>) -> Self {
949 let mut result = AncestorIter(inner);
950 result.skip_until_ancestor();
951 result
952 }
953
954 fn skip_until_ancestor(&mut self) {
957 loop {
958 while self.0.next().is_some() {}
959 if self.0.next_sequence().map_or(true, |x| {
963 matches!(x, Combinator::Child | Combinator::Descendant)
964 }) {
965 break;
966 }
967 }
968 }
969}
970
971impl<'a, Impl: SelectorImpl> Iterator for AncestorIter<'a, Impl> {
972 type Item = &'a Component<Impl>;
973 fn next(&mut self) -> Option<Self::Item> {
974 let next = self.0.next();
976 if next.is_some() {
977 return next;
978 }
979
980 if let Some(combinator) = self.0.next_sequence() {
982 if !matches!(combinator, Combinator::Child | Combinator::Descendant)
983 {
984 self.skip_until_ancestor();
985 }
986 }
987
988 self.0.next()
989 }
990}
991
992#[derive(Clone, Copy, Debug, Eq, PartialEq)]
993pub enum Combinator {
994 Child, Descendant, NextSibling, LaterSibling, PseudoElement,
1005 SlotAssignment,
1008 Part,
1011}
1012
1013impl Combinator {
1014 #[inline]
1016 pub fn is_ancestor(&self) -> bool {
1017 matches!(
1018 *self,
1019 Combinator::Child
1020 | Combinator::Descendant
1021 | Combinator::PseudoElement
1022 | Combinator::SlotAssignment
1023 )
1024 }
1025
1026 #[inline]
1028 pub fn is_pseudo_element(&self) -> bool {
1029 matches!(*self, Combinator::PseudoElement)
1030 }
1031
1032 #[inline]
1034 pub fn is_sibling(&self) -> bool {
1035 matches!(*self, Combinator::NextSibling | Combinator::LaterSibling)
1036 }
1037}
1038
1039#[derive(Clone, Eq, PartialEq)]
1044pub enum Component<Impl: SelectorImpl> {
1045 Combinator(Combinator),
1046
1047 ExplicitAnyNamespace,
1048 ExplicitNoNamespace,
1049 DefaultNamespace(Impl::NamespaceUrl),
1050 Namespace(Impl::NamespacePrefix, Impl::NamespaceUrl),
1051
1052 ExplicitUniversalType,
1053 LocalName(LocalName<Impl>),
1054
1055 ID(Impl::Identifier),
1056 Class(Impl::Identifier),
1057
1058 AttributeInNoNamespaceExists {
1059 local_name: Impl::LocalName,
1060 local_name_lower: Impl::LocalName,
1061 },
1062 AttributeInNoNamespace {
1064 local_name: Impl::LocalName,
1065 operator: AttrSelectorOperator,
1066 value: Impl::AttrValue,
1067 case_sensitivity: ParsedCaseSensitivity,
1068 never_matches: bool,
1069 },
1070 AttributeOther(Box<AttrSelectorWithOptionalNamespace<Impl>>),
1072
1073 Negation(Box<[Selector<Impl>]>),
1075 FirstChild,
1076 LastChild,
1077 OnlyChild,
1078 Root,
1079 Empty,
1080 Scope,
1081 NthChild(i32, i32),
1082 NthLastChild(i32, i32),
1083 NthOfType(i32, i32),
1084 NthLastOfType(i32, i32),
1085 FirstOfType,
1086 LastOfType,
1087 OnlyOfType,
1088 NonTSPseudoClass(Impl::NonTSPseudoClass),
1089 Slotted(Selector<Impl>),
1101 Part(Box<[Impl::Identifier]>),
1104 Host(Option<Selector<Impl>>),
1114 Where(Box<[Selector<Impl>]>),
1121 Is(Box<[Selector<Impl>]>),
1127 PseudoElement(Impl::PseudoElement),
1129}
1130
1131impl<Impl: SelectorImpl> Component<Impl> {
1132 pub fn is_combinator(&self) -> bool {
1134 matches!(*self, Component::Combinator(_))
1135 }
1136
1137 pub fn as_combinator(&self) -> Option<Combinator> {
1139 match *self {
1140 Component::Combinator(c) => Some(c),
1141 _ => None,
1142 }
1143 }
1144
1145 pub fn maybe_allowed_after_pseudo_element(&self) -> bool {
1148 match *self {
1149 Component::NonTSPseudoClass(..) => true,
1150 Component::Negation(ref selectors)
1151 | Component::Is(ref selectors)
1152 | Component::Where(ref selectors) => {
1153 selectors.iter().all(|selector| {
1154 selector
1155 .iter_raw_match_order()
1156 .all(|c| c.maybe_allowed_after_pseudo_element())
1157 })
1158 }
1159 _ => false,
1160 }
1161 }
1162
1163 fn matches_for_stateless_pseudo_element(&self) -> bool {
1170 debug_assert!(
1171 self.maybe_allowed_after_pseudo_element(),
1172 "Someone messed up pseudo-element parsing: {:?}",
1173 *self
1174 );
1175 match *self {
1176 Component::Negation(ref selectors) => {
1177 !selectors.iter().all(|selector| {
1178 selector
1179 .iter_raw_match_order()
1180 .all(|c| c.matches_for_stateless_pseudo_element())
1181 })
1182 }
1183 Component::Is(ref selectors) | Component::Where(ref selectors) => {
1184 selectors.iter().any(|selector| {
1185 selector
1186 .iter_raw_match_order()
1187 .all(|c| c.matches_for_stateless_pseudo_element())
1188 })
1189 }
1190 _ => false,
1191 }
1192 }
1193
1194 pub fn visit<V>(&self, visitor: &mut V) -> bool
1195 where
1196 V: SelectorVisitor<Impl = Impl>,
1197 {
1198 use self::Component::*;
1199 if !visitor.visit_simple_selector(self) {
1200 return false;
1201 }
1202
1203 match *self {
1204 Slotted(ref selector) => {
1205 if !selector.visit(visitor) {
1206 return false;
1207 }
1208 }
1209 Host(Some(ref selector)) => {
1210 if !selector.visit(visitor) {
1211 return false;
1212 }
1213 }
1214 AttributeInNoNamespaceExists {
1215 ref local_name,
1216 ref local_name_lower,
1217 } => {
1218 if !visitor.visit_attribute_selector(
1219 &NamespaceConstraint::Specific(&namespace_empty_string::<
1220 Impl,
1221 >()),
1222 local_name,
1223 local_name_lower,
1224 ) {
1225 return false;
1226 }
1227 }
1228 AttributeInNoNamespace {
1229 ref local_name,
1230 never_matches,
1231 ..
1232 } if !never_matches => {
1233 if !visitor.visit_attribute_selector(
1234 &NamespaceConstraint::Specific(&namespace_empty_string::<
1235 Impl,
1236 >()),
1237 local_name,
1238 local_name,
1239 ) {
1240 return false;
1241 }
1242 }
1243 AttributeOther(ref attr_selector)
1244 if !attr_selector.never_matches =>
1245 {
1246 let empty_string;
1247 let namespace = match attr_selector.namespace() {
1248 Some(ns) => ns,
1249 None => {
1250 empty_string =
1251 crate::parser::namespace_empty_string::<Impl>();
1252 NamespaceConstraint::Specific(&empty_string)
1253 }
1254 };
1255 if !visitor.visit_attribute_selector(
1256 &namespace,
1257 &attr_selector.local_name,
1258 &attr_selector.local_name_lower,
1259 ) {
1260 return false;
1261 }
1262 }
1263
1264 NonTSPseudoClass(ref pseudo_class) => {
1265 if !pseudo_class.visit(visitor) {
1266 return false;
1267 }
1268 }
1269
1270 Negation(ref list) | Is(ref list) | Where(ref list) => {
1271 if !visitor.visit_selector_list(&list) {
1272 return false;
1273 }
1274 }
1275 _ => {}
1276 }
1277
1278 true
1279 }
1280}
1281
1282#[derive(Clone, Eq, PartialEq)]
1283pub struct LocalName<Impl: SelectorImpl> {
1284 pub name: Impl::LocalName,
1285 pub lower_name: Impl::LocalName,
1286}
1287
1288impl<Impl: SelectorImpl> Debug for Selector<Impl> {
1289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1290 f.write_str("Selector(")?;
1291 self.to_css(f)?;
1292 write!(f, ", specificity = 0x{:x})", self.specificity())
1293 }
1294}
1295
1296impl<Impl: SelectorImpl> Debug for Component<Impl> {
1297 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1298 self.to_css(f)
1299 }
1300}
1301impl<Impl: SelectorImpl> Debug for AttrSelectorWithOptionalNamespace<Impl> {
1302 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1303 self.to_css(f)
1304 }
1305}
1306impl<Impl: SelectorImpl> Debug for LocalName<Impl> {
1307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1308 self.to_css(f)
1309 }
1310}
1311
1312fn serialize_selector_list<'a, Impl, I, W>(iter: I, dest: &mut W) -> fmt::Result
1313where
1314 Impl: SelectorImpl,
1315 I: Iterator<Item = &'a Selector<Impl>>,
1316 W: fmt::Write,
1317{
1318 let mut first = true;
1319 for selector in iter {
1320 if !first {
1321 dest.write_str(", ")?;
1322 }
1323 first = false;
1324 selector.to_css(dest)?;
1325 }
1326 Ok(())
1327}
1328
1329impl<Impl: SelectorImpl> ToCss for SelectorList<Impl> {
1330 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1331 where
1332 W: fmt::Write,
1333 {
1334 serialize_selector_list(self.0.iter(), dest)
1335 }
1336}
1337
1338impl<Impl: SelectorImpl> ToCss for Selector<Impl> {
1339 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1340 where
1341 W: fmt::Write,
1342 {
1343 let mut combinators = self
1356 .iter_raw_match_order()
1357 .rev()
1358 .filter_map(|x| x.as_combinator());
1359 let compound_selectors = self
1360 .iter_raw_match_order()
1361 .as_slice()
1362 .split(|x| x.is_combinator())
1363 .rev();
1364
1365 let mut combinators_exhausted = false;
1366 for compound in compound_selectors {
1367 debug_assert!(!combinators_exhausted);
1368
1369 if compound.is_empty() {
1371 continue;
1372 }
1373
1374 let (can_elide_namespace, first_non_namespace) = match compound[0] {
1385 Component::ExplicitAnyNamespace
1386 | Component::ExplicitNoNamespace
1387 | Component::Namespace(..) => (false, 1),
1388 Component::DefaultNamespace(..) => (true, 1),
1389 _ => (true, 0),
1390 };
1391 let mut perform_step_2 = true;
1392 let next_combinator = combinators.next();
1393 if first_non_namespace == compound.len() - 1 {
1394 match (next_combinator, &compound[first_non_namespace]) {
1395 (Some(Combinator::PseudoElement), _)
1403 | (Some(Combinator::SlotAssignment), _) => (),
1404 (_, &Component::ExplicitUniversalType) => {
1405 for simple in compound.iter() {
1408 simple.to_css(dest)?;
1409 }
1410 perform_step_2 = false;
1412 }
1413 _ => (),
1414 }
1415 }
1416
1417 if perform_step_2 {
1427 for simple in compound.iter() {
1428 if let Component::ExplicitUniversalType = *simple {
1429 if can_elide_namespace {
1434 continue;
1435 }
1436 }
1437 simple.to_css(dest)?;
1438 }
1439 }
1440
1441 match next_combinator {
1447 Some(c) => c.to_css(dest)?,
1448 None => combinators_exhausted = true,
1449 };
1450
1451 }
1457
1458 Ok(())
1459 }
1460}
1461
1462impl ToCss for Combinator {
1463 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1464 where
1465 W: fmt::Write,
1466 {
1467 match *self {
1468 Combinator::Child => dest.write_str(" > "),
1469 Combinator::Descendant => dest.write_str(" "),
1470 Combinator::NextSibling => dest.write_str(" + "),
1471 Combinator::LaterSibling => dest.write_str(" ~ "),
1472 Combinator::PseudoElement
1473 | Combinator::Part
1474 | Combinator::SlotAssignment => Ok(()),
1475 }
1476 }
1477}
1478
1479impl<Impl: SelectorImpl> ToCss for Component<Impl> {
1480 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1481 where
1482 W: fmt::Write,
1483 {
1484 use self::Component::*;
1485
1486 fn write_affine<W>(dest: &mut W, a: i32, b: i32) -> fmt::Result
1489 where
1490 W: fmt::Write,
1491 {
1492 match (a, b) {
1493 (0, 0) => dest.write_char('0'),
1494
1495 (1, 0) => dest.write_char('n'),
1496 (-1, 0) => dest.write_str("-n"),
1497 (_, 0) => write!(dest, "{}n", a),
1498
1499 (0, _) => write!(dest, "{}", b),
1500 (1, _) => write!(dest, "n{:+}", b),
1501 (-1, _) => write!(dest, "-n{:+}", b),
1502 (_, _) => write!(dest, "{}n{:+}", a, b),
1503 }
1504 }
1505
1506 match *self {
1507 Combinator(ref c) => c.to_css(dest),
1508 Slotted(ref selector) => {
1509 dest.write_str("::slotted(")?;
1510 selector.to_css(dest)?;
1511 dest.write_char(')')
1512 }
1513 Part(ref part_names) => {
1514 dest.write_str("::part(")?;
1515 for (i, name) in part_names.iter().enumerate() {
1516 if i != 0 {
1517 dest.write_char(' ')?;
1518 }
1519 name.to_css(dest)?;
1520 }
1521 dest.write_char(')')
1522 }
1523 PseudoElement(ref p) => p.to_css(dest),
1524 ID(ref s) => {
1525 dest.write_char('#')?;
1526 s.to_css(dest)
1527 }
1528 Class(ref s) => {
1529 dest.write_char('.')?;
1530 s.to_css(dest)
1531 }
1532 LocalName(ref s) => s.to_css(dest),
1533 ExplicitUniversalType => dest.write_char('*'),
1534
1535 DefaultNamespace(_) => Ok(()),
1536 ExplicitNoNamespace => dest.write_char('|'),
1537 ExplicitAnyNamespace => dest.write_str("*|"),
1538 Namespace(ref prefix, _) => {
1539 prefix.to_css(dest)?;
1540 dest.write_char('|')
1541 }
1542
1543 AttributeInNoNamespaceExists { ref local_name, .. } => {
1544 dest.write_char('[')?;
1545 local_name.to_css(dest)?;
1546 dest.write_char(']')
1547 }
1548 AttributeInNoNamespace {
1549 ref local_name,
1550 operator,
1551 ref value,
1552 case_sensitivity,
1553 ..
1554 } => {
1555 dest.write_char('[')?;
1556 local_name.to_css(dest)?;
1557 operator.to_css(dest)?;
1558 dest.write_char('"')?;
1559 value.to_css(dest)?;
1560 dest.write_char('"')?;
1561 match case_sensitivity {
1562 ParsedCaseSensitivity::CaseSensitive |
1563 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
1564 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
1565 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
1566 }
1567 dest.write_char(']')
1568 }
1569 AttributeOther(ref attr_selector) => attr_selector.to_css(dest),
1570
1571 FirstChild => dest.write_str(":first-child"),
1573 LastChild => dest.write_str(":last-child"),
1574 OnlyChild => dest.write_str(":only-child"),
1575 Root => dest.write_str(":root"),
1576 Empty => dest.write_str(":empty"),
1577 Scope => dest.write_str(":scope"),
1578 Host(ref selector) => {
1579 dest.write_str(":host")?;
1580 if let Some(ref selector) = *selector {
1581 dest.write_char('(')?;
1582 selector.to_css(dest)?;
1583 dest.write_char(')')?;
1584 }
1585 Ok(())
1586 }
1587 FirstOfType => dest.write_str(":first-of-type"),
1588 LastOfType => dest.write_str(":last-of-type"),
1589 OnlyOfType => dest.write_str(":only-of-type"),
1590 NthChild(a, b)
1591 | NthLastChild(a, b)
1592 | NthOfType(a, b)
1593 | NthLastOfType(a, b) => {
1594 match *self {
1595 NthChild(_, _) => dest.write_str(":nth-child(")?,
1596 NthLastChild(_, _) => dest.write_str(":nth-last-child(")?,
1597 NthOfType(_, _) => dest.write_str(":nth-of-type(")?,
1598 NthLastOfType(_, _) => {
1599 dest.write_str(":nth-last-of-type(")?
1600 }
1601 _ => unreachable!(),
1602 }
1603 write_affine(dest, a, b)?;
1604 dest.write_char(')')
1605 }
1606 Is(ref list) | Where(ref list) | Negation(ref list) => {
1607 match *self {
1608 Where(..) => dest.write_str(":where(")?,
1609 Is(..) => dest.write_str(":is(")?,
1610 Negation(..) => dest.write_str(":not(")?,
1611 _ => unreachable!(),
1612 }
1613 serialize_selector_list(list.iter(), dest)?;
1614 dest.write_str(")")
1615 }
1616 NonTSPseudoClass(ref pseudo) => pseudo.to_css(dest),
1617 }
1618 }
1619}
1620
1621impl<Impl: SelectorImpl> ToCss for AttrSelectorWithOptionalNamespace<Impl> {
1622 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1623 where
1624 W: fmt::Write,
1625 {
1626 dest.write_char('[')?;
1627 match self.namespace {
1628 Some(NamespaceConstraint::Specific((ref prefix, _))) => {
1629 prefix.to_css(dest)?;
1630 dest.write_char('|')?
1631 }
1632 Some(NamespaceConstraint::Any) => dest.write_str("*|")?,
1633 None => {}
1634 }
1635 self.local_name.to_css(dest)?;
1636 match self.operation {
1637 ParsedAttrSelectorOperation::Exists => {}
1638 ParsedAttrSelectorOperation::WithValue {
1639 operator,
1640 case_sensitivity,
1641 ref expected_value,
1642 } => {
1643 operator.to_css(dest)?;
1644 dest.write_char('"')?;
1645 expected_value.to_css(dest)?;
1646 dest.write_char('"')?;
1647 match case_sensitivity {
1648 ParsedCaseSensitivity::CaseSensitive |
1649 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {},
1650 ParsedCaseSensitivity::AsciiCaseInsensitive => dest.write_str(" i")?,
1651 ParsedCaseSensitivity::ExplicitCaseSensitive => dest.write_str(" s")?,
1652 }
1653 }
1654 }
1655 dest.write_char(']')
1656 }
1657}
1658
1659impl<Impl: SelectorImpl> ToCss for LocalName<Impl> {
1660 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
1661 where
1662 W: fmt::Write,
1663 {
1664 self.name.to_css(dest)
1665 }
1666}
1667
1668fn parse_selector<'i, 't, P, Impl>(
1673 parser: &P,
1674 input: &mut CssParser<'i, 't>,
1675 mut state: SelectorParsingState,
1676) -> Result<Selector<Impl>, ParseError<'i, P::Error>>
1677where
1678 P: Parser<'i, Impl = Impl>,
1679 Impl: SelectorImpl,
1680{
1681 let mut builder = SelectorBuilder::default();
1682
1683 let mut has_pseudo_element = false;
1684 let mut slotted = false;
1685 let mut part = false;
1686 'outer_loop: loop {
1687 let empty =
1689 parse_compound_selector(parser, &mut state, input, &mut builder)?;
1690 if empty {
1691 return Err(input.new_custom_error(if builder.has_combinators() {
1692 SelectorParseErrorKind::DanglingCombinator
1693 } else {
1694 SelectorParseErrorKind::EmptySelector
1695 }));
1696 }
1697
1698 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
1699 has_pseudo_element =
1700 state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
1701 slotted = state.intersects(SelectorParsingState::AFTER_SLOTTED);
1702 part = state.intersects(SelectorParsingState::AFTER_PART);
1703 debug_assert!(has_pseudo_element || slotted || part);
1704 break;
1705 }
1706
1707 let combinator;
1709 let mut any_whitespace = false;
1710 loop {
1711 let before_this_token = input.state();
1712 match input.next_including_whitespace() {
1713 Err(_e) => break 'outer_loop,
1714 Ok(&Token::WhiteSpace(_)) => any_whitespace = true,
1715 Ok(&Token::Delim('>')) => {
1716 combinator = Combinator::Child;
1717 break;
1718 }
1719 Ok(&Token::Delim('+')) => {
1720 combinator = Combinator::NextSibling;
1721 break;
1722 }
1723 Ok(&Token::Delim('~')) => {
1724 combinator = Combinator::LaterSibling;
1725 break;
1726 }
1727 Ok(_) => {
1728 input.reset(&before_this_token);
1729 if any_whitespace {
1730 combinator = Combinator::Descendant;
1731 break;
1732 } else {
1733 break 'outer_loop;
1734 }
1735 }
1736 }
1737 }
1738
1739 if !state.allows_combinators() {
1740 return Err(
1741 input.new_custom_error(SelectorParseErrorKind::InvalidState)
1742 );
1743 }
1744
1745 builder.push_combinator(combinator);
1746 }
1747
1748 Ok(Selector(builder.build(has_pseudo_element, slotted, part)))
1749}
1750
1751impl<Impl: SelectorImpl> Selector<Impl> {
1752 #[inline]
1754 pub fn parse<'i, 't, P>(
1755 parser: &P,
1756 input: &mut CssParser<'i, 't>,
1757 ) -> Result<Self, ParseError<'i, P::Error>>
1758 where
1759 P: Parser<'i, Impl = Impl>,
1760 {
1761 parse_selector(parser, input, SelectorParsingState::empty())
1762 }
1763}
1764
1765fn parse_type_selector<'i, 't, P, Impl, S>(
1769 parser: &P,
1770 input: &mut CssParser<'i, 't>,
1771 state: SelectorParsingState,
1772 sink: &mut S,
1773) -> Result<bool, ParseError<'i, P::Error>>
1774where
1775 P: Parser<'i, Impl = Impl>,
1776 Impl: SelectorImpl,
1777 S: Push<Component<Impl>>,
1778{
1779 match parse_qualified_name(
1780 parser, input, false,
1781 ) {
1782 Err(ParseError {
1783 kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput),
1784 ..
1785 })
1786 | Ok(OptionalQName::None(_)) => Ok(false),
1787 Ok(OptionalQName::Some(namespace, local_name)) => {
1788 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
1789 return Err(input
1790 .new_custom_error(SelectorParseErrorKind::InvalidState));
1791 }
1792 match namespace {
1793 QNamePrefix::ImplicitAnyNamespace => {}
1794 QNamePrefix::ImplicitDefaultNamespace(url) => {
1795 sink.push(Component::DefaultNamespace(url))
1796 }
1797 QNamePrefix::ExplicitNamespace(prefix, url) => {
1798 sink.push(match parser.default_namespace() {
1799 Some(ref default_url) if url == *default_url => {
1800 Component::DefaultNamespace(url)
1801 }
1802 _ => Component::Namespace(prefix, url),
1803 })
1804 }
1805 QNamePrefix::ExplicitNoNamespace => {
1806 sink.push(Component::ExplicitNoNamespace)
1807 }
1808 QNamePrefix::ExplicitAnyNamespace => {
1809 match parser.default_namespace() {
1810 None => {}
1822 Some(_) => sink.push(Component::ExplicitAnyNamespace),
1823 }
1824 }
1825 QNamePrefix::ImplicitNoNamespace => {
1826 unreachable!() }
1828 }
1829 match local_name {
1830 Some(name) => sink.push(Component::LocalName(LocalName {
1831 lower_name: to_ascii_lowercase(&name).as_ref().into(),
1832 name: name.as_ref().into(),
1833 })),
1834 None => sink.push(Component::ExplicitUniversalType),
1835 }
1836 Ok(true)
1837 }
1838 Err(e) => Err(e),
1839 }
1840}
1841
1842#[derive(Debug)]
1843enum SimpleSelectorParseResult<Impl: SelectorImpl> {
1844 SimpleSelector(Component<Impl>),
1845 PseudoElement(Impl::PseudoElement),
1846 SlottedPseudo(Selector<Impl>),
1847 PartPseudo(Box<[Impl::Identifier]>),
1848}
1849
1850#[derive(Debug)]
1851enum QNamePrefix<Impl: SelectorImpl> {
1852 ImplicitNoNamespace, ImplicitAnyNamespace, ImplicitDefaultNamespace(Impl::NamespaceUrl), ExplicitNoNamespace, ExplicitAnyNamespace, ExplicitNamespace(Impl::NamespacePrefix, Impl::NamespaceUrl), }
1859
1860enum OptionalQName<'i, Impl: SelectorImpl> {
1861 Some(QNamePrefix<Impl>, Option<CowRcStr<'i>>),
1862 None(Token<'i>),
1863}
1864
1865fn parse_qualified_name<'i, 't, P, Impl>(
1870 parser: &P,
1871 input: &mut CssParser<'i, 't>,
1872 in_attr_selector: bool,
1873) -> Result<OptionalQName<'i, Impl>, ParseError<'i, P::Error>>
1874where
1875 P: Parser<'i, Impl = Impl>,
1876 Impl: SelectorImpl,
1877{
1878 let default_namespace = |local_name| {
1879 let namespace = match parser.default_namespace() {
1880 Some(url) => QNamePrefix::ImplicitDefaultNamespace(url),
1881 None => QNamePrefix::ImplicitAnyNamespace,
1882 };
1883 Ok(OptionalQName::Some(namespace, local_name))
1884 };
1885
1886 let explicit_namespace = |input: &mut CssParser<'i, 't>, namespace| {
1887 let location = input.current_source_location();
1888 match input.next_including_whitespace() {
1889 Ok(&Token::Delim('*')) if !in_attr_selector => {
1890 Ok(OptionalQName::Some(namespace, None))
1891 }
1892 Ok(&Token::Ident(ref local_name)) => {
1893 Ok(OptionalQName::Some(namespace, Some(local_name.clone())))
1894 }
1895 Ok(t) if in_attr_selector => {
1896 let e =
1897 SelectorParseErrorKind::InvalidQualNameInAttr(t.clone());
1898 Err(location.new_custom_error(e))
1899 }
1900 Ok(t) => Err(location.new_custom_error(
1901 SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(
1902 t.clone(),
1903 ),
1904 )),
1905 Err(e) => Err(e.into()),
1906 }
1907 };
1908
1909 let start = input.state();
1910 match input.next_including_whitespace().map(|t| t.clone()) {
1912 Ok(Token::Ident(value)) => {
1913 let after_ident = input.state();
1914 match input.next_including_whitespace() {
1915 Ok(&Token::Delim('|')) => {
1916 let prefix = value.as_ref().into();
1917 let result = parser.namespace_for_prefix(&prefix);
1918 let url = result.ok_or(
1919 after_ident.source_location().new_custom_error(
1920 SelectorParseErrorKind::ExpectedNamespace(value),
1921 ),
1922 )?;
1923 explicit_namespace(
1924 input,
1925 QNamePrefix::ExplicitNamespace(prefix, url),
1926 )
1927 }
1928 _ => {
1929 input.reset(&after_ident);
1930 if in_attr_selector {
1931 Ok(OptionalQName::Some(
1932 QNamePrefix::ImplicitNoNamespace,
1933 Some(value),
1934 ))
1935 } else {
1936 default_namespace(Some(value))
1937 }
1938 }
1939 }
1940 }
1941 Ok(Token::Delim('*')) => {
1942 let after_star = input.state();
1943 match input.next_including_whitespace().map(|t| t.clone()) {
1945 Ok(Token::Delim('|')) => {
1946 explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace)
1947 }
1948 result => {
1949 input.reset(&after_star);
1950 if in_attr_selector {
1951 match result {
1952 Ok(t) => Err(after_star
1953 .source_location()
1954 .new_custom_error(
1955 SelectorParseErrorKind::ExpectedBarInAttr(
1956 t,
1957 ),
1958 )),
1959 Err(e) => Err(e.into()),
1960 }
1961 } else {
1962 default_namespace(None)
1963 }
1964 }
1965 }
1966 }
1967 Ok(Token::Delim('|')) => {
1968 explicit_namespace(input, QNamePrefix::ExplicitNoNamespace)
1969 }
1970 Ok(t) => {
1971 input.reset(&start);
1972 Ok(OptionalQName::None(t))
1973 }
1974 Err(e) => {
1975 input.reset(&start);
1976 Err(e.into())
1977 }
1978 }
1979}
1980
1981fn parse_attribute_selector<'i, 't, P, Impl>(
1982 parser: &P,
1983 input: &mut CssParser<'i, 't>,
1984) -> Result<Component<Impl>, ParseError<'i, P::Error>>
1985where
1986 P: Parser<'i, Impl = Impl>,
1987 Impl: SelectorImpl,
1988{
1989 let namespace;
1990 let local_name;
1991
1992 input.skip_whitespace();
1993
1994 match parse_qualified_name(
1995 parser, input, true,
1996 )? {
1997 OptionalQName::None(t) => {
1998 return Err(input.new_custom_error(
1999 SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t),
2000 ));
2001 }
2002 OptionalQName::Some(_, None) => unreachable!(),
2003 OptionalQName::Some(ns, Some(ln)) => {
2004 local_name = ln;
2005 namespace = match ns {
2006 QNamePrefix::ImplicitNoNamespace
2007 | QNamePrefix::ExplicitNoNamespace => None,
2008 QNamePrefix::ExplicitNamespace(prefix, url) => {
2009 Some(NamespaceConstraint::Specific((prefix, url)))
2010 }
2011 QNamePrefix::ExplicitAnyNamespace => {
2012 Some(NamespaceConstraint::Any)
2013 }
2014 QNamePrefix::ImplicitAnyNamespace
2015 | QNamePrefix::ImplicitDefaultNamespace(_) => {
2016 unreachable!() }
2018 }
2019 }
2020 }
2021
2022 let location = input.current_source_location();
2023 let operator = match input.next() {
2024 Err(_) => {
2026 let local_name_lower =
2027 to_ascii_lowercase(&local_name).as_ref().into();
2028 let local_name = local_name.as_ref().into();
2029 if let Some(namespace) = namespace {
2030 return Ok(Component::AttributeOther(Box::new(
2031 AttrSelectorWithOptionalNamespace {
2032 namespace: Some(namespace),
2033 local_name,
2034 local_name_lower,
2035 operation: ParsedAttrSelectorOperation::Exists,
2036 never_matches: false,
2037 },
2038 )));
2039 } else {
2040 return Ok(Component::AttributeInNoNamespaceExists {
2041 local_name,
2042 local_name_lower,
2043 });
2044 }
2045 }
2046
2047 Ok(&Token::Delim('=')) => AttrSelectorOperator::Equal,
2049 Ok(&Token::IncludeMatch) => AttrSelectorOperator::Includes,
2051 Ok(&Token::DashMatch) => AttrSelectorOperator::DashMatch,
2053 Ok(&Token::PrefixMatch) => AttrSelectorOperator::Prefix,
2055 Ok(&Token::SubstringMatch) => AttrSelectorOperator::Substring,
2057 Ok(&Token::SuffixMatch) => AttrSelectorOperator::Suffix,
2059 Ok(t) => {
2060 return Err(location.new_custom_error(
2061 SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(
2062 t.clone(),
2063 ),
2064 ));
2065 }
2066 };
2067
2068 let value = match input.expect_ident_or_string() {
2069 Ok(t) => t.clone(),
2070 Err(BasicParseError {
2071 kind: BasicParseErrorKind::UnexpectedToken(t),
2072 location,
2073 }) => {
2074 return Err(location
2075 .new_custom_error(SelectorParseErrorKind::BadValueInAttr(t)))
2076 }
2077 Err(e) => return Err(e.into()),
2078 };
2079 let never_matches = match operator {
2080 AttrSelectorOperator::Equal | AttrSelectorOperator::DashMatch => false,
2081
2082 AttrSelectorOperator::Includes => {
2083 value.is_empty() || value.contains(SELECTOR_WHITESPACE)
2084 }
2085
2086 AttrSelectorOperator::Prefix
2087 | AttrSelectorOperator::Substring
2088 | AttrSelectorOperator::Suffix => value.is_empty(),
2089 };
2090
2091 let attribute_flags = parse_attribute_flags(input)?;
2092
2093 let value = value.as_ref().into();
2094 let local_name_lower;
2095 let local_name_is_ascii_lowercase;
2096 let case_sensitivity;
2097 {
2098 let local_name_lower_cow = to_ascii_lowercase(&local_name);
2099 case_sensitivity = attribute_flags.to_case_sensitivity(
2100 local_name_lower_cow.as_ref(),
2101 namespace.is_some(),
2102 );
2103 local_name_lower = local_name_lower_cow.as_ref().into();
2104 local_name_is_ascii_lowercase =
2105 matches!(local_name_lower_cow, Cow::Borrowed(..));
2106 }
2107 let local_name = local_name.as_ref().into();
2108 if namespace.is_some() || !local_name_is_ascii_lowercase {
2109 Ok(Component::AttributeOther(Box::new(
2110 AttrSelectorWithOptionalNamespace {
2111 namespace,
2112 local_name,
2113 local_name_lower,
2114 never_matches,
2115 operation: ParsedAttrSelectorOperation::WithValue {
2116 operator,
2117 case_sensitivity,
2118 expected_value: value,
2119 },
2120 },
2121 )))
2122 } else {
2123 Ok(Component::AttributeInNoNamespace {
2124 local_name,
2125 operator,
2126 value,
2127 case_sensitivity,
2128 never_matches,
2129 })
2130 }
2131}
2132
2133enum AttributeFlags {
2135 CaseSensitive,
2137 AsciiCaseInsensitive,
2139 CaseSensitivityDependsOnName,
2141}
2142
2143impl AttributeFlags {
2144 fn to_case_sensitivity(
2145 self,
2146 local_name: &str,
2147 have_namespace: bool,
2148 ) -> ParsedCaseSensitivity {
2149 match self {
2150 AttributeFlags::CaseSensitive => {
2151 ParsedCaseSensitivity::ExplicitCaseSensitive
2152 }
2153 AttributeFlags::AsciiCaseInsensitive => {
2154 ParsedCaseSensitivity::AsciiCaseInsensitive
2155 }
2156 AttributeFlags::CaseSensitivityDependsOnName => {
2157 if !have_namespace
2158 && include!(concat!(
2159 env!("OUT_DIR"),
2160 "/ascii_case_insensitive_html_attributes.rs"
2161 ))
2162 .contains(local_name)
2163 {
2164 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument
2165 } else {
2166 ParsedCaseSensitivity::CaseSensitive
2167 }
2168 }
2169 }
2170 }
2171}
2172
2173fn parse_attribute_flags<'i, 't>(
2174 input: &mut CssParser<'i, 't>,
2175) -> Result<AttributeFlags, BasicParseError<'i>> {
2176 let location = input.current_source_location();
2177 let token = match input.next() {
2178 Ok(t) => t,
2179 Err(..) => {
2180 return Ok(AttributeFlags::CaseSensitivityDependsOnName);
2183 }
2184 };
2185
2186 let ident = match *token {
2187 Token::Ident(ref i) => i,
2188 ref other => {
2189 return Err(location.new_basic_unexpected_token_error(other.clone()))
2190 }
2191 };
2192
2193 Ok(match_ignore_ascii_case! {
2194 ident,
2195 "i" => AttributeFlags::AsciiCaseInsensitive,
2196 "s" => AttributeFlags::CaseSensitive,
2197 _ => return Err(location.new_basic_unexpected_token_error(token.clone())),
2198 })
2199}
2200
2201fn parse_negation<'i, 't, P, Impl>(
2204 parser: &P,
2205 input: &mut CssParser<'i, 't>,
2206 state: SelectorParsingState,
2207) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2208where
2209 P: Parser<'i, Impl = Impl>,
2210 Impl: SelectorImpl,
2211{
2212 let list = SelectorList::parse_with_state(
2213 parser,
2214 input,
2215 state
2216 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
2217 | SelectorParsingState::DISALLOW_PSEUDOS,
2218 ParseErrorRecovery::DiscardList,
2219 )?;
2220
2221 Ok(Component::Negation(list.0.into_vec().into_boxed_slice()))
2222}
2223
2224fn parse_compound_selector<'i, 't, P, Impl>(
2231 parser: &P,
2232 state: &mut SelectorParsingState,
2233 input: &mut CssParser<'i, 't>,
2234 builder: &mut SelectorBuilder<Impl>,
2235) -> Result<bool, ParseError<'i, P::Error>>
2236where
2237 P: Parser<'i, Impl = Impl>,
2238 Impl: SelectorImpl,
2239{
2240 input.skip_whitespace();
2241
2242 let mut empty = true;
2243 if parse_type_selector(parser, input, *state, builder)? {
2244 empty = false;
2245 }
2246
2247 loop {
2248 let result = match parse_one_simple_selector(parser, input, *state)? {
2249 None => break,
2250 Some(result) => result,
2251 };
2252
2253 if empty {
2254 if let Some(url) = parser.default_namespace() {
2255 let ignore_default_ns = state
2283 .intersects(SelectorParsingState::SKIP_DEFAULT_NAMESPACE)
2284 || matches!(
2285 result,
2286 SimpleSelectorParseResult::SimpleSelector(
2287 Component::Host(..)
2288 )
2289 );
2290 if !ignore_default_ns {
2291 builder
2292 .push_simple_selector(Component::DefaultNamespace(url));
2293 }
2294 }
2295 }
2296
2297 empty = false;
2298
2299 match result {
2300 SimpleSelectorParseResult::SimpleSelector(s) => {
2301 builder.push_simple_selector(s);
2302 }
2303 SimpleSelectorParseResult::PartPseudo(part_names) => {
2304 state.insert(SelectorParsingState::AFTER_PART);
2305 builder.push_combinator(Combinator::Part);
2306 builder.push_simple_selector(Component::Part(part_names));
2307 }
2308 SimpleSelectorParseResult::SlottedPseudo(selector) => {
2309 state.insert(SelectorParsingState::AFTER_SLOTTED);
2310 builder.push_combinator(Combinator::SlotAssignment);
2311 builder.push_simple_selector(Component::Slotted(selector));
2312 }
2313 SimpleSelectorParseResult::PseudoElement(p) => {
2314 state.insert(SelectorParsingState::AFTER_PSEUDO_ELEMENT);
2315 if !p.accepts_state_pseudo_classes() {
2316 state.insert(
2317 SelectorParsingState::AFTER_NON_STATEFUL_PSEUDO_ELEMENT,
2318 );
2319 }
2320 builder.push_combinator(Combinator::PseudoElement);
2321 builder.push_simple_selector(Component::PseudoElement(p));
2322 }
2323 }
2324 }
2325 Ok(empty)
2326}
2327
2328fn parse_is_or_where<'i, 't, P, Impl>(
2329 parser: &P,
2330 input: &mut CssParser<'i, 't>,
2331 state: SelectorParsingState,
2332 component: impl FnOnce(Box<[Selector<Impl>]>) -> Component<Impl>,
2333) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2334where
2335 P: Parser<'i, Impl = Impl>,
2336 Impl: SelectorImpl,
2337{
2338 debug_assert!(parser.parse_is_and_where());
2339 let inner = SelectorList::parse_with_state(
2345 parser,
2346 input,
2347 state
2348 | SelectorParsingState::SKIP_DEFAULT_NAMESPACE
2349 | SelectorParsingState::DISALLOW_PSEUDOS,
2350 parser.is_and_where_error_recovery(),
2351 )?;
2352 Ok(component(inner.0.into_vec().into_boxed_slice()))
2353}
2354
2355fn parse_functional_pseudo_class<'i, 't, P, Impl>(
2356 parser: &P,
2357 input: &mut CssParser<'i, 't>,
2358 name: CowRcStr<'i>,
2359 state: SelectorParsingState,
2360) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2361where
2362 P: Parser<'i, Impl = Impl>,
2363 Impl: SelectorImpl,
2364{
2365 match_ignore_ascii_case! { &name,
2366 "nth-child" => return parse_nth_pseudo_class(parser, input, state, Component::NthChild),
2367 "nth-of-type" => return parse_nth_pseudo_class(parser, input, state, Component::NthOfType),
2368 "nth-last-child" => return parse_nth_pseudo_class(parser, input, state, Component::NthLastChild),
2369 "nth-last-of-type" => return parse_nth_pseudo_class(parser, input, state, Component::NthLastOfType),
2370 "is" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Is),
2371 "where" if parser.parse_is_and_where() => return parse_is_or_where(parser, input, state, Component::Where),
2372 "host" => {
2373 if !state.allows_tree_structural_pseudo_classes() {
2374 return Err(input.new_custom_error(SelectorParseErrorKind::InvalidState));
2375 }
2376 return Ok(Component::Host(Some(parse_inner_compound_selector(parser, input, state)?)));
2377 },
2378 "not" => {
2379 return parse_negation(parser, input, state)
2380 },
2381 _ => {}
2382 }
2383
2384 if parser.parse_is_and_where() && parser.is_is_alias(&name) {
2385 return parse_is_or_where(parser, input, state, Component::Is);
2386 }
2387
2388 if !state.allows_custom_functional_pseudo_classes() {
2389 return Err(
2390 input.new_custom_error(SelectorParseErrorKind::InvalidState)
2391 );
2392 }
2393
2394 P::parse_non_ts_functional_pseudo_class(parser, name, input)
2395 .map(Component::NonTSPseudoClass)
2396}
2397
2398fn parse_nth_pseudo_class<'i, 't, P, Impl, F>(
2399 _: &P,
2400 input: &mut CssParser<'i, 't>,
2401 state: SelectorParsingState,
2402 selector: F,
2403) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2404where
2405 P: Parser<'i, Impl = Impl>,
2406 Impl: SelectorImpl,
2407 F: FnOnce(i32, i32) -> Component<Impl>,
2408{
2409 if !state.allows_tree_structural_pseudo_classes() {
2410 return Err(
2411 input.new_custom_error(SelectorParseErrorKind::InvalidState)
2412 );
2413 }
2414 let (a, b) = parse_nth(input)?;
2415 Ok(selector(a, b))
2416}
2417
2418fn is_css2_pseudo_element(name: &str) -> bool {
2422 match_ignore_ascii_case! { name,
2424 "before" | "after" | "first-line" | "first-letter" => true,
2425 _ => false,
2426 }
2427}
2428
2429fn parse_one_simple_selector<'i, 't, P, Impl>(
2435 parser: &P,
2436 input: &mut CssParser<'i, 't>,
2437 state: SelectorParsingState,
2438) -> Result<Option<SimpleSelectorParseResult<Impl>>, ParseError<'i, P::Error>>
2439where
2440 P: Parser<'i, Impl = Impl>,
2441 Impl: SelectorImpl,
2442{
2443 let start = input.state();
2444 let token = match input.next_including_whitespace().map(|t| t.clone()) {
2445 Ok(t) => t,
2446 Err(..) => {
2447 input.reset(&start);
2448 return Ok(None);
2449 }
2450 };
2451
2452 Ok(Some(match token {
2453 Token::IDHash(id) => {
2454 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2455 return Err(input
2456 .new_custom_error(SelectorParseErrorKind::InvalidState));
2457 }
2458 let id = Component::ID(id.as_ref().into());
2459 SimpleSelectorParseResult::SimpleSelector(id)
2460 }
2461 Token::Delim('.') => {
2462 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2463 return Err(input
2464 .new_custom_error(SelectorParseErrorKind::InvalidState));
2465 }
2466 let location = input.current_source_location();
2467 let class = match *input.next_including_whitespace()? {
2468 Token::Ident(ref class) => class,
2469 ref t => {
2470 let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone());
2471 return Err(location.new_custom_error(e));
2472 }
2473 };
2474 let class = Component::Class(class.as_ref().into());
2475 SimpleSelectorParseResult::SimpleSelector(class)
2476 }
2477 Token::SquareBracketBlock => {
2478 if state.intersects(SelectorParsingState::AFTER_PSEUDO) {
2479 return Err(input
2480 .new_custom_error(SelectorParseErrorKind::InvalidState));
2481 }
2482 let attr = input.parse_nested_block(|input| {
2483 parse_attribute_selector(parser, input)
2484 })?;
2485 SimpleSelectorParseResult::SimpleSelector(attr)
2486 }
2487 Token::Colon => {
2488 let location = input.current_source_location();
2489 let (is_single_colon, next_token) =
2490 match input.next_including_whitespace()?.clone() {
2491 Token::Colon => {
2492 (false, input.next_including_whitespace()?.clone())
2493 }
2494 t => (true, t),
2495 };
2496 let (name, is_functional) = match next_token {
2497 Token::Ident(name) => (name, false),
2498 Token::Function(name) => (name, true),
2499 t => {
2500 let e =
2501 SelectorParseErrorKind::PseudoElementExpectedIdent(t);
2502 return Err(input.new_custom_error(e));
2503 }
2504 };
2505 let is_pseudo_element =
2506 !is_single_colon || is_css2_pseudo_element(&name);
2507 if is_pseudo_element {
2508 if !state.allows_pseudos() {
2509 return Err(input.new_custom_error(
2510 SelectorParseErrorKind::InvalidState,
2511 ));
2512 }
2513 let pseudo_element = if is_functional {
2514 if P::parse_part(parser)
2515 && name.eq_ignore_ascii_case("part")
2516 {
2517 if !state.allows_part() {
2518 return Err(input.new_custom_error(
2519 SelectorParseErrorKind::InvalidState,
2520 ));
2521 }
2522 let names = input.parse_nested_block(|input| {
2523 let mut result = Vec::with_capacity(1);
2524 result.push(input.expect_ident()?.as_ref().into());
2525 while !input.is_exhausted() {
2526 result.push(
2527 input.expect_ident()?.as_ref().into(),
2528 );
2529 }
2530 Ok(result.into_boxed_slice())
2531 })?;
2532 return Ok(Some(
2533 SimpleSelectorParseResult::PartPseudo(names),
2534 ));
2535 }
2536 if P::parse_slotted(parser)
2537 && name.eq_ignore_ascii_case("slotted")
2538 {
2539 if !state.allows_slotted() {
2540 return Err(input.new_custom_error(
2541 SelectorParseErrorKind::InvalidState,
2542 ));
2543 }
2544 let selector = input.parse_nested_block(|input| {
2545 parse_inner_compound_selector(parser, input, state)
2546 })?;
2547 return Ok(Some(
2548 SimpleSelectorParseResult::SlottedPseudo(selector),
2549 ));
2550 }
2551 input.parse_nested_block(|input| {
2552 P::parse_functional_pseudo_element(parser, name, input)
2553 })?
2554 } else {
2555 P::parse_pseudo_element(parser, location, name)?
2556 };
2557
2558 if state.intersects(SelectorParsingState::AFTER_SLOTTED)
2559 && !pseudo_element.valid_after_slotted()
2560 {
2561 return Err(input.new_custom_error(
2562 SelectorParseErrorKind::InvalidState,
2563 ));
2564 }
2565 SimpleSelectorParseResult::PseudoElement(pseudo_element)
2566 } else {
2567 let pseudo_class = if is_functional {
2568 input.parse_nested_block(|input| {
2569 parse_functional_pseudo_class(
2570 parser, input, name, state,
2571 )
2572 })?
2573 } else {
2574 parse_simple_pseudo_class(parser, location, name, state)?
2575 };
2576 SimpleSelectorParseResult::SimpleSelector(pseudo_class)
2577 }
2578 }
2579 _ => {
2580 input.reset(&start);
2581 return Ok(None);
2582 }
2583 }))
2584}
2585
2586fn parse_simple_pseudo_class<'i, P, Impl>(
2587 parser: &P,
2588 location: SourceLocation,
2589 name: CowRcStr<'i>,
2590 state: SelectorParsingState,
2591) -> Result<Component<Impl>, ParseError<'i, P::Error>>
2592where
2593 P: Parser<'i, Impl = Impl>,
2594 Impl: SelectorImpl,
2595{
2596 if !state.allows_non_functional_pseudo_classes() {
2597 return Err(
2598 location.new_custom_error(SelectorParseErrorKind::InvalidState)
2599 );
2600 }
2601
2602 if state.allows_tree_structural_pseudo_classes() {
2603 match_ignore_ascii_case! { &name,
2604 "first-child" => return Ok(Component::FirstChild),
2605 "last-child" => return Ok(Component::LastChild),
2606 "only-child" => return Ok(Component::OnlyChild),
2607 "root" => return Ok(Component::Root),
2608 "empty" => return Ok(Component::Empty),
2609 "scope" => return Ok(Component::Scope),
2610 "host" if P::parse_host(parser) => return Ok(Component::Host(None)),
2611 "first-of-type" => return Ok(Component::FirstOfType),
2612 "last-of-type" => return Ok(Component::LastOfType),
2613 "only-of-type" => return Ok(Component::OnlyOfType),
2614 _ => {},
2615 }
2616 }
2617
2618 let pseudo_class = P::parse_non_ts_pseudo_class(parser, location, name)?;
2619 if state.intersects(SelectorParsingState::AFTER_PSEUDO_ELEMENT)
2620 && !pseudo_class.is_user_action_state()
2621 {
2622 return Err(
2623 location.new_custom_error(SelectorParseErrorKind::InvalidState)
2624 );
2625 }
2626 Ok(Component::NonTSPseudoClass(pseudo_class))
2627}
2628
2629#[cfg(test)]
2631pub mod tests {
2632 use {
2633 super::*,
2634 crate::{builder::SelectorFlags, parser},
2635 cssparser::{
2636 serialize_identifier,
2637 Parser as CssParser,
2638 ParserInput,
2639 ToCss,
2640 },
2641 std::{collections::HashMap, fmt},
2642 };
2643
2644 #[derive(Clone, Debug, Eq, PartialEq)]
2645 pub enum PseudoClass {
2646 Hover,
2647 Active,
2648 Lang(String),
2649 }
2650
2651 #[derive(Clone, Debug, Eq, PartialEq)]
2652 pub enum PseudoElement {
2653 Before,
2654 After,
2655 }
2656
2657 impl parser::PseudoElement for PseudoElement {
2658 type Impl = DummySelectorImpl;
2659
2660 fn accepts_state_pseudo_classes(&self) -> bool {
2661 true
2662 }
2663
2664 fn valid_after_slotted(&self) -> bool {
2665 true
2666 }
2667 }
2668
2669 impl parser::NonTSPseudoClass for PseudoClass {
2670 type Impl = DummySelectorImpl;
2671
2672 #[inline]
2673 fn is_active_or_hover(&self) -> bool {
2674 matches!(*self, PseudoClass::Active | PseudoClass::Hover)
2675 }
2676
2677 #[inline]
2678 fn is_user_action_state(&self) -> bool {
2679 self.is_active_or_hover()
2680 }
2681 }
2682
2683 impl ToCss for PseudoClass {
2684 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2685 where
2686 W: fmt::Write,
2687 {
2688 match *self {
2689 PseudoClass::Hover => dest.write_str(":hover"),
2690 PseudoClass::Active => dest.write_str(":active"),
2691 PseudoClass::Lang(ref lang) => {
2692 dest.write_str(":lang(")?;
2693 serialize_identifier(lang, dest)?;
2694 dest.write_char(')')
2695 }
2696 }
2697 }
2698 }
2699
2700 impl ToCss for PseudoElement {
2701 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2702 where
2703 W: fmt::Write,
2704 {
2705 match *self {
2706 PseudoElement::Before => dest.write_str("::before"),
2707 PseudoElement::After => dest.write_str("::after"),
2708 }
2709 }
2710 }
2711
2712 #[derive(Clone, Debug, PartialEq)]
2713 pub struct DummySelectorImpl;
2714
2715 #[derive(Default)]
2716 pub struct DummyParser {
2717 default_ns: Option<DummyAtom>,
2718 ns_prefixes: HashMap<DummyAtom, DummyAtom>,
2719 }
2720
2721 impl DummyParser {
2722 fn default_with_namespace(default_ns: DummyAtom) -> DummyParser {
2723 DummyParser {
2724 default_ns: Some(default_ns),
2725 ns_prefixes: Default::default(),
2726 }
2727 }
2728 }
2729
2730 impl SelectorImpl for DummySelectorImpl {
2731 type ExtraMatchingData = ();
2732 type AttrValue = DummyAttrValue;
2733 type Identifier = DummyAtom;
2734 type LocalName = DummyAtom;
2735 type NamespaceUrl = DummyAtom;
2736 type NamespacePrefix = DummyAtom;
2737 type BorrowedLocalName = DummyAtom;
2738 type BorrowedNamespaceUrl = DummyAtom;
2739 type NonTSPseudoClass = PseudoClass;
2740 type PseudoElement = PseudoElement;
2741 }
2742
2743 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
2744 pub struct DummyAttrValue(String);
2745
2746 impl ToCss for DummyAttrValue {
2747 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2748 where
2749 W: fmt::Write,
2750 {
2751 use std::fmt::Write;
2752
2753 write!(cssparser::CssStringWriter::new(dest), "{}", &self.0)
2754 }
2755 }
2756
2757 impl<'a> From<&'a str> for DummyAttrValue {
2758 fn from(string: &'a str) -> Self {
2759 Self(string.into())
2760 }
2761 }
2762
2763 #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
2764 pub struct DummyAtom(String);
2765
2766 impl ToCss for DummyAtom {
2767 fn to_css<W>(&self, dest: &mut W) -> fmt::Result
2768 where
2769 W: fmt::Write,
2770 {
2771 serialize_identifier(&self.0, dest)
2772 }
2773 }
2774
2775 impl From<String> for DummyAtom {
2776 fn from(string: String) -> Self {
2777 DummyAtom(string)
2778 }
2779 }
2780
2781 impl<'a> From<&'a str> for DummyAtom {
2782 fn from(string: &'a str) -> Self {
2783 DummyAtom(string.into())
2784 }
2785 }
2786
2787 impl<'i> Parser<'i> for DummyParser {
2788 type Impl = DummySelectorImpl;
2789 type Error = SelectorParseErrorKind<'i>;
2790
2791 fn parse_slotted(&self) -> bool {
2792 true
2793 }
2794
2795 fn parse_is_and_where(&self) -> bool {
2796 true
2797 }
2798
2799 fn is_and_where_error_recovery(&self) -> ParseErrorRecovery {
2800 ParseErrorRecovery::DiscardList
2801 }
2802
2803 fn parse_part(&self) -> bool {
2804 true
2805 }
2806
2807 fn parse_non_ts_pseudo_class(
2808 &self,
2809 location: SourceLocation,
2810 name: CowRcStr<'i>,
2811 ) -> Result<PseudoClass, SelectorParseError<'i>> {
2812 match_ignore_ascii_case! { &name,
2813 "hover" => return Ok(PseudoClass::Hover),
2814 "active" => return Ok(PseudoClass::Active),
2815 _ => {}
2816 }
2817 Err(location.new_custom_error(
2818 SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
2819 ))
2820 }
2821
2822 fn parse_non_ts_functional_pseudo_class<'t>(
2823 &self,
2824 name: CowRcStr<'i>,
2825 parser: &mut CssParser<'i, 't>,
2826 ) -> Result<PseudoClass, SelectorParseError<'i>> {
2827 match_ignore_ascii_case! { &name,
2828 "lang" => {
2829 let lang = parser.expect_ident_or_string()?.as_ref().to_owned();
2830 return Ok(PseudoClass::Lang(lang));
2831 },
2832 _ => {}
2833 }
2834 Err(parser.new_custom_error(
2835 SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
2836 ))
2837 }
2838
2839 fn parse_pseudo_element(
2840 &self,
2841 location: SourceLocation,
2842 name: CowRcStr<'i>,
2843 ) -> Result<PseudoElement, SelectorParseError<'i>> {
2844 match_ignore_ascii_case! { &name,
2845 "before" => return Ok(PseudoElement::Before),
2846 "after" => return Ok(PseudoElement::After),
2847 _ => {}
2848 }
2849 Err(location.new_custom_error(
2850 SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name),
2851 ))
2852 }
2853
2854 fn default_namespace(&self) -> Option<DummyAtom> {
2855 self.default_ns.clone()
2856 }
2857
2858 fn namespace_for_prefix(
2859 &self,
2860 prefix: &DummyAtom,
2861 ) -> Option<DummyAtom> {
2862 self.ns_prefixes.get(prefix).cloned()
2863 }
2864 }
2865
2866 fn parse<'i>(
2867 input: &'i str,
2868 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2869 parse_ns(input, &DummyParser::default())
2870 }
2871
2872 fn parse_expected<'i, 'a>(
2873 input: &'i str,
2874 expected: Option<&'a str>,
2875 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2876 parse_ns_expected(input, &DummyParser::default(), expected)
2877 }
2878
2879 fn parse_ns<'i>(
2880 input: &'i str,
2881 parser: &DummyParser,
2882 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2883 parse_ns_expected(input, parser, None)
2884 }
2885
2886 fn parse_ns_expected<'i, 'a>(
2887 input: &'i str,
2888 parser: &DummyParser,
2889 expected: Option<&'a str>,
2890 ) -> Result<SelectorList<DummySelectorImpl>, SelectorParseError<'i>> {
2891 let mut parser_input = ParserInput::new(input);
2892 let result =
2893 SelectorList::parse(parser, &mut CssParser::new(&mut parser_input));
2894 if let Ok(ref selectors) = result {
2895 assert_eq!(selectors.0.len(), 1);
2896 assert_eq!(
2900 selectors.0[0].to_css_string(),
2901 match expected {
2902 Some(x) => x,
2903 None => input,
2904 }
2905 );
2906 }
2907 result
2908 }
2909
2910 fn specificity(a: u32, b: u32, c: u32) -> u32 {
2911 a << 20 | b << 10 | c
2912 }
2913
2914 #[test]
2915 fn test_empty() {
2916 let mut input = ParserInput::new(":empty");
2917 let list = SelectorList::parse(
2918 &DummyParser::default(),
2919 &mut CssParser::new(&mut input),
2920 );
2921 assert!(list.is_ok());
2922 }
2923
2924 const MATHML: &str = "http://www.w3.org/1998/Math/MathML";
2925 const SVG: &str = "http://www.w3.org/2000/svg";
2926
2927 #[test]
2928 fn test_parsing() {
2929 assert!(parse("").is_err());
2930 assert!(parse(":lang(4)").is_err());
2931 assert!(parse(":lang(en US)").is_err());
2932 assert_eq!(
2933 parse("EeÉ"),
2934 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2935 vec![Component::LocalName(LocalName {
2936 name: DummyAtom::from("EeÉ"),
2937 lower_name: DummyAtom::from("eeÉ"),
2938 })],
2939 specificity(0, 0, 1),
2940 Default::default(),
2941 )]))
2942 );
2943 assert_eq!(
2944 parse("|e"),
2945 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2946 vec![
2947 Component::ExplicitNoNamespace,
2948 Component::LocalName(LocalName {
2949 name: DummyAtom::from("e"),
2950 lower_name: DummyAtom::from("e"),
2951 }),
2952 ],
2953 specificity(0, 0, 1),
2954 Default::default(),
2955 )]))
2956 );
2957 assert_eq!(
2960 parse_expected("*|e", Some("e")),
2961 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2962 vec![Component::LocalName(LocalName {
2963 name: DummyAtom::from("e"),
2964 lower_name: DummyAtom::from("e"),
2965 })],
2966 specificity(0, 0, 1),
2967 Default::default(),
2968 )]))
2969 );
2970 assert_eq!(
2975 parse_ns(
2976 "*|e",
2977 &DummyParser::default_with_namespace(DummyAtom::from(
2978 "https://mozilla.org"
2979 ))
2980 ),
2981 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2982 vec![
2983 Component::ExplicitAnyNamespace,
2984 Component::LocalName(LocalName {
2985 name: DummyAtom::from("e"),
2986 lower_name: DummyAtom::from("e"),
2987 }),
2988 ],
2989 specificity(0, 0, 1),
2990 Default::default(),
2991 )]))
2992 );
2993 assert_eq!(
2994 parse("*"),
2995 Ok(SelectorList::from_vec(vec![Selector::from_vec(
2996 vec![Component::ExplicitUniversalType],
2997 specificity(0, 0, 0),
2998 Default::default(),
2999 )]))
3000 );
3001 assert_eq!(
3002 parse("|*"),
3003 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3004 vec![
3005 Component::ExplicitNoNamespace,
3006 Component::ExplicitUniversalType,
3007 ],
3008 specificity(0, 0, 0),
3009 Default::default(),
3010 )]))
3011 );
3012 assert_eq!(
3013 parse_expected("*|*", Some("*")),
3014 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3015 vec![Component::ExplicitUniversalType],
3016 specificity(0, 0, 0),
3017 Default::default(),
3018 )]))
3019 );
3020 assert_eq!(
3021 parse_ns(
3022 "*|*",
3023 &DummyParser::default_with_namespace(DummyAtom::from(
3024 "https://mozilla.org"
3025 ))
3026 ),
3027 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3028 vec![
3029 Component::ExplicitAnyNamespace,
3030 Component::ExplicitUniversalType,
3031 ],
3032 specificity(0, 0, 0),
3033 Default::default(),
3034 )]))
3035 );
3036 assert_eq!(
3037 parse(".foo:lang(en-US)"),
3038 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3039 vec![
3040 Component::Class(DummyAtom::from("foo")),
3041 Component::NonTSPseudoClass(PseudoClass::Lang(
3042 "en-US".to_owned()
3043 )),
3044 ],
3045 specificity(0, 2, 0),
3046 Default::default(),
3047 )]))
3048 );
3049 assert_eq!(
3050 parse("#bar"),
3051 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3052 vec![Component::ID(DummyAtom::from("bar"))],
3053 specificity(1, 0, 0),
3054 Default::default(),
3055 )]))
3056 );
3057 assert_eq!(
3058 parse("e.foo#bar"),
3059 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3060 vec![
3061 Component::LocalName(LocalName {
3062 name: DummyAtom::from("e"),
3063 lower_name: DummyAtom::from("e"),
3064 }),
3065 Component::Class(DummyAtom::from("foo")),
3066 Component::ID(DummyAtom::from("bar")),
3067 ],
3068 specificity(1, 1, 1),
3069 Default::default(),
3070 )]))
3071 );
3072 assert_eq!(
3073 parse("e.foo #bar"),
3074 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3075 vec![
3076 Component::LocalName(LocalName {
3077 name: DummyAtom::from("e"),
3078 lower_name: DummyAtom::from("e"),
3079 }),
3080 Component::Class(DummyAtom::from("foo")),
3081 Component::Combinator(Combinator::Descendant),
3082 Component::ID(DummyAtom::from("bar")),
3083 ],
3084 specificity(1, 1, 1),
3085 Default::default(),
3086 )]))
3087 );
3088 let mut parser = DummyParser::default();
3091 assert_eq!(
3092 parse_ns("[Foo]", &parser),
3093 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3094 vec![Component::AttributeInNoNamespaceExists {
3095 local_name: DummyAtom::from("Foo"),
3096 local_name_lower: DummyAtom::from("foo"),
3097 }],
3098 specificity(0, 1, 0),
3099 Default::default(),
3100 )]))
3101 );
3102 assert!(parse_ns("svg|circle", &parser).is_err());
3103 parser
3104 .ns_prefixes
3105 .insert(DummyAtom("svg".into()), DummyAtom(SVG.into()));
3106 assert_eq!(
3107 parse_ns("svg|circle", &parser),
3108 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3109 vec![
3110 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
3111 Component::LocalName(LocalName {
3112 name: DummyAtom::from("circle"),
3113 lower_name: DummyAtom::from("circle"),
3114 }),
3115 ],
3116 specificity(0, 0, 1),
3117 Default::default(),
3118 )]))
3119 );
3120 assert_eq!(
3121 parse_ns("svg|*", &parser),
3122 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3123 vec![
3124 Component::Namespace(DummyAtom("svg".into()), SVG.into()),
3125 Component::ExplicitUniversalType,
3126 ],
3127 specificity(0, 0, 0),
3128 Default::default(),
3129 )]))
3130 );
3131 parser.default_ns = Some(MATHML.into());
3136 assert_eq!(
3137 parse_ns("[Foo]", &parser),
3138 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3139 vec![
3140 Component::DefaultNamespace(MATHML.into()),
3141 Component::AttributeInNoNamespaceExists {
3142 local_name: DummyAtom::from("Foo"),
3143 local_name_lower: DummyAtom::from("foo"),
3144 },
3145 ],
3146 specificity(0, 1, 0),
3147 Default::default(),
3148 )]))
3149 );
3150 assert_eq!(
3152 parse_ns("e", &parser),
3153 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3154 vec![
3155 Component::DefaultNamespace(MATHML.into()),
3156 Component::LocalName(LocalName {
3157 name: DummyAtom::from("e"),
3158 lower_name: DummyAtom::from("e"),
3159 }),
3160 ],
3161 specificity(0, 0, 1),
3162 Default::default(),
3163 )]))
3164 );
3165 assert_eq!(
3166 parse_ns("*", &parser),
3167 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3168 vec![
3169 Component::DefaultNamespace(MATHML.into()),
3170 Component::ExplicitUniversalType,
3171 ],
3172 specificity(0, 0, 0),
3173 Default::default(),
3174 )]))
3175 );
3176 assert_eq!(
3177 parse_ns("*|*", &parser),
3178 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3179 vec![
3180 Component::ExplicitAnyNamespace,
3181 Component::ExplicitUniversalType,
3182 ],
3183 specificity(0, 0, 0),
3184 Default::default(),
3185 )]))
3186 );
3187 assert_eq!(
3190 parse_ns(":not(.cl)", &parser),
3191 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3192 vec![
3193 Component::DefaultNamespace(MATHML.into()),
3194 Component::Negation(
3195 vec![Selector::from_vec(
3196 vec![Component::Class(DummyAtom::from("cl"))],
3197 specificity(0, 1, 0),
3198 Default::default(),
3199 )]
3200 .into_boxed_slice()
3201 ),
3202 ],
3203 specificity(0, 1, 0),
3204 Default::default(),
3205 )]))
3206 );
3207 assert_eq!(
3208 parse_ns(":not(*)", &parser),
3209 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3210 vec![
3211 Component::DefaultNamespace(MATHML.into()),
3212 Component::Negation(
3213 vec![Selector::from_vec(
3214 vec![
3215 Component::DefaultNamespace(MATHML.into()),
3216 Component::ExplicitUniversalType,
3217 ],
3218 specificity(0, 0, 0),
3219 Default::default(),
3220 )]
3221 .into_boxed_slice(),
3222 ),
3223 ],
3224 specificity(0, 0, 0),
3225 Default::default(),
3226 )]))
3227 );
3228 assert_eq!(
3229 parse_ns(":not(e)", &parser),
3230 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3231 vec![
3232 Component::DefaultNamespace(MATHML.into()),
3233 Component::Negation(
3234 vec![Selector::from_vec(
3235 vec![
3236 Component::DefaultNamespace(MATHML.into()),
3237 Component::LocalName(LocalName {
3238 name: DummyAtom::from("e"),
3239 lower_name: DummyAtom::from("e"),
3240 }),
3241 ],
3242 specificity(0, 0, 1),
3243 Default::default(),
3244 ),]
3245 .into_boxed_slice()
3246 ),
3247 ],
3248 specificity(0, 0, 1),
3249 Default::default(),
3250 )]))
3251 );
3252 assert_eq!(
3253 parse("[attr|=\"foo\"]"),
3254 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3255 vec![Component::AttributeInNoNamespace {
3256 local_name: DummyAtom::from("attr"),
3257 operator: AttrSelectorOperator::DashMatch,
3258 value: DummyAttrValue::from("foo"),
3259 never_matches: false,
3260 case_sensitivity: ParsedCaseSensitivity::CaseSensitive,
3261 }],
3262 specificity(0, 1, 0),
3263 Default::default(),
3264 )]))
3265 );
3266 assert_eq!(
3268 parse("::before"),
3269 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3270 vec![
3271 Component::Combinator(Combinator::PseudoElement),
3272 Component::PseudoElement(PseudoElement::Before),
3273 ],
3274 specificity(0, 0, 1),
3275 SelectorFlags::HAS_PSEUDO,
3276 )]))
3277 );
3278 assert_eq!(
3279 parse("::before:hover"),
3280 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3281 vec![
3282 Component::Combinator(Combinator::PseudoElement),
3283 Component::PseudoElement(PseudoElement::Before),
3284 Component::NonTSPseudoClass(PseudoClass::Hover),
3285 ],
3286 specificity(0, 1, 1),
3287 SelectorFlags::HAS_PSEUDO,
3288 )]))
3289 );
3290 assert_eq!(
3291 parse("::before:hover:hover"),
3292 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3293 vec![
3294 Component::Combinator(Combinator::PseudoElement),
3295 Component::PseudoElement(PseudoElement::Before),
3296 Component::NonTSPseudoClass(PseudoClass::Hover),
3297 Component::NonTSPseudoClass(PseudoClass::Hover),
3298 ],
3299 specificity(0, 2, 1),
3300 SelectorFlags::HAS_PSEUDO,
3301 )]))
3302 );
3303 assert!(parse("::before:hover:lang(foo)").is_err());
3304 assert!(parse("::before:hover .foo").is_err());
3305 assert!(parse("::before .foo").is_err());
3306 assert!(parse("::before ~ bar").is_err());
3307 assert!(parse("::before:active").is_ok());
3308
3309 assert!(parse(":: before").is_err());
3311 assert_eq!(
3312 parse("div ::after"),
3313 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3314 vec![
3315 Component::LocalName(LocalName {
3316 name: DummyAtom::from("div"),
3317 lower_name: DummyAtom::from("div"),
3318 }),
3319 Component::Combinator(Combinator::Descendant),
3320 Component::Combinator(Combinator::PseudoElement),
3321 Component::PseudoElement(PseudoElement::After),
3322 ],
3323 specificity(0, 0, 2),
3324 SelectorFlags::HAS_PSEUDO,
3325 )]))
3326 );
3327 assert_eq!(
3328 parse("#d1 > .ok"),
3329 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3330 vec![
3331 Component::ID(DummyAtom::from("d1")),
3332 Component::Combinator(Combinator::Child),
3333 Component::Class(DummyAtom::from("ok")),
3334 ],
3335 (1 << 20) + (1 << 10) + (0 << 0),
3336 Default::default(),
3337 )]))
3338 );
3339 parser.default_ns = None;
3340 assert!(parse(":not(#provel.old)").is_ok());
3341 assert!(parse(":not(#provel > old)").is_ok());
3342 assert!(
3343 parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])")
3344 .is_ok()
3345 );
3346 assert_eq!(
3348 parse_ns(":not(*)", &parser),
3349 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3350 vec![Component::Negation(
3351 vec![Selector::from_vec(
3352 vec![Component::ExplicitUniversalType],
3353 specificity(0, 0, 0),
3354 Default::default(),
3355 )]
3356 .into_boxed_slice()
3357 )],
3358 specificity(0, 0, 0),
3359 Default::default(),
3360 )]))
3361 );
3362 assert_eq!(
3363 parse_ns(":not(|*)", &parser),
3364 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3365 vec![Component::Negation(
3366 vec![Selector::from_vec(
3367 vec![
3368 Component::ExplicitNoNamespace,
3369 Component::ExplicitUniversalType,
3370 ],
3371 specificity(0, 0, 0),
3372 Default::default(),
3373 )]
3374 .into_boxed_slice(),
3375 )],
3376 specificity(0, 0, 0),
3377 Default::default(),
3378 )]))
3379 );
3380 assert_eq!(
3383 parse_ns_expected(":not(*|*)", &parser, Some(":not(*)")),
3384 Ok(SelectorList::from_vec(vec![Selector::from_vec(
3385 vec![Component::Negation(
3386 vec![Selector::from_vec(
3387 vec![Component::ExplicitUniversalType],
3388 specificity(0, 0, 0),
3389 Default::default()
3390 )]
3391 .into_boxed_slice()
3392 )],
3393 specificity(0, 0, 0),
3394 Default::default(),
3395 )]))
3396 );
3397
3398 assert!(parse("::slotted()").is_err());
3399 assert!(parse("::slotted(div)").is_ok());
3400 assert!(parse("::slotted(div).foo").is_err());
3401 assert!(parse("::slotted(div + bar)").is_err());
3402 assert!(parse("::slotted(div) + foo").is_err());
3403
3404 assert!(parse("::part()").is_err());
3405 assert!(parse("::part(42)").is_err());
3406 assert!(parse("::part(foo bar)").is_ok());
3407 assert!(parse("::part(foo):hover").is_ok());
3408 assert!(parse("::part(foo) + bar").is_err());
3409
3410 assert!(parse("div ::slotted(div)").is_ok());
3411 assert!(parse("div + slot::slotted(div)").is_ok());
3412 assert!(parse("div + slot::slotted(div.foo)").is_ok());
3413 assert!(parse("slot::slotted(div,foo)::first-line").is_err());
3414 assert!(parse("::slotted(div)::before").is_ok());
3415 assert!(parse("slot::slotted(div,foo)").is_err());
3416
3417 assert!(parse("foo:where()").is_err());
3418 assert!(parse("foo:where(div, foo, .bar baz)").is_ok());
3419 assert!(parse("foo:where(::before)").is_err());
3420 }
3421
3422 #[test]
3423 fn test_pseudo_iter() {
3424 let selector = &parse("q::before").unwrap().0[0];
3425 assert!(!selector.is_universal());
3426 let mut iter = selector.iter();
3427 assert_eq!(
3428 iter.next(),
3429 Some(&Component::PseudoElement(PseudoElement::Before))
3430 );
3431 assert_eq!(iter.next(), None);
3432 let combinator = iter.next_sequence();
3433 assert_eq!(combinator, Some(Combinator::PseudoElement));
3434 assert!(matches!(iter.next(), Some(&Component::LocalName(..))));
3435 assert_eq!(iter.next(), None);
3436 assert_eq!(iter.next_sequence(), None);
3437 }
3438
3439 #[test]
3440 fn test_universal() {
3441 let selector = &parse_ns(
3442 "*|*::before",
3443 &DummyParser::default_with_namespace(DummyAtom::from(
3444 "https://mozilla.org",
3445 )),
3446 )
3447 .unwrap()
3448 .0[0];
3449 assert!(selector.is_universal());
3450 }
3451
3452 #[test]
3453 fn test_empty_pseudo_iter() {
3454 let selector = &parse("::before").unwrap().0[0];
3455 assert!(selector.is_universal());
3456 let mut iter = selector.iter();
3457 assert_eq!(
3458 iter.next(),
3459 Some(&Component::PseudoElement(PseudoElement::Before))
3460 );
3461 assert_eq!(iter.next(), None);
3462 assert_eq!(iter.next_sequence(), Some(Combinator::PseudoElement));
3463 assert_eq!(iter.next(), None);
3464 assert_eq!(iter.next_sequence(), None);
3465 }
3466
3467 struct TestVisitor {
3468 seen: Vec<String>,
3469 }
3470
3471 impl SelectorVisitor for TestVisitor {
3472 type Impl = DummySelectorImpl;
3473
3474 fn visit_simple_selector(
3475 &mut self,
3476 s: &Component<DummySelectorImpl>,
3477 ) -> bool {
3478 let mut dest = String::new();
3479 s.to_css(&mut dest).unwrap();
3480 self.seen.push(dest);
3481 true
3482 }
3483 }
3484
3485 #[test]
3486 fn visitor() {
3487 let mut test_visitor = TestVisitor { seen: vec![] };
3488 parse(":not(:hover) ~ label").unwrap().0[0].visit(&mut test_visitor);
3489 assert!(test_visitor.seen.contains(&":hover".into()));
3490
3491 let mut test_visitor = TestVisitor { seen: vec![] };
3492 parse("::before:hover").unwrap().0[0].visit(&mut test_visitor);
3493 assert!(test_visitor.seen.contains(&":hover".into()));
3494 }
3495}