1use crate::bloom::AtomExt as _;
9use crate::context::QuirksMode;
10use crate::dom::{TDocument, TElement, TNode, TShadowRoot};
11use crate::invalidation::element::invalidation_map::Dependency;
12use crate::invalidation::element::invalidator::{
13 DescendantInvalidationLists, Invalidation, SiblingTraversalMap,
14};
15use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
16use crate::selector_parser::SelectorImpl;
17use crate::values::AtomIdent;
18use selectors::attr::CaseSensitivity;
19use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
20use selectors::matching::{
21 self, MatchingContext, MatchingForInvalidation, MatchingMode, NeedsSelectorFlags,
22 SelectorCaches,
23};
24use selectors::parser::{Combinator, Component, LocalName};
25use selectors::{Element, OpaqueElement, SelectorList};
26use smallvec::SmallVec;
27
28pub fn element_matches<E>(
30 element: &E,
31 selector_list: &SelectorList<E::Impl>,
32 quirks_mode: QuirksMode,
33) -> bool
34where
35 E: Element,
36{
37 let mut selector_caches = SelectorCaches::default();
38
39 let mut context = MatchingContext::new(
40 MatchingMode::Normal,
41 None,
42 &mut selector_caches,
43 quirks_mode,
44 NeedsSelectorFlags::No,
45 MatchingForInvalidation::No,
46 );
47 context.scope_element = Some(element.opaque());
48 context.current_host = element.containing_shadow_host().map(|e| e.opaque());
49 matching::matches_selector_list(selector_list, element, &mut context)
50}
51
52pub fn element_closest<E>(
54 element: E,
55 selector_list: &SelectorList<E::Impl>,
56 quirks_mode: QuirksMode,
57) -> Option<E>
58where
59 E: Element,
60{
61 let mut selector_caches = SelectorCaches::default();
62
63 let mut context = MatchingContext::new(
64 MatchingMode::Normal,
65 None,
66 &mut selector_caches,
67 quirks_mode,
68 NeedsSelectorFlags::No,
69 MatchingForInvalidation::No,
70 );
71 context.scope_element = Some(element.opaque());
72 context.current_host = element.containing_shadow_host().map(|e| e.opaque());
73
74 let mut current = Some(element);
75 while let Some(element) = current.take() {
76 if matching::matches_selector_list(selector_list, &element, &mut context) {
77 return Some(element);
78 }
79 current = element.parent_element();
80 }
81
82 None
83}
84
85pub trait SelectorQuery<E: TElement> {
88 type Output;
90
91 fn should_stop_after_first_match() -> bool;
93
94 fn append_element(output: &mut Self::Output, element: E);
96
97 fn is_empty(output: &Self::Output) -> bool;
99}
100
101pub type QuerySelectorAllResult<E> = SmallVec<[E; 128]>;
103
104pub struct QueryAll;
106
107impl<E: TElement> SelectorQuery<E> for QueryAll {
108 type Output = QuerySelectorAllResult<E>;
109
110 fn should_stop_after_first_match() -> bool {
111 false
112 }
113
114 fn append_element(output: &mut Self::Output, element: E) {
115 output.push(element);
116 }
117
118 fn is_empty(output: &Self::Output) -> bool {
119 output.is_empty()
120 }
121}
122
123pub struct QueryFirst;
125
126impl<E: TElement> SelectorQuery<E> for QueryFirst {
127 type Output = Option<E>;
128
129 fn should_stop_after_first_match() -> bool {
130 true
131 }
132
133 fn append_element(output: &mut Self::Output, element: E) {
134 if output.is_none() {
135 *output = Some(element)
136 }
137 }
138
139 fn is_empty(output: &Self::Output) -> bool {
140 output.is_none()
141 }
142}
143
144struct QuerySelectorProcessor<'a, 'b, E, Q>
145where
146 E: TElement + 'a,
147 Q: SelectorQuery<E>,
148 Q::Output: 'a,
149{
150 results: &'a mut Q::Output,
151 matching_context: MatchingContext<'b, E::Impl>,
152 traversal_map: SiblingTraversalMap<E>,
153 dependencies: &'a [Dependency],
154}
155
156impl<'a, 'b, E, Q> InvalidationProcessor<'a, 'b, E> for QuerySelectorProcessor<'a, 'b, E, Q>
157where
158 E: TElement + 'a,
159 Q: SelectorQuery<E>,
160 Q::Output: 'a,
161{
162 fn light_tree_only(&self) -> bool {
163 true
164 }
165
166 fn check_outer_dependency(&mut self, _: &Dependency, _: E, _: Option<OpaqueElement>) -> bool {
167 debug_assert!(
168 false,
169 "How? We should only have parent-less dependencies here!"
170 );
171 true
172 }
173
174 fn collect_invalidations(
175 &mut self,
176 element: E,
177 self_invalidations: &mut InvalidationVector<'a>,
178 descendant_invalidations: &mut DescendantInvalidationLists<'a>,
179 _sibling_invalidations: &mut InvalidationVector<'a>,
180 ) -> bool {
181 debug_assert!(element.parent_element().is_none());
195
196 let target_vector = if self.matching_context.scope_element.is_some() {
197 &mut descendant_invalidations.dom_descendants
198 } else {
199 self_invalidations
200 };
201
202 for dependency in self.dependencies.iter() {
203 target_vector.push(Invalidation::new(
204 dependency,
205 self.matching_context.current_host,
206 self.matching_context.scope_element,
207 ))
208 }
209
210 false
211 }
212
213 fn matching_context(&mut self) -> &mut MatchingContext<'b, E::Impl> {
214 &mut self.matching_context
215 }
216
217 fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> {
218 &self.traversal_map
219 }
220
221 fn should_process_descendants(&mut self, _: E) -> bool {
222 if Q::should_stop_after_first_match() {
223 return Q::is_empty(self.results);
224 }
225
226 true
227 }
228
229 fn invalidated_self(&mut self, e: E) {
230 Q::append_element(self.results, e);
231 }
232
233 fn invalidated_sibling(&mut self, e: E, _of: E) {
234 Q::append_element(self.results, e);
235 }
236
237 fn recursion_limit_exceeded(&mut self, _e: E) {}
238 fn invalidated_descendants(&mut self, _e: E, _child: E) {}
239}
240
241enum Operation {
242 Reject,
243 Accept,
244 RejectSkippingChildren,
245}
246
247impl From<bool> for Operation {
248 #[inline(always)]
249 fn from(matches: bool) -> Self {
250 if matches {
251 Operation::Accept
252 } else {
253 Operation::Reject
254 }
255 }
256}
257
258fn collect_all_elements<E, Q, F>(root: E::ConcreteNode, results: &mut Q::Output, mut filter: F)
259where
260 E: TElement,
261 Q: SelectorQuery<E>,
262 F: FnMut(E) -> Operation,
263{
264 let mut iter = root.dom_descendants();
265 let mut cur = iter.next();
266 while let Some(node) = cur {
267 let element = match node.as_element() {
268 Some(e) => e,
269 None => {
270 cur = iter.next();
271 continue;
272 },
273 };
274 match filter(element) {
275 Operation::Accept => {
277 Q::append_element(results, element);
278 if Q::should_stop_after_first_match() {
279 return;
280 }
281 },
282 Operation::Reject => {},
284 Operation::RejectSkippingChildren => {
286 cur = iter.next_skipping_children();
287 continue;
288 },
289 }
290 cur = iter.next();
291 }
292}
293
294fn connected_element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
298where
299 E: TElement,
300{
301 if root.as_document().is_some() {
304 debug_assert!(element.as_node().is_in_document(), "Not connected?");
305 debug_assert_eq!(
306 root,
307 root.owner_doc().as_node(),
308 "Where did this element come from?",
309 );
310 return true;
311 }
312
313 if root.as_shadow_root().is_some() {
314 debug_assert_eq!(
315 element.containing_shadow().unwrap().as_node(),
316 root,
317 "Not connected?"
318 );
319 return true;
320 }
321
322 let mut current = element.as_node().parent_node();
323 while let Some(n) = current.take() {
324 if n == root {
325 return true;
326 }
327
328 current = n.parent_node();
329 }
330 false
331}
332
333fn fast_connected_elements_with_id<'a, N>(
336 root: N,
337 id: &AtomIdent,
338 case_sensitivity: CaseSensitivity,
339) -> Result<&'a [N::ConcreteElement], ()>
340where
341 N: TNode + 'a,
342{
343 if case_sensitivity != CaseSensitivity::CaseSensitive {
344 return Err(());
345 }
346
347 if root.is_in_document() {
348 return root.owner_doc().elements_with_id(id);
349 }
350
351 if let Some(shadow) = root.as_shadow_root() {
352 return shadow.elements_with_id(id);
353 }
354
355 if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) {
356 return shadow.elements_with_id(id);
357 }
358
359 Err(())
360}
361
362fn collect_elements_with_id<E, Q, F>(
364 root: E::ConcreteNode,
365 id: &AtomIdent,
366 results: &mut Q::Output,
367 class_and_id_case_sensitivity: CaseSensitivity,
368 mut filter: F,
369) where
370 E: TElement,
371 Q: SelectorQuery<E>,
372 F: FnMut(E) -> bool,
373{
374 let elements = match fast_connected_elements_with_id(root, id, class_and_id_case_sensitivity) {
375 Ok(elements) => elements,
376 Err(()) => {
377 collect_all_elements::<E, Q, _>(root, results, |e| {
378 Operation::from(e.has_id(id, class_and_id_case_sensitivity) && filter(e))
379 });
380
381 return;
382 },
383 };
384
385 for element in elements {
386 if !connected_element_is_descendant_of(*element, root) {
389 continue;
390 }
391
392 if !filter(*element) {
393 continue;
394 }
395
396 Q::append_element(results, *element);
397 if Q::should_stop_after_first_match() {
398 break;
399 }
400 }
401}
402
403fn get_attr_name(component: &Component<SelectorImpl>) -> Option<&crate::LocalName> {
404 let (name, name_lower) = match component {
405 Component::AttributeInNoNamespace { local_name, .. } => return Some(local_name),
406 Component::AttributeInNoNamespaceExists {
407 local_name,
408 local_name_lower,
409 ..
410 } => (local_name, local_name_lower),
411 Component::AttributeOther(attr) => {
412 if attr.namespace.is_some() {
413 return None;
414 }
415 (&attr.local_name, &attr.local_name_lower)
416 },
417 _ => return None,
418 };
419 if name != name_lower {
420 return None; }
422 Some(name)
423}
424
425fn get_id(component: &Component<SelectorImpl>) -> Option<&AtomIdent> {
426 use selectors::attr::AttrSelectorOperator;
427 Some(match component {
428 Component::ID(id) => id,
429 Component::AttributeInNoNamespace {
430 operator,
431 local_name,
432 value,
433 ..
434 } => {
435 if *local_name != local_name!("id") {
436 return None;
437 }
438 if *operator != AttrSelectorOperator::Equal {
439 return None;
440 }
441 AtomIdent::cast(&value.0)
442 },
443 _ => return None,
444 })
445}
446
447fn query_selector_single_query<E, Q>(
449 root: E::ConcreteNode,
450 component: &Component<E::Impl>,
451 results: &mut Q::Output,
452 class_and_id_case_sensitivity: CaseSensitivity,
453) -> Result<(), ()>
454where
455 E: TElement,
456 Q: SelectorQuery<E>,
457{
458 match *component {
459 Component::ExplicitUniversalType => {
460 collect_all_elements::<E, Q, _>(root, results, |_| Operation::Accept)
461 },
462 Component::Class(ref class) => {
463 let bloom_hash = if class_and_id_case_sensitivity == CaseSensitivity::CaseSensitive {
465 Some(E::hash_for_bloom_filter(class.0.get_hash32()))
466 } else {
467 None
468 };
469
470 collect_all_elements::<E, Q, _>(root, results, |element| {
471 if bloom_hash.is_some_and(|hash| !element.bloom_may_have_hash(hash)) {
472 return Operation::RejectSkippingChildren;
473 }
474 Operation::from(element.has_class(class, class_and_id_case_sensitivity))
475 });
476 },
477 Component::LocalName(ref local_name) => {
478 let hash = E::hash_for_bloom_filter(local_name.name.0.get_hash32());
479 let hash_lower = if local_name.name == local_name.lower_name {
480 hash
481 } else {
482 E::hash_for_bloom_filter(local_name.lower_name.0.get_hash32())
483 };
484 collect_all_elements::<E, Q, _>(root, results, |element| {
485 if !element.bloom_may_have_hash(hash)
486 && (hash == hash_lower || !element.bloom_may_have_hash(hash_lower))
487 {
488 return Operation::RejectSkippingChildren;
489 }
490 Operation::from(
491 *element.local_name()
492 == ***matching::select_name(
493 &element,
494 &local_name.name,
495 &local_name.lower_name,
496 ),
497 )
498 })
499 },
500 Component::AttributeInNoNamespaceExists {
501 ref local_name,
502 ref local_name_lower,
503 } => {
504 let hash_original = E::hash_for_bloom_filter(local_name.0.get_hash32());
507 let hash_lower = if local_name.0 == local_name_lower.0 {
508 hash_original
509 } else {
510 E::hash_for_bloom_filter(local_name_lower.0.get_hash32())
511 };
512
513 collect_all_elements::<E, Q, _>(root, results, |element| {
514 let bloom_found_hash = if hash_original == hash_lower
516 || !element.as_node().owner_doc().is_html_document()
517 {
518 element.bloom_may_have_hash(hash_original)
519 } else if element.is_html_element_in_html_document() {
520 element.bloom_may_have_hash(hash_lower)
522 } else {
523 element.bloom_may_have_hash(hash_original)
526 || element.bloom_may_have_hash(hash_lower)
527 };
528
529 if !bloom_found_hash {
530 return Operation::RejectSkippingChildren;
531 }
532
533 Operation::from(element.has_attr_in_no_namespace(matching::select_name(
534 &element,
535 local_name,
536 local_name_lower,
537 )))
538 });
539 },
540 Component::AttributeInNoNamespace {
541 ref local_name,
542 ref value,
543 operator,
544 case_sensitivity,
545 } => {
546 let empty_namespace = selectors::parser::namespace_empty_string::<E::Impl>();
547 let namespace_constraint = NamespaceConstraint::Specific(&empty_namespace);
548
549 let bloom_hash = E::hash_for_bloom_filter(local_name.0.get_hash32());
551
552 collect_all_elements::<E, Q, _>(root, results, |element| {
553 if !element.bloom_may_have_hash(bloom_hash) {
554 return Operation::RejectSkippingChildren;
555 }
556 Operation::from(element.attr_matches(
557 &namespace_constraint,
558 local_name,
559 &AttrSelectorOperation::WithValue {
560 operator,
561 case_sensitivity: matching::to_unconditional_case_sensitivity(
562 case_sensitivity,
563 &element,
564 ),
565 value,
566 },
567 ))
568 });
569 },
570 ref other => {
571 let id = match get_id(other) {
572 Some(id) => id,
573 None => return Err(()),
575 };
576 collect_elements_with_id::<E, Q, _>(
577 root,
578 id,
579 results,
580 class_and_id_case_sensitivity,
581 |_| true,
582 );
583 },
584 }
585
586 Ok(())
587}
588
589enum SimpleFilter<'a> {
590 Class(&'a AtomIdent),
591 Attr(&'a crate::LocalName),
592 LocalName(&'a LocalName<SelectorImpl>),
593}
594
595fn query_selector_fast<E, Q>(
605 root: E::ConcreteNode,
606 selector_list: &SelectorList<E::Impl>,
607 results: &mut Q::Output,
608 matching_context: &mut MatchingContext<E::Impl>,
609) -> Result<(), ()>
610where
611 E: TElement,
612 Q: SelectorQuery<E>,
613{
614 if selector_list.len() > 1 {
617 return Err(());
618 }
619
620 let selector = &selector_list.slice()[0];
621 let class_and_id_case_sensitivity = matching_context.classes_and_ids_case_sensitivity();
622 if selector.len() == 1
624 && query_selector_single_query::<E, Q>(
625 root,
626 selector.iter().next().unwrap(),
627 results,
628 class_and_id_case_sensitivity,
629 )
630 .is_ok()
631 {
632 return Ok(());
633 }
634
635 let mut iter = selector.iter();
636 let mut combinator: Option<Combinator> = None;
637
638 let mut simple_filter = None;
642
643 'selector_loop: loop {
644 debug_assert!(combinator.is_none_or(|c| !c.is_sibling()));
645
646 'component_loop: for component in &mut iter {
647 match *component {
648 Component::Class(ref class) => {
649 if combinator.is_none() {
650 simple_filter = Some(SimpleFilter::Class(class));
651 }
652 },
653 Component::LocalName(ref local_name) => {
654 if combinator.is_none() {
655 if let Some(SimpleFilter::Class(..)) = simple_filter {
658 continue;
659 }
660 simple_filter = Some(SimpleFilter::LocalName(local_name));
661 }
662 },
663 ref other => {
664 if let Some(id) = get_id(other) {
665 if combinator.is_none() {
666 collect_elements_with_id::<E, Q, _>(
669 root,
670 id,
671 results,
672 class_and_id_case_sensitivity,
673 |e| {
674 matching::matches_selector_list(
675 selector_list,
676 &e,
677 matching_context,
678 )
679 },
680 );
681 return Ok(());
682 }
683
684 let elements = fast_connected_elements_with_id(
685 root,
686 id,
687 class_and_id_case_sensitivity,
688 )?;
689 if elements.is_empty() {
690 return Ok(());
691 }
692
693 if !Q::should_stop_after_first_match() && elements.len() > 1 {
698 continue;
699 }
700
701 for element in elements {
702 if !connected_element_is_descendant_of(*element, root) {
714 continue 'component_loop;
715 }
716
717 query_selector_slow::<E, Q>(
718 element.as_node(),
719 selector_list,
720 results,
721 matching_context,
722 );
723
724 if Q::should_stop_after_first_match() && !Q::is_empty(results) {
725 break;
726 }
727 }
728
729 return Ok(());
730 }
731 if combinator.is_none() && simple_filter.is_none() {
732 if let Some(attr_name) = get_attr_name(other) {
733 simple_filter = Some(SimpleFilter::Attr(attr_name));
734 }
735 }
736 },
737 }
738 }
739
740 loop {
741 let next_combinator = match iter.next_sequence() {
742 None => break 'selector_loop,
743 Some(c) => c,
744 };
745
746 if next_combinator.is_sibling() {
750 for _ in &mut iter {}
752 continue;
753 }
754
755 combinator = Some(next_combinator);
756 break;
757 }
758 }
759
760 let simple_filter = match simple_filter {
763 Some(f) => f,
764 None => return Err(()),
765 };
766
767 match simple_filter {
768 SimpleFilter::Class(class) => {
769 let bloom_hash = if class_and_id_case_sensitivity == CaseSensitivity::CaseSensitive {
771 Some(E::hash_for_bloom_filter(class.0.get_hash32()))
772 } else {
773 None
774 };
775 collect_all_elements::<E, Q, _>(root, results, |element| {
776 if bloom_hash.is_some_and(|hash| !element.bloom_may_have_hash(hash)) {
777 return Operation::RejectSkippingChildren;
778 }
779 Operation::from(
780 element.has_class(class, class_and_id_case_sensitivity)
781 && matching::matches_selector_list(
782 selector_list,
783 &element,
784 matching_context,
785 ),
786 )
787 });
788 },
789 SimpleFilter::LocalName(local_name) => {
790 let hash = E::hash_for_bloom_filter(local_name.name.0.get_hash32());
791 let hash_lower = if local_name.name == local_name.lower_name {
792 hash
793 } else {
794 E::hash_for_bloom_filter(local_name.lower_name.0.get_hash32())
795 };
796 collect_all_elements::<E, Q, _>(root, results, |element| {
797 if !element.bloom_may_have_hash(hash)
798 && (hash == hash_lower || !element.bloom_may_have_hash(hash_lower))
799 {
800 return Operation::RejectSkippingChildren;
801 }
802 if *element.local_name()
803 != ***matching::select_name(&element, &local_name.name, &local_name.lower_name)
804 {
805 return Operation::Reject;
806 }
807 Operation::from(matching::matches_selector_list(
808 selector_list,
809 &element,
810 matching_context,
811 ))
812 });
813 },
814 SimpleFilter::Attr(local_name) => {
815 let hash = E::hash_for_bloom_filter(local_name.0.get_hash32());
816 collect_all_elements::<E, Q, _>(root, results, |element| {
817 if !element.bloom_may_have_hash(hash) {
818 return Operation::RejectSkippingChildren;
819 }
820 if !element.has_attr_in_no_namespace(local_name) {
821 return Operation::Reject;
822 }
823 Operation::from(matching::matches_selector_list(
824 selector_list,
825 &element,
826 matching_context,
827 ))
828 });
829 },
830 }
831
832 Ok(())
833}
834
835fn query_selector_slow<E, Q>(
837 root: E::ConcreteNode,
838 selector_list: &SelectorList<E::Impl>,
839 results: &mut Q::Output,
840 matching_context: &mut MatchingContext<E::Impl>,
841) where
842 E: TElement,
843 Q: SelectorQuery<E>,
844{
845 collect_all_elements::<E, Q, _>(root, results, |element| {
846 Operation::from(matching::matches_selector_list(
847 selector_list,
848 &element,
849 matching_context,
850 ))
851 });
852}
853
854#[derive(PartialEq)]
856pub enum MayUseInvalidation {
857 Yes,
859 No,
861}
862
863pub fn query_selector<E, Q>(
865 root: E::ConcreteNode,
866 selector_list: &SelectorList<E::Impl>,
867 results: &mut Q::Output,
868 may_use_invalidation: MayUseInvalidation,
869) where
870 E: TElement,
871 Q: SelectorQuery<E>,
872{
873 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
874
875 let mut selector_caches = SelectorCaches::default();
876 let quirks_mode = root.owner_doc().quirks_mode();
877
878 let mut matching_context = MatchingContext::new(
879 MatchingMode::Normal,
880 None,
881 &mut selector_caches,
882 quirks_mode,
883 NeedsSelectorFlags::No,
884 MatchingForInvalidation::No,
885 );
886 let root_element = root.as_element();
887 matching_context.scope_element = root_element.map(|e| e.opaque());
888 matching_context.current_host = match root_element {
889 Some(root) => root.containing_shadow_host().map(|host| host.opaque()),
890 None => root.as_shadow_root().map(|root| root.host().opaque()),
891 };
892
893 let fast_result =
894 query_selector_fast::<E, Q>(root, selector_list, results, &mut matching_context);
895
896 if fast_result.is_ok() {
897 return;
898 }
899
900 let invalidation_may_be_useful = may_use_invalidation == MayUseInvalidation::Yes
913 && selector_list.slice().iter().any(|s| s.len() > 2);
914
915 if root_element.is_some() || !invalidation_may_be_useful {
916 query_selector_slow::<E, Q>(root, selector_list, results, &mut matching_context);
917 } else {
918 let dependencies = selector_list
919 .slice()
920 .iter()
921 .map(|selector| Dependency::for_full_selector_invalidation(selector.clone()))
922 .collect::<SmallVec<[_; 5]>>();
923 let mut processor = QuerySelectorProcessor::<E, Q> {
924 results,
925 matching_context,
926 traversal_map: SiblingTraversalMap::default(),
927 dependencies: &dependencies,
928 };
929
930 for node in root.dom_children() {
931 if let Some(e) = node.as_element() {
932 TreeStyleInvalidator::new(e, None, &mut processor)
933 .invalidate();
934 }
935 }
936 }
937}