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
321fn complex_selector_early_reject_by_local_name<E: Element>(
322 list: &SelectorList<E::Impl>,
323 element: &E,
324) -> bool {
325 list.slice()
326 .iter()
327 .all(|s| early_reject_by_local_name(s, 0, element))
328}
329
330pub fn early_reject_by_local_name<E: Element>(
333 selector: &Selector<E::Impl>,
334 from_offset: usize,
335 element: &E,
336) -> bool {
337 let iter = selector.iter_from(from_offset);
338 for component in iter {
339 if match component {
340 Component::LocalName(name) => !matches_local_name(element, name),
341 Component::Is(list) | Component::Where(list) => {
342 complex_selector_early_reject_by_local_name(list, element)
343 },
344 _ => continue,
345 } {
346 return true;
347 }
348 }
349 false
350}
351
352pub fn matches_compound_selector_from<E>(
360 selector: &Selector<E::Impl>,
361 mut from_offset: usize,
362 context: &mut MatchingContext<E::Impl>,
363 element: &E,
364) -> CompoundSelectorMatchingResult
365where
366 E: Element,
367{
368 debug_assert!(
369 !context
370 .matching_for_invalidation_comparison()
371 .unwrap_or(false),
372 "CompoundSelectorMatchingResult doesn't support unknown"
373 );
374 if cfg!(debug_assertions) && from_offset != 0 {
375 selector.combinator_at_parse_order(from_offset - 1); }
377
378 let mut local_context = LocalMatchingContext {
379 shared: context,
380 rightmost: SubjectOrPseudoElement::No,
384 quirks_data: None,
385 };
386
387 let start_offset = from_offset;
391 for component in selector.iter_raw_parse_order_from(from_offset) {
392 if matches!(*component, Component::Combinator(..)) {
393 debug_assert_ne!(from_offset, 0, "Selector started with a combinator?");
394 break;
395 }
396
397 from_offset += 1;
398 }
399
400 debug_assert!(from_offset >= 1);
401 debug_assert!(from_offset <= selector.len());
402
403 let iter = selector.iter_from(selector.len() - from_offset);
404 debug_assert!(
405 iter.clone().next().is_some() || from_offset != selector.len(),
406 "Got the math wrong: {:?} | {:?} | {} {}",
407 selector,
408 selector.iter_raw_match_order().as_slice(),
409 from_offset,
410 start_offset
411 );
412
413 debug_assert!(
414 !local_context.shared.featureless(),
415 "Invalidating featureless element somehow?"
416 );
417
418 for component in iter {
419 let result = matches_simple_selector(component, element, &mut local_context);
420 debug_assert!(
421 result != KleeneValue::Unknown,
422 "Returned unknown in non invalidation context?"
423 );
424 if !result.to_bool(true) {
425 return CompoundSelectorMatchingResult::NotMatched;
426 }
427 }
428
429 if from_offset != selector.len() {
430 return CompoundSelectorMatchingResult::Matched {
431 next_combinator_offset: from_offset,
432 };
433 }
434
435 CompoundSelectorMatchingResult::FullyMatched
436}
437
438#[inline(always)]
440fn matches_complex_selector<E>(
441 mut iter: SelectorIter<E::Impl>,
442 element: &E,
443 context: &mut MatchingContext<E::Impl>,
444 rightmost: SubjectOrPseudoElement,
445) -> KleeneValue
446where
447 E: Element,
448{
449 if context.matching_mode() == MatchingMode::ForStatelessPseudoElement && !context.is_nested() {
452 match *iter.next().unwrap() {
454 Component::PseudoElement(ref pseudo) => {
455 if let Some(ref f) = context.pseudo_element_matching_fn {
456 if !f(pseudo) {
457 return KleeneValue::False;
458 }
459 }
460 },
461 ref other => {
462 debug_assert!(
463 false,
464 "Used MatchingMode::ForStatelessPseudoElement \
465 in a non-pseudo selector {:?}",
466 other
467 );
468 return KleeneValue::False;
469 },
470 }
471
472 if !iter.matches_for_stateless_pseudo_element() {
473 return KleeneValue::False;
474 }
475
476 let next_sequence = iter.next_sequence().unwrap();
478 debug_assert_eq!(next_sequence, Combinator::PseudoElement);
479 }
480
481 matches_complex_selector_internal(
482 iter,
483 element,
484 context,
485 rightmost,
486 SubjectOrPseudoElement::Yes,
487 )
488 .into()
489}
490
491fn matches_complex_selector_list<E: Element>(
493 list: &[Selector<E::Impl>],
494 element: &E,
495 context: &mut MatchingContext<E::Impl>,
496 rightmost: SubjectOrPseudoElement,
497) -> KleeneValue {
498 KleeneValue::any(list.iter(), |selector| {
499 matches_complex_selector(selector.iter(), element, context, rightmost)
500 })
501}
502
503fn matches_relative_selector<E: Element>(
504 relative_selector: &RelativeSelector<E::Impl>,
505 element: &E,
506 context: &mut MatchingContext<E::Impl>,
507 rightmost: SubjectOrPseudoElement,
508) -> bool {
509 if relative_selector.match_hint.is_descendant_direction() {
512 if context.needs_selector_flags() {
513 element.apply_selector_flags(
514 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
515 );
516 }
517 let mut next_element = element.first_element_child();
518 while let Some(el) = next_element {
519 if context.needs_selector_flags() {
520 el.apply_selector_flags(
521 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
522 );
523 }
524 let mut matched = matches_complex_selector(
525 relative_selector.selector.iter(),
526 &el,
527 context,
528 rightmost,
529 )
530 .to_bool(true);
531 if !matched && relative_selector.match_hint.is_subtree() {
532 matched = matches_relative_selector_subtree(
533 &relative_selector.selector,
534 &el,
535 context,
536 rightmost,
537 );
538 }
539 if matched {
540 return true;
541 }
542 next_element = el.next_sibling_element();
543 }
544 } else {
545 debug_assert!(
546 matches!(
547 relative_selector.match_hint,
548 RelativeSelectorMatchHint::InNextSibling
549 | RelativeSelectorMatchHint::InNextSiblingSubtree
550 | RelativeSelectorMatchHint::InSibling
551 | RelativeSelectorMatchHint::InSiblingSubtree
552 ),
553 "Not descendant direction, but also not sibling direction?"
554 );
555 if context.needs_selector_flags() {
556 element.apply_selector_flags(
557 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
558 );
559 }
560 let sibling_flag = if relative_selector.match_hint.is_subtree() {
561 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING
562 } else {
563 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING
564 };
565 let mut next_element = element.next_sibling_element();
566 while let Some(el) = next_element {
567 if context.needs_selector_flags() {
568 el.apply_selector_flags(sibling_flag);
569 }
570 let matched = if relative_selector.match_hint.is_subtree() {
571 matches_relative_selector_subtree(
572 &relative_selector.selector,
573 &el,
574 context,
575 rightmost,
576 )
577 } else {
578 matches_complex_selector(relative_selector.selector.iter(), &el, context, rightmost)
579 .to_bool(true)
580 };
581 if matched {
582 return true;
583 }
584 if relative_selector.match_hint.is_next_sibling() {
585 break;
586 }
587 next_element = el.next_sibling_element();
588 }
589 }
590 return false;
591}
592
593fn relative_selector_match_early<E: Element>(
594 selector: &RelativeSelector<E::Impl>,
595 element: &E,
596 context: &mut MatchingContext<E::Impl>,
597) -> Option<bool> {
598 if let Some(cached) = context
600 .selector_caches
601 .relative_selector
602 .lookup(element.opaque(), selector)
603 {
604 return Some(cached.matched());
605 }
606 if context
608 .selector_caches
609 .relative_selector_filter_map
610 .fast_reject(element, selector, context.quirks_mode())
611 {
612 context.selector_caches.relative_selector.add(
614 element.opaque(),
615 selector,
616 RelativeSelectorCachedMatch::NotMatched,
617 );
618 return Some(false);
619 }
620 None
621}
622
623fn match_relative_selectors<E: Element>(
624 selectors: &[RelativeSelector<E::Impl>],
625 element: &E,
626 context: &mut MatchingContext<E::Impl>,
627 rightmost: SubjectOrPseudoElement,
628) -> KleeneValue {
629 if context.relative_selector_anchor().is_some() {
630 return KleeneValue::False;
636 }
637 if let Some(may_return_unknown) = context.matching_for_invalidation_comparison() {
638 return if may_return_unknown {
642 KleeneValue::Unknown
643 } else {
644 KleeneValue::from(!context.in_negation())
645 };
646 }
647 context
648 .nest_for_relative_selector(element.opaque(), |context| {
649 do_match_relative_selectors(selectors, element, context, rightmost)
650 })
651 .into()
652}
653
654fn do_match_relative_selectors<E: Element>(
656 selectors: &[RelativeSelector<E::Impl>],
657 element: &E,
658 context: &mut MatchingContext<E::Impl>,
659 rightmost: SubjectOrPseudoElement,
660) -> bool {
661 if rightmost == SubjectOrPseudoElement::Yes {
665 if context.needs_selector_flags() {
666 element.apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR);
667 }
668 } else {
669 if context.needs_selector_flags() {
670 element
671 .apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT);
672 }
673 }
674
675 for relative_selector in selectors.iter() {
676 if let Some(result) = relative_selector_match_early(relative_selector, element, context) {
677 if result {
678 return true;
679 }
680 continue;
682 }
683
684 let matched = matches_relative_selector(relative_selector, element, context, rightmost);
685 context.selector_caches.relative_selector.add(
686 element.opaque(),
687 relative_selector,
688 if matched {
689 RelativeSelectorCachedMatch::Matched
690 } else {
691 RelativeSelectorCachedMatch::NotMatched
692 },
693 );
694 if matched {
695 return true;
696 }
697 }
698
699 false
700}
701
702fn matches_relative_selector_subtree<E: Element>(
703 selector: &Selector<E::Impl>,
704 element: &E,
705 context: &mut MatchingContext<E::Impl>,
706 rightmost: SubjectOrPseudoElement,
707) -> bool {
708 let mut current = element.first_element_child();
709
710 while let Some(el) = current {
711 if context.needs_selector_flags() {
712 el.apply_selector_flags(
713 ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
714 );
715 }
716 if matches_complex_selector(selector.iter(), &el, context, rightmost).to_bool(true) {
717 return true;
718 }
719
720 if matches_relative_selector_subtree(selector, &el, context, rightmost) {
721 return true;
722 }
723
724 current = el.next_sibling_element();
725 }
726
727 false
728}
729
730fn hover_and_active_quirk_applies<Impl: SelectorImpl>(
734 selector_iter: &SelectorIter<Impl>,
735 context: &MatchingContext<Impl>,
736 rightmost: SubjectOrPseudoElement,
737) -> bool {
738 debug_assert_eq!(context.quirks_mode(), QuirksMode::Quirks);
739
740 if context.is_nested() {
741 return false;
742 }
743
744 if rightmost == SubjectOrPseudoElement::Yes
747 && context.matching_mode() == MatchingMode::ForStatelessPseudoElement
748 {
749 return false;
750 }
751
752 selector_iter.clone().all(|simple| match *simple {
753 Component::NonTSPseudoClass(ref pseudo_class) => pseudo_class.is_active_or_hover(),
754 _ => false,
755 })
756}
757
758#[derive(Clone, Copy, PartialEq)]
759enum SubjectOrPseudoElement {
760 Yes,
761 No,
762}
763
764fn host_for_part<E>(element: &E, context: &MatchingContext<E::Impl>) -> Option<E>
765where
766 E: Element,
767{
768 let scope = context.current_host;
769 let mut curr = element.containing_shadow_host()?;
770 if scope == Some(curr.opaque()) {
771 return Some(curr);
772 }
773 loop {
774 let parent = curr.containing_shadow_host();
775 if parent.as_ref().map(|h| h.opaque()) == scope {
776 return Some(curr);
777 }
778 curr = parent?;
779 }
780}
781
782fn assigned_slot<E>(element: &E, context: &MatchingContext<E::Impl>) -> Option<E>
783where
784 E: Element,
785{
786 debug_assert!(element
787 .assigned_slot()
788 .map_or(true, |s| s.is_html_slot_element()));
789 let scope = context.current_host?;
790 let mut current_slot = element.assigned_slot()?;
791 while current_slot.containing_shadow_host().unwrap().opaque() != scope {
792 current_slot = current_slot.assigned_slot()?;
793 }
794 Some(current_slot)
795}
796
797struct NextElement<E> {
798 next_element: Option<E>,
799 featureless: bool,
800}
801
802impl<E> NextElement<E> {
803 #[inline(always)]
804 fn new(next_element: Option<E>, featureless: bool) -> Self {
805 Self {
806 next_element,
807 featureless,
808 }
809 }
810}
811
812#[inline(always)]
813fn next_element_for_combinator<E>(
814 element: &E,
815 combinator: Combinator,
816 context: &MatchingContext<E::Impl>,
817) -> NextElement<E>
818where
819 E: Element,
820{
821 match combinator {
822 Combinator::NextSibling | Combinator::LaterSibling => {
823 NextElement::new(element.prev_sibling_element(), false)
824 },
825 Combinator::Child | Combinator::Descendant => {
826 if let Some(parent) = element.parent_element() {
827 return NextElement::new(Some(parent), false);
828 }
829
830 let element = if element.parent_node_is_shadow_root() {
831 element.containing_shadow_host()
832 } else {
833 None
834 };
835 NextElement::new(element, true)
836 },
837 Combinator::Part => NextElement::new(host_for_part(element, context), false),
838 Combinator::SlotAssignment => NextElement::new(assigned_slot(element, context), false),
839 Combinator::PseudoElement => {
840 NextElement::new(element.pseudo_element_originating_element(), false)
841 },
842 }
843}
844
845fn matches_complex_selector_internal<E>(
846 mut selector_iter: SelectorIter<E::Impl>,
847 element: &E,
848 context: &mut MatchingContext<E::Impl>,
849 mut rightmost: SubjectOrPseudoElement,
850 mut first_subject_compound: SubjectOrPseudoElement,
851) -> SelectorMatchingResult
852where
853 E: Element,
854{
855 debug!(
856 "Matching complex selector {:?} for {:?}",
857 selector_iter, element
858 );
859
860 let matches_compound_selector =
861 matches_compound_selector(&mut selector_iter, element, context, rightmost);
862
863 let Some(combinator) = selector_iter.next_sequence() else {
864 return match matches_compound_selector {
865 KleeneValue::True => SelectorMatchingResult::Matched,
866 KleeneValue::Unknown => SelectorMatchingResult::Unknown,
867 KleeneValue::False => {
868 SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling
869 },
870 };
871 };
872
873 let is_pseudo_combinator = combinator.is_pseudo_element();
874 if context.featureless() && !is_pseudo_combinator {
875 return SelectorMatchingResult::NotMatchedGlobally;
878 }
879
880 let is_sibling_combinator = combinator.is_sibling();
881 if is_sibling_combinator && context.needs_selector_flags() {
882 element.apply_selector_flags(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS);
884 }
885
886 if matches_compound_selector == KleeneValue::False {
887 return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
890 }
891
892 if !is_pseudo_combinator {
893 rightmost = SubjectOrPseudoElement::No;
894 first_subject_compound = SubjectOrPseudoElement::No;
895 }
896
897 let mut visited_handling = if is_sibling_combinator {
900 VisitedHandlingMode::AllLinksUnvisited
901 } else {
902 context.visited_handling()
903 };
904
905 let candidate_not_found = if is_sibling_combinator {
906 SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
907 } else {
908 SelectorMatchingResult::NotMatchedGlobally
909 };
910
911 let mut element = element.clone();
912 loop {
913 if element.is_link() {
914 visited_handling = VisitedHandlingMode::AllLinksUnvisited;
915 }
916
917 let NextElement {
918 next_element,
919 featureless,
920 } = next_element_for_combinator(&element, combinator, &context);
921 element = match next_element {
922 None => return candidate_not_found,
923 Some(e) => e,
924 };
925
926 let result = context.with_visited_handling_mode(visited_handling, |context| {
927 context.with_featureless(featureless, |context| {
928 matches_complex_selector_internal(
929 selector_iter.clone(),
930 &element,
931 context,
932 rightmost,
933 first_subject_compound,
934 )
935 })
936 });
937
938 match result {
940 SelectorMatchingResult::Matched => {
941 debug_assert!(
942 matches_compound_selector.to_bool(true),
943 "Compound didn't match?"
944 );
945 if !matches_compound_selector.to_bool(false) {
946 return SelectorMatchingResult::Unknown;
947 }
948 return result;
949 },
950 SelectorMatchingResult::Unknown | SelectorMatchingResult::NotMatchedGlobally => {
951 return result
952 },
953 _ => {},
954 }
955
956 match combinator {
957 Combinator::Descendant => {
958 },
964 Combinator::Child => {
965 return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant;
967 },
968 Combinator::LaterSibling => {
969 if matches!(
973 result,
974 SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
975 ) {
976 return result;
977 }
978 },
979 Combinator::NextSibling
980 | Combinator::PseudoElement
981 | Combinator::Part
982 | Combinator::SlotAssignment => {
983 return result;
988 },
989 }
990
991 if featureless {
992 return candidate_not_found;
995 }
996 }
997}
998
999#[inline]
1000fn matches_local_name<E>(element: &E, local_name: &LocalName<E::Impl>) -> bool
1001where
1002 E: Element,
1003{
1004 let name = select_name(element, &local_name.name, &local_name.lower_name).borrow();
1005 element.has_local_name(name)
1006}
1007
1008fn matches_part<E>(
1009 element: &E,
1010 parts: &[<E::Impl as SelectorImpl>::Identifier],
1011 context: &mut MatchingContext<E::Impl>,
1012) -> bool
1013where
1014 E: Element,
1015{
1016 let mut hosts = SmallVec::<[E; 4]>::new();
1017
1018 let mut host = match element.containing_shadow_host() {
1019 Some(h) => h,
1020 None => return false,
1021 };
1022
1023 let current_host = context.current_host;
1024 if current_host != Some(host.opaque()) {
1025 loop {
1026 let outer_host = host.containing_shadow_host();
1027 if outer_host.as_ref().map(|h| h.opaque()) == current_host {
1028 break;
1029 }
1030 let outer_host = match outer_host {
1031 Some(h) => h,
1032 None => return false,
1033 };
1034 hosts.push(host);
1037 host = outer_host;
1038 }
1039 }
1040
1041 parts.iter().all(|part| {
1043 let mut part = part.clone();
1044 for host in hosts.iter().rev() {
1045 part = match host.imported_part(&part) {
1046 Some(p) => p,
1047 None => return false,
1048 };
1049 }
1050 element.is_part(&part)
1051 })
1052}
1053
1054fn matches_host<E>(
1055 element: &E,
1056 selector: Option<&Selector<E::Impl>>,
1057 context: &mut MatchingContext<E::Impl>,
1058 rightmost: SubjectOrPseudoElement,
1059) -> KleeneValue
1060where
1061 E: Element,
1062{
1063 let host = match context.shadow_host() {
1064 Some(h) => h,
1065 None => return KleeneValue::False,
1066 };
1067 if host != element.opaque() {
1068 return KleeneValue::False;
1069 }
1070 let Some(selector) = selector else {
1071 return KleeneValue::True;
1072 };
1073 context.nest(|context| {
1074 context.with_featureless(false, |context| {
1075 matches_complex_selector(selector.iter(), element, context, rightmost)
1076 })
1077 })
1078}
1079
1080fn matches_slotted<E>(
1081 element: &E,
1082 selector: &Selector<E::Impl>,
1083 context: &mut MatchingContext<E::Impl>,
1084 rightmost: SubjectOrPseudoElement,
1085) -> KleeneValue
1086where
1087 E: Element,
1088{
1089 if element.is_html_slot_element() {
1091 return KleeneValue::False;
1092 }
1093 context.nest(|context| matches_complex_selector(selector.iter(), element, context, rightmost))
1094}
1095
1096fn matches_rare_attribute_selector<E>(
1097 element: &E,
1098 attr_sel: &AttrSelectorWithOptionalNamespace<E::Impl>,
1099) -> bool
1100where
1101 E: Element,
1102{
1103 let empty_string;
1104 let namespace = match attr_sel.namespace() {
1105 Some(ns) => ns,
1106 None => {
1107 empty_string = crate::parser::namespace_empty_string::<E::Impl>();
1108 NamespaceConstraint::Specific(&empty_string)
1109 },
1110 };
1111 element.attr_matches(
1112 &namespace,
1113 select_name(element, &attr_sel.local_name, &attr_sel.local_name_lower),
1114 &match attr_sel.operation {
1115 ParsedAttrSelectorOperation::Exists => AttrSelectorOperation::Exists,
1116 ParsedAttrSelectorOperation::WithValue {
1117 operator,
1118 case_sensitivity,
1119 ref value,
1120 } => AttrSelectorOperation::WithValue {
1121 operator,
1122 case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element),
1123 value,
1124 },
1125 },
1126 )
1127}
1128
1129pub(crate) fn compound_matches_featureless_host<Impl: SelectorImpl>(
1133 iter: &mut SelectorIter<Impl>,
1134 scope_matches_featureless_host: bool,
1135) -> MatchesFeaturelessHost {
1136 let mut matches = MatchesFeaturelessHost::Only;
1137 for component in iter {
1138 match component {
1139 Component::Scope | Component::ImplicitScope if scope_matches_featureless_host => {},
1140 Component::Host(..) => {},
1142 Component::PseudoElement(..) => {},
1144 Component::Is(ref l) | Component::Where(ref l) => {
1147 let mut any_yes = false;
1148 let mut any_no = false;
1149 for selector in l.slice() {
1150 match selector.matches_featureless_host(scope_matches_featureless_host) {
1151 MatchesFeaturelessHost::Never => {
1152 any_no = true;
1153 },
1154 MatchesFeaturelessHost::Yes => {
1155 any_yes = true;
1156 any_no = true;
1157 },
1158 MatchesFeaturelessHost::Only => {
1159 any_yes = true;
1160 },
1161 }
1162 }
1163 if !any_yes {
1164 return MatchesFeaturelessHost::Never;
1165 }
1166 if any_no {
1167 matches = MatchesFeaturelessHost::Yes;
1169 }
1170 },
1171 Component::Negation(ref l) => {
1172 for selector in l.slice() {
1176 if selector.matches_featureless_host(scope_matches_featureless_host)
1177 != MatchesFeaturelessHost::Only
1178 {
1179 return MatchesFeaturelessHost::Never;
1180 }
1181 }
1182 },
1183 _ => return MatchesFeaturelessHost::Never,
1185 }
1186 }
1187 matches
1188}
1189
1190#[inline]
1192fn matches_compound_selector<E>(
1193 selector_iter: &mut SelectorIter<E::Impl>,
1194 element: &E,
1195 context: &mut MatchingContext<E::Impl>,
1196 rightmost: SubjectOrPseudoElement,
1197) -> KleeneValue
1198where
1199 E: Element,
1200{
1201 if context.featureless()
1202 && compound_matches_featureless_host(
1203 &mut selector_iter.clone(),
1204 true,
1205 ) == MatchesFeaturelessHost::Never
1206 {
1207 return KleeneValue::False;
1208 }
1209 let quirks_data = if context.quirks_mode() == QuirksMode::Quirks {
1210 Some(selector_iter.clone())
1211 } else {
1212 None
1213 };
1214 let mut local_context = LocalMatchingContext {
1215 shared: context,
1216 rightmost,
1217 quirks_data,
1218 };
1219 KleeneValue::any_false(selector_iter, |simple| {
1220 matches_simple_selector(simple, element, &mut local_context)
1221 })
1222}
1223
1224fn matches_simple_selector<E>(
1226 selector: &Component<E::Impl>,
1227 element: &E,
1228 context: &mut LocalMatchingContext<E::Impl>,
1229) -> KleeneValue
1230where
1231 E: Element,
1232{
1233 debug_assert!(context.shared.is_nested() || !context.shared.in_negation());
1234 let rightmost = context.rightmost;
1235 KleeneValue::from(match *selector {
1236 Component::ID(ref id) => {
1237 element.has_id(id, context.shared.classes_and_ids_case_sensitivity())
1238 },
1239 Component::Class(ref class) => {
1240 element.has_class(class, context.shared.classes_and_ids_case_sensitivity())
1241 },
1242 Component::LocalName(ref local_name) => matches_local_name(element, local_name),
1243 Component::AttributeInNoNamespaceExists {
1244 ref local_name,
1245 ref local_name_lower,
1246 } => element.has_attr_in_no_namespace(select_name(element, local_name, local_name_lower)),
1247 Component::AttributeInNoNamespace {
1248 ref local_name,
1249 ref value,
1250 operator,
1251 case_sensitivity,
1252 } => element.attr_matches(
1253 &NamespaceConstraint::Specific(&crate::parser::namespace_empty_string::<E::Impl>()),
1254 local_name,
1255 &AttrSelectorOperation::WithValue {
1256 operator,
1257 case_sensitivity: to_unconditional_case_sensitivity(case_sensitivity, element),
1258 value,
1259 },
1260 ),
1261 Component::AttributeOther(ref attr_sel) => {
1262 matches_rare_attribute_selector(element, attr_sel)
1263 },
1264 Component::Part(ref parts) => matches_part(element, parts, &mut context.shared),
1265 Component::Slotted(ref selector) => {
1266 return matches_slotted(element, selector, &mut context.shared, rightmost);
1267 },
1268 Component::PseudoElement(ref pseudo) => {
1269 element.match_pseudo_element(pseudo, context.shared)
1270 },
1271 Component::ExplicitUniversalType | Component::ExplicitAnyNamespace => true,
1272 Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
1273 element.has_namespace(&url.borrow())
1274 },
1275 Component::ExplicitNoNamespace => {
1276 let ns = crate::parser::namespace_empty_string::<E::Impl>();
1277 element.has_namespace(&ns.borrow())
1278 },
1279 Component::NonTSPseudoClass(ref pc) => {
1280 if let Some(ref iter) = context.quirks_data {
1281 if pc.is_active_or_hover()
1282 && !element.is_link()
1283 && hover_and_active_quirk_applies(iter, context.shared, context.rightmost)
1284 {
1285 return KleeneValue::False;
1286 }
1287 }
1288 element.match_non_ts_pseudo_class(pc, &mut context.shared)
1289 },
1290 Component::Root => element.is_root(),
1291 Component::Empty => {
1292 if context.shared.needs_selector_flags() {
1293 element.apply_selector_flags(ElementSelectorFlags::HAS_EMPTY_SELECTOR);
1294 }
1295 element.is_empty()
1296 },
1297 Component::Host(ref selector) => {
1298 return matches_host(element, selector.as_ref(), &mut context.shared, rightmost);
1299 },
1300 Component::ParentSelector => match context.shared.scope_element {
1301 Some(ref scope_element) => element.opaque() == *scope_element,
1302 None => element.is_root(),
1303 },
1304 Component::Scope | Component::ImplicitScope => {
1305 if let Some(may_return_unknown) = context.shared.matching_for_invalidation_comparison()
1306 {
1307 return if may_return_unknown {
1308 KleeneValue::Unknown
1309 } else {
1310 KleeneValue::from(!context.shared.in_negation())
1311 };
1312 } else {
1313 match context.shared.scope_element {
1314 Some(ref scope_element) => element.opaque() == *scope_element,
1315 None => element.is_root(),
1316 }
1317 }
1318 },
1319 Component::Nth(ref nth_data) => {
1320 return matches_generic_nth_child(element, context.shared, nth_data, &[], rightmost);
1321 },
1322 Component::NthOf(ref nth_of_data) => {
1323 return context.shared.nest(|context| {
1324 matches_generic_nth_child(
1325 element,
1326 context,
1327 nth_of_data.nth_data(),
1328 nth_of_data.selectors(),
1329 rightmost,
1330 )
1331 })
1332 },
1333 Component::Is(ref list) | Component::Where(ref list) => {
1334 return context.shared.nest(|context| {
1335 matches_complex_selector_list(list.slice(), element, context, rightmost)
1336 })
1337 },
1338 Component::Negation(ref list) => {
1339 return context.shared.nest_for_negation(|context| {
1340 !matches_complex_selector_list(list.slice(), element, context, rightmost)
1341 })
1342 },
1343 Component::Has(ref relative_selectors) => {
1344 return match_relative_selectors(
1345 relative_selectors,
1346 element,
1347 context.shared,
1348 rightmost,
1349 );
1350 },
1351 Component::Combinator(_) => unsafe {
1352 debug_unreachable!("Shouldn't try to selector-match combinators")
1353 },
1354 Component::RelativeSelectorAnchor => {
1355 let anchor = context.shared.relative_selector_anchor();
1356 anchor.map_or(true, |a| a == element.opaque())
1358 },
1359 Component::Invalid(..) => false,
1360 })
1361}
1362
1363#[inline(always)]
1364pub fn select_name<'a, E: Element, T: PartialEq>(
1365 element: &E,
1366 local_name: &'a T,
1367 local_name_lower: &'a T,
1368) -> &'a T {
1369 if local_name == local_name_lower || element.is_html_element_in_html_document() {
1370 local_name_lower
1371 } else {
1372 local_name
1373 }
1374}
1375
1376#[inline(always)]
1377pub fn to_unconditional_case_sensitivity<'a, E: Element>(
1378 parsed: ParsedCaseSensitivity,
1379 element: &E,
1380) -> CaseSensitivity {
1381 match parsed {
1382 ParsedCaseSensitivity::CaseSensitive | ParsedCaseSensitivity::ExplicitCaseSensitive => {
1383 CaseSensitivity::CaseSensitive
1384 },
1385 ParsedCaseSensitivity::AsciiCaseInsensitive => CaseSensitivity::AsciiCaseInsensitive,
1386 ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument => {
1387 if element.is_html_element_in_html_document() {
1388 CaseSensitivity::AsciiCaseInsensitive
1389 } else {
1390 CaseSensitivity::CaseSensitive
1391 }
1392 },
1393 }
1394}
1395
1396fn matches_generic_nth_child<E>(
1397 element: &E,
1398 context: &mut MatchingContext<E::Impl>,
1399 nth_data: &NthSelectorData,
1400 selectors: &[Selector<E::Impl>],
1401 rightmost: SubjectOrPseudoElement,
1402) -> KleeneValue
1403where
1404 E: Element,
1405{
1406 if element.ignores_nth_child_selectors() {
1407 return KleeneValue::False;
1408 }
1409 let has_selectors = !selectors.is_empty();
1410 let selectors_match = !has_selectors
1411 || matches_complex_selector_list(selectors, element, context, rightmost).to_bool(true);
1412 if let Some(may_return_unknown) = context.matching_for_invalidation_comparison() {
1413 return if selectors_match && may_return_unknown {
1415 KleeneValue::Unknown
1416 } else {
1417 KleeneValue::from(selectors_match && !context.in_negation())
1418 };
1419 }
1420
1421 let NthSelectorData { ty, an_plus_b, .. } = *nth_data;
1422 let is_of_type = ty.is_of_type();
1423 if ty.is_only() {
1424 debug_assert!(
1425 !has_selectors,
1426 ":only-child and :only-of-type cannot have a selector list!"
1427 );
1428 return KleeneValue::from(
1429 matches_generic_nth_child(
1430 element,
1431 context,
1432 &NthSelectorData::first(is_of_type),
1433 selectors,
1434 rightmost,
1435 )
1436 .to_bool(true)
1437 && matches_generic_nth_child(
1438 element,
1439 context,
1440 &NthSelectorData::last(is_of_type),
1441 selectors,
1442 rightmost,
1443 )
1444 .to_bool(true),
1445 );
1446 }
1447
1448 let is_from_end = ty.is_from_end();
1449
1450 let is_edge_child_selector = nth_data.is_simple_edge() && !has_selectors;
1453
1454 if context.needs_selector_flags() {
1455 let mut flags = if is_edge_child_selector {
1456 ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR
1457 } else if is_from_end {
1458 ElementSelectorFlags::HAS_SLOW_SELECTOR
1459 } else {
1460 ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS
1461 };
1462 flags |= if has_selectors {
1463 ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF
1464 } else {
1465 ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH
1466 };
1467 element.apply_selector_flags(flags);
1468 }
1469
1470 if !selectors_match {
1471 return KleeneValue::False;
1472 }
1473
1474 if is_edge_child_selector {
1477 return if is_from_end {
1478 element.next_sibling_element()
1479 } else {
1480 element.prev_sibling_element()
1481 }
1482 .is_none()
1483 .into();
1484 }
1485
1486 let index = if let Some(i) = context
1488 .nth_index_cache(is_of_type, is_from_end, selectors)
1489 .lookup(element.opaque())
1490 {
1491 i
1492 } else {
1493 let i = nth_child_index(
1494 element,
1495 context,
1496 selectors,
1497 is_of_type,
1498 is_from_end,
1499 true,
1500 rightmost,
1501 );
1502 context
1503 .nth_index_cache(is_of_type, is_from_end, selectors)
1504 .insert(element.opaque(), i);
1505 i
1506 };
1507 debug_assert_eq!(
1508 index,
1509 nth_child_index(
1510 element,
1511 context,
1512 selectors,
1513 is_of_type,
1514 is_from_end,
1515 false,
1516 rightmost,
1517 ),
1518 "invalid cache"
1519 );
1520
1521 an_plus_b.matches_index(index).into()
1522}
1523
1524#[inline]
1525fn nth_child_index<E>(
1526 element: &E,
1527 context: &mut MatchingContext<E::Impl>,
1528 selectors: &[Selector<E::Impl>],
1529 is_of_type: bool,
1530 is_from_end: bool,
1531 check_cache: bool,
1532 rightmost: SubjectOrPseudoElement,
1533) -> i32
1534where
1535 E: Element,
1536{
1537 if check_cache
1544 && is_from_end
1545 && !context
1546 .nth_index_cache(is_of_type, is_from_end, selectors)
1547 .is_empty()
1548 {
1549 let mut index: i32 = 1;
1550 let mut curr = element.clone();
1551 while let Some(e) = curr.prev_sibling_element() {
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 let Some(i) = context
1564 .nth_index_cache(is_of_type, is_from_end, selectors)
1565 .lookup(curr.opaque())
1566 {
1567 return i - index;
1568 }
1569 index += 1;
1570 }
1571 }
1572
1573 let mut index: i32 = 1;
1574 let mut curr = element.clone();
1575 let next = |e: E| {
1576 if is_from_end {
1577 e.next_sibling_element()
1578 } else {
1579 e.prev_sibling_element()
1580 }
1581 };
1582 while let Some(e) = next(curr) {
1583 curr = e;
1584 let matches = if is_of_type {
1585 element.is_same_type(&curr)
1586 } else if !selectors.is_empty() {
1587 matches_complex_selector_list(selectors, &curr, context, rightmost).to_bool(true)
1588 } else {
1589 true
1590 };
1591 if !matches {
1592 continue;
1593 }
1594 if !is_from_end && check_cache {
1598 if let Some(i) = context
1599 .nth_index_cache(is_of_type, is_from_end, selectors)
1600 .lookup(curr.opaque())
1601 {
1602 return i + index;
1603 }
1604 }
1605 index += 1;
1606 }
1607
1608 index
1609}