mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23: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
|
/// TODO: Tune the initial capacity of the HashMap
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub struct SelectorMap<T: 'static> {
|
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.
|
/// A hash from an ID to rules which contain that ID selector.
|
||||||
pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
|
pub id_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
|
||||||
/// A hash from a class name to rules which contain that class selector.
|
/// 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]>>,
|
pub local_name_hash: PrecomputedHashMap<LocalName, SmallVec<[T; 1]>>,
|
||||||
/// A hash from namespace to rules which contain that namespace selector.
|
/// A hash from namespace to rules which contain that namespace selector.
|
||||||
pub namespace_hash: PrecomputedHashMap<Namespace, SmallVec<[T; 1]>>,
|
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]>,
|
pub other: SmallVec<[T; 1]>,
|
||||||
/// The number of entries in this map.
|
/// The number of entries in this map.
|
||||||
pub count: usize,
|
pub count: usize,
|
||||||
|
@ -124,6 +126,7 @@ impl<T: 'static> SelectorMap<T> {
|
||||||
/// Trivially constructs an empty `SelectorMap`.
|
/// Trivially constructs an empty `SelectorMap`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SelectorMap {
|
SelectorMap {
|
||||||
|
root: SmallVec::new(),
|
||||||
id_hash: MaybeCaseInsensitiveHashMap::new(),
|
id_hash: MaybeCaseInsensitiveHashMap::new(),
|
||||||
class_hash: MaybeCaseInsensitiveHashMap::new(),
|
class_hash: MaybeCaseInsensitiveHashMap::new(),
|
||||||
local_name_hash: HashMap::default(),
|
local_name_hash: HashMap::default(),
|
||||||
|
@ -135,6 +138,7 @@ impl<T: 'static> SelectorMap<T> {
|
||||||
|
|
||||||
/// Clears the hashmap retaining storage.
|
/// Clears the hashmap retaining storage.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
|
self.root.clear();
|
||||||
self.id_hash.clear();
|
self.id_hash.clear();
|
||||||
self.class_hash.clear();
|
self.class_hash.clear();
|
||||||
self.local_name_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
|
// At the end, we're going to sort the rules that we added, so remember
|
||||||
// where we began.
|
// where we began.
|
||||||
let init_len = matching_rules_list.len();
|
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(id) = rule_hash_target.id() {
|
||||||
if let Some(rules) = self.id_hash.get(id, quirks_mode) {
|
if let Some(rules) = self.id_hash.get(id, quirks_mode) {
|
||||||
SelectorMap::get_matching_rules(
|
SelectorMap::get_matching_rules(
|
||||||
|
@ -287,6 +304,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
self.count += 1;
|
self.count += 1;
|
||||||
|
|
||||||
let vector = match find_bucket(entry.selector()) {
|
let vector = match find_bucket(entry.selector()) {
|
||||||
|
Bucket::Root => &mut self.root,
|
||||||
Bucket::ID(id) => self.id_hash
|
Bucket::ID(id) => self.id_hash
|
||||||
.try_entry(id.clone(), quirks_mode)?
|
.try_entry(id.clone(), quirks_mode)?
|
||||||
.or_insert_with(SmallVec::new),
|
.or_insert_with(SmallVec::new),
|
||||||
|
@ -340,6 +358,14 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
E: TElement,
|
E: TElement,
|
||||||
F: FnMut(&'a T) -> bool,
|
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(id) = element.id() {
|
||||||
if let Some(v) = self.id_hash.get(id, quirks_mode) {
|
if let Some(v) = self.id_hash.get(id, quirks_mode) {
|
||||||
for entry in v.iter() {
|
for entry in v.iter() {
|
||||||
|
@ -444,6 +470,7 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Bucket<'a> {
|
enum Bucket<'a> {
|
||||||
|
Root,
|
||||||
ID(&'a Atom),
|
ID(&'a Atom),
|
||||||
Class(&'a Atom),
|
Class(&'a Atom),
|
||||||
LocalName {
|
LocalName {
|
||||||
|
@ -456,6 +483,7 @@ enum Bucket<'a> {
|
||||||
|
|
||||||
fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a> {
|
fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a> {
|
||||||
match *component {
|
match *component {
|
||||||
|
Component::Root => Bucket::Root,
|
||||||
Component::ID(ref id) => Bucket::ID(id),
|
Component::ID(ref id) => Bucket::ID(id),
|
||||||
Component::Class(ref class) => Bucket::Class(class),
|
Component::Class(ref class) => Bucket::Class(class),
|
||||||
Component::LocalName(ref selector) => Bucket::LocalName {
|
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,
|
// We basically want to find the most specific bucket,
|
||||||
// where:
|
// where:
|
||||||
//
|
//
|
||||||
// id > class > local name > namespace > universal.
|
// root > id > class > local name > namespace > universal.
|
||||||
//
|
//
|
||||||
for ss in &mut iter {
|
for ss in &mut iter {
|
||||||
let new_bucket = specific_bucket_for(ss);
|
let new_bucket = specific_bucket_for(ss);
|
||||||
match new_bucket {
|
match new_bucket {
|
||||||
Bucket::ID(..) => return new_bucket,
|
Bucket::Root => return new_bucket,
|
||||||
Bucket::Class(..) => {
|
Bucket::ID(..) => {
|
||||||
current_bucket = new_bucket;
|
current_bucket = new_bucket;
|
||||||
|
}
|
||||||
|
Bucket::Class(..) => {
|
||||||
|
if !matches!(current_bucket, Bucket::ID(..)) {
|
||||||
|
current_bucket = new_bucket;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Bucket::LocalName { .. } => {
|
Bucket::LocalName { .. } => {
|
||||||
if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) {
|
if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue