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