diff --git a/components/style/selector_map.rs b/components/style/selector_map.rs index 3b0dcca9525..3ab78ce2d87 100644 --- a/components/style/selector_map.rs +++ b/components/style/selector_map.rs @@ -96,6 +96,8 @@ pub trait SelectorMapEntry: Sized + Clone { /// TODO: Tune the initial capacity of the HashMap #[derive(Debug, MallocSizeOf)] pub struct SelectorMap { + /// Rules that have `:root` selectors. + pub root: SmallVec<[T; 1]>, /// A hash from an ID to rules which contain that ID selector. pub id_hash: MaybeCaseInsensitiveHashMap>, /// A hash from a class name to rules which contain that class selector. @@ -104,7 +106,7 @@ pub struct SelectorMap { pub local_name_hash: PrecomputedHashMap>, /// A hash from namespace to rules which contain that namespace selector. pub namespace_hash: PrecomputedHashMap>, - /// Rules that don't have ID, class, or element selectors. + /// All other rules. pub other: SmallVec<[T; 1]>, /// The number of entries in this map. pub count: usize, @@ -124,6 +126,7 @@ impl SelectorMap { /// Trivially constructs an empty `SelectorMap`. pub fn new() -> Self { SelectorMap { + root: SmallVec::new(), id_hash: MaybeCaseInsensitiveHashMap::new(), class_hash: MaybeCaseInsensitiveHashMap::new(), local_name_hash: HashMap::default(), @@ -135,6 +138,7 @@ impl SelectorMap { /// Clears the hashmap retaining storage. pub fn clear(&mut self) { + self.root.clear(); self.id_hash.clear(); self.class_hash.clear(); self.local_name_hash.clear(); @@ -181,6 +185,19 @@ impl SelectorMap { // At the end, we're going to sort the rules that we added, so remember // where we began. let init_len = matching_rules_list.len(); + + if rule_hash_target.is_root() { + SelectorMap::get_matching_rules( + element, + &self.root, + matching_rules_list, + context, + flags_setter, + cascade_level, + shadow_cascade_order, + ); + } + if let Some(id) = rule_hash_target.id() { if let Some(rules) = self.id_hash.get(id, quirks_mode) { SelectorMap::get_matching_rules( @@ -287,6 +304,7 @@ impl SelectorMap { self.count += 1; let vector = match find_bucket(entry.selector()) { + Bucket::Root => &mut self.root, Bucket::ID(id) => self.id_hash .try_entry(id.clone(), quirks_mode)? .or_insert_with(SmallVec::new), @@ -340,6 +358,14 @@ impl SelectorMap { E: TElement, F: FnMut(&'a T) -> bool, { + if element.is_root() { + for entry in self.root.iter() { + if !f(&entry) { + return false; + } + } + } + if let Some(id) = element.id() { if let Some(v) = self.id_hash.get(id, quirks_mode) { for entry in v.iter() { @@ -444,6 +470,7 @@ impl SelectorMap { } enum Bucket<'a> { + Root, ID(&'a Atom), Class(&'a Atom), LocalName { @@ -456,6 +483,7 @@ enum Bucket<'a> { fn specific_bucket_for<'a>(component: &'a Component) -> Bucket<'a> { match *component { + Component::Root => Bucket::Root, Component::ID(ref id) => Bucket::ID(id), Component::Class(ref class) => Bucket::Class(class), Component::LocalName(ref selector) => Bucket::LocalName { @@ -498,14 +526,19 @@ fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> { // We basically want to find the most specific bucket, // where: // - // id > class > local name > namespace > universal. + // root > id > class > local name > namespace > universal. // for ss in &mut iter { let new_bucket = specific_bucket_for(ss); match new_bucket { - Bucket::ID(..) => return new_bucket, - Bucket::Class(..) => { + Bucket::Root => return new_bucket, + Bucket::ID(..) => { current_bucket = new_bucket; + } + Bucket::Class(..) => { + if !matches!(current_bucket, Bucket::ID(..)) { + current_bucket = new_bucket; + } }, Bucket::LocalName { .. } => { if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) {