mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Factor out the application of selector flags into a helper.
MozReview-Commit-ID: 2FZxnBxvaOb
This commit is contained in:
parent
21eafebd37
commit
f9de1dedd8
1 changed files with 54 additions and 44 deletions
|
@ -822,52 +822,9 @@ pub trait MatchMethods : TElement {
|
|||
let animation_rules = self.get_animation_rules(None);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.apply_selector_flags(tasks, element, flags);
|
||||
};
|
||||
|
||||
// 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
|
||||
/// the rule tree. Returns true if the rule nodes changed.
|
||||
fn cascade_with_replacements(&self,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue