mirror of
https://github.com/servo/servo.git
synced 2025-06-08 00:23:30 +00:00
Hoist flags out of RestyleData.
MozReview-Commit-ID: 8emE83lykh3
This commit is contained in:
parent
9d0f8b9d52
commit
61cad869d9
6 changed files with 103 additions and 114 deletions
|
@ -20,7 +20,8 @@ use std::fmt;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags RestyleFlags: u8 {
|
#[derive(Default)]
|
||||||
|
flags ElementDataFlags: u8 {
|
||||||
/// Whether the styles changed for this restyle.
|
/// Whether the styles changed for this restyle.
|
||||||
const WAS_RESTYLED = 1 << 0,
|
const WAS_RESTYLED = 1 << 0,
|
||||||
/// Whether the last traversal of this element did not do
|
/// Whether the last traversal of this element did not do
|
||||||
|
@ -42,16 +43,13 @@ bitflags! {
|
||||||
/// processing.
|
/// processing.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RestyleData {
|
pub struct RestyleData {
|
||||||
/// The restyle hint, which indicates whether selectors need to be rematched
|
|
||||||
/// for this element, its children, and its descendants.
|
|
||||||
pub hint: RestyleHint,
|
|
||||||
|
|
||||||
/// A few flags to have in mind.
|
|
||||||
flags: RestyleFlags,
|
|
||||||
|
|
||||||
/// The restyle damage, indicating what kind of layout changes are required
|
/// The restyle damage, indicating what kind of layout changes are required
|
||||||
/// afte restyling.
|
/// afte restyling.
|
||||||
pub damage: RestyleDamage,
|
pub damage: RestyleDamage,
|
||||||
|
|
||||||
|
/// The restyle hint, which indicates whether selectors need to be rematched
|
||||||
|
/// for this element, its children, and its descendants.
|
||||||
|
pub hint: RestyleHint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RestyleData {
|
impl Default for RestyleData {
|
||||||
|
@ -63,91 +61,10 @@ impl Default for RestyleData {
|
||||||
impl RestyleData {
|
impl RestyleData {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
hint: RestyleHint::empty(),
|
|
||||||
flags: RestyleFlags::empty(),
|
|
||||||
damage: RestyleDamage::empty(),
|
damage: RestyleDamage::empty(),
|
||||||
|
hint: RestyleHint::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear all the restyle state associated with this element.
|
|
||||||
///
|
|
||||||
/// FIXME(bholley): The only caller of this should probably just assert that
|
|
||||||
/// the hint is empty and call clear_flags_and_damage().
|
|
||||||
#[inline]
|
|
||||||
fn clear_restyle_state(&mut self) {
|
|
||||||
self.clear_restyle_flags_and_damage();
|
|
||||||
self.hint = RestyleHint::empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear restyle flags and damage.
|
|
||||||
///
|
|
||||||
/// Note that we don't touch the TRAVERSED_WITHOUT_STYLING bit, which gets
|
|
||||||
/// set to the correct value on each traversal. There's no reason anyone
|
|
||||||
/// needs to clear it, and clearing it accidentally mid-traversal could
|
|
||||||
/// cause incorrect style sharing behavior.
|
|
||||||
#[inline]
|
|
||||||
fn clear_restyle_flags_and_damage(&mut self) {
|
|
||||||
self.damage = RestyleDamage::empty();
|
|
||||||
self.flags = self.flags & TRAVERSED_WITHOUT_STYLING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether this element or any ancestor is going to be
|
|
||||||
/// reconstructed.
|
|
||||||
pub fn reconstructed_self_or_ancestor(&self) -> bool {
|
|
||||||
self.reconstructed_ancestor() || self.reconstructed_self()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether this element is going to be reconstructed.
|
|
||||||
pub fn reconstructed_self(&self) -> bool {
|
|
||||||
self.damage.contains(RestyleDamage::reconstruct())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether any ancestor of this element is going to be
|
|
||||||
/// reconstructed.
|
|
||||||
fn reconstructed_ancestor(&self) -> bool {
|
|
||||||
self.flags.contains(ANCESTOR_WAS_RECONSTRUCTED)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the flag that tells us whether we've reconstructed an ancestor.
|
|
||||||
pub fn set_reconstructed_ancestor(&mut self, reconstructed: bool) {
|
|
||||||
if reconstructed {
|
|
||||||
// If it weren't for animation-only traversals, we could assert
|
|
||||||
// `!self.reconstructed_ancestor()` here.
|
|
||||||
self.flags.insert(ANCESTOR_WAS_RECONSTRUCTED);
|
|
||||||
} else {
|
|
||||||
self.flags.remove(ANCESTOR_WAS_RECONSTRUCTED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mark this element as restyled, which is useful to know whether we need
|
|
||||||
/// to do a post-traversal.
|
|
||||||
pub fn set_restyled(&mut self) {
|
|
||||||
self.flags.insert(WAS_RESTYLED);
|
|
||||||
self.flags.remove(TRAVERSED_WITHOUT_STYLING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if this element was restyled.
|
|
||||||
#[inline]
|
|
||||||
pub fn is_restyle(&self) -> bool {
|
|
||||||
self.flags.contains(WAS_RESTYLED)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mark that we traversed this element without computing any style for it.
|
|
||||||
pub fn set_traversed_without_styling(&mut self) {
|
|
||||||
self.flags.insert(TRAVERSED_WITHOUT_STYLING);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the element was traversed without computing any style for
|
|
||||||
/// it.
|
|
||||||
pub fn traversed_without_styling(&self) -> bool {
|
|
||||||
self.flags.contains(TRAVERSED_WITHOUT_STYLING)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether this element has been part of a restyle.
|
|
||||||
#[inline]
|
|
||||||
pub fn contains_restyle_data(&self) -> bool {
|
|
||||||
self.is_restyle() || !self.hint.is_empty() || !self.damage.is_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A lazily-allocated list of styles for eagerly-cascaded pseudo-elements.
|
/// A lazily-allocated list of styles for eagerly-cascaded pseudo-elements.
|
||||||
|
@ -305,6 +222,9 @@ pub struct ElementData {
|
||||||
|
|
||||||
/// Restyle state.
|
/// Restyle state.
|
||||||
pub restyle: RestyleData,
|
pub restyle: RestyleData,
|
||||||
|
|
||||||
|
/// Flags.
|
||||||
|
flags: ElementDataFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of restyle that a single element should do.
|
/// The kind of restyle that a single element should do.
|
||||||
|
@ -440,17 +360,94 @@ impl ElementData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drops any restyle state from the element.
|
/// Drops any restyle state from the element.
|
||||||
|
///
|
||||||
|
/// FIXME(bholley): The only caller of this should probably just assert that
|
||||||
|
/// the hint is empty and call clear_flags_and_damage().
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clear_restyle_state(&mut self) {
|
pub fn clear_restyle_state(&mut self) {
|
||||||
self.restyle.clear_restyle_state();
|
self.restyle.hint = RestyleHint::empty();
|
||||||
|
self.clear_restyle_flags_and_damage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drops restyle flags and damage from the element.
|
/// Drops restyle flags and damage from the element.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clear_restyle_flags_and_damage(&mut self) {
|
pub fn clear_restyle_flags_and_damage(&mut self) {
|
||||||
self.restyle.clear_restyle_flags_and_damage();
|
self.restyle.damage = RestyleDamage::empty();
|
||||||
|
self.flags.remove(WAS_RESTYLED | ANCESTOR_WAS_RECONSTRUCTED)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether this element or any ancestor is going to be
|
||||||
|
/// reconstructed.
|
||||||
|
pub fn reconstructed_self_or_ancestor(&self) -> bool {
|
||||||
|
self.reconstructed_ancestor() || self.reconstructed_self()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this element is going to be reconstructed.
|
||||||
|
pub fn reconstructed_self(&self) -> bool {
|
||||||
|
self.restyle.damage.contains(RestyleDamage::reconstruct())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether any ancestor of this element is going to be
|
||||||
|
/// reconstructed.
|
||||||
|
fn reconstructed_ancestor(&self) -> bool {
|
||||||
|
self.flags.contains(ANCESTOR_WAS_RECONSTRUCTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the flag that tells us whether we've reconstructed an ancestor.
|
||||||
|
pub fn set_reconstructed_ancestor(&mut self, reconstructed: bool) {
|
||||||
|
if reconstructed {
|
||||||
|
// If it weren't for animation-only traversals, we could assert
|
||||||
|
// `!self.reconstructed_ancestor()` here.
|
||||||
|
self.flags.insert(ANCESTOR_WAS_RECONSTRUCTED);
|
||||||
|
} else {
|
||||||
|
self.flags.remove(ANCESTOR_WAS_RECONSTRUCTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark this element as restyled, which is useful to know whether we need
|
||||||
|
/// to do a post-traversal.
|
||||||
|
pub fn set_restyled(&mut self) {
|
||||||
|
self.flags.insert(WAS_RESTYLED);
|
||||||
|
self.flags.remove(TRAVERSED_WITHOUT_STYLING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this element was restyled.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_restyle(&self) -> bool {
|
||||||
|
self.flags.contains(WAS_RESTYLED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark that we traversed this element without computing any style for it.
|
||||||
|
pub fn set_traversed_without_styling(&mut self) {
|
||||||
|
self.flags.insert(TRAVERSED_WITHOUT_STYLING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the element was traversed without computing any style for
|
||||||
|
/// it.
|
||||||
|
pub fn traversed_without_styling(&self) -> bool {
|
||||||
|
self.flags.contains(TRAVERSED_WITHOUT_STYLING)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this element has been part of a restyle.
|
||||||
|
#[inline]
|
||||||
|
pub fn contains_restyle_data(&self) -> bool {
|
||||||
|
self.is_restyle() || !self.restyle.hint.is_empty() || !self.restyle.damage.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If an ancestor is already getting reconstructed by Gecko's top-down
|
||||||
|
/// frame constructor, no need to apply damage. Similarly if we already
|
||||||
|
/// have an explicitly stored ReconstructFrame hint.
|
||||||
|
///
|
||||||
|
/// See https://bugzilla.mozilla.org/show_bug.cgi?id=1301258#c12
|
||||||
|
/// for followup work to make the optimization here more optimal by considering
|
||||||
|
/// each bit individually.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
pub fn skip_applying_damage(&self) -> bool { self.reconstructed_self_or_ancestor() }
|
||||||
|
|
||||||
|
/// N/A in Servo.
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
|
pub fn skip_applying_damage(&self) -> bool { false }
|
||||||
|
|
||||||
/// Measures memory usage.
|
/// Measures memory usage.
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
|
pub fn size_of_excluding_cvs(&self, ops: &mut MallocSizeOfOps) -> usize {
|
||||||
|
|
|
@ -510,7 +510,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
|
ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
|
||||||
NODE_DESCENDANTS_NEED_FRAMES as u32 |
|
NODE_DESCENDANTS_NEED_FRAMES as u32 |
|
||||||
NODE_NEEDS_FRAME as u32) != 0;
|
NODE_NEEDS_FRAME as u32) != 0;
|
||||||
has_flag || self.borrow_data().unwrap().restyle.contains_restyle_data()
|
has_flag || self.borrow_data().unwrap().contains_restyle_data()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this element has a shadow root.
|
/// Returns true if this element has a shadow root.
|
||||||
|
|
|
@ -352,10 +352,11 @@ trait PrivateMatchMethods: TElement {
|
||||||
fn accumulate_damage_for(
|
fn accumulate_damage_for(
|
||||||
&self,
|
&self,
|
||||||
shared_context: &SharedStyleContext,
|
shared_context: &SharedStyleContext,
|
||||||
|
skip_applying_damage: bool,
|
||||||
restyle: &mut RestyleData,
|
restyle: &mut RestyleData,
|
||||||
old_values: &ComputedValues,
|
old_values: &ComputedValues,
|
||||||
new_values: &ComputedValues,
|
new_values: &ComputedValues,
|
||||||
pseudo: Option<&PseudoElement>
|
pseudo: Option<&PseudoElement>,
|
||||||
) -> ChildCascadeRequirement {
|
) -> ChildCascadeRequirement {
|
||||||
debug!("accumulate_damage_for: {:?}", self);
|
debug!("accumulate_damage_for: {:?}", self);
|
||||||
|
|
||||||
|
@ -365,16 +366,6 @@ trait PrivateMatchMethods: TElement {
|
||||||
return ChildCascadeRequirement::MustCascadeChildren;
|
return ChildCascadeRequirement::MustCascadeChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an ancestor is already getting reconstructed by Gecko's top-down
|
|
||||||
// frame constructor, no need to apply damage. Similarly if we already
|
|
||||||
// have an explicitly stored ReconstructFrame hint.
|
|
||||||
//
|
|
||||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1301258#c12
|
|
||||||
// for followup work to make the optimization here more optimal by considering
|
|
||||||
// each bit individually.
|
|
||||||
let skip_applying_damage =
|
|
||||||
cfg!(feature = "gecko") && restyle.reconstructed_self_or_ancestor();
|
|
||||||
|
|
||||||
let difference =
|
let difference =
|
||||||
self.compute_style_difference(old_values, new_values, pseudo);
|
self.compute_style_difference(old_values, new_values, pseudo);
|
||||||
|
|
||||||
|
@ -615,6 +606,7 @@ pub trait MatchMethods : TElement {
|
||||||
cascade_requirement,
|
cascade_requirement,
|
||||||
self.accumulate_damage_for(
|
self.accumulate_damage_for(
|
||||||
context.shared,
|
context.shared,
|
||||||
|
data.skip_applying_damage(),
|
||||||
&mut data.restyle,
|
&mut data.restyle,
|
||||||
&old_primary_style,
|
&old_primary_style,
|
||||||
new_primary_style,
|
new_primary_style,
|
||||||
|
@ -636,6 +628,7 @@ pub trait MatchMethods : TElement {
|
||||||
(&Some(ref old), &Some(ref new)) => {
|
(&Some(ref old), &Some(ref new)) => {
|
||||||
self.accumulate_damage_for(
|
self.accumulate_damage_for(
|
||||||
context.shared,
|
context.shared,
|
||||||
|
data.skip_applying_damage(),
|
||||||
&mut data.restyle,
|
&mut data.restyle,
|
||||||
old,
|
old,
|
||||||
new,
|
new,
|
||||||
|
|
|
@ -40,8 +40,7 @@ pub fn can_share_style_across_parents<E>(first: Option<E>, second: Option<E>) ->
|
||||||
//
|
//
|
||||||
// This is a somewhat conservative check. We could tighten it by having the
|
// This is a somewhat conservative check. We could tighten it by having the
|
||||||
// invalidation logic explicitly flag elements for which it ellided styling.
|
// invalidation logic explicitly flag elements for which it ellided styling.
|
||||||
if first_data.restyle.traversed_without_styling() ||
|
if first_data.traversed_without_styling() || second_data.traversed_without_styling() {
|
||||||
second_data.restyle.traversed_without_styling() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
// the last traversal (at a potentially-higher root). From the
|
// the last traversal (at a potentially-higher root). From the
|
||||||
// perspective of this traversal, the root cannot have reconstructed
|
// perspective of this traversal, the root cannot have reconstructed
|
||||||
// ancestors.
|
// ancestors.
|
||||||
data.restyle.set_reconstructed_ancestor(false);
|
data.set_reconstructed_ancestor(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
let parent = root.traversal_parent();
|
let parent = root.traversal_parent();
|
||||||
|
@ -244,7 +244,7 @@ pub trait DomTraversal<E: TElement> : Sync {
|
||||||
if el.is_native_anonymous() {
|
if el.is_native_anonymous() {
|
||||||
if let Some(parent_data) = parent_data {
|
if let Some(parent_data) = parent_data {
|
||||||
let going_to_reframe =
|
let going_to_reframe =
|
||||||
parent_data.restyle.reconstructed_self_or_ancestor();
|
parent_data.reconstructed_self_or_ancestor();
|
||||||
|
|
||||||
let mut is_before_or_after_pseudo = false;
|
let mut is_before_or_after_pseudo = false;
|
||||||
if let Some(pseudo) = el.implemented_pseudo_element() {
|
if let Some(pseudo) = el.implemented_pseudo_element() {
|
||||||
|
@ -499,7 +499,7 @@ where
|
||||||
notify_paint_worklet(context, data);
|
notify_paint_worklet(context, data);
|
||||||
} else {
|
} else {
|
||||||
debug_assert!(data.has_styles());
|
debug_assert!(data.has_styles());
|
||||||
data.restyle.set_traversed_without_styling();
|
data.set_traversed_without_styling();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that matching and cascading is done, clear the bits corresponding to
|
// Now that matching and cascading is done, clear the bits corresponding to
|
||||||
|
@ -551,7 +551,7 @@ where
|
||||||
!propagated_hint.is_empty() ||
|
!propagated_hint.is_empty() ||
|
||||||
!child_cascade_requirement.can_skip_cascade() ||
|
!child_cascade_requirement.can_skip_cascade() ||
|
||||||
context.thread_local.is_initial_style() ||
|
context.thread_local.is_initial_style() ||
|
||||||
data.restyle.reconstructed_self() ||
|
data.reconstructed_self() ||
|
||||||
is_servo_nonincremental_layout();
|
is_servo_nonincremental_layout();
|
||||||
|
|
||||||
traverse_children = traverse_children &&
|
traverse_children = traverse_children &&
|
||||||
|
@ -565,7 +565,7 @@ where
|
||||||
data,
|
data,
|
||||||
propagated_hint,
|
propagated_hint,
|
||||||
child_cascade_requirement,
|
child_cascade_requirement,
|
||||||
data.restyle.reconstructed_self_or_ancestor(),
|
data.reconstructed_self_or_ancestor(),
|
||||||
note_child
|
note_child
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -631,7 +631,7 @@ where
|
||||||
debug!("compute_style: {:?} (kind={:?})", element, kind);
|
debug!("compute_style: {:?} (kind={:?})", element, kind);
|
||||||
|
|
||||||
if data.has_styles() {
|
if data.has_styles() {
|
||||||
data.restyle.set_restyled();
|
data.set_restyled();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut important_rules_changed = false;
|
let mut important_rules_changed = false;
|
||||||
|
@ -811,7 +811,7 @@ where
|
||||||
if let Some(ref mut child_data) = child_data {
|
if let Some(ref mut child_data) = child_data {
|
||||||
// Propagate the parent restyle hint, that may make us restyle the whole
|
// Propagate the parent restyle hint, that may make us restyle the whole
|
||||||
// subtree.
|
// subtree.
|
||||||
child_data.restyle.set_reconstructed_ancestor(reconstructed_ancestor);
|
child_data.set_reconstructed_ancestor(reconstructed_ancestor);
|
||||||
|
|
||||||
let mut child_hint = propagated_hint;
|
let mut child_hint = propagated_hint;
|
||||||
match cascade_requirement {
|
match cascade_requirement {
|
||||||
|
|
|
@ -2980,7 +2980,7 @@ pub extern "C" fn Servo_TakeChangeHint(element: RawGeckoElementBorrowed,
|
||||||
|
|
||||||
let damage = match element.mutate_data() {
|
let damage = match element.mutate_data() {
|
||||||
Some(mut data) => {
|
Some(mut data) => {
|
||||||
*was_restyled = data.restyle.is_restyle();
|
*was_restyled = data.is_restyle();
|
||||||
|
|
||||||
let damage = data.restyle.damage;
|
let damage = data.restyle.damage;
|
||||||
data.clear_restyle_state();
|
data.clear_restyle_state();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue