mirror of
https://github.com/servo/servo.git
synced 2025-08-04 21:20:23 +01:00
layout: Cache applicable-declarations-to-computed-values mappings.
If the cache is hit, then we can only compute inherited properties. This is a WebKit optimization.
This commit is contained in:
parent
1678cc9a88
commit
0fa0940ce9
8 changed files with 453 additions and 78 deletions
|
@ -6,13 +6,16 @@
|
||||||
|
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::extra::LayoutAuxMethods;
|
use layout::extra::LayoutAuxMethods;
|
||||||
use layout::incremental;
|
|
||||||
use layout::util::LayoutDataAccess;
|
use layout::util::LayoutDataAccess;
|
||||||
use layout::wrapper::LayoutNode;
|
use layout::wrapper::LayoutNode;
|
||||||
|
|
||||||
use extra::arc::Arc;
|
use extra::arc::Arc;
|
||||||
use script::layout_interface::LayoutChan;
|
use script::layout_interface::LayoutChan;
|
||||||
|
use servo_util::cache::{Cache, LRUCache, SimpleHashCache};
|
||||||
|
use servo_util::namespace::Null;
|
||||||
use servo_util::smallvec::{SmallVec, SmallVec0, SmallVec16};
|
use servo_util::smallvec::{SmallVec, SmallVec0, SmallVec16};
|
||||||
|
use std::cast;
|
||||||
|
use std::to_bytes;
|
||||||
use style::{After, Before, ComputedValues, PropertyDeclaration, Stylist, TNode, cascade};
|
use style::{After, Before, ComputedValues, PropertyDeclaration, Stylist, TNode, cascade};
|
||||||
|
|
||||||
pub struct ApplicableDeclarations {
|
pub struct ApplicableDeclarations {
|
||||||
|
@ -37,6 +40,108 @@ impl ApplicableDeclarations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deriving(Clone)]
|
||||||
|
struct ApplicableDeclarationsCacheEntry {
|
||||||
|
declarations: SmallVec16<Arc<~[PropertyDeclaration]>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicableDeclarationsCacheEntry {
|
||||||
|
fn new(slice: &[Arc<~[PropertyDeclaration]>]) -> ApplicableDeclarationsCacheEntry {
|
||||||
|
let mut entry_declarations = SmallVec16::new();
|
||||||
|
for declarations in slice.iter() {
|
||||||
|
entry_declarations.push(declarations.clone());
|
||||||
|
}
|
||||||
|
ApplicableDeclarationsCacheEntry {
|
||||||
|
declarations: entry_declarations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for ApplicableDeclarationsCacheEntry {
|
||||||
|
fn eq(&self, other: &ApplicableDeclarationsCacheEntry) -> bool {
|
||||||
|
let this_as_query = ApplicableDeclarationsCacheQuery::new(self.declarations.as_slice());
|
||||||
|
this_as_query.equiv(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IterBytes for ApplicableDeclarationsCacheEntry {
|
||||||
|
fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
|
||||||
|
ApplicableDeclarationsCacheQuery::new(self.declarations.as_slice()).iter_bytes(lsb0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ApplicableDeclarationsCacheQuery<'a> {
|
||||||
|
declarations: &'a [Arc<~[PropertyDeclaration]>],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ApplicableDeclarationsCacheQuery<'a> {
|
||||||
|
fn new(declarations: &'a [Arc<~[PropertyDeclaration]>])
|
||||||
|
-> ApplicableDeclarationsCacheQuery<'a> {
|
||||||
|
ApplicableDeclarationsCacheQuery {
|
||||||
|
declarations: declarations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Equiv<ApplicableDeclarationsCacheEntry> for ApplicableDeclarationsCacheQuery<'a> {
|
||||||
|
fn equiv(&self, other: &ApplicableDeclarationsCacheEntry) -> bool {
|
||||||
|
if self.declarations.len() != other.declarations.len() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (this, other) in self.declarations.iter().zip(other.declarations.iter()) {
|
||||||
|
unsafe {
|
||||||
|
// Workaround for lack of `ptr_eq` on Arcs...
|
||||||
|
let this: uint = cast::transmute_copy(this);
|
||||||
|
let other: uint = cast::transmute_copy(other);
|
||||||
|
if this != other {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IterBytes for ApplicableDeclarationsCacheQuery<'a> {
|
||||||
|
fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) -> bool {
|
||||||
|
let mut result = true;
|
||||||
|
for declaration in self.declarations.iter() {
|
||||||
|
let ptr: uint = unsafe {
|
||||||
|
cast::transmute_copy(declaration)
|
||||||
|
};
|
||||||
|
result = ptr.iter_bytes(lsb0, |x| f(x));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static APPLICABLE_DECLARATIONS_CACHE_SIZE: uint = 32;
|
||||||
|
|
||||||
|
pub struct ApplicableDeclarationsCache {
|
||||||
|
cache: SimpleHashCache<ApplicableDeclarationsCacheEntry,Arc<ComputedValues>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicableDeclarationsCache {
|
||||||
|
pub fn new() -> ApplicableDeclarationsCache {
|
||||||
|
ApplicableDeclarationsCache {
|
||||||
|
cache: SimpleHashCache::new(APPLICABLE_DECLARATIONS_CACHE_SIZE),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find(&self, declarations: &[Arc<~[PropertyDeclaration]>]) -> Option<Arc<ComputedValues>> {
|
||||||
|
match self.cache.find_equiv(&ApplicableDeclarationsCacheQuery::new(declarations)) {
|
||||||
|
None => None,
|
||||||
|
Some(ref values) => Some((*values).clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self,
|
||||||
|
declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
|
style: Arc<ComputedValues>) {
|
||||||
|
drop(self.cache.insert(ApplicableDeclarationsCacheEntry::new(declarations), style))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait MatchMethods {
|
pub trait MatchMethods {
|
||||||
/// Performs aux initialization, selector matching, and cascading sequentially.
|
/// Performs aux initialization, selector matching, and cascading sequentially.
|
||||||
fn match_and_cascade_subtree(&self,
|
fn match_and_cascade_subtree(&self,
|
||||||
|
@ -44,6 +149,7 @@ pub trait MatchMethods {
|
||||||
layout_chan: &LayoutChan,
|
layout_chan: &LayoutChan,
|
||||||
applicable_declarations: &mut ApplicableDeclarations,
|
applicable_declarations: &mut ApplicableDeclarations,
|
||||||
initial_values: &ComputedValues,
|
initial_values: &ComputedValues,
|
||||||
|
applicable_declarations_cache: &mut ApplicableDeclarationsCache,
|
||||||
parent: Option<LayoutNode>);
|
parent: Option<LayoutNode>);
|
||||||
|
|
||||||
fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations);
|
fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations);
|
||||||
|
@ -51,11 +157,68 @@ pub trait MatchMethods {
|
||||||
unsafe fn cascade_node(&self,
|
unsafe fn cascade_node(&self,
|
||||||
parent: Option<LayoutNode>,
|
parent: Option<LayoutNode>,
|
||||||
initial_values: &ComputedValues,
|
initial_values: &ComputedValues,
|
||||||
applicable_declarations: &ApplicableDeclarations);
|
applicable_declarations: &ApplicableDeclarations,
|
||||||
|
applicable_declarations_cache: &mut ApplicableDeclarationsCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PrivateMatchMethods {
|
||||||
|
fn cascade_node_pseudo_element(&self,
|
||||||
|
parent_style: Option<&Arc<ComputedValues>>,
|
||||||
|
applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
|
style: &mut Option<Arc<ComputedValues>>,
|
||||||
|
initial_values: &ComputedValues,
|
||||||
|
applicable_declarations_cache: &mut
|
||||||
|
ApplicableDeclarationsCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ln> PrivateMatchMethods for LayoutNode<'ln> {
|
||||||
|
fn cascade_node_pseudo_element(&self,
|
||||||
|
parent_style: Option<&Arc<ComputedValues>>,
|
||||||
|
applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
|
style: &mut Option<Arc<ComputedValues>>,
|
||||||
|
initial_values: &ComputedValues,
|
||||||
|
applicable_declarations_cache: &mut
|
||||||
|
ApplicableDeclarationsCache) {
|
||||||
|
let this_style;
|
||||||
|
let cacheable;
|
||||||
|
match parent_style {
|
||||||
|
Some(ref parent_style) => {
|
||||||
|
let cached_computed_values;
|
||||||
|
let cache_entry = applicable_declarations_cache.find(applicable_declarations);
|
||||||
|
match cache_entry {
|
||||||
|
None => cached_computed_values = None,
|
||||||
|
Some(ref style) => cached_computed_values = Some(style.get()),
|
||||||
|
}
|
||||||
|
let (the_style, is_cacheable) = cascade(applicable_declarations,
|
||||||
|
Some(parent_style.get()),
|
||||||
|
initial_values,
|
||||||
|
cached_computed_values);
|
||||||
|
cacheable = is_cacheable;
|
||||||
|
this_style = Arc::new(the_style);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let (the_style, is_cacheable) = cascade(applicable_declarations,
|
||||||
|
None,
|
||||||
|
initial_values,
|
||||||
|
None);
|
||||||
|
cacheable = is_cacheable;
|
||||||
|
this_style = Arc::new(the_style);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cache the resolved style if it was cacheable.
|
||||||
|
if cacheable {
|
||||||
|
applicable_declarations_cache.insert(applicable_declarations, this_style.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
*style = Some(this_style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ln> MatchMethods for LayoutNode<'ln> {
|
impl<'ln> MatchMethods for LayoutNode<'ln> {
|
||||||
fn match_node(&self, stylist: &Stylist, applicable_declarations: &mut ApplicableDeclarations) {
|
fn match_node(&self,
|
||||||
|
stylist: &Stylist,
|
||||||
|
applicable_declarations: &mut ApplicableDeclarations) {
|
||||||
let style_attribute = self.with_element(|element| {
|
let style_attribute = self.with_element(|element| {
|
||||||
match *element.style_attribute() {
|
match *element.style_attribute() {
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -82,6 +245,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
||||||
layout_chan: &LayoutChan,
|
layout_chan: &LayoutChan,
|
||||||
applicable_declarations: &mut ApplicableDeclarations,
|
applicable_declarations: &mut ApplicableDeclarations,
|
||||||
initial_values: &ComputedValues,
|
initial_values: &ComputedValues,
|
||||||
|
applicable_declarations_cache: &mut ApplicableDeclarationsCache,
|
||||||
parent: Option<LayoutNode>) {
|
parent: Option<LayoutNode>) {
|
||||||
self.initialize_layout_data((*layout_chan).clone());
|
self.initialize_layout_data((*layout_chan).clone());
|
||||||
|
|
||||||
|
@ -90,7 +254,10 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.cascade_node(parent, initial_values, applicable_declarations)
|
self.cascade_node(parent,
|
||||||
|
initial_values,
|
||||||
|
applicable_declarations,
|
||||||
|
applicable_declarations_cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
applicable_declarations.clear();
|
applicable_declarations.clear();
|
||||||
|
@ -100,6 +267,7 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
||||||
layout_chan,
|
layout_chan,
|
||||||
applicable_declarations,
|
applicable_declarations,
|
||||||
initial_values,
|
initial_values,
|
||||||
|
applicable_declarations_cache,
|
||||||
Some(*self))
|
Some(*self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,65 +275,53 @@ impl<'ln> MatchMethods for LayoutNode<'ln> {
|
||||||
unsafe fn cascade_node(&self,
|
unsafe fn cascade_node(&self,
|
||||||
parent: Option<LayoutNode>,
|
parent: Option<LayoutNode>,
|
||||||
initial_values: &ComputedValues,
|
initial_values: &ComputedValues,
|
||||||
applicable_declarations: &ApplicableDeclarations) {
|
applicable_declarations: &ApplicableDeclarations,
|
||||||
macro_rules! cascade_node(
|
applicable_declarations_cache: &mut ApplicableDeclarationsCache) {
|
||||||
($applicable_declarations: expr, $style: ident) => {{
|
// Get our parent's style. This must be unsafe so that we don't touch the parent's
|
||||||
// Get our parent's style. This must be unsafe so that we don't touch the parent's
|
// borrow flags.
|
||||||
// borrow flags.
|
//
|
||||||
//
|
// FIXME(pcwalton): Isolate this unsafety into the `wrapper` module to allow
|
||||||
// FIXME(pcwalton): Isolate this unsafety into the `wrapper` module to allow
|
// enforced safe, race-free access to the parent style.
|
||||||
// enforced safe, race-free access to the parent style.
|
let parent_style = match parent {
|
||||||
let parent_style = match parent {
|
None => None,
|
||||||
None => None,
|
Some(parent_node) => {
|
||||||
Some(parent_node) => {
|
let parent_layout_data = parent_node.borrow_layout_data_unchecked();
|
||||||
let parent_layout_data = parent_node.borrow_layout_data_unchecked();
|
match *parent_layout_data {
|
||||||
match *parent_layout_data {
|
None => fail!("no parent data?!"),
|
||||||
None => fail!("no parent data?!"),
|
Some(ref parent_layout_data) => {
|
||||||
Some(ref parent_layout_data) => {
|
match parent_layout_data.data.style {
|
||||||
match parent_layout_data.data.style {
|
None => fail!("parent hasn't been styled yet?!"),
|
||||||
None => fail!("parent hasn't been styled yet?!"),
|
Some(ref style) => Some(style),
|
||||||
Some(ref style) => Some(style),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let computed_values = match parent_style {
|
|
||||||
Some(ref style) => {
|
|
||||||
Arc::new(cascade($applicable_declarations.as_slice(),
|
|
||||||
Some(style.get()),
|
|
||||||
initial_values))
|
|
||||||
}
|
|
||||||
None => Arc::new(cascade($applicable_declarations.as_slice(),
|
|
||||||
None,
|
|
||||||
initial_values)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut layout_data_ref = self.mutate_layout_data();
|
|
||||||
match *layout_data_ref.get() {
|
|
||||||
None => fail!("no layout data"),
|
|
||||||
Some(ref mut layout_data) => {
|
|
||||||
let style = &mut layout_data.data.$style;
|
|
||||||
match *style {
|
|
||||||
None => (),
|
|
||||||
Some(ref previous_style) => {
|
|
||||||
layout_data.data.restyle_damage = Some(incremental::compute_damage(
|
|
||||||
previous_style.get(), computed_values.get()).to_int())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*style = Some(computed_values)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
);
|
};
|
||||||
|
|
||||||
cascade_node!(applicable_declarations.normal, style);
|
let mut layout_data_ref = self.mutate_layout_data();
|
||||||
if applicable_declarations.before.len() > 0 {
|
match *layout_data_ref.get() {
|
||||||
cascade_node!(applicable_declarations.before, before_style);
|
None => fail!("no layout data"),
|
||||||
}
|
Some(ref mut layout_data) => {
|
||||||
if applicable_declarations.after.len() > 0 {
|
self.cascade_node_pseudo_element(parent_style,
|
||||||
cascade_node!(applicable_declarations.after, after_style);
|
applicable_declarations.normal.as_slice(),
|
||||||
|
&mut layout_data.data.style,
|
||||||
|
initial_values,
|
||||||
|
applicable_declarations_cache);
|
||||||
|
if applicable_declarations.before.len() > 0 {
|
||||||
|
self.cascade_node_pseudo_element(parent_style,
|
||||||
|
applicable_declarations.before.as_slice(),
|
||||||
|
&mut layout_data.data.before_style,
|
||||||
|
initial_values,
|
||||||
|
applicable_declarations_cache);
|
||||||
|
}
|
||||||
|
if applicable_declarations.after.len() > 0 {
|
||||||
|
self.cascade_node_pseudo_element(parent_style,
|
||||||
|
applicable_declarations.after.as_slice(),
|
||||||
|
&mut layout_data.data.after_style,
|
||||||
|
initial_values,
|
||||||
|
applicable_declarations_cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,28 +4,33 @@
|
||||||
|
|
||||||
//! Data needed by the layout task.
|
//! Data needed by the layout task.
|
||||||
|
|
||||||
use extra::arc::{Arc, MutexArc};
|
use css::matching::ApplicableDeclarationsCache;
|
||||||
use green::task::GreenTask;
|
|
||||||
use layout::flow::FlowLeafSet;
|
use layout::flow::FlowLeafSet;
|
||||||
use layout::util::OpaqueNode;
|
use layout::util::OpaqueNode;
|
||||||
use layout::wrapper::DomLeafSet;
|
use layout::wrapper::DomLeafSet;
|
||||||
|
|
||||||
|
use extra::arc::{Arc, MutexArc};
|
||||||
|
use geom::size::Size2D;
|
||||||
|
use gfx::font_context::{FontContext, FontContextInfo};
|
||||||
|
use green::task::GreenTask;
|
||||||
|
use script::layout_interface::LayoutChan;
|
||||||
|
use servo_msg::constellation_msg::ConstellationChan;
|
||||||
|
use servo_net::local_image_cache::LocalImageCache;
|
||||||
|
use servo_util::geometry::Au;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rt::Runtime;
|
use std::rt::Runtime;
|
||||||
use std::rt::local::Local;
|
use std::rt::local::Local;
|
||||||
use std::rt::task::Task;
|
use std::rt::task::Task;
|
||||||
|
|
||||||
use geom::size::Size2D;
|
|
||||||
use gfx::font_context::{FontContext, FontContextInfo};
|
|
||||||
use script::layout_interface::LayoutChan;
|
|
||||||
use servo_msg::constellation_msg::ConstellationChan;
|
|
||||||
use servo_net::local_image_cache::LocalImageCache;
|
|
||||||
use servo_util::geometry::Au;
|
|
||||||
use style::{ComputedValues, Stylist};
|
use style::{ComputedValues, Stylist};
|
||||||
|
|
||||||
#[thread_local]
|
#[thread_local]
|
||||||
static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext;
|
static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext;
|
||||||
|
|
||||||
|
#[thread_local]
|
||||||
|
static mut APPLICABLE_DECLARATIONS_CACHE: *mut ApplicableDeclarationsCache =
|
||||||
|
0 as *mut ApplicableDeclarationsCache;
|
||||||
|
|
||||||
/// Data shared by all layout workers.
|
/// Data shared by all layout workers.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct LayoutContext {
|
pub struct LayoutContext {
|
||||||
|
@ -82,5 +87,27 @@ impl LayoutContext {
|
||||||
cast::transmute(FONT_CONTEXT)
|
cast::transmute(FONT_CONTEXT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn applicable_declarations_cache<'a>(&'a self) -> &'a mut ApplicableDeclarationsCache {
|
||||||
|
// Sanity check.
|
||||||
|
{
|
||||||
|
let mut task = Local::borrow(None::<Task>);
|
||||||
|
match task.get().maybe_take_runtime::<GreenTask>() {
|
||||||
|
Some(green) => {
|
||||||
|
task.get().put_runtime(green as ~Runtime);
|
||||||
|
fail!("can't call this on a green task!")
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if APPLICABLE_DECLARATIONS_CACHE == ptr::mut_null() {
|
||||||
|
let cache = ~ApplicableDeclarationsCache::new();
|
||||||
|
APPLICABLE_DECLARATIONS_CACHE = cast::transmute(cache)
|
||||||
|
}
|
||||||
|
cast::transmute(APPLICABLE_DECLARATIONS_CACHE)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
|
//! The layout task. Performs layout on the DOM, builds display lists and sends them to be
|
||||||
/// rendered.
|
/// rendered.
|
||||||
|
|
||||||
use css::matching::{ApplicableDeclarations, MatchMethods};
|
use css::matching::{ApplicableDeclarations, ApplicableDeclarationsCache, MatchMethods};
|
||||||
use css::select::new_stylist;
|
use css::select::new_stylist;
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::construct::{FlowConstructionResult, FlowConstructor, NoConstructionResult};
|
use layout::construct::{FlowConstructionResult, FlowConstructor, NoConstructionResult};
|
||||||
|
@ -568,10 +568,13 @@ impl LayoutTask {
|
||||||
match self.parallel_traversal {
|
match self.parallel_traversal {
|
||||||
None => {
|
None => {
|
||||||
let mut applicable_declarations = ApplicableDeclarations::new();
|
let mut applicable_declarations = ApplicableDeclarations::new();
|
||||||
|
let mut applicable_declarations_cache =
|
||||||
|
ApplicableDeclarationsCache::new();
|
||||||
node.match_and_cascade_subtree(self.stylist,
|
node.match_and_cascade_subtree(self.stylist,
|
||||||
&layout_ctx.layout_chan,
|
&layout_ctx.layout_chan,
|
||||||
&mut applicable_declarations,
|
&mut applicable_declarations,
|
||||||
layout_ctx.initial_css_values.get(),
|
layout_ctx.initial_css_values.get(),
|
||||||
|
&mut applicable_declarations_cache,
|
||||||
None)
|
None)
|
||||||
}
|
}
|
||||||
Some(ref mut traversal) => {
|
Some(ref mut traversal) => {
|
||||||
|
|
|
@ -165,7 +165,8 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
|
||||||
};
|
};
|
||||||
node.cascade_node(parent_opt,
|
node.cascade_node(parent_opt,
|
||||||
layout_context.initial_css_values.get(),
|
layout_context.initial_css_values.get(),
|
||||||
&applicable_declarations);
|
&applicable_declarations,
|
||||||
|
layout_context.applicable_declarations_cache());
|
||||||
|
|
||||||
// Enqueue kids.
|
// Enqueue kids.
|
||||||
let mut child_count = 0;
|
let mut child_count = 0;
|
||||||
|
|
|
@ -130,10 +130,12 @@ impl ElementMapping {
|
||||||
/// Data that layout associates with a node.
|
/// Data that layout associates with a node.
|
||||||
pub struct PrivateLayoutData {
|
pub struct PrivateLayoutData {
|
||||||
/// The results of CSS styling for this node.
|
/// The results of CSS styling for this node.
|
||||||
before_style: Option<Arc<ComputedValues>>,
|
|
||||||
|
|
||||||
style: Option<Arc<ComputedValues>>,
|
style: Option<Arc<ComputedValues>>,
|
||||||
|
|
||||||
|
/// The results of CSS styling for this node's `before` pseudo-element, if any.
|
||||||
|
before_style: Option<Arc<ComputedValues>>,
|
||||||
|
|
||||||
|
/// The results of CSS styling for this node's `after` pseudo-element, if any.
|
||||||
after_style: Option<Arc<ComputedValues>>,
|
after_style: Option<Arc<ComputedValues>>,
|
||||||
|
|
||||||
/// Description of how to account for recent style changes.
|
/// Description of how to account for recent style changes.
|
||||||
|
|
|
@ -1152,6 +1152,82 @@ pub fn initial_values() -> ComputedValues {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fast path for the function below. Only computes new inherited styles.
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
fn cascade_with_cached_declarations(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
|
parent_style: &ComputedValues,
|
||||||
|
cached_style: &ComputedValues)
|
||||||
|
-> ComputedValues {
|
||||||
|
% for style_struct in STYLE_STRUCTS:
|
||||||
|
% if style_struct.inherited:
|
||||||
|
let mut style_${style_struct.name} = parent_style.${style_struct.name}.clone();
|
||||||
|
% else:
|
||||||
|
let mut style_${style_struct.name} = cached_style.${style_struct.name}.clone();
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
let mut context = computed::Context::new(&style_Color,
|
||||||
|
&style_Font,
|
||||||
|
&style_Box,
|
||||||
|
&style_Border,
|
||||||
|
false);
|
||||||
|
|
||||||
|
<%def name="apply_cached(priority)">
|
||||||
|
for sub_list in applicable_declarations.iter() {
|
||||||
|
for declaration in sub_list.get().iter() {
|
||||||
|
match declaration {
|
||||||
|
% for style_struct in STYLE_STRUCTS:
|
||||||
|
% if style_struct.inherited:
|
||||||
|
% for property in style_struct.longhands:
|
||||||
|
% if (property.needed_for_context and needed_for_context) or not \
|
||||||
|
needed_for_context:
|
||||||
|
&${property.ident}_declaration(SpecifiedValue(ref value)) => {
|
||||||
|
% if property.needed_for_context and needed_for_context:
|
||||||
|
context.set_${property.ident}(computed_value)
|
||||||
|
% elif not needed_for_context:
|
||||||
|
// Overwrite earlier declarations.
|
||||||
|
let computed_value =
|
||||||
|
longhands::${property.ident}::to_computed_value(
|
||||||
|
(*value).clone(),
|
||||||
|
&context);
|
||||||
|
style_${style_struct.name}.get_mut()
|
||||||
|
.${property.ident} =
|
||||||
|
computed_value
|
||||||
|
% endif
|
||||||
|
}
|
||||||
|
&${property.ident}_declaration(CSSWideKeyword(Initial)) => {
|
||||||
|
let computed_value =
|
||||||
|
longhands::${property.ident}::get_initial_value();
|
||||||
|
% if property.needed_for_context and needed_for_context:
|
||||||
|
context.set_${property.ident}(computed_value)
|
||||||
|
% elif not needed_for_context:
|
||||||
|
// Overwrite earlier declarations.
|
||||||
|
style_${style_struct.name}.get_mut()
|
||||||
|
.${property.ident} =
|
||||||
|
computed_value
|
||||||
|
% endif
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
${apply_cached(True)}
|
||||||
|
context.use_parent_font_size = false;
|
||||||
|
${apply_cached(False)}
|
||||||
|
|
||||||
|
ComputedValues {
|
||||||
|
% for style_struct in STYLE_STRUCTS:
|
||||||
|
${style_struct.name}: style_${style_struct.name},
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs the CSS cascade, computing new styles for an element from its parent style and
|
/// Performs the CSS cascade, computing new styles for an element from its parent style and
|
||||||
/// optionally a cached related style. The arguments are:
|
/// optionally a cached related style. The arguments are:
|
||||||
///
|
///
|
||||||
|
@ -1161,11 +1237,26 @@ pub fn initial_values() -> ComputedValues {
|
||||||
///
|
///
|
||||||
/// * `initial_values`: The initial set of CSS values as defined by the specification.
|
/// * `initial_values`: The initial set of CSS values as defined by the specification.
|
||||||
///
|
///
|
||||||
/// Returns the computed values.
|
/// * `cached_style`: If present, cascading is short-circuited for everything but inherited
|
||||||
|
/// values and these values are used instead. Obviously, you must be careful when supplying
|
||||||
|
/// this that it is safe to only provide inherited declarations. If `parent_style` is `None`,
|
||||||
|
/// this is ignored.
|
||||||
|
///
|
||||||
|
/// Returns the computed values and a boolean indicating whether the result is cacheable.
|
||||||
pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
parent_style: Option< &ComputedValues>,
|
parent_style: Option< &ComputedValues >,
|
||||||
initial_values: &ComputedValues)
|
initial_values: &ComputedValues,
|
||||||
-> ComputedValues {
|
cached_style: Option< &ComputedValues >)
|
||||||
|
-> (ComputedValues, bool) {
|
||||||
|
match (cached_style, parent_style) {
|
||||||
|
(Some(cached_style), Some(parent_style)) => {
|
||||||
|
return (cascade_with_cached_declarations(applicable_declarations,
|
||||||
|
parent_style,
|
||||||
|
cached_style), false)
|
||||||
|
}
|
||||||
|
(_, _) => {}
|
||||||
|
}
|
||||||
|
|
||||||
let is_root_element;
|
let is_root_element;
|
||||||
% for style_struct in STYLE_STRUCTS:
|
% for style_struct in STYLE_STRUCTS:
|
||||||
let mut style_${style_struct.name};
|
let mut style_${style_struct.name};
|
||||||
|
@ -1195,6 +1286,7 @@ pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
&style_Border,
|
&style_Border,
|
||||||
is_root_element);
|
is_root_element);
|
||||||
|
|
||||||
|
let mut cacheable = true;
|
||||||
<%def name="apply(needed_for_context)">
|
<%def name="apply(needed_for_context)">
|
||||||
for sub_list in applicable_declarations.iter() {
|
for sub_list in applicable_declarations.iter() {
|
||||||
for declaration in sub_list.get().iter() {
|
for declaration in sub_list.get().iter() {
|
||||||
|
@ -1231,6 +1323,7 @@ pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
% if not needed_for_context:
|
% if not needed_for_context:
|
||||||
&${property.ident}_declaration(CSSWideKeyword(Inherit)) => {
|
&${property.ident}_declaration(CSSWideKeyword(Inherit)) => {
|
||||||
// This is a bit slow, but this is rare so it shouldn't matter.
|
// This is a bit slow, but this is rare so it shouldn't matter.
|
||||||
|
cacheable = false;
|
||||||
match parent_style {
|
match parent_style {
|
||||||
None => {
|
None => {
|
||||||
style_${style_struct.name}.get_mut()
|
style_${style_struct.name}.get_mut()
|
||||||
|
@ -1262,11 +1355,11 @@ pub fn cascade(applicable_declarations: &[Arc<~[PropertyDeclaration]>],
|
||||||
context.use_parent_font_size = false;
|
context.use_parent_font_size = false;
|
||||||
${apply(False)}
|
${apply(False)}
|
||||||
|
|
||||||
ComputedValues {
|
(ComputedValues {
|
||||||
% for style_struct in STYLE_STRUCTS:
|
% for style_struct in STYLE_STRUCTS:
|
||||||
${style_struct.name}: style_${style_struct.name},
|
${style_struct.name}: style_${style_struct.name},
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}, cacheable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
|
use std::rand::Rng;
|
||||||
|
use std::rand;
|
||||||
|
use std::vec::VecIterator;
|
||||||
|
use std::vec;
|
||||||
|
|
||||||
pub trait Cache<K: Eq, V: Clone> {
|
pub trait Cache<K: Eq, V: Clone> {
|
||||||
fn insert(&mut self, key: K, value: V);
|
fn insert(&mut self, key: K, value: V);
|
||||||
|
@ -165,6 +169,73 @@ impl<K: Clone + Eq, V: Clone> Cache<K,V> for LRUCache<K,V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SimpleHashCache<K,V> {
|
||||||
|
entries: ~[Option<(K,V)>],
|
||||||
|
k0: u64,
|
||||||
|
k1: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K:Clone+Eq+Hash,V:Clone> SimpleHashCache<K,V> {
|
||||||
|
pub fn new(cache_size: uint) -> SimpleHashCache<K,V> {
|
||||||
|
let mut r = rand::task_rng();
|
||||||
|
SimpleHashCache {
|
||||||
|
entries: vec::from_elem(cache_size, None),
|
||||||
|
k0: r.gen(),
|
||||||
|
k1: r.gen(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_bucket(&self, h: uint) -> uint {
|
||||||
|
h % self.entries.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn bucket_for_key<Q:Hash>(&self, key: &Q) -> uint {
|
||||||
|
self.to_bucket(key.hash_keyed(self.k0, self.k1) as uint)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn find_equiv<'a,Q:Hash+Equiv<K>>(&'a self, key: &Q) -> Option<&'a V> {
|
||||||
|
let bucket_index = self.bucket_for_key(key);
|
||||||
|
match self.entries[bucket_index] {
|
||||||
|
Some((ref existing_key, ref value)) if key.equiv(existing_key) => Some(value),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K:Clone+Eq+Hash,V:Clone> Cache<K,V> for SimpleHashCache<K,V> {
|
||||||
|
fn insert(&mut self, key: K, value: V) {
|
||||||
|
let bucket_index = self.bucket_for_key(&key);
|
||||||
|
self.entries[bucket_index] = Some((key, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find(&mut self, key: &K) -> Option<V> {
|
||||||
|
let bucket_index = self.bucket_for_key(key);
|
||||||
|
match self.entries[bucket_index] {
|
||||||
|
Some((ref existing_key, ref value)) if existing_key == key => Some((*value).clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_or_create(&mut self, key: &K, blk: |&K| -> V) -> V {
|
||||||
|
match self.find(key) {
|
||||||
|
Some(value) => return value,
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
let value = blk(key);
|
||||||
|
self.insert((*key).clone(), value.clone());
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn evict_all(&mut self) {
|
||||||
|
for slot in self.entries.mut_iter() {
|
||||||
|
*slot = None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lru_cache() {
|
fn test_lru_cache() {
|
||||||
let one = @"one";
|
let one = @"one";
|
||||||
|
|
|
@ -324,6 +324,20 @@ macro_rules! def_small_vector_drop_impl(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
macro_rules! def_small_vector_clone_impl(
|
||||||
|
($name:ident) => (
|
||||||
|
impl<T:Clone> Clone for $name<T> {
|
||||||
|
fn clone(&self) -> $name<T> {
|
||||||
|
let mut new_vector = $name::new();
|
||||||
|
for element in self.iter() {
|
||||||
|
new_vector.push((*element).clone())
|
||||||
|
}
|
||||||
|
new_vector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
macro_rules! def_small_vector_impl(
|
macro_rules! def_small_vector_impl(
|
||||||
($name:ident, $size:expr) => (
|
($name:ident, $size:expr) => (
|
||||||
impl<T> $name<T> {
|
impl<T> $name<T> {
|
||||||
|
@ -396,47 +410,55 @@ impl<T> SmallVec0<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
def_small_vector_drop_impl!(SmallVec0, 0)
|
def_small_vector_drop_impl!(SmallVec0, 0)
|
||||||
|
def_small_vector_clone_impl!(SmallVec0)
|
||||||
|
|
||||||
def_small_vector!(SmallVec1, 1)
|
def_small_vector!(SmallVec1, 1)
|
||||||
def_small_vector_private_trait_impl!(SmallVec1, 1)
|
def_small_vector_private_trait_impl!(SmallVec1, 1)
|
||||||
def_small_vector_trait_impl!(SmallVec1, 1)
|
def_small_vector_trait_impl!(SmallVec1, 1)
|
||||||
def_small_vector_drop_impl!(SmallVec1, 1)
|
def_small_vector_drop_impl!(SmallVec1, 1)
|
||||||
|
def_small_vector_clone_impl!(SmallVec1)
|
||||||
def_small_vector_impl!(SmallVec1, 1)
|
def_small_vector_impl!(SmallVec1, 1)
|
||||||
|
|
||||||
def_small_vector!(SmallVec2, 2)
|
def_small_vector!(SmallVec2, 2)
|
||||||
def_small_vector_private_trait_impl!(SmallVec2, 2)
|
def_small_vector_private_trait_impl!(SmallVec2, 2)
|
||||||
def_small_vector_trait_impl!(SmallVec2, 2)
|
def_small_vector_trait_impl!(SmallVec2, 2)
|
||||||
def_small_vector_drop_impl!(SmallVec2, 2)
|
def_small_vector_drop_impl!(SmallVec2, 2)
|
||||||
|
def_small_vector_clone_impl!(SmallVec2)
|
||||||
def_small_vector_impl!(SmallVec2, 2)
|
def_small_vector_impl!(SmallVec2, 2)
|
||||||
|
|
||||||
def_small_vector!(SmallVec4, 4)
|
def_small_vector!(SmallVec4, 4)
|
||||||
def_small_vector_private_trait_impl!(SmallVec4, 4)
|
def_small_vector_private_trait_impl!(SmallVec4, 4)
|
||||||
def_small_vector_trait_impl!(SmallVec4, 4)
|
def_small_vector_trait_impl!(SmallVec4, 4)
|
||||||
def_small_vector_drop_impl!(SmallVec4, 4)
|
def_small_vector_drop_impl!(SmallVec4, 4)
|
||||||
|
def_small_vector_clone_impl!(SmallVec4)
|
||||||
def_small_vector_impl!(SmallVec4, 4)
|
def_small_vector_impl!(SmallVec4, 4)
|
||||||
|
|
||||||
def_small_vector!(SmallVec8, 8)
|
def_small_vector!(SmallVec8, 8)
|
||||||
def_small_vector_private_trait_impl!(SmallVec8, 8)
|
def_small_vector_private_trait_impl!(SmallVec8, 8)
|
||||||
def_small_vector_trait_impl!(SmallVec8, 8)
|
def_small_vector_trait_impl!(SmallVec8, 8)
|
||||||
def_small_vector_drop_impl!(SmallVec8, 8)
|
def_small_vector_drop_impl!(SmallVec8, 8)
|
||||||
|
def_small_vector_clone_impl!(SmallVec8)
|
||||||
def_small_vector_impl!(SmallVec8, 8)
|
def_small_vector_impl!(SmallVec8, 8)
|
||||||
|
|
||||||
def_small_vector!(SmallVec16, 16)
|
def_small_vector!(SmallVec16, 16)
|
||||||
def_small_vector_private_trait_impl!(SmallVec16, 16)
|
def_small_vector_private_trait_impl!(SmallVec16, 16)
|
||||||
def_small_vector_trait_impl!(SmallVec16, 16)
|
def_small_vector_trait_impl!(SmallVec16, 16)
|
||||||
def_small_vector_drop_impl!(SmallVec16, 16)
|
def_small_vector_drop_impl!(SmallVec16, 16)
|
||||||
|
def_small_vector_clone_impl!(SmallVec16)
|
||||||
def_small_vector_impl!(SmallVec16, 16)
|
def_small_vector_impl!(SmallVec16, 16)
|
||||||
|
|
||||||
def_small_vector!(SmallVec24, 24)
|
def_small_vector!(SmallVec24, 24)
|
||||||
def_small_vector_private_trait_impl!(SmallVec24, 24)
|
def_small_vector_private_trait_impl!(SmallVec24, 24)
|
||||||
def_small_vector_trait_impl!(SmallVec24, 24)
|
def_small_vector_trait_impl!(SmallVec24, 24)
|
||||||
def_small_vector_drop_impl!(SmallVec24, 24)
|
def_small_vector_drop_impl!(SmallVec24, 24)
|
||||||
|
def_small_vector_clone_impl!(SmallVec24)
|
||||||
def_small_vector_impl!(SmallVec24, 24)
|
def_small_vector_impl!(SmallVec24, 24)
|
||||||
|
|
||||||
def_small_vector!(SmallVec32, 32)
|
def_small_vector!(SmallVec32, 32)
|
||||||
def_small_vector_private_trait_impl!(SmallVec32, 32)
|
def_small_vector_private_trait_impl!(SmallVec32, 32)
|
||||||
def_small_vector_trait_impl!(SmallVec32, 32)
|
def_small_vector_trait_impl!(SmallVec32, 32)
|
||||||
def_small_vector_drop_impl!(SmallVec32, 32)
|
def_small_vector_drop_impl!(SmallVec32, 32)
|
||||||
|
def_small_vector_clone_impl!(SmallVec32)
|
||||||
def_small_vector_impl!(SmallVec32, 32)
|
def_small_vector_impl!(SmallVec32, 32)
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue