mirror of
https://github.com/servo/servo.git
synced 2025-08-10 07:55:33 +01:00
Incremental Style Recalc
This patch puts in the initial framework for incremental reflow. Nodes' styles are no longer recalculated unless the node has changed. I've been hacking on the general problem of incremental reflow for the past couple weeks, and I've yet to get a full implementation that actually passes all the reftests + wikipedia + cnn. Therefore, I'm going to try to land the different parts of it one by one. This patch only does incremental style recalc, without incremental flow construction, inline-size bubbling, reflow, or display lists. Those will be coming in that order as I finish them. At least with this strategy, I can land a working version of incremental reflow, even if not yet complete. r? @pcwalton
This commit is contained in:
parent
510f8a817f
commit
d12c6e7383
31 changed files with 641 additions and 424 deletions
|
@ -7,6 +7,8 @@
|
|||
use css::node_style::StyledNode;
|
||||
use construct::FlowConstructor;
|
||||
use context::LayoutContext;
|
||||
use incremental;
|
||||
use incremental::RestyleDamage;
|
||||
use util::{LayoutDataAccess, LayoutDataWrapper};
|
||||
use wrapper::{LayoutElement, LayoutNode, PostorderNodeMutTraversal, ThreadSafeLayoutNode};
|
||||
use wrapper::{TLayoutNode};
|
||||
|
@ -331,7 +333,7 @@ trait PrivateMatchMethods {
|
|||
style: &mut Option<Arc<ComputedValues>>,
|
||||
applicable_declarations_cache: &mut
|
||||
ApplicableDeclarationsCache,
|
||||
shareable: bool);
|
||||
shareable: bool) -> RestyleDamage;
|
||||
|
||||
fn share_style_with_candidate_if_possible(&self,
|
||||
parent_node: Option<LayoutNode>,
|
||||
|
@ -346,7 +348,7 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
|
|||
style: &mut Option<Arc<ComputedValues>>,
|
||||
applicable_declarations_cache: &mut
|
||||
ApplicableDeclarationsCache,
|
||||
shareable: bool) {
|
||||
shareable: bool) -> RestyleDamage {
|
||||
let this_style;
|
||||
let cacheable;
|
||||
match parent_style {
|
||||
|
@ -378,7 +380,9 @@ impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
|
|||
applicable_declarations_cache.insert(applicable_declarations, this_style.clone());
|
||||
}
|
||||
|
||||
let damage = incremental::compute_damage(style, &*this_style);
|
||||
*style = Some(this_style);
|
||||
damage
|
||||
}
|
||||
|
||||
|
||||
|
@ -468,8 +472,15 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
|||
match self.share_style_with_candidate_if_possible(parent.clone(), candidate) {
|
||||
Some(shared_style) => {
|
||||
// Yay, cache hit. Share the style.
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
layout_data_ref.as_mut().unwrap().shared_data.style = Some(shared_style);
|
||||
let damage = {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
let shared_data = &mut layout_data_ref.as_mut().unwrap().shared_data;
|
||||
let style = &mut shared_data.style;
|
||||
let damage = incremental::compute_damage(style, &*shared_style);
|
||||
*style = Some(shared_style);
|
||||
damage
|
||||
};
|
||||
ThreadSafeLayoutNode::new(self).set_restyle_damage(damage);
|
||||
return StyleWasShared(i)
|
||||
}
|
||||
None => {}
|
||||
|
@ -602,58 +613,71 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
|||
//
|
||||
// FIXME(pcwalton): Isolate this unsafety into the `wrapper` module to allow
|
||||
// enforced safe, race-free access to the parent style.
|
||||
let parent_style = match parent {
|
||||
None => None,
|
||||
let (down_restyle_damage, parent_style) = match parent {
|
||||
None => (RestyleDamage::empty(), None),
|
||||
Some(parent_node) => {
|
||||
let parent_layout_data = parent_node.borrow_layout_data_unchecked();
|
||||
match *parent_layout_data {
|
||||
None => fail!("no parent data?!"),
|
||||
Some(ref parent_layout_data) => {
|
||||
let down_restyle_damage =
|
||||
parent_layout_data.data.restyle_damage.propagate_down();
|
||||
match parent_layout_data.shared_data.style {
|
||||
None => fail!("parent hasn't been styled yet?!"),
|
||||
Some(ref style) => Some(style),
|
||||
Some(ref style) => (down_restyle_damage, Some(style)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match &mut *layout_data_ref {
|
||||
&None => fail!("no layout data"),
|
||||
&Some(ref mut layout_data) => {
|
||||
match self.type_id() {
|
||||
Some(TextNodeTypeId) => {
|
||||
// Text nodes get a copy of the parent style. This ensures
|
||||
// that during fragment construction any non-inherited
|
||||
// CSS properties (such as vertical-align) are correctly
|
||||
// set on the fragment(s).
|
||||
let cloned_parent_style = parent_style.unwrap().clone();
|
||||
layout_data.shared_data.style = Some(cloned_parent_style);
|
||||
}
|
||||
_ => {
|
||||
self.cascade_node_pseudo_element(parent_style,
|
||||
applicable_declarations.normal.as_slice(),
|
||||
&mut layout_data.shared_data.style,
|
||||
applicable_declarations_cache,
|
||||
applicable_declarations.normal_shareable);
|
||||
if applicable_declarations.before.len() > 0 {
|
||||
self.cascade_node_pseudo_element(Some(layout_data.shared_data.style.as_ref().unwrap()),
|
||||
applicable_declarations.before.as_slice(),
|
||||
&mut layout_data.data.before_style,
|
||||
applicable_declarations_cache,
|
||||
false);
|
||||
let mut damage = down_restyle_damage;
|
||||
|
||||
{
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match &mut *layout_data_ref {
|
||||
&None => fail!("no layout data"),
|
||||
&Some(ref mut layout_data) => {
|
||||
match self.type_id() {
|
||||
Some(TextNodeTypeId) => {
|
||||
// Text nodes get a copy of the parent style. This ensures
|
||||
// that during fragment construction any non-inherited
|
||||
// CSS properties (such as vertical-align) are correctly
|
||||
// set on the fragment(s).
|
||||
let cloned_parent_style = parent_style.unwrap().clone();
|
||||
layout_data.shared_data.style = Some(cloned_parent_style);
|
||||
}
|
||||
if applicable_declarations.after.len() > 0 {
|
||||
self.cascade_node_pseudo_element(Some(layout_data.shared_data.style.as_ref().unwrap()),
|
||||
applicable_declarations.after.as_slice(),
|
||||
&mut layout_data.data.after_style,
|
||||
applicable_declarations_cache,
|
||||
false);
|
||||
_ => {
|
||||
damage = damage
|
||||
| self.cascade_node_pseudo_element(
|
||||
parent_style,
|
||||
applicable_declarations.normal.as_slice(),
|
||||
&mut layout_data.shared_data.style,
|
||||
applicable_declarations_cache,
|
||||
applicable_declarations.normal_shareable);
|
||||
if applicable_declarations.before.len() > 0 {
|
||||
damage = damage
|
||||
| self.cascade_node_pseudo_element(
|
||||
Some(layout_data.shared_data.style.as_ref().unwrap()),
|
||||
applicable_declarations.before.as_slice(),
|
||||
&mut layout_data.data.before_style,
|
||||
applicable_declarations_cache,
|
||||
false);
|
||||
}
|
||||
if applicable_declarations.after.len() > 0 {
|
||||
damage = damage
|
||||
| self.cascade_node_pseudo_element(Some(layout_data.shared_data.style.as_ref().unwrap()),
|
||||
applicable_declarations.after.as_slice(),
|
||||
&mut layout_data.data.after_style,
|
||||
applicable_declarations_cache,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreadSafeLayoutNode::new(self).set_restyle_damage(damage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ use sync::Arc;
|
|||
/// Node mixin providing `style` method that returns a `NodeStyle`
|
||||
pub trait StyledNode {
|
||||
fn style<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||
fn restyle_damage(&self) -> RestyleDamage;
|
||||
fn restyle_damage(self) -> RestyleDamage;
|
||||
fn set_restyle_damage(self, damage: RestyleDamage);
|
||||
}
|
||||
|
||||
impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
|
||||
|
@ -23,8 +24,14 @@ impl<'ln> StyledNode for ThreadSafeLayoutNode<'ln> {
|
|||
self.get_css_select_results()
|
||||
}
|
||||
|
||||
fn restyle_damage(&self) -> RestyleDamage {
|
||||
fn restyle_damage(self) -> RestyleDamage {
|
||||
self.get_restyle_damage()
|
||||
}
|
||||
}
|
||||
|
||||
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||
fn doit<N: NodeUtil>(n: N, damage: RestyleDamage) {
|
||||
n.set_restyle_damage(damage);
|
||||
}
|
||||
doit(self, damage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use incremental::RestyleDamage;
|
||||
use util::LayoutDataAccess;
|
||||
use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
use wrapper::{After, Before, Normal};
|
||||
use std::mem;
|
||||
use style::ComputedValues;
|
||||
|
@ -14,8 +14,8 @@ pub trait NodeUtil {
|
|||
fn get_css_select_results<'a>(&'a self) -> &'a Arc<ComputedValues>;
|
||||
fn have_css_select_results(&self) -> bool;
|
||||
|
||||
fn get_restyle_damage(&self) -> RestyleDamage;
|
||||
fn set_restyle_damage(&self, damage: RestyleDamage);
|
||||
fn get_restyle_damage(self) -> RestyleDamage;
|
||||
fn set_restyle_damage(self, damage: RestyleDamage);
|
||||
}
|
||||
|
||||
impl<'ln> NodeUtil for ThreadSafeLayoutNode<'ln> {
|
||||
|
@ -62,28 +62,19 @@ impl<'ln> NodeUtil for ThreadSafeLayoutNode<'ln> {
|
|||
|
||||
/// Get the description of how to account for recent style changes.
|
||||
/// This is a simple bitfield and fine to copy by value.
|
||||
fn get_restyle_damage(&self) -> RestyleDamage {
|
||||
// For DOM elements, if we haven't computed damage yet, assume the worst.
|
||||
// Other nodes don't have styles.
|
||||
let default = if self.node_is_element() {
|
||||
RestyleDamage::all()
|
||||
} else {
|
||||
RestyleDamage::empty()
|
||||
};
|
||||
|
||||
fn get_restyle_damage(self) -> RestyleDamage {
|
||||
let layout_data_ref = self.borrow_layout_data();
|
||||
layout_data_ref
|
||||
.as_ref().unwrap()
|
||||
.data
|
||||
.restyle_damage
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
/// Set the restyle damage field.
|
||||
fn set_restyle_damage(&self, damage: RestyleDamage) {
|
||||
fn set_restyle_damage(self, damage: RestyleDamage) {
|
||||
let mut layout_data_ref = self.mutate_layout_data();
|
||||
match &mut *layout_data_ref {
|
||||
&Some(ref mut layout_data) => layout_data.data.restyle_damage = Some(damage),
|
||||
&Some(ref mut layout_data) => layout_data.data.restyle_damage = damage,
|
||||
_ => fail!("no layout data for this node"),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue