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