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
240fn collect_all_elements<E, Q, F>(root: E::ConcreteNode, results: &mut Q::Output, mut filter: F)
241where
242 E: TElement,
243 Q: SelectorQuery<E>,
244 F: FnMut(E) -> bool,
245{
246 for node in root.dom_descendants() {
247 let element = match node.as_element() {
248 Some(e) => e,
249 None => continue,
250 };
251
252 if !filter(element) {
253 continue;
254 }
255
256 Q::append_element(results, element);
257 if Q::should_stop_after_first_match() {
258 return;
259 }
260 }
261}
262
263fn connected_element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
267where
268 E: TElement,
269{
270 if root.as_document().is_some() {
273 debug_assert!(element.as_node().is_in_document(), "Not connected?");
274 debug_assert_eq!(
275 root,
276 root.owner_doc().as_node(),
277 "Where did this element come from?",
278 );
279 return true;
280 }
281
282 if root.as_shadow_root().is_some() {
283 debug_assert_eq!(
284 element.containing_shadow().unwrap().as_node(),
285 root,
286 "Not connected?"
287 );
288 return true;
289 }
290
291 let mut current = element.as_node().parent_node();
292 while let Some(n) = current.take() {
293 if n == root {
294 return true;
295 }
296
297 current = n.parent_node();
298 }
299 false
300}
301
302fn fast_connected_elements_with_id<'a, N>(
305 root: N,
306 id: &AtomIdent,
307 case_sensitivity: CaseSensitivity,
308) -> Result<&'a [N::ConcreteElement], ()>
309where
310 N: TNode + 'a,
311{
312 if case_sensitivity != CaseSensitivity::CaseSensitive {
313 return Err(());
314 }
315
316 if root.is_in_document() {
317 return root.owner_doc().elements_with_id(id);
318 }
319
320 if let Some(shadow) = root.as_shadow_root() {
321 return shadow.elements_with_id(id);
322 }
323
324 if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) {
325 return shadow.elements_with_id(id);
326 }
327
328 Err(())
329}
330
331fn collect_elements_with_id<E, Q, F>(
333 root: E::ConcreteNode,
334 id: &AtomIdent,
335 results: &mut Q::Output,
336 class_and_id_case_sensitivity: CaseSensitivity,
337 mut filter: F,
338) where
339 E: TElement,
340 Q: SelectorQuery<E>,
341 F: FnMut(E) -> bool,
342{
343 let elements = match fast_connected_elements_with_id(root, id, class_and_id_case_sensitivity) {
344 Ok(elements) => elements,
345 Err(()) => {
346 collect_all_elements::<E, Q, _>(root, results, |e| {
347 e.has_id(id, class_and_id_case_sensitivity) && filter(e)
348 });
349
350 return;
351 },
352 };
353
354 for element in elements {
355 if !connected_element_is_descendant_of(*element, root) {
358 continue;
359 }
360
361 if !filter(*element) {
362 continue;
363 }
364
365 Q::append_element(results, *element);
366 if Q::should_stop_after_first_match() {
367 break;
368 }
369 }
370}
371
372fn has_attr<E>(element: E, local_name: &crate::LocalName) -> bool
373where
374 E: TElement,
375{
376 let mut found = false;
377 element.each_attr_name(|name| found |= name == local_name);
378 found
379}
380
381#[inline(always)]
382fn local_name_matches<E>(element: E, local_name: &LocalName<E::Impl>) -> bool
383where
384 E: TElement,
385{
386 let LocalName {
387 ref name,
388 ref lower_name,
389 } = *local_name;
390
391 let chosen_name = if name == lower_name || element.is_html_element_in_html_document() {
392 lower_name
393 } else {
394 name
395 };
396
397 element.local_name() == &**chosen_name
398}
399
400fn get_attr_name(component: &Component<SelectorImpl>) -> Option<&crate::LocalName> {
401 let (name, name_lower) = match component {
402 Component::AttributeInNoNamespace { ref local_name, .. } => return Some(local_name),
403 Component::AttributeInNoNamespaceExists {
404 ref local_name,
405 ref local_name_lower,
406 ..
407 } => (local_name, local_name_lower),
408 Component::AttributeOther(ref attr) => (&attr.local_name, &attr.local_name_lower),
409 _ => return None,
410 };
411 if name != name_lower {
412 return None; }
414 Some(name)
415}
416
417fn get_id(component: &Component<SelectorImpl>) -> Option<&AtomIdent> {
418 use selectors::attr::AttrSelectorOperator;
419 Some(match component {
420 Component::ID(ref id) => id,
421 Component::AttributeInNoNamespace {
422 ref operator,
423 ref local_name,
424 ref value,
425 ..
426 } => {
427 if *local_name != local_name!("id") {
428 return None;
429 }
430 if *operator != AttrSelectorOperator::Equal {
431 return None;
432 }
433 AtomIdent::cast(&value.0)
434 },
435 _ => return None,
436 })
437}
438
439fn query_selector_single_query<E, Q>(
441 root: E::ConcreteNode,
442 component: &Component<E::Impl>,
443 results: &mut Q::Output,
444 class_and_id_case_sensitivity: CaseSensitivity,
445) -> Result<(), ()>
446where
447 E: TElement,
448 Q: SelectorQuery<E>,
449{
450 match *component {
451 Component::ExplicitUniversalType => {
452 collect_all_elements::<E, Q, _>(root, results, |_| true)
453 },
454 Component::Class(ref class) => collect_all_elements::<E, Q, _>(root, results, |element| {
455 element.has_class(class, class_and_id_case_sensitivity)
456 }),
457 Component::LocalName(ref local_name) => {
458 collect_all_elements::<E, Q, _>(root, results, |element| {
459 local_name_matches(element, local_name)
460 })
461 },
462 Component::AttributeInNoNamespaceExists {
463 ref local_name,
464 ref local_name_lower,
465 } => collect_all_elements::<E, Q, _>(root, results, |element| {
466 element.has_attr_in_no_namespace(matching::select_name(
467 &element,
468 local_name,
469 local_name_lower,
470 ))
471 }),
472 Component::AttributeInNoNamespace {
473 ref local_name,
474 ref value,
475 operator,
476 case_sensitivity,
477 } => {
478 let empty_namespace = selectors::parser::namespace_empty_string::<E::Impl>();
479 let namespace_constraint = NamespaceConstraint::Specific(&empty_namespace);
480 collect_all_elements::<E, Q, _>(root, results, |element| {
481 element.attr_matches(
482 &namespace_constraint,
483 local_name,
484 &AttrSelectorOperation::WithValue {
485 operator,
486 case_sensitivity: matching::to_unconditional_case_sensitivity(
487 case_sensitivity,
488 &element,
489 ),
490 value,
491 },
492 )
493 })
494 },
495 ref other => {
496 let id = match get_id(other) {
497 Some(id) => id,
498 None => return Err(()),
500 };
501 collect_elements_with_id::<E, Q, _>(
502 root,
503 id,
504 results,
505 class_and_id_case_sensitivity,
506 |_| true,
507 );
508 },
509 }
510
511 Ok(())
512}
513
514enum SimpleFilter<'a> {
515 Class(&'a AtomIdent),
516 Attr(&'a crate::LocalName),
517 LocalName(&'a LocalName<SelectorImpl>),
518}
519
520fn query_selector_fast<E, Q>(
530 root: E::ConcreteNode,
531 selector_list: &SelectorList<E::Impl>,
532 results: &mut Q::Output,
533 matching_context: &mut MatchingContext<E::Impl>,
534) -> Result<(), ()>
535where
536 E: TElement,
537 Q: SelectorQuery<E>,
538{
539 if selector_list.len() > 1 {
542 return Err(());
543 }
544
545 let selector = &selector_list.slice()[0];
546 let class_and_id_case_sensitivity = matching_context.classes_and_ids_case_sensitivity();
547 if selector.len() == 1 {
549 if query_selector_single_query::<E, Q>(
550 root,
551 selector.iter().next().unwrap(),
552 results,
553 class_and_id_case_sensitivity,
554 )
555 .is_ok()
556 {
557 return Ok(());
558 }
559 }
560
561 let mut iter = selector.iter();
562 let mut combinator: Option<Combinator> = None;
563
564 let mut simple_filter = None;
568
569 'selector_loop: loop {
570 debug_assert!(combinator.map_or(true, |c| !c.is_sibling()));
571
572 'component_loop: for component in &mut iter {
573 match *component {
574 Component::Class(ref class) => {
575 if combinator.is_none() {
576 simple_filter = Some(SimpleFilter::Class(class));
577 }
578 },
579 Component::LocalName(ref local_name) => {
580 if combinator.is_none() {
581 if let Some(SimpleFilter::Class(..)) = simple_filter {
584 continue;
585 }
586 simple_filter = Some(SimpleFilter::LocalName(local_name));
587 }
588 },
589 ref other => {
590 if let Some(id) = get_id(other) {
591 if combinator.is_none() {
592 collect_elements_with_id::<E, Q, _>(
595 root,
596 id,
597 results,
598 class_and_id_case_sensitivity,
599 |e| {
600 matching::matches_selector_list(
601 selector_list,
602 &e,
603 matching_context,
604 )
605 },
606 );
607 return Ok(());
608 }
609
610 let elements = fast_connected_elements_with_id(
611 root,
612 id,
613 class_and_id_case_sensitivity,
614 )?;
615 if elements.is_empty() {
616 return Ok(());
617 }
618
619 if !Q::should_stop_after_first_match() && elements.len() > 1 {
624 continue;
625 }
626
627 for element in elements {
628 if !connected_element_is_descendant_of(*element, root) {
640 continue 'component_loop;
641 }
642
643 query_selector_slow::<E, Q>(
644 element.as_node(),
645 selector_list,
646 results,
647 matching_context,
648 );
649
650 if Q::should_stop_after_first_match() && !Q::is_empty(&results) {
651 break;
652 }
653 }
654
655 return Ok(());
656 }
657 if combinator.is_none() && simple_filter.is_none() {
658 if let Some(attr_name) = get_attr_name(other) {
659 simple_filter = Some(SimpleFilter::Attr(attr_name));
660 }
661 }
662 },
663 }
664 }
665
666 loop {
667 let next_combinator = match iter.next_sequence() {
668 None => break 'selector_loop,
669 Some(c) => c,
670 };
671
672 if next_combinator.is_sibling() {
676 for _ in &mut iter {}
678 continue;
679 }
680
681 combinator = Some(next_combinator);
682 break;
683 }
684 }
685
686 let simple_filter = match simple_filter {
689 Some(f) => f,
690 None => return Err(()),
691 };
692
693 match simple_filter {
694 SimpleFilter::Class(ref class) => {
695 collect_all_elements::<E, Q, _>(root, results, |element| {
696 element.has_class(class, class_and_id_case_sensitivity)
697 && matching::matches_selector_list(selector_list, &element, matching_context)
698 });
699 },
700 SimpleFilter::LocalName(ref local_name) => {
701 collect_all_elements::<E, Q, _>(root, results, |element| {
702 local_name_matches(element, local_name)
703 && matching::matches_selector_list(selector_list, &element, matching_context)
704 });
705 },
706 SimpleFilter::Attr(ref local_name) => {
707 collect_all_elements::<E, Q, _>(root, results, |element| {
708 has_attr(element, local_name)
709 && matching::matches_selector_list(selector_list, &element, matching_context)
710 });
711 },
712 }
713
714 Ok(())
715}
716
717fn query_selector_slow<E, Q>(
719 root: E::ConcreteNode,
720 selector_list: &SelectorList<E::Impl>,
721 results: &mut Q::Output,
722 matching_context: &mut MatchingContext<E::Impl>,
723) where
724 E: TElement,
725 Q: SelectorQuery<E>,
726{
727 collect_all_elements::<E, Q, _>(root, results, |element| {
728 matching::matches_selector_list(selector_list, &element, matching_context)
729 });
730}
731
732#[derive(PartialEq)]
734pub enum MayUseInvalidation {
735 Yes,
737 No,
739}
740
741pub fn query_selector<E, Q>(
743 root: E::ConcreteNode,
744 selector_list: &SelectorList<E::Impl>,
745 results: &mut Q::Output,
746 may_use_invalidation: MayUseInvalidation,
747) where
748 E: TElement,
749 Q: SelectorQuery<E>,
750{
751 use crate::invalidation::element::invalidator::TreeStyleInvalidator;
752
753 let mut selector_caches = SelectorCaches::default();
754 let quirks_mode = root.owner_doc().quirks_mode();
755
756 let mut matching_context = MatchingContext::new(
757 MatchingMode::Normal,
758 None,
759 &mut selector_caches,
760 quirks_mode,
761 NeedsSelectorFlags::No,
762 MatchingForInvalidation::No,
763 );
764 let root_element = root.as_element();
765 matching_context.scope_element = root_element.map(|e| e.opaque());
766 matching_context.current_host = match root_element {
767 Some(root) => root.containing_shadow_host().map(|host| host.opaque()),
768 None => root.as_shadow_root().map(|root| root.host().opaque()),
769 };
770
771 let fast_result =
772 query_selector_fast::<E, Q>(root, selector_list, results, &mut matching_context);
773
774 if fast_result.is_ok() {
775 return;
776 }
777
778 let invalidation_may_be_useful = may_use_invalidation == MayUseInvalidation::Yes
791 && selector_list.slice().iter().any(|s| s.len() > 2);
792
793 if root_element.is_some() || !invalidation_may_be_useful {
794 query_selector_slow::<E, Q>(root, selector_list, results, &mut matching_context);
795 } else {
796 let dependencies = selector_list
797 .slice()
798 .iter()
799 .map(|selector| Dependency::for_full_selector_invalidation(selector.clone()))
800 .collect::<SmallVec<[_; 5]>>();
801 let mut processor = QuerySelectorProcessor::<E, Q> {
802 results,
803 matching_context,
804 traversal_map: SiblingTraversalMap::default(),
805 dependencies: &dependencies,
806 };
807
808 for node in root.dom_children() {
809 if let Some(e) = node.as_element() {
810 TreeStyleInvalidator::new(e, None, &mut processor)
811 .invalidate();
812 }
813 }
814 }
815}