1use crate::attr::{
6 AttrSelectorOperation, AttrSelectorWithOptionalNamespace, CaseSensitivity, NamespaceConstraint,
7 ParsedAttrSelectorOperation, ParsedCaseSensitivity,
8};
9use crate::bloom::{BloomFilter, BLOOM_HASH_MASK};
10use crate::kleene_value::KleeneValue;
11use crate::parser::{
12 AncestorHashes, Combinator, Component, LocalName, MatchesFeaturelessHost, NthSelectorData,
13 RelativeSelectorMatchHint,
14};
15use crate::parser::{
16 NonTSPseudoClass, RelativeSelector, Selector, SelectorImpl, SelectorIter, SelectorList,
17};
18use crate::relative_selector::cache::RelativeSelectorCachedMatch;
19use crate::tree::Element;
20use bitflags::bitflags;
21use debug_unreachable::debug_unreachable;
22use log::debug;
23use smallvec::SmallVec;
24use std::borrow::Borrow;
25
26pub use crate::context::*;
27
28pub static RECOMMENDED_SELECTOR_BLOOM_FILTER_SIZE: usize = 4096;
32
33bitflags! {
34 #[derive(Clone, Copy)]
37 pub struct ElementSelectorFlags: usize {
38 const HAS_SLOW_SELECTOR = 1 << 0;
42
43 const HAS_SLOW_SELECTOR_LATER_SIBLINGS = 1 << 1;
47
48 const HAS_SLOW_SELECTOR_NTH = 1 << 2;
50
51 const HAS_SLOW_SELECTOR_NTH_OF = 1 << 3;
60
61 const HAS_EDGE_CHILD_SELECTOR = 1 << 4;
65
66 const HAS_EMPTY_SELECTOR = 1 << 5;
69
70 const ANCHORS_RELATIVE_SELECTOR = 1 << 6;
72
73 const ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT = 1 << 7;
76
77 const RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING = 1 << 8;
79
80 const RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR = 1 << 9;
82
83 const RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING =
85 Self::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING.bits() |
86 Self::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR.bits();
87 }
88}
89
90impl ElementSelectorFlags {
91 pub fn for_self(self) -> ElementSelectorFlags {
93 self & (ElementSelectorFlags::HAS_EMPTY_SELECTOR
94 | ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR
95 | ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT
96 | ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING
97 | ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR)
98 }
99
100 pub fn for_parent(self) -> ElementSelectorFlags {
102 self & (ElementSelectorFlags::HAS_SLOW_SELECTOR
103 | ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
104 | ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH
105 | ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF
106 | ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR)
107 }
108}
109
110struct LocalMatchingContext<'a, 'b: 'a, Impl: SelectorImpl> {
112 shared: &'a mut MatchingContext<'b, Impl>,
113 rightmost: SubjectOrPseudoElement,
114 quirks_data: Option<SelectorIter<'a, Impl>>,
115}
116
117#[inline(always)]
118pub fn matches_selector_list<E>(
119 selector_list: &SelectorList<E::Impl>,
120 element: &E,
121 context: &mut MatchingContext<E::Impl>,
122) -> bool
123where
124 E: Element,
125{
126 for selector in selector_list.slice() {
129 let matches = matches_selector(selector, 0, None, element, context);
130 if matches {
131 return true;
132 }
133 }
134
135 false
136}
137
138#[inline(always)]
141pub fn selector_may_match(hashes: &AncestorHashes, bf: &BloomFilter) -> bool {
142 for i in 0..3 {
150 let packed = hashes.packed_hashes[i];
151 if packed == 0 {
152 return true;
154 }
155
156 if !bf.might_contain_hash(packed & BLOOM_HASH_MASK) {
157 return false;
159 }
160 }
161
162 let fourth = hashes.fourth_hash();
165 fourth == 0 || bf.might_contain_hash(fourth)
166}
167
168#[derive(Clone, Copy, Eq, PartialEq)]
225enum SelectorMatchingResult {
226 Matched,
227 NotMatchedAndRestartFromClosestLaterSibling,
228 NotMatchedAndRestartFromClosestDescendant,
229 NotMatchedGlobally,
230 Unknown,
231}
232
233impl From<SelectorMatchingResult> for KleeneValue {
234 #[inline]
235 fn from(value: SelectorMatchingResult) -> Self {
236 match value {
237 SelectorMatchingResult::Matched => KleeneValue::True,
238 SelectorMatchingResult::Unknown => KleeneValue::Unknown,
239 SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling
240 | SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
241 | SelectorMatchingResult::NotMatchedGlobally => KleeneValue::False,
242 }
243 }
244}
245
246#[inline(always)]
255pub fn matches_selector<E>(
256 selector: &Selector<E::Impl>,
257 offset: usize,
258 hashes: Option<&AncestorHashes>,
259 element: &E,
260 context: &mut MatchingContext<E::Impl>,
261) -> bool
262where
263 E: Element,
264{
265 let result = matches_selector_kleene(selector, offset, hashes, element, context);
266 if cfg!(debug_assertions) && result == KleeneValue::Unknown {
267 debug_assert!(
268 context
269 .matching_for_invalidation_comparison()
270 .unwrap_or(false),
271 "How did we return unknown?"
272 );
273 }
274 result.to_bool(true)
275}
276
277#[inline(always)]
279pub fn matches_selector_kleene<E>(
280 selector: &Selector<E::Impl>,
281 offset: usize,
282 hashes: Option<&AncestorHashes>,
283 element: &E,
284 context: &mut MatchingContext<E::Impl>,
285) -> KleeneValue
286where
287 E: Element,
288{
289 if let Some(hashes) = hashes {
291 if let Some(filter) = context.bloom_filter {
292 if !selector_may_match(hashes, filter) {
293 return KleeneValue::False;
294 }
295 }
296 }
297 matches_complex_selector(
298 selector.iter_from(offset),
299 element,
300 context,
301 if selector.is_rightmost(offset) {
302 SubjectOrPseudoElement::Yes
303 } else {
304 SubjectOrPseudoElement::No
305 },
306 )
307}
308
309pub enum CompoundSelectorMatchingResult {
312 FullyMatched,
314 Matched { next_combinator_offset: usize },
317 NotMatched,
319}
320
321pub fn matches_compound_selector_from<E>(
329 selector: &Selector<E::Impl>,
330 mut from_offset: usize,
331 context: &mut MatchingContext<E::Impl>,
332 element: &E,
333) -> CompoundSelectorMatchingResult
334where
335 E: Element,
336{
337 debug_assert!(
338 !context
339 .matching_for_invalidation_comparison()
340 .unwrap_or(false),
341 "CompoundSelectorMatchingResult doesn't support unknown"
342 );
343 if cfg!(debug_assertions) && from_offset != 0 {
344 selector.combinator_at_parse_order(from_offset - 1); }
346
347 let mut local_context = LocalMatchingContext {
348 shared: context,
349 rightmost: SubjectOrPseudoElement::No,
353 quirks_data: None,
354 };
355
356 let start_offset = from_offset;
360 for component in selector.iter_raw_parse_order_from(from_offset) {
361 if matches!(*component, Component::Combinator(..)) {
362 debug_assert_ne!(from_offset, 0, "Selector started with a combinator?");
363 break;
364 }
365
366 from_offset += 1;
367 }
368
369 debug_assert!(from_offset >= 1);
370 debug_assert!(from_offset <= selector.len());
371
372 let iter = selector.iter_from(selector.len() - from_offset);
373 debug_assert!(
374 iter.clone().next().is_some() || from_offset != selector.len(),
375 "Got the math wrong: {:?} | {:?} | {} {}",
376 selector,
377 selector.iter_raw_match_order().as_slice(),
378 from_offset,
379 start_offset
380 );
381
382 debug_assert!(
383 !local_context.shared.featureless(),
384 "Invalidating featureless element somehow?"
385 );
386
387 for component in iter {
388 let result = matches_simple_selector(component, element, &mut local_context);
389 debug_assert!(
390 result != KleeneValue::Unknown,
391 "Returned unknown in non invalidation context?"
392 );
393 if !result.to_bool(true) {
394 return CompoundSelectorMatchingResult::NotMatched;
395 }
396 }
397
398 if from_offset != selector.len() {
399 return CompoundSelectorMatchingResult::Matched {
400 next_combinator_offset: from_offset,
401 };
402 }
403
404 CompoundSelectorMatchingResult::FullyMatched
405}
406
407#[inline(always)]
409fn matches_complex_selector<E>(
410 mut iter: SelectorIter<E::Impl>,
411 element: &E,
412 context: &mut MatchingContext<E::Impl>,
413 rightmost: SubjectOrPseudoElement,
414) -> KleeneValue
415where
416 E: Element,
417{
418 if context.matching_mode() == MatchingMode::ForStatelessPseudoElement && !context.is_nested() {
421 match *iter.next().unwrap() {
423 Component::PseudoElement(ref pseudo) => {
424 if let Some(ref f) = context.pseudo_element_matching_fn {
425 if !f(pseudo) {
426 return KleeneValue::False;
427 }
428 }
429 },
430 ref other => {
431 debug_assert!(
432 false,
433 "Used MatchingMode::ForStatelessPseudoElement \
434 in a non-pseudo selector {:?}",
435 other
436 );
437 return KleeneValue::False;
438 },
439 }
440
441 if !iter.matches_for_stateless_pseudo_element() {
442 return KleeneValue::False;
443 }
444
445 let next_sequence = iter.next_sequence().unwrap();
447 debug_assert_eq!(next_sequence, Combinator::PseudoElement);
448 }
449
450 matches_complex_selector_internal(
451 iter,
452 element,
453 context,
454 rightmost,
455 SubjectOrPseudoElement::Yes,
456 )
457 .into()
458}
459
460fn matches_complex_selector_list<E: Element>(
462 list: &[Selector<E::Impl>],
463 element: &E,
464 context: &mut MatchingContext<E::Impl>,
465 rightmost: SubjectOrPseudoElement,
466) -> KleeneValue {
467 KleeneValue::any(list.iter(), |selector| {
468 matches_complex_selector(selector.iter(), element, context, rightmost)
469 })
470}
471
472fn matches_relative_selector<E: Element>(
473 relative_selector: &RelativeSelector<E::Impl>,
474 element: &E,
475 context: &mut MatchingContext<E::Impl>,
476 rightmost: SubjectOrPseudoElement,
477) -> bool {
478 if relative_selector.match_hint.is_descendant_direction() {
481 if context.needs_selector_flags() {
482 element.apply_selector_flags(
483 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
484 );
485 }
486 let mut next_element = element.first_element_child();
487 while let Some(el) = next_element {
488 if context.needs_selector_flags() {
489 el.apply_selector_flags(
490 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
491 );
492 }
493 let mut matched = matches_complex_selector(
494 relative_selector.selector.iter(),
495 &el,
496 context,
497 rightmost,
498 )
499 .to_bool(true);
500 if !matched && relative_selector.match_hint.is_subtree() {
501 matched = matches_relative_selector_subtree(
502 &relative_selector.selector,
503 &el,
504 context,
505 rightmost,
506 );
507 }
508 if matched {
509 return true;
510 }
511 next_element = el.next_sibling_element();
512 }
513 } else {
514 debug_assert!(
515 matches!(
516 relative_selector.match_hint,
517 RelativeSelectorMatchHint::InNextSibling
518 | RelativeSelectorMatchHint::InNextSiblingSubtree
519 | RelativeSelectorMatchHint::InSibling
520 | RelativeSelectorMatchHint::InSiblingSubtree
521 ),
522 "Not descendant direction, but also not sibling direction?"
523 );
524 if context.needs_selector_flags() {
525 element.apply_selector_flags(
526 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
527 );
528 }
529 let sibling_flag = if relative_selector.match_hint.is_subtree() {
530 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING
531 } else {
532 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING
533 };
534 let mut next_element = element.next_sibling_element();
535 while let Some(el) = next_element {
536 if context.needs_selector_flags() {
537 el.apply_selector_flags(sibling_flag);
538 }
539 let matched = if relative_selector.match_hint.is_subtree() {
540 matches_relative_selector_subtree(
541 &relative_selector.selector,
542 &el,
543 context,
544 rightmost,
545 )
546 } else {
547 matches_complex_selector(relative_selector.selector.iter(), &el, context, rightmost)
548 .to_bool(true)
549 };
550 if matched {
551 return true;
552 }
553 if relative_selector.match_hint.is_next_sibling() {
554 break;
555 }
556 next_element = el.next_sibling_element();
557 }
558 }
559 return false;
560}
561
562fn relative_selector_match_early<E: Element>(
563 selector: &RelativeSelector<E::Impl>,
564 element: &E,
565 context: &mut MatchingContext<E::Impl>,
566) -> Option<bool> {
567 if let Some(cached) = context
569 .selector_caches
570 .relative_selector
571 .lookup(element.opaque(), selector)
572 {
573 return Some(cached.matched());
574 }
575 if context
577 .selector_caches
578 .relative_selector_filter_map
579 .fast_reject(element, selector, context.quirks_mode())
580 {
581 context.selector_caches.relative_selector.add(
583 element.opaque(),
584 selector,
585 RelativeSelectorCachedMatch::NotMatched,
586 );
587 return Some(false);
588 }
589 None
590}
591
592fn match_relative_selectors<E: Element>(
593 selectors: &[RelativeSelector<E::Impl>],
594 element: &E,
595 context: &mut MatchingContext<E::Impl>,
596 rightmost: SubjectOrPseudoElement,
597) -> KleeneValue {
598 if context.relative_selector_anchor().is_some() {
599 return KleeneValue::False;
605 }
606 if let Some(may_return_unknown) = context.matching_for_invalidation_comparison() {
607 return if may_return_unknown {
611 KleeneValue::Unknown
612 } else {
613 KleeneValue::from(!context.in_negation())
614 };
615 }
616 context
617 .nest_for_relative_selector(element.opaque(), |context| {
618 do_match_relative_selectors(selectors, element, context, rightmost)
619 })
620 .into()
621}
622
623fn do_match_relative_selectors<E: Element>(
625 selectors: &[RelativeSelector<E::Impl>],
626 element: &E,
627 context: &mut MatchingContext<E::Impl>,
628 rightmost: SubjectOrPseudoElement,
629) -> bool {
630 if rightmost == SubjectOrPseudoElement::Yes {
634 if context.needs_selector_flags() {
635 element.apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR);
636 }
637 } else {
638 if context.needs_selector_flags() {
639 element
640 .apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT);
641 }
642 }
643
644 for relative_selector in selectors.iter() {
645 if let Some(result) = relative_selector_match_early(relative_selector, element, context) {
646 if result {
647 return true;
648 }
649 continue;
651 }
652
653 let matched = matches_relative_selector(relative_selector, element, context, rightmost);
654 context.selector_caches.relative_selector.add(
655 element.opaque(),
656 relative_selector,
657 if matched {
658 RelativeSelectorCachedMatch::Matched
659 } else {
660 RelativeSelectorCachedMatch::NotMatched
661 },
662 );
663 if matched {
664 return true;
665 }
666 }
667
668 false
669}
670
671fn matches_relative_selector_subtree<E: Element>(
672 selector: &Selector<E::Impl>,
673 element: &E,
674 context: &mut MatchingContext<E::Impl>,
675 rightmost: SubjectOrPseudoElement,
676) -> bool {
677 let mut current = element.first_element_child();
678
679 while let Some(el) = current {
680 if context.needs_selector_flags() {
681 el.apply_selector_flags(
682 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
683 );
684 }
685 if matches_complex_selector(selector.iter(), &el, context, rightmost).to_bool(true) {
686 return true;
687 }
688
689 if matches_relative_selector_subtree(selector, &el, context, rightmost) {
690 return true;
691 }
692
693 current = el.next_sibling_element();
694 }
695
696 false
697}
698
699fn hover_and_active_quirk_applies<Impl: SelectorImpl>(
703 selector_iter: &SelectorIter<Impl>,
704 context: &MatchingContext<Impl>,
705 rightmost: SubjectOrPseudoElement,
706) -> bool {
707 debug_assert_eq!(context.quirks_mode(), QuirksMode::Quirks);
708
709 if context.is_nested() {
710 return false;
711 }
712
713 if rightmost == SubjectOrPseudoElement::Yes
716 && context.matching_mode() == MatchingMode::ForStatelessPseudoElement
717 {
718 return false;
719 }
720
721 selector_iter.clone().all(|simple| match *simple {
722 Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
723 _ => false,
724 })
725}
726
727#[derive(Clone, Copy, PartialEq)]
728enum SubjectOrPseudoElement {
729 Yes,
730 No,
731}
732
733fn host_for_part<E>(element: &E, context: &MatchingContext<E::Impl>) -> Option<E>
734where
735 E: Element,
736{
737 let scope = context.current_host;
738 let mut curr = element.containing_shadow_host()?;
739 if scope == Some(curr.opaque()) {
740 return Some(curr);
741 }
742 loop {
743 let parent = curr.containing_shadow_host();
744 if parent.as_ref().map(|h| h.opaque()) == scope {
745 return Some(curr);
746 }
747 curr = parent?;
748 }
749}
750
751fn assigned_slot<E>(element: &E, context: &MatchingContext<E::Impl>) -> Option<E>
752where
753 E: Element,
754{
755 debug_assert!(element
756 .assigned_slot()
757 .map_or(true, |s| s.is_html_slot_element()));
758 let scope = context.current_host?;
759 let mut current_slot = element.assigned_slot()?;
760 while current_slot.containing_shadow_host().unwrap().opaque() != scope {
761 current_slot = current_slot.assigned_slot()?;
762 }
763 Some(current_slot)
764}
765
766struct NextElement<E> {
767 next_element: Option<E>,
768 featureless: bool,
769}
770
771impl<E> NextElement<E> {
772 #[inline(always)]
773 fn new(next_element: Option<E>, featureless: bool) -> Self {
774 Self {
775 next_element,
776 featureless,
777 }
778 }
779}
780
781#[inline(always)]
782fn next_element_for_combinator<E>(
783 element: &E,
784 combinator: Combinator,
785 context: &MatchingContext<E::Impl>,
786) -> NextElement<E>
787where
788 E: Element,
789{
790 match combinator {
791 Combinator::NextSibling | Combinator::LaterSibling => {
792 NextElement::new(element.prev_sibling_element(), false)
793 },
794 Combinator::Child | Combinator::Descendant => {
795 if let Some(parent) = element.parent_element() {
796 return NextElement::new(Some(parent), false);
797 }
798
799 let element = if element.parent_node_is_shadow_root() {
800 element.containing_shadow_host()
801 } else {
802 None
803 };
804 NextElement::new(element, true)
805 },
806 Combinator::Part => NextElement::new(host_for_part(element, context), false),
807 Combinator::SlotAssignment => NextElement::new(assigned_slot(element, context), false),
808 Combinator::PseudoElement => {
809 NextElement::new(element.pseudo_element_originating_element(), false)
810 },
811 }
812}
813
814fn matches_complex_selector_internal<E>(
815 mut selector_iter: SelectorIter<E::Impl>,
816 element: &E,
817 context: &mut MatchingContext<E::Impl>,
818 mut rightmost: SubjectOrPseudoElement,
819 mut first_subject_compound: SubjectOrPseudoElement,
820) -> SelectorMatchingResult
821where
822 E: Element,
823{
824 debug!(
825 "Matching complex selector {:?} for {:?}",
826 selector_iter, element
827 );
828
829 let matches_compound_selector =
830 matches_compound_selector(&mut selector_iter, element, context, rightmost);
831
832 let Some(combinator) = selector_iter.next_sequence() else {
833 return match matches_compound_selector {
834 KleeneValue::True => SelectorMatchingResult::Matched,
835 KleeneValue::Unknown => SelectorMatchingResult::Unknown,
836 KleeneValue::False => {
837 SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling
838 },
839 };
840 };
841
842 let is_pseudo_combinator = combinator.is_pseudo_element();
843 if context.featureless() && !is_pseudo_combinator {
844 return SelectorMatchingResult::NotMatchedGlobally;
847 }
848
849 let is_sibling_combinator = combinator.is_sibling();
850 if is_sibling_combinator && context.needs_selector_flags() {
851 element.apply_selector_flags(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS);
853 }
854
855 if matches_compound_selector == KleeneValue::False {
856 return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
859 }
860
861 if !is_pseudo_combinator {
862 rightmost = SubjectOrPseudoElement::No;
863 first_subject_compound = SubjectOrPseudoElement::No;
864 }
865
866 let mut visited_handling = if is_sibling_combinator {
869 VisitedHandlingMode::AllLinksUnvisited
870 } else {
871 context.visited_handling()
872 };
873
874 let candidate_not_found = if is_sibling_combinator {
875 SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
876 } else {
877 SelectorMatchingResult::NotMatchedGlobally
878 };
879
880 let mut element = element.clone();
881 loop {
882 if element.is_link() {
883 visited_handling = VisitedHandlingMode::AllLinksUnvisited;
884 }
885
886 let NextElement {
887 next_element,
888 featureless,
889 } = next_element_for_combinator(&element, combinator, &context);
890 element = match next_element {
891 None => return candidate_not_found,
892 Some(e) => e,
893 };
894
895 let result = context.with_visited_handling_mode(visited_handling, |context| {
896 context.with_featureless(featureless, |context| {
897 matches_complex_selector_internal(
898 selector_iter.clone(),
899 &element,
900 context,
901 rightmost,
902 first_subject_compound,
903 )
904 })
905 });
906
907 match result {
909 SelectorMatchingResult::Matched => {
910 debug_assert!(
911 matches_compound_selector.to_bool(true),
912 "Compound didn't match?"
913 );
914 if !matches_compound_selector.to_bool(false) {
915 return SelectorMatchingResult::Unknown;
916 }
917 return result;
918 },
919 SelectorMatchingResult::Unknown | SelectorMatchingResult::NotMatchedGlobally => {
920 return result
921 },
922 _ => {},
923 }
924
925 match combinator {
926 Combinator::Descendant => {
927 },
933 Combinator::Child => {
934 return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant;
936 },
937 Combinator::LaterSibling => {
938 if matches!(
942 result,
943 SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
944 ) {
945 return result;
946 }
947 },
948 Combinator::NextSibling
949 | Combinator::PseudoElement
950 | Combinator::Part
951 | Combinator::SlotAssignment => {
952 return result;
957 },
958 }
959
960 if featureless {
961 return candidate_not_found;
964 }
965 }
966}
967
968#[inline]
969fn matches_local_name<E>(element: &E, local_name: &LocalName<E::Impl>) -> bool
970where
971 E: Element,
972{
973 let name = select_name(element, &local_name.name, &local_name.lower_name).borrow();
974 element.has_local_name(name)
975}
976
977fn matches_part<E>(
978 element: &E,
979 parts: &[<E::Impl as SelectorImpl>::Identifier],
980 context: &mut MatchingContext<E::Impl>,
981) -> bool
982where
983 E: Element,
984{
985 let mut hosts = SmallVec::<[E; 4]>::new();
986
987 let mut host = match element.containing_shadow_host() {
988 Some(h) => h,
989 None => return false,
990 };
991
992 let current_host = context.current_host;
993 if current_host != Some(host.opaque()) {
994 loop {
995 let outer_host = host.containing_shadow_host();
996 if outer_host.as_ref().map(|h| h.opaque()) == current_host {
997 break;
998 }
999 let outer_host = match outer_host {
1000 Some(h) => h,
1001 None => return false,
1002 };
1003 hosts.push(host);
1006 host = outer_host;
1007 }
1008 }
1009
1010 parts.iter().all(|part| {
1012 let mut part = part.clone();
1013 for host in hosts.iter().rev() {
1014 part = match host.imported_part(&part) {
1015 Some(p) => p,
1016 None => return false,
1017 };
1018 }
1019 element.is_part(&part)
1020 })
1021}
1022
1023fn matches_host<E>(
1024 element: &E,
1025 selector: Option<&Selector<E::Impl>>,
1026 context: &mut MatchingContext<E::Impl>,
1027 rightmost: SubjectOrPseudoElement,
1028) -> KleeneValue
1029where
1030 E: Element,
1031{
1032 let host = match context.shadow_host() {
1033 Some(h) => h,
1034 None => return KleeneValue::False,
1035 };
1036 if host != element.opaque() {
1037 return KleeneValue::False;
1038 }
1039 let Some(selector) = selector else {
1040 return KleeneValue::True;
1041 };
1042 context.nest(|context| {
1043 context.with_featureless(false, |context| {
1044 matches_complex_selector(selector.iter(), element, context, rightmost)
1045 })
1046 })
1047}
1048
1049fn matches_slotted<E>(
1050 element: &E,
1051 selector: &Selector<E::Impl>,
1052 context: &mut MatchingContext<E::Impl>,
1053 rightmost: SubjectOrPseudoElement,
1054) -> KleeneValue
1055where
1056 E: Element,
1057{
1058 if element.is_html_slot_element() {
1060 return KleeneValue::False;
1061 }
1062 context.nest(|context| matches_complex_selector(selector.iter(), element, context, rightmost))
1063}
1064
1065fn matches_rare_attribute_selector<E>(
1066 element: &E,
1067 attr_sel: &AttrSelectorWithOptionalNamespace<E::Impl>,
1068) -> bool
1069where
1070 E: Element,
1071{
1072 let empty_string;
1073 let namespace = match attr_sel.namespace() {
1074 Some(ns) => ns,
1075 None => {
1076 empty_string = crate::parser::namespace_empty_string::<E::Impl>();
1077 NamespaceConstraint::Specific(&empty_string)
1078 },
1079 };
1080 element.attr_matches(
1081 &namespace,
1082 select_name(element, &attr_sel.local_name, &attr_sel.local_name_lower),
1083 &match attr_sel.operation {
1084 ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
1085 ParsedAttrSelectorOperation::WithValue {
1086 operator,
1087 case_sensitivity,
1088 ref value,
1089 } => AttrSelectorOperation::WithValue {
1090 operator,
1091 case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element),
1092 value,
1093 },
1094 },
1095 )
1096}
1097
1098pub(crate) fn compound_matches_featureless_host<Impl: SelectorImpl>(
1102 iter: &mut SelectorIter<Impl>,
1103 scope_matches_featureless_host: bool,
1104) -> MatchesFeaturelessHost {
1105 let mut matches = MatchesFeaturelessHost::Only;
1106 for component in iter {
1107 match component {
1108 Component::Scope | Component::ImplicitScope if scope_matches_featureless_host => {},
1109 Component::Host(..) => {},
1111 Component::PseudoElement(..) => {},
1113 Component::Is(ref l) | Component::Where(ref l) => {
1116 let mut any_yes = false;
1117 let mut any_no = false;
1118 for selector in l.slice() {
1119 match selector.matches_featureless_host(scope_matches_featureless_host) {
1120 MatchesFeaturelessHost::Never => {
1121 any_no = true;
1122 },
1123 MatchesFeaturelessHost::Yes => {
1124 any_yes = true;
1125 any_no = true;
1126 },
1127 MatchesFeaturelessHost::Only => {
1128 any_yes = true;
1129 },
1130 }
1131 }
1132 if !any_yes {
1133 return MatchesFeaturelessHost::Never;
1134 }
1135 if any_no {
1136 matches = MatchesFeaturelessHost::Yes;
1138 }
1139 },
1140 Component::Negation(ref l) => {
1141 for selector in l.slice() {
1145 if selector.matches_featureless_host(scope_matches_featureless_host)
1146 != MatchesFeaturelessHost::Only
1147 {
1148 return MatchesFeaturelessHost::Never;
1149 }
1150 }
1151 },
1152 _ => return MatchesFeaturelessHost::Never,
1154 }
1155 }
1156 matches
1157}
1158
1159#[inline]
1161fn matches_compound_selector<E>(
1162 selector_iter: &mut SelectorIter<E::Impl>,
1163 element: &E,
1164 context: &mut MatchingContext<E::Impl>,
1165 rightmost: SubjectOrPseudoElement,
1166) -> KleeneValue
1167where
1168 E: Element,
1169{
1170 if context.featureless()
1171 && compound_matches_featureless_host(
1172 &mut selector_iter.clone(),
1173 true,
1174 ) == MatchesFeaturelessHost::Never
1175 {
1176 return KleeneValue::False;
1177 }
1178 let quirks_data = if context.quirks_mode() == QuirksMode::Quirks {
1179 Some(selector_iter.clone())
1180 } else {
1181 None
1182 };
1183 let mut local_context = LocalMatchingContext {
1184 shared: context,
1185 rightmost,
1186 quirks_data,
1187 };
1188 KleeneValue::any_false(selector_iter, |simple| {
1189 matches_simple_selector(simple, element, &mut local_context)
1190 })
1191}
1192
1193fn matches_simple_selector<E>(
1195 selector: &Component<E::Impl>,
1196 element: &E,
1197 context: &mut LocalMatchingContext<E::Impl>,
1198) -> KleeneValue
1199where
1200 E: Element,
1201{
1202 debug_assert!(context.shared.is_nested() || !context.shared.in_negation());
1203 let rightmost = context.rightmost;
1204 KleeneValue::from(match *selector {
1205 Component::ID(ref id) => {
1206 element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
1207 },
1208 Component::Class(ref class) => {
1209 element.has_class(class, context.shared.classes_and_ids_case_sensitivity())
1210 },
1211 Component::LocalName(ref local_name) => matches_local_name(element, local_name),
1212 Component::AttributeInNoNamespaceExists {
1213 ref local_name,
1214 ref local_name_lower,
1215 } => element.has_attr_in_no_namespace(select_name(element, local_name, local_name_lower)),
1216 Component::AttributeInNoNamespace {
1217 ref local_name,
1218 ref value,
1219 operator,
1220 case_sensitivity,
1221 } => element.attr_matches(
1222 &NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::<E::Impl>()),
1223 local_name,
1224 &AttrSelectorOperation::WithValue {
1225 operator,
1226 case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element),
1227 value,
1228 },
1229 ),
1230 Component::AttributeOther(ref attr_sel) => {
1231 matches_rare_attribute_selector(element, attr_sel)
1232 },
1233 Component::Part(ref parts) => matches_part(element, parts, &mut context.shared),
1234 Component::Slotted(ref selector) => {
1235 return matches_slotted(element, selector, &mut context.shared, rightmost);
1236 },
1237 Component::PseudoElement(ref pseudo) => {
1238 element.match_pseudo_element(pseudo, context.shared)
1239 },
1240 Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
1241 Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
1242 element.has_namespace(&url.borrow())
1243 },
1244 Component::ExplicitNoNamespace => {
1245 let ns = crate::parser::namespace_empty_string::<E::Impl>();
1246 element.has_namespace(&ns.borrow())
1247 },
1248 Component::NonTSPseudoClass(ref pc) => {
1249 if let Some(ref iter) = context.quirks_data {
1250 if pc.is_active_or_hover()
1251 && !element.is_link()
1252 && hover_and_active_quirk_applies(iter, context.shared, context.rightmost)
1253 {
1254 return KleeneValue::False;
1255 }
1256 }
1257 element.match_non_ts_pseudo_class(pc, &mut context.shared)
1258 },
1259 Component::Root => element.is_root(),
1260 Component::Empty => {
1261 if context.shared.needs_selector_flags() {
1262 element.apply_selector_flags(ElementSelectorFlags::HAS_EMPTY_SELECTOR);
1263 }
1264 element.is_empty()
1265 },
1266 Component::Host(ref selector) => {
1267 return matches_host(element, selector.as_ref(), &mut context.shared, rightmost);
1268 },
1269 Component::ParentSelector => match context.shared.scope_element {
1270 Some(ref scope_element) => element.opaque() == *scope_element,
1271 None => element.is_root(),
1272 },
1273 Component::Scope | Component::ImplicitScope => {
1274 if let Some(may_return_unknown) = context.shared.matching_for_invalidation_comparison()
1275 {
1276 return if may_return_unknown {
1277 KleeneValue::Unknown
1278 } else {
1279 KleeneValue::from(!context.shared.in_negation())
1280 };
1281 } else {
1282 match context.shared.scope_element {
1283 Some(ref scope_element) => element.opaque() == *scope_element,
1284 None => element.is_root(),
1285 }
1286 }
1287 },
1288 Component::Nth(ref nth_data) => {
1289 return matches_generic_nth_child(element, context.shared, nth_data, &[], rightmost);
1290 },
1291 Component::NthOf(ref nth_of_data) => {
1292 return context.shared.nest(|context| {
1293 matches_generic_nth_child(
1294 element,
1295 context,
1296 nth_of_data.nth_data(),
1297 nth_of_data.selectors(),
1298 rightmost,
1299 )
1300 })
1301 },
1302 Component::Is(ref list) | Component::Where(ref list) => {
1303 return context.shared.nest(|context| {
1304 matches_complex_selector_list(list.slice(), element, context, rightmost)
1305 })
1306 },
1307 Component::Negation(ref list) => {
1308 return context.shared.nest_for_negation(|context| {
1309 !matches_complex_selector_list(list.slice(), element, context, rightmost)
1310 })
1311 },
1312 Component::Has(ref relative_selectors) => {
1313 return match_relative_selectors(
1314 relative_selectors,
1315 element,
1316 context.shared,
1317 rightmost,
1318 );
1319 },
1320 Component::Combinator(_) => unsafe {
1321 debug_unreachable!("Shouldn't try to selector-match combinators")
1322 },
1323 Component::RelativeSelectorAnchor => {
1324 let anchor = context.shared.relative_selector_anchor();
1325 anchor.map_or(true, |a| a == element.opaque())
1327 },
1328 Component::Invalid(..) => false,
1329 })
1330}
1331
1332#[inline(always)]
1333pub fn select_name<'a, E: Element, T: PartialEq>(
1334 element: &E,
1335 local_name: &'a T,
1336 local_name_lower: &'a T,
1337) -> &'a T {
1338 if local_name == local_name_lower || element.is_html_element_in_html_document() {
1339 local_name_lower
1340 } else {
1341 local_name
1342 }
1343}
1344
1345#[inline(always)]
1346pub fn to_unconditional_case_sensitivity<'a, E: Element>(
1347 parsed: ParsedCaseSensitivity,
1348 element: &E,
1349) -> CaseSensitivity {
1350 match parsed {
1351 ParsedCaseSensitivity::CaseSensitive | ParsedCaseSensitivity::ExplicitCaseSensitive => {
1352 CaseSensitivity::CaseSensitive
1353 },
1354 ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
1355 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
1356 if element.is_html_element_in_html_document() {
1357 CaseSensitivity::AsciiCaseInsensitive
1358 } else {
1359 CaseSensitivity::CaseSensitive
1360 }
1361 },
1362 }
1363}
1364
1365fn matches_generic_nth_child<E>(
1366 element: &E,
1367 context: &mut MatchingContext<E::Impl>,
1368 nth_data: &NthSelectorData,
1369 selectors: &[Selector<E::Impl>],
1370 rightmost: SubjectOrPseudoElement,
1371) -> KleeneValue
1372where
1373 E: Element,
1374{
1375 if element.ignores_nth_child_selectors() {
1376 return KleeneValue::False;
1377 }
1378 let has_selectors = !selectors.is_empty();
1379 let selectors_match = !has_selectors
1380 || matches_complex_selector_list(selectors, element, context, rightmost).to_bool(true);
1381 if let Some(may_return_unknown) = context.matching_for_invalidation_comparison() {
1382 return if selectors_match && may_return_unknown {
1384 KleeneValue::Unknown
1385 } else {
1386 KleeneValue::from(selectors_match && !context.in_negation())
1387 };
1388 }
1389
1390 let NthSelectorData { ty, an_plus_b, .. } = *nth_data;
1391 let is_of_type = ty.is_of_type();
1392 if ty.is_only() {
1393 debug_assert!(
1394 !has_selectors,
1395 ":only-child and :only-of-type cannot have a selector list!"
1396 );
1397 return KleeneValue::from(
1398 matches_generic_nth_child(
1399 element,
1400 context,
1401 &NthSelectorData::first(is_of_type),
1402 selectors,
1403 rightmost,
1404 )
1405 .to_bool(true)
1406 && matches_generic_nth_child(
1407 element,
1408 context,
1409 &NthSelectorData::last(is_of_type),
1410 selectors,
1411 rightmost,
1412 )
1413 .to_bool(true),
1414 );
1415 }
1416
1417 let is_from_end = ty.is_from_end();
1418
1419 let is_edge_child_selector = nth_data.is_simple_edge() && !has_selectors;
1422
1423 if context.needs_selector_flags() {
1424 let mut flags = if is_edge_child_selector {
1425 ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR
1426 } else if is_from_end {
1427 ElementSelectorFlags::HAS_SLOW_SELECTOR
1428 } else {
1429 ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
1430 };
1431 flags |= if has_selectors {
1432 ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF
1433 } else {
1434 ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH
1435 };
1436 element.apply_selector_flags(flags);
1437 }
1438
1439 if !selectors_match {
1440 return KleeneValue::False;
1441 }
1442
1443 if is_edge_child_selector {
1446 return if is_from_end {
1447 element.next_sibling_element()
1448 } else {
1449 element.prev_sibling_element()
1450 }
1451 .is_none()
1452 .into();
1453 }
1454
1455 let index = if let Some(i) = context
1457 .nth_index_cache(is_of_type, is_from_end, selectors)
1458 .lookup(element.opaque())
1459 {
1460 i
1461 } else {
1462 let i = nth_child_index(
1463 element,
1464 context,
1465 selectors,
1466 is_of_type,
1467 is_from_end,
1468 true,
1469 rightmost,
1470 );
1471 context
1472 .nth_index_cache(is_of_type, is_from_end, selectors)
1473 .insert(element.opaque(), i);
1474 i
1475 };
1476 debug_assert_eq!(
1477 index,
1478 nth_child_index(
1479 element,
1480 context,
1481 selectors,
1482 is_of_type,
1483 is_from_end,
1484 false,
1485 rightmost,
1486 ),
1487 "invalid cache"
1488 );
1489
1490 an_plus_b.matches_index(index).into()
1491}
1492
1493#[inline]
1494fn nth_child_index<E>(
1495 element: &E,
1496 context: &mut MatchingContext<E::Impl>,
1497 selectors: &[Selector<E::Impl>],
1498 is_of_type: bool,
1499 is_from_end: bool,
1500 check_cache: bool,
1501 rightmost: SubjectOrPseudoElement,
1502) -> i32
1503where
1504 E: Element,
1505{
1506 if check_cache
1513 && is_from_end
1514 && !context
1515 .nth_index_cache(is_of_type, is_from_end, selectors)
1516 .is_empty()
1517 {
1518 let mut index: i32 = 1;
1519 let mut curr = element.clone();
1520 while let Some(e) = curr.prev_sibling_element() {
1521 curr = e;
1522 let matches = if is_of_type {
1523 element.is_same_type(&curr)
1524 } else if !selectors.is_empty() {
1525 matches_complex_selector_list(selectors, &curr, context, rightmost).to_bool(true)
1526 } else {
1527 true
1528 };
1529 if !matches {
1530 continue;
1531 }
1532 if let Some(i) = context
1533 .nth_index_cache(is_of_type, is_from_end, selectors)
1534 .lookup(curr.opaque())
1535 {
1536 return i - index;
1537 }
1538 index += 1;
1539 }
1540 }
1541
1542 let mut index: i32 = 1;
1543 let mut curr = element.clone();
1544 let next = |e: E| {
1545 if is_from_end {
1546 e.next_sibling_element()
1547 } else {
1548 e.prev_sibling_element()
1549 }
1550 };
1551 while let Some(e) = next(curr) {
1552 curr = e;
1553 let matches = if is_of_type {
1554 element.is_same_type(&curr)
1555 } else if !selectors.is_empty() {
1556 matches_complex_selector_list(selectors, &curr, context, rightmost).to_bool(true)
1557 } else {
1558 true
1559 };
1560 if !matches {
1561 continue;
1562 }
1563 if !is_from_end && check_cache {
1567 if let Some(i) = context
1568 .nth_index_cache(is_of_type, is_from_end, selectors)
1569 .lookup(curr.opaque())
1570 {
1571 return i + index;
1572 }
1573 }
1574 index += 1;
1575 }
1576
1577 index
1578}