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