mirror of
https://github.com/servo/servo.git
synced 2025-06-25 01:24:37 +01:00
style: Add namespace bucket for the selector map.
After bug 1470163 we have some nasty selectors from mathml.css in every page. We only want to match them against MathML elements. This patch brings the global revalidation selectors from 14 to 2 in about:blank. Also halves the ones from XUL documents. Bug: 1374017 Reviewed-by: heycam MozReview-Commit-ID: nOVyknNcVm
This commit is contained in:
parent
2d2e84aad5
commit
fa7d9bf74a
1 changed files with 42 additions and 9 deletions
|
@ -5,7 +5,7 @@
|
|||
//! A data structure to efficiently index structs containing selectors by local
|
||||
//! name, ids and hash.
|
||||
|
||||
use {Atom, LocalName, WeakAtom};
|
||||
use {Atom, LocalName, Namespace, WeakAtom};
|
||||
use applicable_declarations::ApplicableDeclarationList;
|
||||
use context::QuirksMode;
|
||||
use dom::TElement;
|
||||
|
@ -102,6 +102,8 @@ pub struct SelectorMap<T: 'static> {
|
|||
pub class_hash: MaybeCaseInsensitiveHashMap<Atom, SmallVec<[T; 1]>>,
|
||||
/// A hash from local name to rules which contain that local name selector.
|
||||
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.
|
||||
pub other: SmallVec<[T; 1]>,
|
||||
/// The number of entries in this map.
|
||||
|
@ -125,6 +127,7 @@ impl<T: 'static> SelectorMap<T> {
|
|||
id_hash: MaybeCaseInsensitiveHashMap::new(),
|
||||
class_hash: MaybeCaseInsensitiveHashMap::new(),
|
||||
local_name_hash: HashMap::default(),
|
||||
namespace_hash: HashMap::default(),
|
||||
other: SmallVec::new(),
|
||||
count: 0,
|
||||
}
|
||||
|
@ -135,6 +138,7 @@ impl<T: 'static> SelectorMap<T> {
|
|||
self.id_hash.clear();
|
||||
self.class_hash.clear();
|
||||
self.local_name_hash.clear();
|
||||
self.namespace_hash.clear();
|
||||
self.other.clear();
|
||||
self.count = 0;
|
||||
}
|
||||
|
@ -217,6 +221,18 @@ impl SelectorMap<Rule> {
|
|||
)
|
||||
}
|
||||
|
||||
if let Some(rules) = self.namespace_hash.get(rule_hash_target.namespace()) {
|
||||
SelectorMap::get_matching_rules(
|
||||
element,
|
||||
rules,
|
||||
matching_rules_list,
|
||||
context,
|
||||
flags_setter,
|
||||
cascade_level,
|
||||
shadow_cascade_order,
|
||||
)
|
||||
}
|
||||
|
||||
SelectorMap::get_matching_rules(
|
||||
element,
|
||||
&self.other,
|
||||
|
@ -261,7 +277,8 @@ impl SelectorMap<Rule> {
|
|||
}
|
||||
|
||||
impl<T: SelectorMapEntry> SelectorMap<T> {
|
||||
/// Inserts into the correct hash, trying id, class, and localname.
|
||||
/// Inserts into the correct hash, trying id, class, localname and
|
||||
/// namespace.
|
||||
pub fn insert(
|
||||
&mut self,
|
||||
entry: T,
|
||||
|
@ -298,13 +315,17 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
|||
.try_entry(name.clone())?
|
||||
.or_insert_with(SmallVec::new)
|
||||
},
|
||||
Bucket::Namespace(url) => self.namespace_hash
|
||||
.try_entry(url.clone())?
|
||||
.or_insert_with(SmallVec::new),
|
||||
Bucket::Universal => &mut self.other,
|
||||
};
|
||||
|
||||
vector.try_push(entry)
|
||||
}
|
||||
|
||||
/// Looks up entries by id, class, local name, and other (in order).
|
||||
/// Looks up entries by id, class, local name, namespace, and other (in
|
||||
/// order).
|
||||
///
|
||||
/// Each entry is passed to the callback, which returns true to continue
|
||||
/// iterating entries, or false to terminate the lookup.
|
||||
|
@ -319,7 +340,6 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
|||
E: TElement,
|
||||
F: FnMut(&'a T) -> bool,
|
||||
{
|
||||
// Id.
|
||||
if let Some(id) = element.id() {
|
||||
if let Some(v) = self.id_hash.get(id, quirks_mode) {
|
||||
for entry in v.iter() {
|
||||
|
@ -330,7 +350,6 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Class.
|
||||
let mut done = false;
|
||||
element.each_class(|class| {
|
||||
if !done {
|
||||
|
@ -348,7 +367,6 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Local name.
|
||||
if let Some(v) = self.local_name_hash.get(element.local_name()) {
|
||||
for entry in v.iter() {
|
||||
if !f(&entry) {
|
||||
|
@ -357,7 +375,14 @@ impl<T: SelectorMapEntry> SelectorMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Other.
|
||||
if let Some(v) = self.namespace_hash.get(element.namespace()) {
|
||||
for entry in v.iter() {
|
||||
if !f(&entry) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for entry in self.other.iter() {
|
||||
if !f(&entry) {
|
||||
return false;
|
||||
|
@ -425,6 +450,7 @@ enum Bucket<'a> {
|
|||
name: &'a LocalName,
|
||||
lower_name: &'a LocalName,
|
||||
},
|
||||
Namespace(&'a Namespace),
|
||||
Universal,
|
||||
}
|
||||
|
||||
|
@ -436,6 +462,8 @@ fn specific_bucket_for<'a>(component: &'a Component<SelectorImpl>) -> Bucket<'a>
|
|||
name: &selector.name,
|
||||
lower_name: &selector.lower_name,
|
||||
},
|
||||
Component::Namespace(_, ref url) |
|
||||
Component::DefaultNamespace(ref url) => Bucket::Namespace(url),
|
||||
// ::slotted(..) isn't a normal pseudo-element, so we can insert it on
|
||||
// the rule hash normally without much problem. For example, in a
|
||||
// selector like:
|
||||
|
@ -470,7 +498,7 @@ 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 > universal.
|
||||
// id > class > local name > namespace > universal.
|
||||
//
|
||||
for ss in &mut iter {
|
||||
let new_bucket = specific_bucket_for(ss);
|
||||
|
@ -480,10 +508,15 @@ fn find_bucket<'a>(mut iter: SelectorIter<'a, SelectorImpl>) -> Bucket<'a> {
|
|||
current_bucket = new_bucket;
|
||||
},
|
||||
Bucket::LocalName { .. } => {
|
||||
if matches!(current_bucket, Bucket::Universal) {
|
||||
if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) {
|
||||
current_bucket = new_bucket;
|
||||
}
|
||||
},
|
||||
Bucket::Namespace(..) => {
|
||||
if matches!(current_bucket, Bucket::Universal) {
|
||||
current_bucket = new_bucket;
|
||||
}
|
||||
}
|
||||
Bucket::Universal => {},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue