1use crate::applicable_declarations::{ApplicableDeclarationList, ScopeProximity};
9use crate::context::QuirksMode;
10use crate::derives::*;
11use crate::dom::TElement;
12use crate::rule_tree::CascadeLevel;
13use crate::selector_parser::SelectorImpl;
14use crate::stylist::{CascadeData, ContainerConditionId, Rule, ScopeConditionId, Stylist};
15use crate::AllocErr;
16use crate::{Atom, LocalName, Namespace, ShrinkIfNeeded, WeakAtom};
17use dom::ElementState;
18use precomputed_hash::PrecomputedHash;
19use selectors::matching::{matches_selector, MatchingContext};
20use selectors::parser::{Combinator, Component, SelectorIter};
21use smallvec::SmallVec;
22use std::collections::hash_map;
23use std::collections::{HashMap, HashSet};
24use std::hash::{BuildHasherDefault, Hash, Hasher};
25
26pub struct PrecomputedHasher {
29 hash: Option<u32>,
30}
31
32impl Default for PrecomputedHasher {
33 fn default() -> Self {
34 Self { hash: None }
35 }
36}
37
38pub type RelevantAttributes = thin_vec::ThinVec<LocalName>;
40
41const RARE_PSEUDO_CLASS_STATES: ElementState = ElementState::from_bits_retain(
48 ElementState::FULLSCREEN.bits()
49 | ElementState::VISITED_OR_UNVISITED.bits()
50 | ElementState::URLTARGET.bits()
51 | ElementState::INERT.bits()
52 | ElementState::FOCUS.bits()
53 | ElementState::FOCUSRING.bits()
54 | ElementState::TOPMOST_MODAL.bits()
55 | ElementState::SUPPRESS_FOR_PRINT_SELECTION.bits()
56 | ElementState::ACTIVE_VIEW_TRANSITION.bits()
57 | ElementState::HEADING_LEVEL_BITS.bits(),
58);
59
60pub type PrecomputedHashMap<K, V> = HashMap<K, V, BuildHasherDefault<PrecomputedHasher>>;
62
63pub type PrecomputedHashSet<K> = HashSet<K, BuildHasherDefault<PrecomputedHasher>>;
65
66impl Hasher for PrecomputedHasher {
67 #[inline]
68 fn write(&mut self, _: &[u8]) {
69 unreachable!(
70 "Called into PrecomputedHasher with something that isn't \
71 a u32"
72 )
73 }
74
75 #[inline]
76 fn write_u32(&mut self, i: u32) {
77 debug_assert!(self.hash.is_none());
78 self.hash = Some(i);
79 }
80
81 #[inline]
82 fn finish(&self) -> u64 {
83 self.hash.expect("PrecomputedHasher wasn't fed?") as u64
84 }
85}
86
87pub trait SelectorMapEntry: Sized + Clone {
89 fn selector(&self) -> SelectorIter<'_, SelectorImpl>;
91}
92
93#[derive(Clone, Debug, MallocSizeOf)]
121pub struct SelectorMap<T: 'static> {
122 pub root: SmallVec<[T; 1]>,
124 pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
126 pub class_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
128 pub local_name_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
130 pub attribute_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
132 pub namespace_hash: PrecomputedHashMap<Namespace, SmallVec<[T; 1]>>,
134 pub rare_pseudo_classes: SmallVec<[T; 1]>,
136 pub other: SmallVec<[T; 1]>,
138 pub count: usize,
140}
141
142impl<T: 'static> Default for SelectorMap<T> {
143 #[inline]
144 fn default() -> Self {
145 Self::new()
146 }
147}
148
149impl<T> SelectorMap<T> {
150 pub fn new() -> Self {
152 SelectorMap {
153 root: SmallVec::new(),
154 id_hash: MaybeCaseInsensitiveHashMap::new(),
155 class_hash: MaybeCaseInsensitiveHashMap::new(),
156 attribute_hash: HashMap::default(),
157 local_name_hash: HashMap::default(),
158 namespace_hash: HashMap::default(),
159 rare_pseudo_classes: SmallVec::new(),
160 other: SmallVec::new(),
161 count: 0,
162 }
163 }
164
165 pub fn shrink_if_needed(&mut self) {
167 self.id_hash.shrink_if_needed();
168 self.class_hash.shrink_if_needed();
169 self.attribute_hash.shrink_if_needed();
170 self.local_name_hash.shrink_if_needed();
171 self.namespace_hash.shrink_if_needed();
172 }
173
174 pub fn clear(&mut self) {
176 self.root.clear();
177 self.id_hash.clear();
178 self.class_hash.clear();
179 self.attribute_hash.clear();
180 self.local_name_hash.clear();
181 self.namespace_hash.clear();
182 self.rare_pseudo_classes.clear();
183 self.other.clear();
184 self.count = 0;
185 }
186
187 pub fn is_empty(&self) -> bool {
189 self.count == 0
190 }
191
192 pub fn len(&self) -> usize {
194 self.count
195 }
196}
197
198impl SelectorMap<Rule> {
199 pub fn get_all_matching_rules<E>(
204 &self,
205 element: E,
206 rule_hash_target: E,
207 matching_rules_list: &mut ApplicableDeclarationList,
208 matching_context: &mut MatchingContext<E::Impl>,
209 cascade_level: CascadeLevel,
210 cascade_data: &CascadeData,
211 stylist: &Stylist,
212 ) where
213 E: TElement,
214 {
215 if self.is_empty() {
216 return;
217 }
218
219 let quirks_mode = matching_context.quirks_mode();
220
221 if rule_hash_target.is_root() {
222 SelectorMap::get_matching_rules(
223 element,
224 &self.root,
225 matching_rules_list,
226 matching_context,
227 cascade_level,
228 cascade_data,
229 stylist,
230 );
231 }
232
233 if let Some(id) = rule_hash_target.id() {
234 if let Some(rules) = self.id_hash.get(id, quirks_mode) {
235 SelectorMap::get_matching_rules(
236 element,
237 rules,
238 matching_rules_list,
239 matching_context,
240 cascade_level,
241 cascade_data,
242 stylist,
243 )
244 }
245 }
246
247 rule_hash_target.each_class(|class| {
248 if let Some(rules) = self.class_hash.get(&class, quirks_mode) {
249 SelectorMap::get_matching_rules(
250 element,
251 rules,
252 matching_rules_list,
253 matching_context,
254 cascade_level,
255 cascade_data,
256 stylist,
257 )
258 }
259 });
260
261 rule_hash_target.each_attr_name(|name| {
262 if let Some(rules) = self.attribute_hash.get(name) {
263 SelectorMap::get_matching_rules(
264 element,
265 rules,
266 matching_rules_list,
267 matching_context,
268 cascade_level,
269 cascade_data,
270 stylist,
271 )
272 }
273 });
274
275 if let Some(rules) = self.local_name_hash.get(rule_hash_target.local_name()) {
276 SelectorMap::get_matching_rules(
277 element,
278 rules,
279 matching_rules_list,
280 matching_context,
281 cascade_level,
282 cascade_data,
283 stylist,
284 )
285 }
286
287 if rule_hash_target
288 .state()
289 .intersects(RARE_PSEUDO_CLASS_STATES)
290 {
291 SelectorMap::get_matching_rules(
292 element,
293 &self.rare_pseudo_classes,
294 matching_rules_list,
295 matching_context,
296 cascade_level,
297 cascade_data,
298 stylist,
299 );
300 }
301
302 if let Some(rules) = self.namespace_hash.get(rule_hash_target.namespace()) {
303 SelectorMap::get_matching_rules(
304 element,
305 rules,
306 matching_rules_list,
307 matching_context,
308 cascade_level,
309 cascade_data,
310 stylist,
311 )
312 }
313
314 SelectorMap::get_matching_rules(
315 element,
316 &self.other,
317 matching_rules_list,
318 matching_context,
319 cascade_level,
320 cascade_data,
321 stylist,
322 );
323 }
324
325 pub(crate) fn get_matching_rules<E>(
327 element: E,
328 rules: &[Rule],
329 matching_rules: &mut ApplicableDeclarationList,
330 matching_context: &mut MatchingContext<E::Impl>,
331 cascade_level: CascadeLevel,
332 cascade_data: &CascadeData,
333 stylist: &Stylist,
334 ) where
335 E: TElement,
336 {
337 for rule in rules {
338 let scope_proximity = if rule.scope_condition_id == ScopeConditionId::none() {
339 if !matches_selector(
340 &rule.selector,
341 0,
342 Some(&rule.hashes),
343 &element,
344 matching_context,
345 ) {
346 continue;
347 }
348 ScopeProximity::infinity()
349 } else {
350 let result =
351 cascade_data.find_scope_proximity_if_matching(rule, element, matching_context);
352 if result == ScopeProximity::infinity() {
353 continue;
354 }
355 result
356 };
357
358 if rule.container_condition_id != ContainerConditionId::none() {
359 if !cascade_data.container_condition_matches(
360 rule.container_condition_id,
361 stylist,
362 element,
363 matching_context,
364 ) {
365 continue;
366 }
367 }
368 matching_rules.push(rule.to_applicable_declaration_block(
369 cascade_level,
370 cascade_data,
371 scope_proximity,
372 ));
373 }
374 }
375}
376
377impl<T: SelectorMapEntry> SelectorMap<T> {
378 pub fn insert(&mut self, entry: T, quirks_mode: QuirksMode) -> Result<(), AllocErr> {
380 self.count += 1;
381
382 macro_rules! insert_into_bucket {
387 ($entry:ident, $bucket:expr) => {{
388 let vec = match $bucket {
389 Bucket::Root => &mut self.root,
390 Bucket::ID(id) => self
391 .id_hash
392 .try_entry(id.clone(), quirks_mode)?
393 .or_default(),
394 Bucket::Class(class) => self
395 .class_hash
396 .try_entry(class.clone(), quirks_mode)?
397 .or_default(),
398 Bucket::Attribute { name, lower_name }
399 | Bucket::LocalName { name, lower_name } => {
400 let is_attribute = matches!($bucket, Bucket::Attribute { .. });
414 let hash = if is_attribute {
415 &mut self.attribute_hash
416 } else {
417 &mut self.local_name_hash
418 };
419 if name != lower_name {
420 hash.try_reserve(1)?;
421 let vec = hash.entry(lower_name.clone()).or_default();
422 vec.try_reserve(1)?;
423 vec.push($entry.clone());
424 }
425 hash.try_reserve(1)?;
426 hash.entry(name.clone()).or_default()
427 },
428 Bucket::Namespace(url) => {
429 self.namespace_hash.try_reserve(1)?;
430 self.namespace_hash.entry(url.clone()).or_default()
431 },
432 Bucket::RarePseudoClasses => &mut self.rare_pseudo_classes,
433 Bucket::Universal => &mut self.other,
434 };
435 vec.try_reserve(1)?;
436 vec.push($entry);
437 }};
438 }
439
440 let bucket = {
441 let mut disjoint_buckets = SmallVec::new();
442 let bucket = find_bucket(entry.selector(), &mut disjoint_buckets);
443
444 if !disjoint_buckets.is_empty()
460 && disjoint_buckets
461 .iter()
462 .all(|b| b.more_specific_than(&bucket))
463 {
464 for bucket in &disjoint_buckets {
465 let entry = entry.clone();
466 insert_into_bucket!(entry, *bucket);
467 }
468 return Ok(());
469 }
470 bucket
471 };
472
473 insert_into_bucket!(entry, bucket);
474 Ok(())
475 }
476
477 pub fn lookup<'a, E, F>(
488 &'a self,
489 element: E,
490 quirks_mode: QuirksMode,
491 relevant_attributes: Option<&mut RelevantAttributes>,
492 f: F,
493 ) -> bool
494 where
495 E: TElement,
496 F: FnMut(&'a T) -> bool,
497 {
498 self.lookup_with_state(
499 element,
500 element.state(),
501 quirks_mode,
502 relevant_attributes,
503 f,
504 )
505 }
506
507 #[inline]
508 fn lookup_with_state<'a, E, F>(
509 &'a self,
510 element: E,
511 element_state: ElementState,
512 quirks_mode: QuirksMode,
513 mut relevant_attributes: Option<&mut RelevantAttributes>,
514 mut f: F,
515 ) -> bool
516 where
517 E: TElement,
518 F: FnMut(&'a T) -> bool,
519 {
520 if element.is_root() {
521 for entry in self.root.iter() {
522 if !f(&entry) {
523 return false;
524 }
525 }
526 }
527
528 if let Some(id) = element.id() {
529 if let Some(v) = self.id_hash.get(id, quirks_mode) {
530 for entry in v.iter() {
531 if !f(&entry) {
532 return false;
533 }
534 }
535 }
536 }
537
538 let mut done = false;
539 element.each_class(|class| {
540 if done {
541 return;
542 }
543 if let Some(v) = self.class_hash.get(class, quirks_mode) {
544 for entry in v.iter() {
545 if !f(&entry) {
546 done = true;
547 return;
548 }
549 }
550 }
551 });
552
553 if done {
554 return false;
555 }
556
557 element.each_attr_name(|name| {
558 if done {
559 return;
560 }
561 if let Some(v) = self.attribute_hash.get(name) {
562 if let Some(ref mut relevant_attributes) = relevant_attributes {
563 relevant_attributes.push(name.clone());
564 }
565 for entry in v.iter() {
566 if !f(&entry) {
567 done = true;
568 return;
569 }
570 }
571 }
572 });
573
574 if done {
575 return false;
576 }
577
578 if let Some(v) = self.local_name_hash.get(element.local_name()) {
579 for entry in v.iter() {
580 if !f(&entry) {
581 return false;
582 }
583 }
584 }
585
586 if let Some(v) = self.namespace_hash.get(element.namespace()) {
587 for entry in v.iter() {
588 if !f(&entry) {
589 return false;
590 }
591 }
592 }
593
594 if element_state.intersects(RARE_PSEUDO_CLASS_STATES) {
595 for entry in self.rare_pseudo_classes.iter() {
596 if !f(&entry) {
597 return false;
598 }
599 }
600 }
601
602 for entry in self.other.iter() {
603 if !f(&entry) {
604 return false;
605 }
606 }
607
608 true
609 }
610
611 #[inline]
619 pub fn lookup_with_additional<'a, E, F>(
620 &'a self,
621 element: E,
622 quirks_mode: QuirksMode,
623 additional_id: Option<&WeakAtom>,
624 additional_classes: &[Atom],
625 additional_states: ElementState,
626 mut f: F,
627 ) -> bool
628 where
629 E: TElement,
630 F: FnMut(&'a T) -> bool,
631 {
632 if !self.lookup_with_state(
634 element,
635 element.state() | additional_states,
636 quirks_mode,
637 None,
638 |entry| f(entry),
639 ) {
640 return false;
641 }
642
643 if let Some(id) = additional_id {
645 if let Some(v) = self.id_hash.get(id, quirks_mode) {
646 for entry in v.iter() {
647 if !f(&entry) {
648 return false;
649 }
650 }
651 }
652 }
653
654 for class in additional_classes {
656 if let Some(v) = self.class_hash.get(class, quirks_mode) {
657 for entry in v.iter() {
658 if !f(&entry) {
659 return false;
660 }
661 }
662 }
663 }
664
665 true
666 }
667}
668
669#[derive(PartialEq)]
670enum Bucket<'a> {
671 Universal,
672 Namespace(&'a Namespace),
673 RarePseudoClasses,
674 LocalName {
675 name: &'a LocalName,
676 lower_name: &'a LocalName,
677 },
678 Attribute {
679 name: &'a LocalName,
680 lower_name: &'a LocalName,
681 },
682 Class(&'a Atom),
683 ID(&'a Atom),
684 Root,
685}
686
687impl<'a> Bucket<'a> {
688 #[inline]
690 fn specificity(&self) -> usize {
691 match *self {
692 Bucket::Universal => 0,
693 Bucket::Namespace(..) => 1,
694 Bucket::RarePseudoClasses => 2,
695 Bucket::LocalName { .. } => 3,
696 Bucket::Attribute { .. } => 4,
697 Bucket::Class(..) => 5,
698 Bucket::ID(..) => 6,
699 Bucket::Root => 7,
700 }
701 }
702
703 #[inline]
704 fn more_or_equally_specific_than(&self, other: &Self) -> bool {
705 self.specificity() >= other.specificity()
706 }
707
708 #[inline]
709 fn more_specific_than(&self, other: &Self) -> bool {
710 self.specificity() > other.specificity()
711 }
712}
713
714type DisjointBuckets<'a> = SmallVec<[Bucket<'a>; 5]>;
715
716fn specific_bucket_for<'a>(
717 component: &'a Component<SelectorImpl>,
718 disjoint_buckets: &mut DisjointBuckets<'a>,
719) -> Bucket<'a> {
720 match *component {
721 Component::Root => Bucket::Root,
722 Component::ID(ref id) => Bucket::ID(id),
723 Component::Class(ref class) => Bucket::Class(class),
724 Component::AttributeInNoNamespace { ref local_name, .. } => Bucket::Attribute {
725 name: local_name,
726 lower_name: local_name,
727 },
728 Component::AttributeInNoNamespaceExists {
729 ref local_name,
730 ref local_name_lower,
731 } => Bucket::Attribute {
732 name: local_name,
733 lower_name: local_name_lower,
734 },
735 Component::AttributeOther(ref selector) => Bucket::Attribute {
736 name: &selector.local_name,
737 lower_name: &selector.local_name_lower,
738 },
739 Component::LocalName(ref selector) => Bucket::LocalName {
740 name: &selector.name,
741 lower_name: &selector.lower_name,
742 },
743 Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
744 Bucket::Namespace(url)
745 },
746 Component::Slotted(ref selector) => find_bucket(selector.iter(), disjoint_buckets),
765 Component::Host(Some(ref selector)) => find_bucket(selector.iter(), disjoint_buckets),
766 Component::Is(ref list) | Component::Where(ref list) => {
767 if list.len() == 1 {
768 find_bucket(list.slice()[0].iter(), disjoint_buckets)
769 } else {
770 for selector in list.slice() {
771 let bucket = find_bucket(selector.iter(), disjoint_buckets);
772 if disjoint_buckets.last() == Some(&bucket) {
773 continue;
777 }
778 disjoint_buckets.push(bucket);
779 }
780 Bucket::Universal
781 }
782 },
783 Component::NonTSPseudoClass(ref pseudo_class)
784 if pseudo_class
785 .state_flag()
786 .intersects(RARE_PSEUDO_CLASS_STATES) =>
787 {
788 Bucket::RarePseudoClasses
789 },
790 _ => Bucket::Universal,
791 }
792}
793
794#[inline(always)]
800fn find_bucket<'a>(
801 mut iter: SelectorIter<'a, SelectorImpl>,
802 disjoint_buckets: &mut DisjointBuckets<'a>,
803) -> Bucket<'a> {
804 let mut current_bucket = Bucket::Universal;
805
806 loop {
807 for ss in &mut iter {
808 let new_bucket = specific_bucket_for(ss, disjoint_buckets);
809 if new_bucket.more_or_equally_specific_than(¤t_bucket) {
812 current_bucket = new_bucket;
813 }
814 }
815
816 if iter.next_sequence() != Some(Combinator::PseudoElement) {
819 break;
820 }
821 }
822
823 current_bucket
824}
825
826#[derive(Clone, Debug, MallocSizeOf)]
828pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V>(PrecomputedHashMap<K, V>);
829
830impl<V> Default for MaybeCaseInsensitiveHashMap<Atom, V> {
831 #[inline]
832 fn default() -> Self {
833 MaybeCaseInsensitiveHashMap(PrecomputedHashMap::default())
834 }
835}
836
837impl<V> MaybeCaseInsensitiveHashMap<Atom, V> {
838 pub fn new() -> Self {
840 Self::default()
841 }
842
843 pub fn shrink_if_needed(&mut self) {
845 self.0.shrink_if_needed()
846 }
847
848 pub fn try_entry(
850 &mut self,
851 mut key: Atom,
852 quirks_mode: QuirksMode,
853 ) -> Result<hash_map::Entry<'_, Atom, V>, AllocErr> {
854 if quirks_mode == QuirksMode::Quirks {
855 key = key.to_ascii_lowercase()
856 }
857 self.0.try_reserve(1)?;
858 Ok(self.0.entry(key))
859 }
860
861 #[inline]
863 pub fn is_empty(&self) -> bool {
864 self.0.is_empty()
865 }
866
867 pub fn iter(&self) -> hash_map::Iter<'_, Atom, V> {
869 self.0.iter()
870 }
871
872 pub fn clear(&mut self) {
874 self.0.clear()
875 }
876
877 pub fn get(&self, key: &WeakAtom, quirks_mode: QuirksMode) -> Option<&V> {
879 if quirks_mode == QuirksMode::Quirks {
880 self.0.get(&key.to_ascii_lowercase())
881 } else {
882 self.0.get(key)
883 }
884 }
885}