1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 //! Generic implementations of some DOM APIs so they can be shared between Servo
6 //! and Gecko.
7 
8 use crate::context::QuirksMode;
9 use crate::dom::{TDocument, TElement, TNode, TShadowRoot};
10 use crate::invalidation::element::invalidation_map::Dependency;
11 use crate::invalidation::element::invalidator::{DescendantInvalidationLists, Invalidation};
12 use crate::invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector};
13 use crate::values::AtomIdent;
14 use selectors::attr::CaseSensitivity;
15 use selectors::matching::{self, MatchingContext, MatchingMode};
16 use selectors::parser::{Combinator, Component, LocalName, SelectorImpl};
17 use selectors::{Element, NthIndexCache, SelectorList};
18 use smallvec::SmallVec;
19 
20 /// <https://dom.spec.whatwg.org/#dom-element-matches>
element_matches<E>( element: &E, selector_list: &SelectorList<E::Impl>, quirks_mode: QuirksMode, ) -> bool where E: Element,21 pub fn element_matches<E>(
22     element: &E,
23     selector_list: &SelectorList<E::Impl>,
24     quirks_mode: QuirksMode,
25 ) -> bool
26 where
27     E: Element,
28 {
29     let mut context = MatchingContext::new(MatchingMode::Normal, None, None, quirks_mode);
30     context.scope_element = Some(element.opaque());
31     context.current_host = element.containing_shadow_host().map(|e| e.opaque());
32     matching::matches_selector_list(selector_list, element, &mut context)
33 }
34 
35 /// <https://dom.spec.whatwg.org/#dom-element-closest>
element_closest<E>( element: E, selector_list: &SelectorList<E::Impl>, quirks_mode: QuirksMode, ) -> Option<E> where E: Element,36 pub fn element_closest<E>(
37     element: E,
38     selector_list: &SelectorList<E::Impl>,
39     quirks_mode: QuirksMode,
40 ) -> Option<E>
41 where
42     E: Element,
43 {
44     let mut nth_index_cache = NthIndexCache::default();
45 
46     let mut context = MatchingContext::new(
47         MatchingMode::Normal,
48         None,
49         Some(&mut nth_index_cache),
50         quirks_mode,
51     );
52     context.scope_element = Some(element.opaque());
53     context.current_host = element.containing_shadow_host().map(|e| e.opaque());
54 
55     let mut current = Some(element);
56     while let Some(element) = current.take() {
57         if matching::matches_selector_list(selector_list, &element, &mut context) {
58             return Some(element);
59         }
60         current = element.parent_element();
61     }
62 
63     return None;
64 }
65 
66 /// A selector query abstraction, in order to be generic over QuerySelector and
67 /// QuerySelectorAll.
68 pub trait SelectorQuery<E: TElement> {
69     /// The output of the query.
70     type Output;
71 
72     /// Whether the query should stop after the first element has been matched.
should_stop_after_first_match() -> bool73     fn should_stop_after_first_match() -> bool;
74 
75     /// Append an element matching after the first query.
append_element(output: &mut Self::Output, element: E)76     fn append_element(output: &mut Self::Output, element: E);
77 
78     /// Returns true if the output is empty.
is_empty(output: &Self::Output) -> bool79     fn is_empty(output: &Self::Output) -> bool;
80 }
81 
82 /// The result of a querySelectorAll call.
83 pub type QuerySelectorAllResult<E> = SmallVec<[E; 128]>;
84 
85 /// A query for all the elements in a subtree.
86 pub struct QueryAll;
87 
88 impl<E: TElement> SelectorQuery<E> for QueryAll {
89     type Output = QuerySelectorAllResult<E>;
90 
should_stop_after_first_match() -> bool91     fn should_stop_after_first_match() -> bool {
92         false
93     }
94 
append_element(output: &mut Self::Output, element: E)95     fn append_element(output: &mut Self::Output, element: E) {
96         output.push(element);
97     }
98 
is_empty(output: &Self::Output) -> bool99     fn is_empty(output: &Self::Output) -> bool {
100         output.is_empty()
101     }
102 }
103 
104 /// A query for the first in-tree match of all the elements in a subtree.
105 pub struct QueryFirst;
106 
107 impl<E: TElement> SelectorQuery<E> for QueryFirst {
108     type Output = Option<E>;
109 
should_stop_after_first_match() -> bool110     fn should_stop_after_first_match() -> bool {
111         true
112     }
113 
append_element(output: &mut Self::Output, element: E)114     fn append_element(output: &mut Self::Output, element: E) {
115         if output.is_none() {
116             *output = Some(element)
117         }
118     }
119 
is_empty(output: &Self::Output) -> bool120     fn is_empty(output: &Self::Output) -> bool {
121         output.is_none()
122     }
123 }
124 
125 struct QuerySelectorProcessor<'a, E, Q>
126 where
127     E: TElement + 'a,
128     Q: SelectorQuery<E>,
129     Q::Output: 'a,
130 {
131     results: &'a mut Q::Output,
132     matching_context: MatchingContext<'a, E::Impl>,
133     dependencies: &'a [Dependency],
134 }
135 
136 impl<'a, E, Q> InvalidationProcessor<'a, E> for QuerySelectorProcessor<'a, E, Q>
137 where
138     E: TElement + 'a,
139     Q: SelectorQuery<E>,
140     Q::Output: 'a,
141 {
light_tree_only(&self) -> bool142     fn light_tree_only(&self) -> bool {
143         true
144     }
145 
check_outer_dependency(&mut self, _: &Dependency, _: E) -> bool146     fn check_outer_dependency(&mut self, _: &Dependency, _: E) -> bool {
147         debug_assert!(
148             false,
149             "How? We should only have parent-less dependencies here!"
150         );
151         true
152     }
153 
collect_invalidations( &mut self, element: E, self_invalidations: &mut InvalidationVector<'a>, descendant_invalidations: &mut DescendantInvalidationLists<'a>, _sibling_invalidations: &mut InvalidationVector<'a>, ) -> bool154     fn collect_invalidations(
155         &mut self,
156         element: E,
157         self_invalidations: &mut InvalidationVector<'a>,
158         descendant_invalidations: &mut DescendantInvalidationLists<'a>,
159         _sibling_invalidations: &mut InvalidationVector<'a>,
160     ) -> bool {
161         // TODO(emilio): If the element is not a root element, and
162         // selector_list has any descendant combinator, we need to do extra work
163         // in order to handle properly things like:
164         //
165         //   <div id="a">
166         //     <div id="b">
167         //       <div id="c"></div>
168         //     </div>
169         //   </div>
170         //
171         // b.querySelector('#a div'); // Should return "c".
172         //
173         // For now, assert it's a root element.
174         debug_assert!(element.parent_element().is_none());
175 
176         let target_vector = if self.matching_context.scope_element.is_some() {
177             &mut descendant_invalidations.dom_descendants
178         } else {
179             self_invalidations
180         };
181 
182         for dependency in self.dependencies.iter() {
183             target_vector.push(Invalidation::new(
184                 dependency,
185                 self.matching_context.current_host.clone(),
186             ))
187         }
188 
189         false
190     }
191 
matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl>192     fn matching_context(&mut self) -> &mut MatchingContext<'a, E::Impl> {
193         &mut self.matching_context
194     }
195 
should_process_descendants(&mut self, _: E) -> bool196     fn should_process_descendants(&mut self, _: E) -> bool {
197         if Q::should_stop_after_first_match() {
198             return Q::is_empty(&self.results);
199         }
200 
201         true
202     }
203 
invalidated_self(&mut self, e: E)204     fn invalidated_self(&mut self, e: E) {
205         Q::append_element(self.results, e);
206     }
207 
recursion_limit_exceeded(&mut self, _e: E)208     fn recursion_limit_exceeded(&mut self, _e: E) {}
invalidated_descendants(&mut self, _e: E, _child: E)209     fn invalidated_descendants(&mut self, _e: E, _child: E) {}
210 }
211 
collect_all_elements<E, Q, F>(root: E::ConcreteNode, results: &mut Q::Output, mut filter: F) where E: TElement, Q: SelectorQuery<E>, F: FnMut(E) -> bool,212 fn collect_all_elements<E, Q, F>(root: E::ConcreteNode, results: &mut Q::Output, mut filter: F)
213 where
214     E: TElement,
215     Q: SelectorQuery<E>,
216     F: FnMut(E) -> bool,
217 {
218     for node in root.dom_descendants() {
219         let element = match node.as_element() {
220             Some(e) => e,
221             None => continue,
222         };
223 
224         if !filter(element) {
225             continue;
226         }
227 
228         Q::append_element(results, element);
229         if Q::should_stop_after_first_match() {
230             return;
231         }
232     }
233 }
234 
235 /// Returns whether a given element connected to `root` is descendant of `root`.
236 ///
237 /// NOTE(emilio): if root == element, this returns false.
connected_element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool where E: TElement,238 fn connected_element_is_descendant_of<E>(element: E, root: E::ConcreteNode) -> bool
239 where
240     E: TElement,
241 {
242     // Optimize for when the root is a document or a shadow root and the element
243     // is connected to that root.
244     if root.as_document().is_some() {
245         debug_assert!(element.as_node().is_in_document(), "Not connected?");
246         debug_assert_eq!(
247             root,
248             root.owner_doc().as_node(),
249             "Where did this element come from?",
250         );
251         return true;
252     }
253 
254     if root.as_shadow_root().is_some() {
255         debug_assert_eq!(
256             element.containing_shadow().unwrap().as_node(),
257             root,
258             "Not connected?"
259         );
260         return true;
261     }
262 
263     let mut current = element.as_node().parent_node();
264     while let Some(n) = current.take() {
265         if n == root {
266             return true;
267         }
268 
269         current = n.parent_node();
270     }
271     false
272 }
273 
274 /// Fast path for iterating over every element with a given id in the document
275 /// or shadow root that `root` is connected to.
fast_connected_elements_with_id<'a, N>( root: N, id: &AtomIdent, quirks_mode: QuirksMode, ) -> Result<&'a [N::ConcreteElement], ()> where N: TNode + 'a,276 fn fast_connected_elements_with_id<'a, N>(
277     root: N,
278     id: &AtomIdent,
279     quirks_mode: QuirksMode,
280 ) -> Result<&'a [N::ConcreteElement], ()>
281 where
282     N: TNode + 'a,
283 {
284     let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
285     if case_sensitivity != CaseSensitivity::CaseSensitive {
286         return Err(());
287     }
288 
289     if root.is_in_document() {
290         return root.owner_doc().elements_with_id(id);
291     }
292 
293     if let Some(shadow) = root.as_shadow_root() {
294         return shadow.elements_with_id(id);
295     }
296 
297     if let Some(shadow) = root.as_element().and_then(|e| e.containing_shadow()) {
298         return shadow.elements_with_id(id);
299     }
300 
301     Err(())
302 }
303 
304 /// Collects elements with a given id under `root`, that pass `filter`.
collect_elements_with_id<E, Q, F>( root: E::ConcreteNode, id: &AtomIdent, results: &mut Q::Output, quirks_mode: QuirksMode, mut filter: F, ) where E: TElement, Q: SelectorQuery<E>, F: FnMut(E) -> bool,305 fn collect_elements_with_id<E, Q, F>(
306     root: E::ConcreteNode,
307     id: &AtomIdent,
308     results: &mut Q::Output,
309     quirks_mode: QuirksMode,
310     mut filter: F,
311 ) where
312     E: TElement,
313     Q: SelectorQuery<E>,
314     F: FnMut(E) -> bool,
315 {
316     let elements = match fast_connected_elements_with_id(root, id, quirks_mode) {
317         Ok(elements) => elements,
318         Err(()) => {
319             let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
320 
321             collect_all_elements::<E, Q, _>(root, results, |e| {
322                 e.has_id(id, case_sensitivity) && filter(e)
323             });
324 
325             return;
326         },
327     };
328 
329     for element in elements {
330         // If the element is not an actual descendant of the root, even though
331         // it's connected, we don't really care about it.
332         if !connected_element_is_descendant_of(*element, root) {
333             continue;
334         }
335 
336         if !filter(*element) {
337             continue;
338         }
339 
340         Q::append_element(results, *element);
341         if Q::should_stop_after_first_match() {
342             break;
343         }
344     }
345 }
346 
347 #[inline(always)]
local_name_matches<E>(element: E, local_name: &LocalName<E::Impl>) -> bool where E: TElement,348 fn local_name_matches<E>(element: E, local_name: &LocalName<E::Impl>) -> bool
349 where
350     E: TElement,
351 {
352     let LocalName {
353         ref name,
354         ref lower_name,
355     } = *local_name;
356 
357     let chosen_name = if element.is_html_element_in_html_document() {
358         lower_name
359     } else {
360         name
361     };
362 
363     element.local_name() == &**chosen_name
364 }
365 
366 /// Fast paths for querySelector with a single simple selector.
query_selector_single_query<E, Q>( root: E::ConcreteNode, component: &Component<E::Impl>, results: &mut Q::Output, quirks_mode: QuirksMode, ) -> Result<(), ()> where E: TElement, Q: SelectorQuery<E>,367 fn query_selector_single_query<E, Q>(
368     root: E::ConcreteNode,
369     component: &Component<E::Impl>,
370     results: &mut Q::Output,
371     quirks_mode: QuirksMode,
372 ) -> Result<(), ()>
373 where
374     E: TElement,
375     Q: SelectorQuery<E>,
376 {
377     match *component {
378         Component::ExplicitUniversalType => {
379             collect_all_elements::<E, Q, _>(root, results, |_| true)
380         },
381         Component::ID(ref id) => {
382             collect_elements_with_id::<E, Q, _>(root, id, results, quirks_mode, |_| true);
383         },
384         Component::Class(ref class) => {
385             let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
386             collect_all_elements::<E, Q, _>(root, results, |element| {
387                 element.has_class(class, case_sensitivity)
388             })
389         },
390         Component::LocalName(ref local_name) => {
391             collect_all_elements::<E, Q, _>(root, results, |element| {
392                 local_name_matches(element, local_name)
393             })
394         },
395         // TODO(emilio): More fast paths?
396         _ => return Err(()),
397     }
398 
399     Ok(())
400 }
401 
402 enum SimpleFilter<'a, Impl: SelectorImpl> {
403     Class(&'a AtomIdent),
404     LocalName(&'a LocalName<Impl>),
405 }
406 
407 /// Fast paths for a given selector query.
408 ///
409 /// When there's only one component, we go directly to
410 /// `query_selector_single_query`, otherwise, we try to optimize by looking just
411 /// at the subtrees rooted at ids in the selector, and otherwise we try to look
412 /// up by class name or local name in the rightmost compound.
413 ///
414 /// FIXME(emilio, nbp): This may very well be a good candidate for code to be
415 /// replaced by HolyJit :)
query_selector_fast<E, Q>( root: E::ConcreteNode, selector_list: &SelectorList<E::Impl>, results: &mut Q::Output, matching_context: &mut MatchingContext<E::Impl>, ) -> Result<(), ()> where E: TElement, Q: SelectorQuery<E>,416 fn query_selector_fast<E, Q>(
417     root: E::ConcreteNode,
418     selector_list: &SelectorList<E::Impl>,
419     results: &mut Q::Output,
420     matching_context: &mut MatchingContext<E::Impl>,
421 ) -> Result<(), ()>
422 where
423     E: TElement,
424     Q: SelectorQuery<E>,
425 {
426     // We need to return elements in document order, and reordering them
427     // afterwards is kinda silly.
428     if selector_list.0.len() > 1 {
429         return Err(());
430     }
431 
432     let selector = &selector_list.0[0];
433     let quirks_mode = matching_context.quirks_mode();
434 
435     // Let's just care about the easy cases for now.
436     if selector.len() == 1 {
437         return query_selector_single_query::<E, Q>(
438             root,
439             selector.iter().next().unwrap(),
440             results,
441             quirks_mode,
442         );
443     }
444 
445     let mut iter = selector.iter();
446     let mut combinator: Option<Combinator> = None;
447 
448     // We want to optimize some cases where there's no id involved whatsoever,
449     // like `.foo .bar`, but we don't want to make `#foo .bar` slower because of
450     // that.
451     let mut simple_filter = None;
452 
453     'selector_loop: loop {
454         debug_assert!(combinator.map_or(true, |c| !c.is_sibling()));
455 
456         'component_loop: for component in &mut iter {
457             match *component {
458                 Component::ID(ref id) => {
459                     if combinator.is_none() {
460                         // In the rightmost compound, just find descendants of
461                         // root that match the selector list with that id.
462                         collect_elements_with_id::<E, Q, _>(root, id, results, quirks_mode, |e| {
463                             matching::matches_selector_list(selector_list, &e, matching_context)
464                         });
465 
466                         return Ok(());
467                     }
468 
469                     let elements = fast_connected_elements_with_id(root, id, quirks_mode)?;
470                     if elements.is_empty() {
471                         return Ok(());
472                     }
473 
474                     // Results need to be in document order. Let's not bother
475                     // reordering or deduplicating nodes, which we would need to
476                     // do if one element with the given id were a descendant of
477                     // another element with that given id.
478                     if !Q::should_stop_after_first_match() && elements.len() > 1 {
479                         continue;
480                     }
481 
482                     for element in elements {
483                         // If the element is not a descendant of the root, then
484                         // it may have descendants that match our selector that
485                         // _are_ descendants of the root, and other descendants
486                         // that match our selector that are _not_.
487                         //
488                         // So we can't just walk over the element's descendants
489                         // and match the selector against all of them, nor can
490                         // we skip looking at this element's descendants.
491                         //
492                         // Give up on trying to optimize based on this id and
493                         // keep walking our selector.
494                         if !connected_element_is_descendant_of(*element, root) {
495                             continue 'component_loop;
496                         }
497 
498                         query_selector_slow::<E, Q>(
499                             element.as_node(),
500                             selector_list,
501                             results,
502                             matching_context,
503                         );
504 
505                         if Q::should_stop_after_first_match() && !Q::is_empty(&results) {
506                             break;
507                         }
508                     }
509 
510                     return Ok(());
511                 },
512                 Component::Class(ref class) => {
513                     if combinator.is_none() {
514                         simple_filter = Some(SimpleFilter::Class(class));
515                     }
516                 },
517                 Component::LocalName(ref local_name) => {
518                     if combinator.is_none() {
519                         // Prefer to look at class rather than local-name if
520                         // both are present.
521                         if let Some(SimpleFilter::Class(..)) = simple_filter {
522                             continue;
523                         }
524                         simple_filter = Some(SimpleFilter::LocalName(local_name));
525                     }
526                 },
527                 _ => {},
528             }
529         }
530 
531         loop {
532             let next_combinator = match iter.next_sequence() {
533                 None => break 'selector_loop,
534                 Some(c) => c,
535             };
536 
537             // We don't want to scan stuff affected by sibling combinators,
538             // given we scan the subtree of elements with a given id (and we
539             // don't want to care about scanning the siblings' subtrees).
540             if next_combinator.is_sibling() {
541                 // Advance to the next combinator.
542                 for _ in &mut iter {}
543                 continue;
544             }
545 
546             combinator = Some(next_combinator);
547             break;
548         }
549     }
550 
551     // We got here without finding any ID or such that we could handle. Try to
552     // use one of the simple filters.
553     let simple_filter = match simple_filter {
554         Some(f) => f,
555         None => return Err(()),
556     };
557 
558     match simple_filter {
559         SimpleFilter::Class(ref class) => {
560             let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity();
561             collect_all_elements::<E, Q, _>(root, results, |element| {
562                 element.has_class(class, case_sensitivity) &&
563                     matching::matches_selector_list(selector_list, &element, matching_context)
564             });
565         },
566         SimpleFilter::LocalName(ref local_name) => {
567             collect_all_elements::<E, Q, _>(root, results, |element| {
568                 local_name_matches(element, local_name) &&
569                     matching::matches_selector_list(selector_list, &element, matching_context)
570             });
571         },
572     }
573 
574     Ok(())
575 }
576 
577 // Slow path for a given selector query.
query_selector_slow<E, Q>( root: E::ConcreteNode, selector_list: &SelectorList<E::Impl>, results: &mut Q::Output, matching_context: &mut MatchingContext<E::Impl>, ) where E: TElement, Q: SelectorQuery<E>,578 fn query_selector_slow<E, Q>(
579     root: E::ConcreteNode,
580     selector_list: &SelectorList<E::Impl>,
581     results: &mut Q::Output,
582     matching_context: &mut MatchingContext<E::Impl>,
583 ) where
584     E: TElement,
585     Q: SelectorQuery<E>,
586 {
587     collect_all_elements::<E, Q, _>(root, results, |element| {
588         matching::matches_selector_list(selector_list, &element, matching_context)
589     });
590 }
591 
592 /// Whether the invalidation machinery should be used for this query.
593 #[derive(PartialEq)]
594 pub enum MayUseInvalidation {
595     /// We may use it if we deem it useful.
596     Yes,
597     /// Don't use it.
598     No,
599 }
600 
601 /// <https://dom.spec.whatwg.org/#dom-parentnode-queryselector>
query_selector<E, Q>( root: E::ConcreteNode, selector_list: &SelectorList<E::Impl>, results: &mut Q::Output, may_use_invalidation: MayUseInvalidation, ) where E: TElement, Q: SelectorQuery<E>,602 pub fn query_selector<E, Q>(
603     root: E::ConcreteNode,
604     selector_list: &SelectorList<E::Impl>,
605     results: &mut Q::Output,
606     may_use_invalidation: MayUseInvalidation,
607 ) where
608     E: TElement,
609     Q: SelectorQuery<E>,
610 {
611     use crate::invalidation::element::invalidator::TreeStyleInvalidator;
612 
613     let quirks_mode = root.owner_doc().quirks_mode();
614 
615     let mut nth_index_cache = NthIndexCache::default();
616     let mut matching_context = MatchingContext::new(
617         MatchingMode::Normal,
618         None,
619         Some(&mut nth_index_cache),
620         quirks_mode,
621     );
622 
623     let root_element = root.as_element();
624     matching_context.scope_element = root_element.map(|e| e.opaque());
625     matching_context.current_host = match root_element {
626         Some(root) => root.containing_shadow_host().map(|host| host.opaque()),
627         None => root.as_shadow_root().map(|root| root.host().opaque()),
628     };
629 
630     let fast_result =
631         query_selector_fast::<E, Q>(root, selector_list, results, &mut matching_context);
632 
633     if fast_result.is_ok() {
634         return;
635     }
636 
637     // Slow path: Use the invalidation machinery if we're a root, and tree
638     // traversal otherwise.
639     //
640     // See the comment in collect_invalidations to see why only if we're a root.
641     //
642     // The invalidation mechanism is only useful in presence of combinators.
643     //
644     // We could do that check properly here, though checking the length of the
645     // selectors is a good heuristic.
646     //
647     // A selector with a combinator needs to have a length of at least 3: A
648     // simple selector, a combinator, and another simple selector.
649     let invalidation_may_be_useful = may_use_invalidation == MayUseInvalidation::Yes &&
650         selector_list.0.iter().any(|s| s.len() > 2);
651 
652     if root_element.is_some() || !invalidation_may_be_useful {
653         query_selector_slow::<E, Q>(root, selector_list, results, &mut matching_context);
654     } else {
655         let dependencies = selector_list
656             .0
657             .iter()
658             .map(|selector| Dependency::for_full_selector_invalidation(selector.clone()))
659             .collect::<SmallVec<[_; 5]>>();
660         let mut processor = QuerySelectorProcessor::<E, Q> {
661             results,
662             matching_context,
663             dependencies: &dependencies,
664         };
665 
666         for node in root.dom_children() {
667             if let Some(e) = node.as_element() {
668                 TreeStyleInvalidator::new(e, /* stack_limit_checker = */ None, &mut processor)
669                     .invalidate();
670             }
671         }
672     }
673 }
674