style: Record in RestyleHints how far down the tree selector matching must be re-run.

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

View file

@ -37,11 +37,8 @@ use stylist::SelectorMap;
/// unnecessary.
#[derive(Debug, Clone, PartialEq)]
pub struct RestyleHint {
/// Rerun selector matching on the element.
match_self: bool,
/// Rerun selector matching on all of the element's descendants.
match_descendants: bool,
/// Depths at which selector matching must be re-run.
match_under_self: RestyleDepths,
/// Rerun selector matching on all later siblings of the element and all
/// of their descendants.
@ -82,6 +79,75 @@ bitflags! {
}
}
/// Eight bit wide bitfield representing depths of a DOM subtree's descendants,
/// used to represent which elements must have selector matching re-run on them.
///
/// The least significant bit indicates that selector matching must be re-run
/// for the element itself, the second least significant bit for the element's
/// children, the third its grandchildren, and so on. If the most significant
/// bit it set, it indicates that that selector matching must be re-run for
/// elements at that depth and all of their descendants.
#[derive(Debug, Clone, Copy, PartialEq)]
struct RestyleDepths(u8);
impl RestyleDepths {
/// Returns a `RestyleDepths` representing no element depths.
fn empty() -> Self {
RestyleDepths(0)
}
/// Returns a `RestyleDepths` representing the current element depth.
fn for_self() -> Self {
RestyleDepths(0x01)
}
/// Returns a `RestyleDepths` representing the depths of all descendants of
/// the current element.
fn for_descendants() -> Self {
RestyleDepths(0xfe)
}
/// Returns a `RestyleDepths` representing the current element depth and the
/// depths of all the current element's descendants.
fn for_self_and_descendants() -> Self {
RestyleDepths(0xff)
}
/// Returns whether this `RestyleDepths` represents the current element
/// depth and the depths of all the current element's descendants.
fn is_self_and_descendants(&self) -> bool {
self.0 == 0xff
}
/// Returns whether this `RestyleDepths` includes any element depth.
fn is_any(&self) -> bool {
self.0 != 0
}
/// Returns whether this `RestyleDepths` includes the current element depth.
fn has_self(&self) -> bool {
(self.0 & 0x01) != 0
}
/// Returns a new `RestyleDepths` with all depth values represented by this
/// `RestyleDepths` reduced by one.
fn propagate(&self) -> Self {
RestyleDepths((self.0 >> 1) | (self.0 & 0x80))
}
/// Returns a new `RestyleDepths` that represents the union of the depths
/// from `self` and `other`.
fn insert(&mut self, other: RestyleDepths) {
self.0 |= other.0;
}
/// Returns whether this `RestyleDepths` includes all depths represented
/// by `other`.
fn contains(&self, other: RestyleDepths) -> bool {
(self.0 & other.0) == other.0
}
}
/// Asserts that all RestyleReplacements have a matching nsRestyleHint value.
#[cfg(feature = "gecko")]
#[inline]
@ -116,8 +182,7 @@ impl RestyleHint {
#[inline]
pub fn empty() -> Self {
RestyleHint {
match_self: false,
match_descendants: false,
match_under_self: RestyleDepths::empty(),
match_later_siblings: false,
replacements: RestyleReplacements::empty(),
}
@ -128,8 +193,7 @@ impl RestyleHint {
#[inline]
pub fn for_self() -> Self {
RestyleHint {
match_self: true,
match_descendants: false,
match_under_self: RestyleDepths::for_self(),
match_later_siblings: false,
replacements: RestyleReplacements::empty(),
}
@ -140,8 +204,7 @@ impl RestyleHint {
#[inline]
pub fn descendants() -> Self {
RestyleHint {
match_self: false,
match_descendants: true,
match_under_self: RestyleDepths::for_descendants(),
match_later_siblings: false,
replacements: RestyleReplacements::empty(),
}
@ -152,8 +215,7 @@ impl RestyleHint {
#[inline]
pub fn later_siblings() -> Self {
RestyleHint {
match_self: false,
match_descendants: false,
match_under_self: RestyleDepths::empty(),
match_later_siblings: true,
replacements: RestyleReplacements::empty(),
}
@ -164,8 +226,7 @@ impl RestyleHint {
#[inline]
pub fn subtree() -> Self {
RestyleHint {
match_self: true,
match_descendants: true,
match_under_self: RestyleDepths::for_self_and_descendants(),
match_later_siblings: false,
replacements: RestyleReplacements::empty(),
}
@ -177,8 +238,7 @@ impl RestyleHint {
#[inline]
pub fn subtree_and_later_siblings() -> Self {
RestyleHint {
match_self: true,
match_descendants: true,
match_under_self: RestyleDepths::for_self_and_descendants(),
match_later_siblings: true,
replacements: RestyleReplacements::empty(),
}
@ -189,8 +249,7 @@ impl RestyleHint {
#[inline]
pub fn for_replacements(replacements: RestyleReplacements) -> Self {
RestyleHint {
match_self: false,
match_descendants: false,
match_under_self: RestyleDepths::empty(),
match_later_siblings: false,
replacements: replacements,
}
@ -206,14 +265,16 @@ impl RestyleHint {
/// restyle work, and thus any `insert()` calls will have no effect.
#[inline]
pub fn is_maximum(&self) -> bool {
self.match_self && self.match_descendants && self.match_later_siblings && self.replacements.is_all()
self.match_under_self.is_self_and_descendants() &&
self.match_later_siblings &&
self.replacements.is_all()
}
/// Returns whether the hint specifies that some work must be performed on
/// the current element.
#[inline]
pub fn affects_self(&self) -> bool {
self.match_self || !self.replacements.is_empty()
self.match_self() || !self.replacements.is_empty()
}
/// Returns whether the hint specifies that later siblings must be restyled.
@ -233,7 +294,7 @@ impl RestyleHint {
/// animation cascade level replacement.
#[inline]
pub fn has_non_animation_hint(&self) -> bool {
self.match_self || self.match_descendants || self.match_later_siblings ||
self.match_under_self.is_any() || self.match_later_siblings ||
self.replacements.contains(RESTYLE_STYLE_ATTRIBUTE)
}
@ -241,17 +302,17 @@ impl RestyleHint {
/// for the element.
#[inline]
pub fn match_self(&self) -> bool {
self.match_self
self.match_under_self.has_self()
}
/// Returns a new `RestyleHint` appropriate for children of the current
/// element.
#[inline]
pub fn propagate_for_non_animation_restyle(&self) -> Self {
if self.match_descendants {
Self::subtree()
} else {
Self::empty()
RestyleHint {
match_under_self: self.match_under_self.propagate(),
match_later_siblings: false,
replacements: RestyleReplacements::empty(),
}
}
@ -271,8 +332,7 @@ impl RestyleHint {
/// Unions the specified `RestyleHint` into this one.
#[inline]
pub fn insert_from(&mut self, other: &Self) {
self.match_self |= other.match_self;
self.match_descendants |= other.match_descendants;
self.match_under_self.insert(other.match_under_self);
self.match_later_siblings |= other.match_later_siblings;
self.replacements.insert(other.replacements);
}
@ -289,9 +349,8 @@ impl RestyleHint {
/// work as the specified one.
#[inline]
pub fn contains(&mut self, other: &Self) -> bool {
!(other.match_self && !self.match_self) &&
!(other.match_descendants && !self.match_descendants) &&
!(other.match_later_siblings && !self.match_later_siblings) &&
self.match_under_self.contains(other.match_under_self) &&
(self.match_later_siblings & other.match_later_siblings) == other.match_later_siblings &&
self.replacements.contains(other.replacements)
}
}
@ -319,9 +378,16 @@ impl From<nsRestyleHint> for RestyleHint {
use gecko_bindings::structs::nsRestyleHint_eRestyle_SomeDescendants as eRestyle_SomeDescendants;
use gecko_bindings::structs::nsRestyleHint_eRestyle_Subtree as eRestyle_Subtree;
let mut match_under_self = RestyleDepths::empty();
if (raw.0 & (eRestyle_Self.0 | eRestyle_Subtree.0)) != 0 {
match_under_self.insert(RestyleDepths::for_self());
}
if (raw.0 & (eRestyle_Subtree.0 | eRestyle_SomeDescendants.0)) != 0 {
match_under_self.insert(RestyleDepths::for_descendants());
}
RestyleHint {
match_self: (raw.0 & (eRestyle_Self.0 | eRestyle_Subtree.0)) != 0,
match_descendants: (raw.0 & (eRestyle_Subtree.0 | eRestyle_SomeDescendants.0)) != 0,
match_under_self: match_under_self,
match_later_siblings: (raw.0 & eRestyle_LaterSiblings.0) != 0,
replacements: raw.into(),
}