Make Restyle tracking more granular.

The primary idea of this patch is to ditch the rigid enum of Previous/Current
styles, and replace it with a series of indicators for the various types of
work that needs to be performed (expanding snapshots, rematching, recascading,
and damage processing). This loses us a little bit of sanity checking (since
the up-to-date-ness of our style is no longer baked into the type system), but
gives us a lot more flexibility that we'll need going forward (especially when
we separate matching from cascading). We also eliminate get_styling_mode in
favor of a method on the traversal.

This patch does a few other things as ridealongs:
* Temporarily eliminates the handling for transfering ownership of styles to the
  frame. We'll need this again at some point, but for now it's causing too much
  complexity for a half-implemented feature.
* Ditches TRestyleDamage, which is no longer necessary post-crate-merge, and is
  a constant source of compilation failures from either needing to be imported
  or being unnecessarily imported (which varies between gecko and servo).
* Expands Snapshots for the traversal root, which was missing before.
* Fixes up the skip_root stuff to avoid visiting the skipped root.
* Unifies parallel traversal and avoids spawning for a single work item.
* Adds an explicit pre_traverse step do any pre-processing and determine whether
  we need to traverse at all.

MozReview-Commit-ID: IKhLAkAigXE
This commit is contained in:
Bobby Holley 2016-11-30 19:36:08 -08:00
parent 4cb3404c09
commit 80460cc549
27 changed files with 502 additions and 474 deletions

View file

@ -8,17 +8,15 @@
use {Atom, Namespace, LocalName};
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use data::{ElementStyles, ElementData};
use data::ElementData;
use element_state::ElementState;
use parking_lot::RwLock;
use properties::{ComputedValues, PropertyDeclarationBlock};
use selector_parser::{ElementExt, PseudoElement, RestyleDamage};
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
use sink::Push;
use std::fmt::Debug;
use std::ops::{BitOr, BitOrAssign};
use std::sync::Arc;
use stylist::ApplicableDeclarationBlock;
use util::opts;
pub use style_traits::UnsafeNode;
@ -43,42 +41,6 @@ impl OpaqueNode {
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum StylingMode {
/// The node has never been styled before, and needs a full style computation.
Initial,
/// The node has been styled before, but needs some amount of recomputation.
Restyle,
/// The node does not need any style processing, but one or more of its
/// descendants do.
Traverse,
/// No nodes in this subtree require style processing.
Stop,
}
pub trait TRestyleDamage : BitOr<Output=Self> + BitOrAssign + Copy + Debug + PartialEq {
/// The source for our current computed values in the cascade. This is a
/// ComputedValues in Servo and a StyleContext in Gecko.
///
/// This is needed because Gecko has a few optimisations for the calculation
/// of the difference depending on which values have been used during
/// layout.
///
/// This should be obtained via TNode::existing_style_for_restyle_damage
type PreExistingComputedValues;
fn compute(old: &Self::PreExistingComputedValues,
new: &Arc<ComputedValues>) -> Self;
fn empty() -> Self;
fn rebuild_and_reflow() -> Self;
fn is_empty(&self) -> bool {
*self == Self::empty()
}
}
/// Simple trait to provide basic information about the type of an element.
///
/// We avoid exposing the full type id, since computing it in the general case
@ -174,7 +136,7 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
fn existing_style_for_restyle_damage<'a>(&'a self,
current_computed_values: Option<&'a Arc<ComputedValues>>,
pseudo: Option<&PseudoElement>)
-> Option<&'a <RestyleDamage as TRestyleDamage>::PreExistingComputedValues>;
-> Option<&'a PreExistingComputedValues>;
/// Returns true if this element may have a descendant needing style processing.
///
@ -201,60 +163,11 @@ pub trait TElement : PartialEq + Debug + Sized + Copy + Clone + ElementExt + Pre
/// traversal. Returns the number of children left to process.
fn did_process_child(&self) -> isize;
/// Returns true if this element's current style is display:none. Only valid
/// to call after styling.
/// Returns true if this element's style is display:none.
fn is_display_none(&self) -> bool {
self.borrow_data().unwrap().current_styles().is_display_none()
}
/// Returns true if this node has a styled layout frame that owns the style.
fn frame_has_style(&self) -> bool { false }
/// Returns the styles from the layout frame that owns them, if any.
///
/// FIXME(bholley): Once we start dropping ElementData from nodes when
/// creating frames, we'll want to teach this method to actually get
/// style data from the frame.
fn get_styles_from_frame(&self) -> Option<ElementStyles> { None }
/// Returns the styling mode for this node. This is only valid to call before
/// and during restyling, before finish_styling is invoked.
///
/// See the comments around StylingMode.
fn styling_mode(&self) -> StylingMode {
use self::StylingMode::*;
// Non-incremental layout impersonates Initial.
if opts::get().nonincremental_layout {
return Initial;
}
// Compute the default result if this node doesn't require processing.
let mode_for_descendants = if self.has_dirty_descendants() {
Traverse
} else {
Stop
};
match self.borrow_data() {
// No element data, no style on the frame.
None if !self.frame_has_style() => Initial,
// No element data, style on the frame.
None => mode_for_descendants,
// We have element data. Decide below.
Some(d) => match *d {
ElementData::Restyle(_) => Restyle,
ElementData::Persistent(_) => mode_for_descendants,
ElementData::Initial(None) => Initial,
// We previously computed the initial style for this element
// and then never consumed it. This is arguably a bug, since
// it means we either styled an element unnecessarily, or missed
// an opportunity to coalesce style traversals. However, this
// happens now for various reasons, so we just let it slide and
// treat it as persistent for now.
ElementData::Initial(Some(_)) => mode_for_descendants,
},
}
let data = self.borrow_data().unwrap();
debug_assert!(data.has_current_styles());
data.styles().is_display_none()
}
/// Gets a reference to the ElementData container.