mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
style: Add a root bucket to the selector map.
:root can't change without getting unbound from the tree so no fancy stuff other than that needed. This removes a lot of revalidation and attribute invalidation matching from the Chrome, and looks like it should be a good idea in general. Differential Revision: https://phabricator.services.mozilla.com/D2462
This commit is contained in:
parent
0b520c9558
commit
2e3aacdf80
1 changed files with 37 additions and 4 deletions
|
@ -96,6 +96,8 @@ pub trait SelectorMapEntry: Sized + Clone {
|
|||
/// TODO: Tune the initial capacity of the HashMap
|
||||
#[derive(Debug, MallocSizeOf)]
|
||||
pub struct SelectorMap<T: 'static> {
|
||||
/// 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<Atom, SmallVec<[T; 1]>>,
|
||||
/// A hash from a class name to rules which contain that class selector.
|
||||
|
@ -104,7 +106,7 @@ pub struct SelectorMap<T: 'static> {
|
|||
pub local_name_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
|
||||
/// A hash from namespace to rules which contain that namespace selector.
|
||||
pub namespace_hash: PrecomputedHashMap<Namespace, SmallVec<[T; 1]>>,
|
||||
/// 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<T: 'static> SelectorMap<T> {
|
|||
/// 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<T: 'static> SelectorMap<T> {
|
|||
|
||||
/// 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<Rule> {
|
|||
// 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<T: SelectorMapEntry> SelectorMap<T> {
|
|||
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<T: SelectorMapEntry> SelectorMap<T> {
|
|||
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<T: SelectorMapEntry> SelectorMap<T> {
|
|||
}
|
||||
|
||||
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<SelectorImpl>) -> 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(..)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue