1use crate::context::QuirksMode;
9use crate::dom::{TDocument, TElement, TNode, TShadowRoot};
10use crate::invalidation::element::invalidation_map::Dependency;
11use crate::invalidation::element::invalidator::{
12 DescendantInvalidationLists, Invalidation, SiblingTraversalMap,
13};
14use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
15use crate::selector_parser::SelectorImpl;
16use crate::values::AtomIdent;
17use selectors::attr::CaseSensitivity;
18use selectors::attr::{AttrSelectorOperation, NamespaceConstraint};
19use selectors::matching::{
20 self, MatchingContext, MatchingForInvalidation, MatchingMode, NeedsSelectorFlags,
21 SelectorCaches,
22};
23use selectors::parser::{Combinator, Component, LocalName};
24use selectors::{Element, OpaqueElement, SelectorList};
25use smallvec::SmallVec;
26
27pub fn element_matches<E>(
29 element: &E,
30 selector_list: &SelectorList<E::Impl>,
31 quirks_mode: QuirksMode,
32) -> bool
33where
34 E: Element,
35{
36 let mut selector_caches = SelectorCaches::default();
37
38 let mut context = MatchingContext::new(
39 MatchingMode::Normal,
40 None,
41 &mut selector_caches,
42 quirks_mode,
43 NeedsSelectorFlags::No,
44 MatchingForInvalidation::No,
45 );
46 context.scope_element = Some(element.opaque());
47 context.current_host = element.containing_shadow_host().map(|e| e.opaque());
48 matching::matches_selector_list(selector_list, element, &mut context)
49}
50
51pub fn element_closest<E>(
53 element: E,
54 selector_list: &SelectorList<E::Impl>,
55 quirks_mode: QuirksMode,
56) -> Option<E>
57where
58 E: Element,
59{
60 let mut selector_caches = SelectorCaches::default();
61
62 let mut context = MatchingContext::new(
63 MatchingMode::Normal,
64 None,
65 &mut selector_caches,
66 quirks_mode,
67 NeedsSelectorFlags::No,
68 MatchingForInvalidation::No,
69 );
70 context.scope_element = Some(element.opaque());
71 context.current_host = element.containing_shadow_host().map(|e| e.opaque());
72
73 let mut current = Some(element);
74 while let Some(element) = current.take() {
75 if matching::matches_selector_list(selector_list, &element, &mut context) {
76 return Some(element);
77 }
78 current = element.parent_element();
79 }
80
81 return None;
82}
83
84pub trait SelectorQuery<E: TElement> {
87 type Output;
89
90 fn should_stop_after_first_match() -> bool;
92
93 fn append_element(output: &mut Self::Output, element: E);
95
96 fn is_empty(output: &Self::Output) -> bool;
98}
99
100pub type QuerySelectorAllResult<E> = SmallVec<[E; 128]>;
102
103pub struct QueryAll;
105
106impl<E: TElement> SelectorQuery<E> for QueryAll {
107 type Output = QuerySelectorAllResult<E>;
108
109 fn should_stop_after_first_match() -> bool {
110 false
111 }
112
113 fn append_element(output: &mut Self::Output, element: E) {
114 output.push(element);
115 }
116
117 fn is_empty(output: &Self::Output) -> bool {
118 output.is_empty()
119 }
120}
121
122pub struct QueryFirst;
124
125impl<E: TElement> SelectorQuery<E> for QueryFirst {
126 type Output = Option<E>;
127
128 fn should_stop_after_first_match() -> bool {
129 true
130 }
131
132 fn append_element(output: &mut Self::Output, element: E) {
133 if output.is_none() {
134 *output = Some(element)
135 }
136 }
137
138 fn is_empty(output: &Self::Output) -> bool {
139 output.is_none()
140 }
141}
142
143struct QuerySelectorProcessor<'a, 'b, E, Q>
144where
145 E: TElement + 'a,
146 Q: SelectorQuery<E>,
147 Q::Output: 'a,
148{
149 results: &'a mut Q::Output,
150 matching_context: MatchingContext<'b, E::Impl>,
151 traversal_map: SiblingTraversalMap<E>,
152 dependencies: &'a [Dependency],
153}
154
155impl<'a, 'b, E, Q> InvalidationProcessor<'a, 'b, E> for QuerySelectorProcessor<'a, 'b, E, Q>
156where
157 E: TElement + 'a,
158 Q: SelectorQuery<E>,
159 Q::Output: 'a,
160{
161 fn light_tree_only(&self) -> bool {
162 true
163 }
164
165 fn check_outer_dependency(&mut self, _: &Dependency, _: E, _: Option<OpaqueElement>) -> bool {
166 debug_assert!(
167 false,
168 "How? We should only have parent-less dependencies here!"
169 );
170 true
171 }
172
173 fn collect_invalidations(
174 &mut self,
175 element: E,
176 self_invalidations: &mut InvalidationVector<'a>,
177 descendant_invalidations: &mut DescendantInvalidationLists<'a>,
178 _sibling_invalidations: &mut InvalidationVector<'a>,
179 ) -> bool {
180 debug_assert!(element.parent_element().is_none());
194
195 let target_vector = if self.matching_context.scope_element.is_some() {
196 &mut descendant_invalidations.dom_descendants
197 } else {
198 self_invalidations
199 };
200
201 for dependency in self.dependencies.iter() {
202 target_vector.push(Invalidation::new(
203 dependency,
204 self.matching_context.current_host.clone(),
205 self.matching_context.scope_element.clone(),
206 ))
207 }
208
209 false
210 }
211
212 fn matching_context(&mut self) -> &mut MatchingContext<'b, E::Impl> {
213 &mut self.matching_context
214 }
215
216 fn sibling_traversal_map(&self) -> &SiblingTraversalMap<E> {
217 &self.traversal_map
218 }
219
220 fn should_process_descendants(&mut self, _: E) -> bool {
221 if Q::should_stop_after_first_match() {
222 return Q::is_empty(&self.results);
223 }
224
225 true
226 }
227
228 fn invalidated_self(&mut self, e: E) {
229 Q::append_element(self.results, e);
230 }
231
232 fn invalidated_sibling(&mut self, e: E, _of: E) {
233 Q::append_element(self.results, e);
234 }
235
236 fn recursion_limit_exceeded(&mut self, _e: E) {}
237 fn invalidated_descendants(&mut self, _e: E, _child: E) {}
238}
239
240enum Operation {
241 Reject,
242 Accept,
243 RejectSkippingChildren,
244}
245
246impl From<bool> for Operation {
247 #[inline(always)]
248 fn from(matches: bool) -> Self {
249 if matches {
250 Operation::Accept
251 } else {
252 Operation::Reject
253 }
254 }
255}
256
257fn collect_all_elements<E, Q, F>(root: E::ConcreteNode, results: &mut Q::Output, mut filter: F)
258where
259 E: TElement,
260 Q: SelectorQuery<E>,
261 F: FnMut(E) -> Operation,
262{
263 let mut iter = root.dom_descendants();
264 let mut cur = iter.next();
265 while let Some(node) = cur {
266 let element = match node.as_element() {
267 Some(e) => e,
268 None => {
269 cur = iter.next();
270 continue;
271 },
272 };
273 match filter(element) {
274 Operation::Accept => {
276 Q::append_element(results, element);
277 if Q::should_stop_after_first_match() {
278 return;
279 }
280 },
281 Operation::Reject => {},
283 Operation::RejectSkippingChildren => {
285 cur = iter.next_skipping_children();
286 continue;
287 },
288 }
289 cur = iter.next();
290 }
291}
292
293fn connected_element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
297where
298 E: TElement,
299{
300 if root.as_document().is_some() {
303 debug_assert!(element.as_node().is_in_document(), "Not connected?");
304 debug_assert_eq!(
305 root,
306 root.owner_doc().as_node(),
307 "Where did this element come from?",
308 );
309 return true;
310 }
311
312 if root.as_shadow_root().is_some() {
313 debug_assert_eq!(
314 element.containing_shadow().unwrap().as_node(),
315 root,
316 "Not connected?"
317 );
318 return true;
319 }
320
321 let mut current = element.as_node().parent_node();
322 while let Some(n) = current.take() {
323 if n == root {
324 return true;
325 }
326
327 current = n.parent_node();
328 }
329 false
330}
331
332fn fast_connected_elements_with_id<'a, N>(
335 root: N,
336 id: &AtomIdent,
337 case_sensitivity: CaseSensitivity,
338) -> Result<&'a [N::ConcreteElement], ()>
339where
340 N: TNode + 'a,
341{
342 if case_sensitivity != CaseSensitivity::CaseSensitive {
343 return Err(());
344 }
345
346 if root.is_in_document() {
347 return root.owner_doc().elements_with_id(id);
348 }
349
350 if let Some(shadow) = root.as_shadow_root() {
351 return shadow.elements_with_id(id);
352 }
353
354 if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) {
355 return shadow.elements_with_id(id);
356 }
357
358 Err(())
359}
360
361fn collect_elements_with_id<E, Q, F>(
363 root: E::ConcreteNode,
364 id: &AtomIdent,
365 results: &mut Q::Output,
366 class_and_id_case_sensitivity: CaseSensitivity,
367 mut filter: F,
368) where
369 E: TElement,
370 Q: SelectorQuery<E>,
371 F: FnMut(E) -> bool,
372{
373 let elements = match fast_connected_elements_with_id(root, id, class_and_id_case_sensitivity) {
374 Ok(elements) => elements,
375 Err(()) => {
376 collect_all_elements::<E, Q, _>(root, results, |e| {
377 Operation::from(e.has_id(id, class_and_id_case_sensitivity) && filter(e))
378 });
379
380 return;
381 },
382 };
383
384 for element in elements {
385 if !connected_element_is_descendant_of(*element, root) {
388 continue;
389 }
390
391 if !filter(*element) {
392 continue;
393 }
394
395 Q::append_element(results, *element);
396 if Q::should_stop_after_first_match() {
397 break;
398 }
399 }
400}
401
402fn get_attr_name(component: &Component<SelectorImpl>) -> Option<&crate::LocalName> {
403 let (name, name_lower) = match component {
404 Component::AttributeInNoNamespace { ref local_name, .. } => return Some(local_name),
405 Component::AttributeInNoNamespaceExists {
406 ref local_name,
407 ref local_name_lower,
408 ..
409 } => (local_name, local_name_lower),
410 Component::AttributeOther(ref attr) => {
411 if attr.namespace.is_some() {
412 return None;
413 }
414 (&attr.local_name, &attr.local_name_lower)
415 },
416 _ => return None,
417 };
418 if name != name_lower {
419 return None; }
421 Some(name)
422}
423
424fn get_id(component: &Component<SelectorImpl>) -> Option<&AtomIdent> {
425 use selectors::attr::AttrSelectorOperator;
426 Some(match component {
427 Component::ID(ref id) => id,
428 Component::AttributeInNoNamespace {
429 ref operator,
430 ref local_name,
431 ref value,
432 ..
433 } => {
434 if *local_name != local_name!("id") {
435 return None;
436 }
437 if *operator != AttrSelectorOperator::Equal {
438 return None;
439 }
440 AtomIdent::cast(&value.0)
441 },
442 _ => return None,
443 })
444}
445
446fn query_selector_single_query<E, Q>(
448 root: E::ConcreteNode,
449 component: &Component<E::Impl>,
450 results: &mut Q::Output,
451 class_and_id_case_sensitivity: CaseSensitivity,
452) -> Result<(), ()>
453where
454 E: TElement,
455 Q: SelectorQuery<E>,
456{
457 match *component {
458 Component::ExplicitUniversalType => {
459 collect_all_elements::<E, Q, _>(root, results, |_| Operation::Accept)
460 },
461 Component::Class(ref class) => {
462 let bloom_hash = if class_and_id_case_sensitivity == CaseSensitivity::CaseSensitive {
464 Some(E::hash_for_bloom_filter(class.0.get_hash()))
465 } else {
466 None
467 };
468
469 collect_all_elements::<E, Q, _>(root, results, |element| {
470 if bloom_hash.is_some_and(|hash| !element.bloom_may_have_hash(hash)) {
471 return Operation::RejectSkippingChildren;
472 }
473 Operation::from(element.has_class(class, class_and_id_case_sensitivity))
474 });
475 },
476 Component::LocalName(ref local_name) => {
477 let hash = E::hash_for_bloom_filter(local_name.name.0.get_hash());
478 let hash_lower = if local_name.name == local_name.lower_name {
479 hash
480 } else {
481 E::hash_for_bloom_filter(local_name.lower_name.0.get_hash())
482 };
483 collect_all_elements::<E, Q, _>(root, results, |element| {
484 if !element.bloom_may_have_hash(hash)
485 && (hash == hash_lower || !element.bloom_may_have_hash(hash_lower))
486 {
487 return Operation::RejectSkippingChildren;
488 }
489 Operation::from(
490 *element.local_name()
491 == ***matching::select_name(
492 &element,
493 &local_name.name,
494 &local_name.lower_name,
495 ),
496 )
497 })
498 },
499 Component::AttributeInNoNamespaceExists {
500 ref local_name,
501 ref local_name_lower,
502 } => {
503 let hash_original = E::hash_for_bloom_filter(local_name.0.get_hash());
506 let hash_lower = if local_name.0 == local_name_lower.0 {
507 hash_original
508 } else {
509 E::hash_for_bloom_filter(local_name_lower.0.get_hash())
510 };
511
512 collect_all_elements::<E, Q, _>(root, results, |element| {
513 let bloom_found_hash = if hash_original == hash_lower
515 || !element.as_node().owner_doc().is_html_document()
516 {
517 element.bloom_may_have_hash(hash_original)
518 } else if element.is_html_element_in_html_document() {
519 element.bloom_may_have_hash(hash_lower)
521 } else {
522 element.bloom_may_have_hash(hash_original)
525 || element.bloom_may_have_hash(hash_lower)
526 };
527
528 if !bloom_found_hash {
529 return Operation::RejectSkippingChildren;
530 }
531
532 Operation::from(element.has_attr_in_no_namespace(matching::select_name(
533 &element,
534 local_name,
535 local_name_lower,
536 )))
537 });
538 },
539 Component::AttributeInNoNamespace {
540 ref local_name,
541 ref value,
542 operator,
543 case_sensitivity,
544 } => {
545 let empty_namespace = selectors::parser::namespace_empty_string::<E::Impl>();
546 let namespace_constraint = NamespaceConstraint::Specific(&empty_namespace);
547
548 let bloom_hash = E::hash_for_bloom_filter(local_name.0.get_hash());
550
551 collect_all_elements::<E, Q, _>(root, results, |element| {
552 if !element.bloom_may_have_hash(bloom_hash) {
553 return Operation::RejectSkippingChildren;
554 }
555 Operation::from(element.attr_matches(
556 &namespace_constraint,
557 local_name,
558 &AttrSelectorOperation::WithValue {
559 operator,
560 case_sensitivity: matching::to_unconditional_case_sensitivity(
561 case_sensitivity,
562 &element,
563 ),
564 value,
565 },
566 ))
567 });
568 },
569 ref other => {
570 let id = match get_id(other) {
571 Some(id) => id,
572 None => return Err(()),
574 };
575 collect_elements_with_id::<E, Q, _>(
576 root,
577 id,
578 results,
579 class_and_id_case_sensitivity,
580 |_| true,
581 );
582 },
583 }
584
585 Ok(())
586}
587
588enum SimpleFilter<'a> {
589 Class(&'a AtomIdent),
590 Attr(&'a crate::LocalName),
591 LocalName(&'a LocalName<SelectorImpl>),
592}
593
594fn query_selector_fast<E, Q>(
604 root: E::ConcreteNode,
605 selector_list: &SelectorList<E::Impl>,
606 results: &mut Q::Output,
607 matching_context: &mut MatchingContext<E::Impl>,
608) -> Result<(), ()>
609where
610 E: TElement,
611 Q: SelectorQuery<E>,
612{
613 if selector_list.len() > 1 {
616 return Err(());
617 }
618
619 let selector = &selector_list.slice()[0];
620 let class_and_id_case_sensitivity = matching_context.classes_and_ids_case_sensitivity();
621 if selector.len() == 1 {
623 if query_selector_single_query::<E, Q>(
624 root,
625 selector.iter().next().unwrap(),
626 results,
627 class_and_id_case_sensitivity,
628 )
629 .is_ok()
630 {
631 return Ok(());
632 }
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.map_or(true, |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(ref class) => {
769 let bloom_hash = if class_and_id_case_sensitivity == CaseSensitivity::CaseSensitive {
771 Some(E::hash_for_bloom_filter(class.0.get_hash()))
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(ref local_name) => {
790 let hash = E::hash_for_bloom_filter(local_name.name.0.get_hash());
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_hash())
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(ref local_name) => {
815 let hash = E::hash_for_bloom_filter(local_name.0.get_hash());
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}