mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
layout: Stop storing intermediate applicable declarations inside layout
data. 9% improvement in style recalc on the rainbow page.
This commit is contained in:
parent
758f5ba755
commit
cf8203848a
4 changed files with 77 additions and 84 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue