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