layout: Stop storing intermediate applicable declarations inside layout

data.

9% improvement in style recalc on the rainbow page.
This commit is contained in:
Patrick Walton 2014-02-07 11:00:24 -08:00
parent 758f5ba755
commit cf8203848a
4 changed files with 77 additions and 84 deletions

View file

@ -12,24 +12,48 @@ use layout::wrapper::LayoutNode;
use extra::arc::Arc;
use script::layout_interface::LayoutChan;
use servo_util::smallvec::SmallVec;
use style::{TNode, Stylist, cascade};
use style::{Before, After};
use servo_util::smallvec::{SmallVec, SmallVec0, SmallVec16};
use style::{After, Before, PropertyDeclaration, Stylist, TNode, cascade};
pub struct ApplicableDeclarations {
normal: SmallVec16<Arc<~[PropertyDeclaration]>>,
before: SmallVec0<Arc<~[PropertyDeclaration]>>,
after: SmallVec0<Arc<~[PropertyDeclaration]>>,
}
impl ApplicableDeclarations {
pub fn new() -> ApplicableDeclarations {
ApplicableDeclarations {
normal: SmallVec16::new(),
before: SmallVec0::new(),
after: SmallVec0::new(),
}
}
pub fn clear(&mut self) {
self.normal = SmallVec16::new();
self.before = SmallVec0::new();
self.after = SmallVec0::new();
}
}
pub trait MatchMethods {
fn match_node(&self, stylist: &Stylist);
/// Performs aux initialization, selector matching, and cascading sequentially.
fn match_and_cascade_subtree(&self,
stylist: &Stylist,
layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations,
parent: Option<LayoutNode>);
unsafe fn cascade_node(&self, parent: Option<LayoutNode>);
fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations);
unsafe fn cascade_node(&self,
parent: Option<LayoutNode>,
applicable_declarations: &ApplicableDeclarations);
}
impl<'ln> MatchMethods for LayoutNode<'ln> {
fn match_node(&self, stylist: &Stylist) {
fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations) {
let style_attribute = self.with_element(|element| {
match *element.style_attribute() {
None => None,
@ -37,55 +61,50 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
}
});
let mut layout_data_ref = self.mutate_layout_data();
match *layout_data_ref.get() {
Some(ref mut layout_data) => {
//FIXME To implement a clear() on SmallVec and use it(init_applicable_declarations).
layout_data.data.init_applicable_declarations();
stylist.push_applicable_declarations(self,
style_attribute,
None,
&mut layout_data.data.applicable_declarations);
stylist.push_applicable_declarations(self,
None,
Some(Before),
&mut layout_data
.data
.before_applicable_declarations);
stylist.push_applicable_declarations(self,
None,
Some(After),
&mut layout_data
.data
.after_applicable_declarations);
}
None => fail!("no layout data")
}
stylist.push_applicable_declarations(self,
style_attribute,
None,
&mut applicable_declarations.normal);
stylist.push_applicable_declarations(self,
None,
Some(Before),
&mut applicable_declarations.before);
stylist.push_applicable_declarations(self,
None,
Some(After),
&mut applicable_declarations.after);
}
fn match_and_cascade_subtree(&self,
stylist: &Stylist,
layout_chan: &LayoutChan,
applicable_declarations: &mut ApplicableDeclarations,
parent: Option<LayoutNode>) {
self.initialize_layout_data((*layout_chan).clone());
if self.is_element() {
self.match_node(stylist);
self.match_node(stylist, applicable_declarations);
}
unsafe {
self.cascade_node(parent)
self.cascade_node(parent, applicable_declarations)
}
applicable_declarations.clear();
for kid in self.children() {
kid.match_and_cascade_subtree(stylist, layout_chan, Some(*self))
kid.match_and_cascade_subtree(stylist,
layout_chan,
applicable_declarations,
Some(*self))
}
}
unsafe fn cascade_node(&self, parent: Option<LayoutNode>) {
unsafe fn cascade_node(&self,
parent: Option<LayoutNode>,
applicable_declarations: &ApplicableDeclarations) {
macro_rules! cascade_node(
($applicable_declarations: ident, $style: ident) => {{
($applicable_declarations: expr, $style: ident) => {{
// Get our parent's style. This must be unsafe so that we don't touch the parent's
// borrow flags.
//
@ -100,18 +119,19 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
Some(ref parent_layout_data) => {
match parent_layout_data.data.style {
None => fail!("parent hasn't been styled yet?!"),
Some(ref style) => Some(style.get()),
Some(ref style) => Some(style),
}
}
}
}
};
let computed_values = {
let layout_data_ref = self.borrow_layout_data();
let layout_data = layout_data_ref.get().as_ref().unwrap();
Arc::new(cascade(layout_data.data.$applicable_declarations.as_slice(),
parent_style))
let computed_values = match parent_style {
Some(ref style) => {
Arc::new(cascade($applicable_declarations.as_slice(),
Some(style.get())))
}
None => Arc::new(cascade($applicable_declarations.as_slice(), None)),
};
let mut layout_data_ref = self.mutate_layout_data();
@ -132,24 +152,12 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
}}
);
{
let before_len = {
let layout_data_ref = self.borrow_layout_data();
layout_data_ref.get().as_ref().unwrap().data.before_applicable_declarations.len()
};
if before_len > 0 {
cascade_node!(before_applicable_declarations, before_style);
}
cascade_node!(applicable_declarations.normal, style);
if applicable_declarations.before.len() > 0 {
cascade_node!(applicable_declarations.before, before_style);
}
cascade_node!(applicable_declarations, style);
{
let after_len = {
let layout_data_ref = self.borrow_layout_data();
layout_data_ref.get().as_ref().unwrap().data.after_applicable_declarations.len()
};
if after_len > 0 {
cascade_node!(after_applicable_declarations, after_style);
}
if applicable_declarations.after.len() > 0 {
cascade_node!(applicable_declarations.after, after_style);
}
}
}

View file

@ -5,7 +5,7 @@
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
/// rendered.
use css::matching::MatchMethods;
use css::matching::{ApplicableDeclarations, MatchMethods};
use css::select::new_stylist;
use css::node_style::StyledNode;
use layout::construct::{FlowConstructionResult, FlowConstructor, NoConstructionResult};
@ -561,8 +561,10 @@ impl LayoutTask {
profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || {
match self.parallel_traversal {
None => {
let mut applicable_declarations = ApplicableDeclarations::new();
node.match_and_cascade_subtree(self.stylist,
&layout_ctx.layout_chan,
&mut applicable_declarations,
None)
}
Some(ref mut traversal) => {

View file

@ -6,7 +6,7 @@
//!
//! This code is highly unsafe. Keep this file small and easy to audit.
use css::matching::MatchMethods;
use css::matching::{ApplicableDeclarations, MatchMethods};
use layout::context::LayoutContext;
use layout::extra::LayoutAuxMethods;
use layout::flow::{Flow, FlowLeafSet, PostorderFlowTraversal};
@ -149,10 +149,12 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
// parser.
node.initialize_layout_data(layout_context.layout_chan.clone());
let mut applicable_declarations = ApplicableDeclarations::new();
if node.is_element() {
// Perform the CSS selector matching.
let stylist: &Stylist = cast::transmute(layout_context.stylist);
node.match_node(stylist);
node.match_node(stylist, &mut applicable_declarations);
}
// Perform the CSS cascade.
@ -161,7 +163,7 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
} else {
node.parent_node()
};
node.cascade_node(parent_opt);
node.cascade_node(parent_opt, &applicable_declarations);
// Enqueue kids.
let mut child_count = 0;

View file

@ -12,13 +12,12 @@ use script::dom::bindings::utils::Reflectable;
use script::dom::node::AbstractNode;
use script::layout_interface::{LayoutChan, UntrustedNodeAddress};
use servo_util::range::Range;
use servo_util::smallvec::{SmallVec0, SmallVec16};
use std::cast;
use std::cell::{Ref, RefMut};
use std::iter::Enumerate;
use std::libc::uintptr_t;
use std::vec::VecIterator;
use style::{ComputedValues, PropertyDeclaration};
use style::ComputedValues;
/// A range of nodes.
pub struct NodeRange {
@ -130,13 +129,6 @@ impl ElementMapping {
/// Data that layout associates with a node.
pub struct PrivateLayoutData {
/// The results of CSS matching for this node.
applicable_declarations: SmallVec16<Arc<~[PropertyDeclaration]>>,
before_applicable_declarations: SmallVec0<Arc<~[PropertyDeclaration]>>,
after_applicable_declarations: SmallVec0<Arc<~[PropertyDeclaration]>>,
/// The results of CSS styling for this node.
before_style: Option<Arc<ComputedValues>>,
@ -159,9 +151,6 @@ impl PrivateLayoutData {
/// Creates new layout data.
pub fn new() -> PrivateLayoutData {
PrivateLayoutData {
applicable_declarations: SmallVec16::new(),
before_applicable_declarations: SmallVec0::new(),
after_applicable_declarations: SmallVec0::new(),
before_style: None,
style: None,
after_style: None,
@ -170,14 +159,6 @@ impl PrivateLayoutData {
parallel: DomParallelInfo::new(),
}
}
/// Initialize the function for applicable_declarations.
pub fn init_applicable_declarations(&mut self) {
//FIXME To implement a clear() on SmallVec and use it(init_applicable_declarations).
self.applicable_declarations = SmallVec16::new();
self.before_applicable_declarations = SmallVec0::new();
self.after_applicable_declarations = SmallVec0::new();
}
}
pub struct LayoutDataWrapper {