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

@ -18,7 +18,7 @@ use style::arc_ptr_eq;
use style::atomic_refcell::AtomicRefMut;
use style::context::{LocalStyleContextCreationInfo, ReflowGoal, SharedStyleContext};
use style::data::{ElementData, RestyleData};
use style::dom::{StylingMode, TElement, TNode, TRestyleDamage};
use style::dom::{TElement, TNode};
use style::error_reporting::StdoutErrorReporter;
use style::gecko::context::StandaloneStyleContext;
use style::gecko::context::clear_local_context;
@ -58,7 +58,7 @@ use style::string_cache::Atom;
use style::stylesheets::{CssRule, CssRules, Origin, Stylesheet, StyleRule};
use style::thread_state;
use style::timer::Timer;
use style::traversal::{recalc_style_at, PerLevelTraversalData};
use style::traversal::{recalc_style_at, DomTraversalContext, PerLevelTraversalData};
use style_traits::ToCss;
/*
@ -106,7 +106,6 @@ fn create_shared_context(mut per_doc_data: &mut AtomicRefMut<PerDocumentStyleDat
// FIXME (bug 1303229): Use the actual viewport size here
viewport_size: Size2D::new(Au(0), Au(0)),
screen_size_changed: false,
skip_root: false,
generation: 0,
goal: ReflowGoal::ForScriptQuery,
stylist: per_doc_data.stylist.clone(),
@ -138,20 +137,22 @@ fn traverse_subtree(element: GeckoElement, raw_data: RawServoStyleSetBorrowed,
}
}
if !skip_root && element.styling_mode() == StylingMode::Stop {
let mut per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let token = RecalcStyleOnly::pre_traverse(element, &per_doc_data.stylist, skip_root);
if !token.should_traverse() {
error!("Unnecessary call to traverse_subtree");
return;
}
let mut per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let mut shared_style_context = create_shared_context(&mut per_doc_data);
shared_style_context.skip_root = skip_root;
let shared_style_context = create_shared_context(&mut per_doc_data);
let known_depth = None;
if per_doc_data.num_threads == 1 || per_doc_data.work_queue.is_none() {
sequential::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), &shared_style_context);
sequential::traverse_dom::<_, RecalcStyleOnly>(element, &shared_style_context, token);
} else {
parallel::traverse_dom::<_, RecalcStyleOnly>(element.as_node(), known_depth, &shared_style_context,
parallel::traverse_dom::<_, RecalcStyleOnly>(element, known_depth,
&shared_style_context, token,
per_doc_data.work_queue.as_mut().unwrap());
}
}
@ -735,10 +736,7 @@ pub extern "C" fn Servo_Element_GetSnapshot(element: RawGeckoElementBorrowed) ->
let element = GeckoElement(element);
let mut data = unsafe { element.ensure_data().borrow_mut() };
let snapshot = if let Some(restyle_data) = unsafe { maybe_restyle(&mut data, element) } {
if restyle_data.snapshot.is_none() {
restyle_data.snapshot = Some(element.create_snapshot());
}
restyle_data.snapshot.as_mut().unwrap().borrow_mut_raw()
restyle_data.snapshot.ensure(|| element.create_snapshot()).borrow_mut_raw()
} else {
ptr::null_mut()
};
@ -757,8 +755,6 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
debug!("Servo_NoteExplicitHints: {:?}, restyle_hint={:?}, change_hint={:?}",
element, restyle_hint, change_hint);
let restore_current_style = restyle_hint.0 == 0 && data.get_current_styles().is_some();
if let Some(restyle_data) = unsafe { maybe_restyle(&mut data, element) } {
let restyle_hint: RestyleHint = restyle_hint.into();
restyle_data.hint.insert(&restyle_hint.into());
@ -766,21 +762,6 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
} else {
debug!("(Element not styled, discarding hints)");
}
// If we had up-to-date style before and only posted a change hint,
// avoid invalidating that style.
//
// This allows for posting explicit change hints during restyle between
// the servo style traversal and the gecko post-traversal (i.e. during the
// call to CreateNeedeFrames in ServoRestyleManager::ProcessPendingRestyles).
//
// FIXME(bholley): The is a very inefficient and hacky way of doing this,
// we should fix the ElementData restyle() API to be more granular so that it
// does the right thing automatically.
if restore_current_style {
let styles = data.previous_styles().unwrap().clone();
data.finish_styling(styles, GeckoRestyleDamage::empty());
}
}
#[no_mangle]
@ -817,12 +798,14 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
let element = GeckoElement(element);
debug!("Servo_ResolveStyle: {:?}, consume={:?}, compute={:?}", element, consume, compute);
let mut data = unsafe { element.ensure_data() }.borrow_mut();
if compute == structs::LazyComputeBehavior::Allow {
let should_compute = unsafe { element.ensure_data() }.borrow().get_current_styles().is_none();
let should_compute = !data.has_current_styles();
if should_compute {
debug!("Performing manual style computation");
if let Some(parent) = element.parent_element() {
if parent.borrow_data().map_or(true, |d| d.get_current_styles().is_none()) {
if parent.borrow_data().map_or(true, |d| !d.has_current_styles()) {
error!("Attempting manual style computation with unstyled parent");
return Arc::new(ComputedValues::initial_values().clone()).into_strong();
}
@ -832,10 +815,11 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
let shared_style_context = create_shared_context(&mut per_doc_data);
let context = StandaloneStyleContext::new(&shared_style_context);
let mut data = PerLevelTraversalData {
let mut traversal_data = PerLevelTraversalData {
current_dom_depth: None,
};
recalc_style_at::<_, _, RecalcStyleOnly>(&context, &mut data, element);
recalc_style_at::<_, _, RecalcStyleOnly>(&context, &mut traversal_data, element, &mut data);
// The element was either unstyled or needed restyle. If it was unstyled, it may have
// additional unstyled children that subsequent traversals won't find now that the style
@ -846,19 +830,17 @@ pub extern "C" fn Servo_ResolveStyle(element: RawGeckoElementBorrowed,
}
}
let data = element.mutate_data();
let values = match data.as_ref().and_then(|d| d.get_current_styles()) {
Some(x) => x.primary.values.clone(),
None => {
error!("Resolving style on unstyled element with lazy computation forbidden.");
return Arc::new(ComputedValues::initial_values().clone()).into_strong();
}
};
if !data.has_current_styles() {
error!("Resolving style on unstyled element with lazy computation forbidden.");
return Arc::new(ComputedValues::initial_values().clone()).into_strong();
}
let values = data.styles().primary.values.clone();
if consume == structs::ConsumeStyleBehavior::Consume {
// FIXME(bholley): Once we start storing style data on frames, we'll want to
// drop the data here instead.
data.unwrap().persist();
data.persist();
}
values.into_strong()