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