mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
style: Rework how precomputed pseudo stuff works, to avoid malloc/free churn.
This showed up in a few profiles, and was an easy improvement. MozReview-Commit-ID: HVqATaSB2Ak Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
This commit is contained in:
parent
48b7e6d27c
commit
64a96ce21c
3 changed files with 50 additions and 67 deletions
|
@ -201,29 +201,6 @@ impl SelectorMap<Rule> {
|
||||||
|block| (block.specificity, block.source_order()));
|
|block| (block.specificity, block.source_order()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append to `rule_list` all universal Rules (rules with selector `*|*`) in
|
|
||||||
/// `self` sorted by specificity and source order.
|
|
||||||
pub fn get_universal_rules(&self,
|
|
||||||
cascade_level: CascadeLevel)
|
|
||||||
-> Vec<ApplicableDeclarationBlock> {
|
|
||||||
debug_assert!(!cascade_level.is_important());
|
|
||||||
if self.is_empty() {
|
|
||||||
return vec![];
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rules_list = vec![];
|
|
||||||
for rule in self.other.iter() {
|
|
||||||
if rule.selector.is_universal() {
|
|
||||||
rules_list.push(rule.to_applicable_declaration_block(cascade_level))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort_by_key(&mut rules_list,
|
|
||||||
|block| (block.specificity, block.source_order()));
|
|
||||||
|
|
||||||
rules_list
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds rules in `rules` that match `element` to the `matching_rules` list.
|
/// Adds rules in `rules` that match `element` to the `matching_rules` list.
|
||||||
fn get_matching_rules<E, V, F>(element: &E,
|
fn get_matching_rules<E, V, F>(element: &E,
|
||||||
rules: &[Rule],
|
rules: &[Rule],
|
||||||
|
|
|
@ -403,13 +403,6 @@ impl Stylist {
|
||||||
self.add_stylesheet(stylesheet, guards.author, extra_data);
|
self.add_stylesheet(stylesheet, guards.author, extra_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectorImpl::each_precomputed_pseudo_element(|pseudo| {
|
|
||||||
if let Some(map) = self.cascade_data.user_agent.pseudos_map.remove(&pseudo) {
|
|
||||||
let declarations = map.get_universal_rules(CascadeLevel::UANormal);
|
|
||||||
self.precomputed_pseudo_element_decls.insert(pseudo, declarations);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
self.is_device_dirty = false;
|
self.is_device_dirty = false;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -470,17 +463,49 @@ impl Stylist {
|
||||||
for selector in &style_rule.selectors.0 {
|
for selector in &style_rule.selectors.0 {
|
||||||
self.num_selectors += 1;
|
self.num_selectors += 1;
|
||||||
|
|
||||||
|
let map = match selector.pseudo_element() {
|
||||||
|
None => &mut origin_cascade_data.element_map,
|
||||||
|
Some(pseudo) => {
|
||||||
|
if pseudo.is_precomputed() {
|
||||||
|
if !selector.is_universal() ||
|
||||||
|
!matches!(origin, Origin::UserAgent) {
|
||||||
|
// ::-moz-tree selectors may appear in
|
||||||
|
// non-UA sheets (even though they never
|
||||||
|
// match).
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.precomputed_pseudo_element_decls
|
||||||
|
.entry(pseudo.canonical())
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push(ApplicableDeclarationBlock::new(
|
||||||
|
StyleSource::Style(locked.clone()),
|
||||||
|
self.rules_source_order,
|
||||||
|
CascadeLevel::UANormal,
|
||||||
|
selector.specificity()
|
||||||
|
));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
origin_cascade_data
|
||||||
|
.pseudos_map
|
||||||
|
.entry(pseudo.canonical())
|
||||||
|
.or_insert_with(SelectorMap::new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let hashes =
|
let hashes =
|
||||||
AncestorHashes::new(&selector, self.quirks_mode);
|
AncestorHashes::new(&selector, self.quirks_mode);
|
||||||
|
|
||||||
origin_cascade_data
|
let rule = Rule::new(
|
||||||
.borrow_mut_for_pseudo_or_insert(selector.pseudo_element())
|
selector.clone(),
|
||||||
.insert(
|
hashes.clone(),
|
||||||
Rule::new(selector.clone(),
|
locked.clone(),
|
||||||
hashes.clone(),
|
self.rules_source_order
|
||||||
locked.clone(),
|
);
|
||||||
self.rules_source_order),
|
|
||||||
self.quirks_mode);
|
map.insert(rule, self.quirks_mode);
|
||||||
|
|
||||||
self.invalidation_map.note_selector(selector, self.quirks_mode);
|
self.invalidation_map.note_selector(selector, self.quirks_mode);
|
||||||
let mut visitor = StylistSelectorVisitor {
|
let mut visitor = StylistSelectorVisitor {
|
||||||
|
@ -1660,18 +1685,6 @@ impl PerOriginCascadeData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn borrow_mut_for_pseudo_or_insert(&mut self, pseudo: Option<&PseudoElement>) -> &mut SelectorMap<Rule> {
|
|
||||||
match pseudo {
|
|
||||||
Some(pseudo) => {
|
|
||||||
self.pseudos_map
|
|
||||||
.entry(pseudo.canonical())
|
|
||||||
.or_insert_with(SelectorMap::new)
|
|
||||||
}
|
|
||||||
None => &mut self.element_map,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&mut self) {
|
fn clear(&mut self) {
|
||||||
*self = Self::new();
|
*self = Self::new();
|
||||||
}
|
}
|
||||||
|
@ -1720,14 +1733,17 @@ impl Rule {
|
||||||
|
|
||||||
/// Turns this rule into an `ApplicableDeclarationBlock` for the given
|
/// Turns this rule into an `ApplicableDeclarationBlock` for the given
|
||||||
/// cascade level.
|
/// cascade level.
|
||||||
pub fn to_applicable_declaration_block(&self,
|
pub fn to_applicable_declaration_block(
|
||||||
level: CascadeLevel)
|
&self,
|
||||||
-> ApplicableDeclarationBlock {
|
level: CascadeLevel
|
||||||
|
) -> ApplicableDeclarationBlock {
|
||||||
let source = StyleSource::Style(self.style_rule.clone());
|
let source = StyleSource::Style(self.style_rule.clone());
|
||||||
ApplicableDeclarationBlock::new(source,
|
ApplicableDeclarationBlock::new(
|
||||||
self.source_order,
|
source,
|
||||||
level,
|
self.source_order,
|
||||||
self.specificity())
|
level,
|
||||||
|
self.specificity()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new Rule.
|
/// Creates a new Rule.
|
||||||
|
|
|
@ -222,16 +222,6 @@ fn test_insert() {
|
||||||
assert!(selector_map.class_hash.get(&Atom::from("foo"), QuirksMode::NoQuirks).is_none());
|
assert!(selector_map.class_hash.get(&Atom::from("foo"), QuirksMode::NoQuirks).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_universal_rules() {
|
|
||||||
thread_state::initialize(thread_state::LAYOUT);
|
|
||||||
let (map, _shared_lock) = get_mock_map(&["*|*", "#foo > *|*", "*|* > *|*", ".klass", "#id"]);
|
|
||||||
|
|
||||||
let decls = map.get_universal_rules(CascadeLevel::UserNormal);
|
|
||||||
|
|
||||||
assert_eq!(decls.len(), 1, "{:?}", decls);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mock_stylist() -> Stylist {
|
fn mock_stylist() -> Stylist {
|
||||||
let device = Device::new(MediaType::Screen, TypedSize2D::new(0f32, 0f32), ScaleFactor::new(1.0));
|
let device = Device::new(MediaType::Screen, TypedSize2D::new(0f32, 0f32), ScaleFactor::new(1.0));
|
||||||
Stylist::new(device, QuirksMode::NoQuirks)
|
Stylist::new(device, QuirksMode::NoQuirks)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue