mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Bug 1345950: stylo: Fix slow selector flags. r=bholley
MozReview-Commit-ID: QwuSxulNG0 Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
This commit is contained in:
parent
f90f7d6824
commit
a9b133bcbb
9 changed files with 288 additions and 189 deletions
|
@ -18,7 +18,7 @@ use dom::{AnimationRules, SendElement, TElement, TNode};
|
|||
use properties::{CascadeFlags, ComputedValues, SHAREABLE, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
||||
use properties::longhands::display::computed_value as display;
|
||||
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RestyleHint};
|
||||
use rule_tree::{CascadeLevel, StrongRuleNode};
|
||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
|
||||
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
|
||||
use selectors::MatchAttr;
|
||||
use selectors::bloom::BloomFilter;
|
||||
|
@ -750,12 +750,12 @@ trait PrivateMatchMethods: TElement {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_rule_node<E: TElement>(context: &StyleContext<E>,
|
||||
fn compute_rule_node<E: TElement>(rule_tree: &RuleTree,
|
||||
applicable_declarations: &mut Vec<ApplicableDeclarationBlock>)
|
||||
-> StrongRuleNode
|
||||
{
|
||||
let rules = applicable_declarations.drain(..).map(|d| (d.source, d.level));
|
||||
let rule_node = context.shared.stylist.rule_tree.insert_ordered_rules(rules);
|
||||
let rule_node = rule_tree.insert_ordered_rules(rules);
|
||||
rule_node
|
||||
}
|
||||
|
||||
|
@ -775,20 +775,75 @@ pub trait MatchMethods : TElement {
|
|||
let stylist = &context.shared.stylist;
|
||||
let style_attribute = self.style_attribute();
|
||||
let animation_rules = self.get_animation_rules(None);
|
||||
let mut flags = ElementSelectorFlags::empty();
|
||||
let mut rule_nodes_changed = false;
|
||||
|
||||
// TODO(emilio): This is somewhat inefficient, because of a variety of
|
||||
// reasons:
|
||||
//
|
||||
// * It doesn't coalesce flags.
|
||||
// * It doesn't look at flags already sent in a task for the main
|
||||
// thread to process.
|
||||
// * It doesn't take advantage of us knowing that the traversal is
|
||||
// sequential.
|
||||
//
|
||||
// I suspect (need to measure!) that we don't use to set flags on
|
||||
// a lot of different elements, but we could end up posting the same
|
||||
// flag over and over with this approach.
|
||||
//
|
||||
// If the number of elements is low, perhaps a small cache with the
|
||||
// flags already sent would be appropriate.
|
||||
//
|
||||
// The sequential task business for this is kind of sad :(.
|
||||
//
|
||||
// Anyway, let's do the obvious thing for now.
|
||||
let tasks = &mut context.thread_local.tasks;
|
||||
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
|
||||
// Apply the selector flags.
|
||||
let self_flags = flags.for_self();
|
||||
if !self_flags.is_empty() {
|
||||
if element == self {
|
||||
unsafe { element.set_selector_flags(self_flags); }
|
||||
} else {
|
||||
if !element.has_selector_flags(self_flags) {
|
||||
let task =
|
||||
SequentialTask::set_selector_flags(element.clone(),
|
||||
self_flags);
|
||||
tasks.push(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
let parent_flags = flags.for_parent();
|
||||
if !parent_flags.is_empty() {
|
||||
if let Some(p) = element.parent_element() {
|
||||
// Avoid the overhead of the SequentialTask if the flags are
|
||||
// already set.
|
||||
if !p.has_selector_flags(parent_flags) {
|
||||
let task = SequentialTask::set_selector_flags(p, parent_flags);
|
||||
tasks.push(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Borrow the stuff we need here so the borrow checker doesn't get mad
|
||||
// at us later in the closure.
|
||||
let guards = &context.shared.guards;
|
||||
let rule_tree = &context.shared.stylist.rule_tree;
|
||||
let bloom_filter = context.thread_local.bloom_filter.filter();
|
||||
|
||||
// Compute the primary rule node.
|
||||
let mut primary_relations =
|
||||
stylist.push_applicable_declarations(self,
|
||||
Some(context.thread_local.bloom_filter.filter()),
|
||||
Some(bloom_filter),
|
||||
style_attribute,
|
||||
animation_rules,
|
||||
None,
|
||||
&context.shared.guards,
|
||||
guards,
|
||||
&mut applicable_declarations,
|
||||
&mut flags);
|
||||
let primary_rule_node = compute_rule_node(context, &mut applicable_declarations);
|
||||
&mut set_selector_flags);
|
||||
|
||||
let primary_rule_node =
|
||||
compute_rule_node::<Self>(rule_tree, &mut applicable_declarations);
|
||||
if !data.has_styles() {
|
||||
data.set_styles(ElementStyles::new(ComputedStyle::new_partial(primary_rule_node)));
|
||||
rule_nodes_changed = true;
|
||||
|
@ -808,15 +863,16 @@ pub trait MatchMethods : TElement {
|
|||
AnimationRules(None, None)
|
||||
};
|
||||
stylist.push_applicable_declarations(self,
|
||||
Some(context.thread_local.bloom_filter.filter()),
|
||||
Some(bloom_filter),
|
||||
None, pseudo_animation_rules,
|
||||
Some(&pseudo),
|
||||
&context.shared.guards,
|
||||
&guards,
|
||||
&mut applicable_declarations,
|
||||
&mut flags);
|
||||
&mut set_selector_flags);
|
||||
|
||||
if !applicable_declarations.is_empty() {
|
||||
let new_rules = compute_rule_node(context, &mut applicable_declarations);
|
||||
let new_rules =
|
||||
compute_rule_node::<Self>(rule_tree, &mut applicable_declarations);
|
||||
match per_pseudo.entry(pseudo) {
|
||||
Entry::Occupied(mut e) => {
|
||||
if e.get().rules != new_rules {
|
||||
|
@ -848,22 +904,6 @@ pub trait MatchMethods : TElement {
|
|||
primary_relations |= AFFECTED_BY_PSEUDO_ELEMENTS;
|
||||
}
|
||||
|
||||
// Apply the selector flags.
|
||||
let self_flags = flags.for_self();
|
||||
if !self_flags.is_empty() {
|
||||
unsafe { self.set_selector_flags(self_flags); }
|
||||
}
|
||||
let parent_flags = flags.for_parent();
|
||||
if !parent_flags.is_empty() {
|
||||
if let Some(p) = self.parent_element() {
|
||||
// Avoid the overhead of the SequentialTask if the flags are already set.
|
||||
if !p.has_selector_flags(parent_flags) {
|
||||
let task = SequentialTask::set_selector_flags(p, parent_flags);
|
||||
context.thread_local.tasks.push(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MatchResults {
|
||||
primary_relations: Some(primary_relations),
|
||||
rule_nodes_changed: rule_nodes_changed,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue