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 has_attr<E>(element: E, local_name: &crate::LocalName) -> bool
403where
404 E: TElement,
405{
406 let mut found = false;
407 element.each_attr_name(|name| found |= name == local_name);
408 found
409}
410
411#[inline(always)]
412fn local_name_matches<E>(element: E, local_name: &LocalName<E::Impl>) -> bool
413where
414 E: TElement,
415{
416 let LocalName {
417 ref name,
418 ref lower_name,
419 } = *local_name;
420
421 let chosen_name = if name == lower_name || element.is_html_element_in_html_document() {
422 lower_name
423 } else {
424 name
425 };
426
427 element.local_name() == &**chosen_name
428}
429
430fn get_attr_name(component: &Component<SelectorImpl>) -> Option<&crate::LocalName> {
431 let (name, name_lower) = match component {
432 Component::AttributeInNoNamespace { ref local_name, .. } => return Some(local_name),
433 Component::AttributeInNoNamespaceExists {
434 ref local_name,
435 ref local_name_lower,
436 ..
437 } => (local_name, local_name_lower),
438 Component::AttributeOther(ref attr) => (&attr.local_name, &attr.local_name_lower),
439 _ => return None,
440 };
441 if name != name_lower {
442 return None; }
444 Some(name)
445}
446
447fn get_id(component: &Component<SelectorImpl>) -> Option<&AtomIdent> {
448 use selectors::attr::AttrSelectorOperator;
449 Some(match component {
450 Component::ID(ref id) => id,
451 Component::AttributeInNoNamespace {
452 ref operator,
453 ref local_name,
454 ref value,
455 ..
456 } => {
457 if *local_name != local_name!("id") {
458 return None;
459 }
460 if *operator != AttrSelectorOperator::Equal {
461 return None;
462 }
463 AtomIdent::cast(&value.0)
464 },
465 _ => return None,
466 })
467}
468
469fn query_selector_single_query<E, Q>(
471 root: E::ConcreteNode,
472 component: &Component<E::Impl>,
473 results: &mut Q::Output,
474 class_and_id_case_sensitivity: CaseSensitivity,
475) -> Result<(), ()>
476where
477 E: TElement,
478 Q: SelectorQuery<E>,
479{
480 match *component {
481 Component::ExplicitUniversalType => {
482 collect_all_elements::<E, Q, _>(root, results, |_| Operation::Accept)
483 },
484 Component::Class(ref class) => {
485 let bloom_hash = if class_and_id_case_sensitivity == CaseSensitivity::CaseSensitive {
487 Some(E::hash_for_bloom_filter(class.0.get_hash()))
488 } else {
489 None
490 };
491
492 collect_all_elements::<E, Q, _>(root, results, |element| {
493 if bloom_hash.is_some_and(|hash| !element.bloom_may_have_hash(hash)) {
494 return Operation::RejectSkippingChildren;
495 }
496 Operation::from(element.has_class(class, class_and_id_case_sensitivity))
497 });
498 },
499 Component::LocalName(ref local_name) => {
500 collect_all_elements::<E, Q, _>(root, results, |element| {
501 Operation::from(local_name_matches(element, local_name))
502 })
503 },
504 Component::AttributeInNoNamespaceExists {
505 ref local_name,
506 ref local_name_lower,
507 } => {
508 let hash_original = E::hash_for_bloom_filter(local_name.0.get_hash());
511 let hash_lower = if local_name.0 == local_name_lower.0 {
512 hash_original
513 } else {
514 E::hash_for_bloom_filter(local_name_lower.0.get_hash())
515 };
516
517 collect_all_elements::<E, Q, _>(root, results, |element| {
518 let bloom_found_hash = if hash_original == hash_lower
520 || !element.as_node().owner_doc().is_html_document()
521 {
522 element.bloom_may_have_hash(hash_original)
523 } else if element.is_html_element_in_html_document() {
524 element.bloom_may_have_hash(hash_lower)
526 } else {
527 element.bloom_may_have_hash(hash_original)
530 || element.bloom_may_have_hash(hash_lower)
531 };
532
533 if !bloom_found_hash {
534 return Operation::RejectSkippingChildren;
535 }
536
537 Operation::from(element.has_attr_in_no_namespace(matching::select_name(
538 &element,
539 local_name,
540 local_name_lower,
541 )))
542 });
543 },
544 Component::AttributeInNoNamespace {
545 ref local_name,
546 ref value,
547 operator,
548 case_sensitivity,
549 } => {
550 let empty_namespace = selectors::parser::namespace_empty_string::<E::Impl>();
551 let namespace_constraint = NamespaceConstraint::Specific(&empty_namespace);
552
553 let bloom_hash = E::hash_for_bloom_filter(local_name.0.get_hash());
555
556 collect_all_elements::<E, Q, _>(root, results, |element| {
557 if !element.bloom_may_have_hash(bloom_hash) {
558 return Operation::RejectSkippingChildren;
559 }
560 Operation::from(element.attr_matches(
561 &namespace_constraint,
562 local_name,
563 &AttrSelectorOperation::WithValue {
564 operator,
565 case_sensitivity: matching::to_unconditional_case_sensitivity(
566 case_sensitivity,
567 &element,
568 ),
569 value,
570 },
571 ))
572 });
573 },
574 ref other => {
575 let id = match get_id(other) {
576 Some(id) => id,
577 None => return Err(()),
579 };
580 collect_elements_with_id::<E, Q, _>(
581 root,
582 id,
583 results,
584 class_and_id_case_sensitivity,
585 |_| true,
586 );
587 },
588 }
589
590 Ok(())
591}
592
593enum SimpleFilter<'a> {
594 Class(&'a AtomIdent),
595 Attr(&'a crate::LocalName),
596 LocalName(&'a LocalName<SelectorImpl>),
597}
598
599fn query_selector_fast<E, Q>(
609 root: E::ConcreteNode,
610 selector_list: &SelectorList<E::Impl>,
611 results: &mut Q::Output,
612 matching_context: &mut MatchingContext<E::Impl>,
613) -> Result<(), ()>
614where
615 E: TElement,
616 Q: SelectorQuery<E>,
617{
618 if selector_list.len() > 1 {
621 return Err(());
622 }
623
624 let selector = &selector_list.slice()[0];
625 let class_and_id_case_sensitivity = matching_context.classes_and_ids_case_sensitivity();
626 if selector.len() == 1 {
628 if query_selector_single_query::<E, Q>(
629 root,
630 selector.iter().next().unwrap(),
631 results,
632 class_and_id_case_sensitivity,
633 )
634 .is_ok()
635 {
636 return Ok(());
637 }
638 }
639
640 let mut iter = selector.iter();
641 let mut combinator: Option<Combinator> = None;
642
643 let mut simple_filter = None;
647
648 'selector_loop: loop {
649 debug_assert!(combinator.map_or(true, |c| !c.is_sibling()));
650
651 'component_loop: for component in &mut iter {
652 match *component {
653 Component::Class(ref class) => {
654 if combinator.is_none() {
655 simple_filter = Some(SimpleFilter::Class(class));
656 }
657 },
658 Component::LocalName(ref local_name) => {
659 if combinator.is_none() {
660 if let Some(SimpleFilter::Class(..)) = simple_filter {
663 continue;
664 }
665 simple_filter = Some(SimpleFilter::LocalName(local_name));
666 }
667 },
668 ref other => {
669 if let Some(id) = get_id(other) {
670 if combinator.is_none() {
671 collect_elements_with_id::<E, Q, _>(
674 root,
675 id,
676 results,
677 class_and_id_case_sensitivity,
678 |e| {
679 matching::matches_selector_list(
680 selector_list,
681 &e,
682 matching_context,
683 )
684 },
685 );
686 return Ok(());
687 }
688
689 let elements = fast_connected_elements_with_id(
690 root,
691 id,
692 class_and_id_case_sensitivity,
693 )?;
694 if elements.is_empty() {
695 return Ok(());
696 }
697
698 if !Q::should_stop_after_first_match() && elements.len() > 1 {
703 continue;
704 }
705
706 for element in elements {
707 if !connected_element_is_descendant_of(*element, root) {
719 continue 'component_loop;
720 }
721
722 query_selector_slow::<E, Q>(
723 element.as_node(),
724 selector_list,
725 results,
726 matching_context,
727 );
728
729 if Q::should_stop_after_first_match() && !Q::is_empty(&results) {
730 break;
731 }
732 }
733
734 return Ok(());
735 }
736 if combinator.is_none() && simple_filter.is_none() {
737 if let Some(attr_name) = get_attr_name(other) {
738 simple_filter = Some(SimpleFilter::Attr(attr_name));
739 }
740 }
741 },
742 }
743 }
744
745 loop {
746 let next_combinator = match iter.next_sequence() {
747 None => break 'selector_loop,
748 Some(c) => c,
749 };
750
751 if next_combinator.is_sibling() {
755 for _ in &mut iter {}
757 continue;
758 }
759
760 combinator = Some(next_combinator);
761 break;
762 }
763 }
764
765 let simple_filter = match simple_filter {
768 Some(f) => f,
769 None => return Err(()),
770 };
771
772 match simple_filter {
773 SimpleFilter::Class(ref class) => {
774 collect_all_elements::<E, Q, _>(root, results, |element| {
775 Operation::from(
776 element.has_class(class, class_and_id_case_sensitivity)
777 && matching::matches_selector_list(
778 selector_list,
779 &element,
780 matching_context,
781 ),
782 )
783 });
784 },
785 SimpleFilter::LocalName(ref local_name) => {
786 collect_all_elements::<E, Q, _>(root, results, |element| {
787 Operation::from(
788 local_name_matches(element, local_name)
789 && matching::matches_selector_list(
790 selector_list,
791 &element,
792 matching_context,
793 ),
794 )
795 });
796 },
797 SimpleFilter::Attr(ref local_name) => {
798 collect_all_elements::<E, Q, _>(root, results, |element| {
799 Operation::from(
800 has_attr(element, local_name)
801 && matching::matches_selector_list(
802 selector_list,
803 &element,
804 matching_context,
805 ),
806 )
807 });
808 },
809 }
810
811 Ok(())
812}
813
814fn query_selector_slow<E, Q>(
816 root: E::ConcreteNode,
817 selector_list: &SelectorList<E::Impl>,
818 results: &mut Q::Output,
819 matching_context: &mut MatchingContext<E::Impl>,
820) where
821 E: TElement,
822 Q: SelectorQuery<E>,
823{
824 collect_all_elements::<E, Q, _>(root, results, |element| {
825 Operation::from(matching::matches_selector_list(
826 selector_list,
827 &element,
828 matching_context,
829 ))
830 });
831}
832
833#[derive(PartialEq)]
835pub enum MayUseInvalidation {
836 Yes,
838 No,
840}
841
842pub fn query_selector<E, Q>(
844 root: E::ConcreteNode,
845 selector_list: &SelectorList<E::Impl>,
846 results: &mut Q::Output,
847 may_use_invalidation: MayUseInvalidation,
848) where
849 E: TElement,
850 Q: SelectorQuery<E>,
851{
852 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
853
854 let mut selector_caches = SelectorCaches::default();
855 let quirks_mode = root.owner_doc().quirks_mode();
856
857 let mut matching_context = MatchingContext::new(
858 MatchingMode::Normal,
859 None,
860 &mut selector_caches,
861 quirks_mode,
862 NeedsSelectorFlags::No,
863 MatchingForInvalidation::No,
864 );
865 let root_element = root.as_element();
866 matching_context.scope_element = root_element.map(|e| e.opaque());
867 matching_context.current_host = match root_element {
868 Some(root) => root.containing_shadow_host().map(|host| host.opaque()),
869 None => root.as_shadow_root().map(|root| root.host().opaque()),
870 };
871
872 let fast_result =
873 query_selector_fast::<E, Q>(root, selector_list, results, &mut matching_context);
874
875 if fast_result.is_ok() {
876 return;
877 }
878
879 let invalidation_may_be_useful = may_use_invalidation == MayUseInvalidation::Yes
892 && selector_list.slice().iter().any(|s| s.len() > 2);
893
894 if root_element.is_some() || !invalidation_may_be_useful {
895 query_selector_slow::<E, Q>(root, selector_list, results, &mut matching_context);
896 } else {
897 let dependencies = selector_list
898 .slice()
899 .iter()
900 .map(|selector| Dependency::for_full_selector_invalidation(selector.clone()))
901 .collect::<SmallVec<[_; 5]>>();
902 let mut processor = QuerySelectorProcessor::<E, Q> {
903 results,
904 matching_context,
905 traversal_map: SiblingTraversalMap::default(),
906 dependencies: &dependencies,
907 };
908
909 for node in root.dom_children() {
910 if let Some(e) = node.as_element() {
911 TreeStyleInvalidator::new(e, None, &mut processor)
912 .invalidate();
913 }
914 }
915 }
916}