style: Generate RestyleHints to selector match at specific descendant depths.

This commit is contained in:
Cameron McCormack 2017-05-19 17:39:16 +08:00 committed by Emilio Cobos Álvarez
parent 178939d8ce
commit b46e196fa9
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C

View file

@ -26,6 +26,7 @@ use smallvec::SmallVec;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::cell::Cell; use std::cell::Cell;
use std::clone::Clone; use std::clone::Clone;
use std::cmp;
use stylist::SelectorMap; use stylist::SelectorMap;
/// When the ElementState of an element (like IN_HOVER_STATE) changes, /// When the ElementState of an element (like IN_HOVER_STATE) changes,
@ -113,6 +114,12 @@ impl RestyleDepths {
RestyleDepths(0xff) RestyleDepths(0xff)
} }
/// Returns a `RestyleDepths` representing the specified depth, where zero
/// is the current element depth, one is its children's depths, etc.
fn for_depth(depth: u32) -> Self {
RestyleDepths(1u8 << cmp::min(depth, 7))
}
/// Returns whether this `RestyleDepths` represents the current element /// Returns whether this `RestyleDepths` represents the current element
/// depth and the depths of all the current element's descendants. /// depth and the depths of all the current element's descendants.
fn is_self_and_descendants(&self) -> bool { fn is_self_and_descendants(&self) -> bool {
@ -210,6 +217,19 @@ impl RestyleHint {
} }
} }
/// Creates a new `RestyleHint` that indicates selector matching must be
/// re-run on the descendants of element at the specified depth, where 0
/// indicates the element itself, 1 is its children, 2 its grandchildren,
/// etc.
#[inline]
pub fn descendants_at_depth(depth: u32) -> Self {
RestyleHint {
match_under_self: RestyleDepths::for_depth(depth),
match_later_siblings: false,
replacements: RestyleReplacements::empty(),
}
}
/// Creates a new `RestyleHint` that indicates selector matching must be /// Creates a new `RestyleHint` that indicates selector matching must be
/// re-run on all of the element's later siblings and their descendants. /// re-run on all of the element's later siblings and their descendants.
#[inline] #[inline]
@ -682,22 +702,6 @@ fn is_attr_selector(sel: &Component<SelectorImpl>) -> bool {
} }
} }
fn combinator_to_restyle_hint(combinator: Option<Combinator>) -> RestyleHint {
match combinator {
None => RestyleHint::for_self(),
Some(c) => match c {
// NB: RestyleHint::subtree() and not RestyleHint::descendants() is
// needed to handle properly eager pseudos, otherwise we may leave
// a stale style on the parent.
Combinator::PseudoElement => RestyleHint::subtree(),
Combinator::Child => RestyleHint::descendants(),
Combinator::Descendant => RestyleHint::descendants(),
Combinator::NextSibling => RestyleHint::later_siblings(),
Combinator::LaterSibling => RestyleHint::later_siblings(),
}
}
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// The aspects of an selector which are sensitive. /// The aspects of an selector which are sensitive.
@ -827,6 +831,8 @@ impl DependencySet {
let mut combinator = None; let mut combinator = None;
let mut iter = selector.inner.complex.iter(); let mut iter = selector.inner.complex.iter();
let mut index = 0; let mut index = 0;
let mut child_combinators_seen = 0;
let mut saw_descendant_combinator = false;
loop { loop {
let sequence_start = index; let sequence_start = index;
@ -844,9 +850,34 @@ impl DependencySet {
index += 1; // Account for the simple selector. index += 1; // Account for the simple selector.
} }
// Keep track of how many child combinators we've encountered,
// and whether we've encountered a descendant combinator at all.
match combinator {
Some(Combinator::Child) => child_combinators_seen += 1,
Some(Combinator::Descendant) => saw_descendant_combinator = true,
_ => {}
}
// If we found a sensitivity, add an entry in the dependency set. // If we found a sensitivity, add an entry in the dependency set.
if !visitor.sensitivities.is_empty() { if !visitor.sensitivities.is_empty() {
let hint = combinator_to_restyle_hint(combinator); // Compute a RestyleHint given the current combinator and the
// tracked number of child combinators and presence of a
// descendant combinator.
let hint = match combinator {
// NB: RestyleHint::subtree() and not
// RestyleHint::descendants() is needed to handle properly
// eager pseudos, otherwise we may leave a stale style on
// the parent.
Some(Combinator::PseudoElement) => RestyleHint::subtree(),
Some(Combinator::Child) if !saw_descendant_combinator => {
RestyleHint::descendants_at_depth(child_combinators_seen)
}
Some(Combinator::Child) |
Some(Combinator::Descendant) => RestyleHint::descendants(),
Some(Combinator::NextSibling) |
Some(Combinator::LaterSibling) => RestyleHint::later_siblings(),
None => RestyleHint::for_self(),
};
let dep_selector = if sequence_start == 0 { let dep_selector = if sequence_start == 0 {
// Reuse the bloom hashes if this is the base selector. // Reuse the bloom hashes if this is the base selector.
@ -953,7 +984,7 @@ impl DependencySet {
return true; return true;
} }
// We can ignore the selector replacements, since they would have already // We can ignore the selector flags, since they would have already
// been set during original matching for any element that might // been set during original matching for any element that might
// change its matching behavior here. // change its matching behavior here.
let matched_then = let matched_then =