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 use selectors::matching::IncludeStartingStyle;
338
339 let include_starting_style = matches!(
340 matching_context.include_starting_style,
341 IncludeStartingStyle::Yes
342 );
343 for rule in rules {
344 let scope_proximity = if rule.scope_condition_id == ScopeConditionId::none() {
345 if !matches_selector(
346 &rule.selector,
347 0,
348 Some(&rule.hashes),
349 &element,
350 matching_context,
351 ) {
352 continue;
353 }
354 ScopeProximity::infinity()
355 } else {
356 let result =
357 cascade_data.find_scope_proximity_if_matching(rule, element, matching_context);
358 if result == ScopeProximity::infinity() {
359 continue;
360 }
361 result
362 };
363
364 if rule.container_condition_id != ContainerConditionId::none() {
365 if !cascade_data.container_condition_matches(
366 rule.container_condition_id,
367 stylist,
368 element,
369 matching_context,
370 ) {
371 continue;
372 }
373 }
374
375 if rule.is_starting_style {
376 matching_context.has_starting_style = true;
380
381 if !include_starting_style {
382 continue;
383 }
384 }
385
386 matching_rules.push(rule.to_applicable_declaration_block(
387 cascade_level,
388 cascade_data,
389 scope_proximity,
390 ));
391 }
392 }
393}
394
395impl<T: SelectorMapEntry> SelectorMap<T> {
396 pub fn insert(&mut self, entry: T, quirks_mode: QuirksMode) -> Result<(), AllocErr> {
398 self.count += 1;
399
400 macro_rules! insert_into_bucket {
405 ($entry:ident, $bucket:expr) => {{
406 let vec = match $bucket {
407 Bucket::Root => &mut self.root,
408 Bucket::ID(id) => self
409 .id_hash
410 .try_entry(id.clone(), quirks_mode)?
411 .or_default(),
412 Bucket::Class(class) => self
413 .class_hash
414 .try_entry(class.clone(), quirks_mode)?
415 .or_default(),
416 Bucket::Attribute { name, lower_name }
417 | Bucket::LocalName { name, lower_name } => {
418 let is_attribute = matches!($bucket, Bucket::Attribute { .. });
432 let hash = if is_attribute {
433 &mut self.attribute_hash
434 } else {
435 &mut self.local_name_hash
436 };
437 if name != lower_name {
438 hash.try_reserve(1)?;
439 let vec = hash.entry(lower_name.clone()).or_default();
440 vec.try_reserve(1)?;
441 vec.push($entry.clone());
442 }
443 hash.try_reserve(1)?;
444 hash.entry(name.clone()).or_default()
445 },
446 Bucket::Namespace(url) => {
447 self.namespace_hash.try_reserve(1)?;
448 self.namespace_hash.entry(url.clone()).or_default()
449 },
450 Bucket::RarePseudoClasses => &mut self.rare_pseudo_classes,
451 Bucket::Universal => &mut self.other,
452 };
453 vec.try_reserve(1)?;
454 vec.push($entry);
455 }};
456 }
457
458 let bucket = {
459 let mut disjoint_buckets = SmallVec::new();
460 let bucket = find_bucket(entry.selector(), &mut disjoint_buckets);
461
462 if !disjoint_buckets.is_empty()
478 && disjoint_buckets
479 .iter()
480 .all(|b| b.more_specific_than(&bucket))
481 {
482 for bucket in &disjoint_buckets {
483 let entry = entry.clone();
484 insert_into_bucket!(entry, *bucket);
485 }
486 return Ok(());
487 }
488 bucket
489 };
490
491 insert_into_bucket!(entry, bucket);
492 Ok(())
493 }
494
495 pub fn lookup<'a, E, F>(
506 &'a self,
507 element: E,
508 quirks_mode: QuirksMode,
509 relevant_attributes: Option<&mut RelevantAttributes>,
510 f: F,
511 ) -> bool
512 where
513 E: TElement,
514 F: FnMut(&'a T) -> bool,
515 {
516 self.lookup_with_state(
517 element,
518 element.state(),
519 quirks_mode,
520 relevant_attributes,
521 f,
522 )
523 }
524
525 #[inline]
526 fn lookup_with_state<'a, E, F>(
527 &'a self,
528 element: E,
529 element_state: ElementState,
530 quirks_mode: QuirksMode,
531 mut relevant_attributes: Option<&mut RelevantAttributes>,
532 mut f: F,
533 ) -> bool
534 where
535 E: TElement,
536 F: FnMut(&'a T) -> bool,
537 {
538 if element.is_root() {
539 for entry in self.root.iter() {
540 if !f(&entry) {
541 return false;
542 }
543 }
544 }
545
546 if let Some(id) = element.id() {
547 if let Some(v) = self.id_hash.get(id, quirks_mode) {
548 for entry in v.iter() {
549 if !f(&entry) {
550 return false;
551 }
552 }
553 }
554 }
555
556 let mut done = false;
557 element.each_class(|class| {
558 if done {
559 return;
560 }
561 if let Some(v) = self.class_hash.get(class, quirks_mode) {
562 for entry in v.iter() {
563 if !f(&entry) {
564 done = true;
565 return;
566 }
567 }
568 }
569 });
570
571 if done {
572 return false;
573 }
574
575 element.each_attr_name(|name| {
576 if done {
577 return;
578 }
579 if let Some(v) = self.attribute_hash.get(name) {
580 if let Some(ref mut relevant_attributes) = relevant_attributes {
581 relevant_attributes.push(name.clone());
582 }
583 for entry in v.iter() {
584 if !f(&entry) {
585 done = true;
586 return;
587 }
588 }
589 }
590 });
591
592 if done {
593 return false;
594 }
595
596 if let Some(v) = self.local_name_hash.get(element.local_name()) {
597 for entry in v.iter() {
598 if !f(&entry) {
599 return false;
600 }
601 }
602 }
603
604 if let Some(v) = self.namespace_hash.get(element.namespace()) {
605 for entry in v.iter() {
606 if !f(&entry) {
607 return false;
608 }
609 }
610 }
611
612 if element_state.intersects(RARE_PSEUDO_CLASS_STATES) {
613 for entry in self.rare_pseudo_classes.iter() {
614 if !f(&entry) {
615 return false;
616 }
617 }
618 }
619
620 for entry in self.other.iter() {
621 if !f(&entry) {
622 return false;
623 }
624 }
625
626 true
627 }
628
629 #[inline]
637 pub fn lookup_with_additional<'a, E, F>(
638 &'a self,
639 element: E,
640 quirks_mode: QuirksMode,
641 additional_id: Option<&WeakAtom>,
642 additional_classes: &[Atom],
643 additional_states: ElementState,
644 mut f: F,
645 ) -> bool
646 where
647 E: TElement,
648 F: FnMut(&'a T) -> bool,
649 {
650 if !self.lookup_with_state(
652 element,
653 element.state() | additional_states,
654 quirks_mode,
655 None,
656 |entry| f(entry),
657 ) {
658 return false;
659 }
660
661 if let Some(id) = additional_id {
663 if let Some(v) = self.id_hash.get(id, quirks_mode) {
664 for entry in v.iter() {
665 if !f(&entry) {
666 return false;
667 }
668 }
669 }
670 }
671
672 for class in additional_classes {
674 if let Some(v) = self.class_hash.get(class, quirks_mode) {
675 for entry in v.iter() {
676 if !f(&entry) {
677 return false;
678 }
679 }
680 }
681 }
682
683 true
684 }
685}
686
687enum Bucket<'a> {
688 Universal,
689 Namespace(&'a Namespace),
690 RarePseudoClasses,
691 LocalName {
692 name: &'a LocalName,
693 lower_name: &'a LocalName,
694 },
695 Attribute {
696 name: &'a LocalName,
697 lower_name: &'a LocalName,
698 },
699 Class(&'a Atom),
700 ID(&'a Atom),
701 Root,
702}
703
704impl<'a> Bucket<'a> {
705 #[inline]
707 fn specificity(&self) -> usize {
708 match *self {
709 Bucket::Universal => 0,
710 Bucket::Namespace(..) => 1,
711 Bucket::RarePseudoClasses => 2,
712 Bucket::LocalName { .. } => 3,
713 Bucket::Attribute { .. } => 4,
714 Bucket::Class(..) => 5,
715 Bucket::ID(..) => 6,
716 Bucket::Root => 7,
717 }
718 }
719
720 #[inline]
721 fn more_or_equally_specific_than(&self, other: &Self) -> bool {
722 self.specificity() >= other.specificity()
723 }
724
725 #[inline]
726 fn more_specific_than(&self, other: &Self) -> bool {
727 self.specificity() > other.specificity()
728 }
729}
730
731type DisjointBuckets<'a> = SmallVec<[Bucket<'a>; 5]>;
732
733fn specific_bucket_for<'a>(
734 component: &'a Component<SelectorImpl>,
735 disjoint_buckets: &mut DisjointBuckets<'a>,
736) -> Bucket<'a> {
737 match *component {
738 Component::Root => Bucket::Root,
739 Component::ID(ref id) => Bucket::ID(id),
740 Component::Class(ref class) => Bucket::Class(class),
741 Component::AttributeInNoNamespace { ref local_name, .. } => Bucket::Attribute {
742 name: local_name,
743 lower_name: local_name,
744 },
745 Component::AttributeInNoNamespaceExists {
746 ref local_name,
747 ref local_name_lower,
748 } => Bucket::Attribute {
749 name: local_name,
750 lower_name: local_name_lower,
751 },
752 Component::AttributeOther(ref selector) => Bucket::Attribute {
753 name: &selector.local_name,
754 lower_name: &selector.local_name_lower,
755 },
756 Component::LocalName(ref selector) => Bucket::LocalName {
757 name: &selector.name,
758 lower_name: &selector.lower_name,
759 },
760 Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) => {
761 Bucket::Namespace(url)
762 },
763 Component::Slotted(ref selector) => find_bucket(selector.iter(), disjoint_buckets),
782 Component::Host(Some(ref selector)) => find_bucket(selector.iter(), disjoint_buckets),
783 Component::Is(ref list) | Component::Where(ref list) => {
784 if list.len() == 1 {
785 find_bucket(list.slice()[0].iter(), disjoint_buckets)
786 } else {
787 for selector in list.slice() {
788 let bucket = find_bucket(selector.iter(), disjoint_buckets);
789 disjoint_buckets.push(bucket);
790 }
791 Bucket::Universal
792 }
793 },
794 Component::NonTSPseudoClass(ref pseudo_class)
795 if pseudo_class
796 .state_flag()
797 .intersects(RARE_PSEUDO_CLASS_STATES) =>
798 {
799 Bucket::RarePseudoClasses
800 },
801 _ => Bucket::Universal,
802 }
803}
804
805#[inline(always)]
811fn find_bucket<'a>(
812 mut iter: SelectorIter<'a, SelectorImpl>,
813 disjoint_buckets: &mut DisjointBuckets<'a>,
814) -> Bucket<'a> {
815 let mut current_bucket = Bucket::Universal;
816
817 loop {
818 for ss in &mut iter {
819 let new_bucket = specific_bucket_for(ss, disjoint_buckets);
820 if new_bucket.more_or_equally_specific_than(¤t_bucket) {
823 current_bucket = new_bucket;
824 }
825 }
826
827 if iter.next_sequence() != Some(Combinator::PseudoElement) {
830 break;
831 }
832 }
833
834 current_bucket
835}
836
837#[derive(Clone, Debug, MallocSizeOf)]
839pub struct MaybeCaseInsensitiveHashMap<K: PrecomputedHash + Hash + Eq, V>(PrecomputedHashMap<K, V>);
840
841impl<V> Default for MaybeCaseInsensitiveHashMap<Atom, V> {
842 #[inline]
843 fn default() -> Self {
844 MaybeCaseInsensitiveHashMap(PrecomputedHashMap::default())
845 }
846}
847
848impl<V> MaybeCaseInsensitiveHashMap<Atom, V> {
849 pub fn new() -> Self {
851 Self::default()
852 }
853
854 pub fn shrink_if_needed(&mut self) {
856 self.0.shrink_if_needed()
857 }
858
859 pub fn try_entry(
861 &mut self,
862 mut key: Atom,
863 quirks_mode: QuirksMode,
864 ) -> Result<hash_map::Entry<'_, Atom, V>, AllocErr> {
865 if quirks_mode == QuirksMode::Quirks {
866 key = key.to_ascii_lowercase()
867 }
868 self.0.try_reserve(1)?;
869 Ok(self.0.entry(key))
870 }
871
872 #[inline]
874 pub fn is_empty(&self) -> bool {
875 self.0.is_empty()
876 }
877
878 pub fn iter(&self) -> hash_map::Iter<'_, Atom, V> {
880 self.0.iter()
881 }
882
883 pub fn clear(&mut self) {
885 self.0.clear()
886 }
887
888 pub fn get(&self, key: &WeakAtom, quirks_mode: QuirksMode) -> Option<&V> {
890 if quirks_mode == QuirksMode::Quirks {
891 self.0.get(&key.to_ascii_lowercase())
892 } else {
893 self.0.get(key)
894 }
895 }
896}