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