Factor out the application of selector flags into a helper.

MozReview-Commit-ID: 2FZxnBxvaOb
This commit is contained in:
Bobby Holley 2017-04-05 17:52:17 -07:00
parent 21eafebd37
commit f9de1dedd8

View file

@ -822,52 +822,9 @@ pub trait MatchMethods : TElement {
let animation_rules = self.get_animation_rules(None); let animation_rules = self.get_animation_rules(None);
let mut rule_nodes_changed = false; 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 tasks = &mut context.thread_local.tasks;
let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| { let mut set_selector_flags = |element: &Self, flags: ElementSelectorFlags| {
// Apply the selector flags. self.apply_selector_flags(tasks, element, 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 // Borrow the stuff we need here so the borrow checker doesn't get mad
@ -949,6 +906,59 @@ pub trait MatchMethods : TElement {
} }
} }
/// Applies selector flags to an element, deferring mutations of the parent
/// until after the traversal.
///
/// 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.
fn apply_selector_flags(&self,
tasks: &mut Vec<SequentialTask<Self>>,
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);
}
}
}
}
/// Updates the rule nodes without re-running selector matching, using just /// Updates the rule nodes without re-running selector matching, using just
/// the rule tree. Returns true if the rule nodes changed. /// the rule tree. Returns true if the rule nodes changed.
fn cascade_with_replacements(&self, fn cascade_with_replacements(&self,