mirror of
https://github.com/servo/servo.git
synced 2025-06-19 22:59:03 +01:00
layout: Use the concurrent hash map for the leaf sets.
64% improvement in style recalc.
This commit is contained in:
parent
0dd37d9cd3
commit
a8e35fbeac
7 changed files with 47 additions and 52 deletions
|
@ -27,7 +27,7 @@ use std::cast;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::ApproxEq;
|
use std::cmp::ApproxEq;
|
||||||
use std::num::Zero;
|
use std::num::Zero;
|
||||||
use style::{ComputedValues, TElement, TNode, cascade};
|
use style::{ComputedValues, TElement, TNode};
|
||||||
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto, overflow, LPA_Auto};
|
use style::computed_values::{LengthOrPercentage, LengthOrPercentageOrAuto, overflow, LPA_Auto};
|
||||||
use style::computed_values::{border_style, clear, font_family, line_height};
|
use style::computed_values::{border_style, clear, font_family, line_height};
|
||||||
use style::computed_values::{text_align, text_decoration, vertical_align, visibility, white_space};
|
use style::computed_values::{text_align, text_decoration, vertical_align, visibility, white_space};
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub enum ConstructionResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstructionResult {
|
impl ConstructionResult {
|
||||||
fn destroy(&mut self, leaf_set: &mut FlowLeafSet) {
|
fn destroy(&mut self, leaf_set: &FlowLeafSet) {
|
||||||
match *self {
|
match *self {
|
||||||
NoConstructionResult => {}
|
NoConstructionResult => {}
|
||||||
FlowConstructionResult(ref mut flow) => flow.destroy(leaf_set),
|
FlowConstructionResult(ref mut flow) => flow.destroy(leaf_set),
|
||||||
|
@ -76,7 +76,7 @@ enum ConstructionItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstructionItem {
|
impl ConstructionItem {
|
||||||
fn destroy(&mut self, leaf_set: &mut FlowLeafSet) {
|
fn destroy(&mut self, leaf_set: &FlowLeafSet) {
|
||||||
match *self {
|
match *self {
|
||||||
InlineBoxesConstructionItem(ref mut result) => {
|
InlineBoxesConstructionItem(ref mut result) => {
|
||||||
for splits in result.splits.mut_iter() {
|
for splits in result.splits.mut_iter() {
|
||||||
|
@ -133,7 +133,7 @@ struct InlineBlockSplit {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineBlockSplit {
|
impl InlineBlockSplit {
|
||||||
fn destroy(&mut self, leaf_set: &mut FlowLeafSet) {
|
fn destroy(&mut self, leaf_set: &FlowLeafSet) {
|
||||||
self.flow.destroy(leaf_set)
|
self.flow.destroy(leaf_set)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ impl<'fc> FlowConstructor<'fc> {
|
||||||
|
|
||||||
let inline_base = BaseFlow::new(self.next_flow_id(), node);
|
let inline_base = BaseFlow::new(self.next_flow_id(), node);
|
||||||
let mut inline_flow = ~InlineFlow::from_boxes(inline_base, boxes) as ~Flow;
|
let mut inline_flow = ~InlineFlow::from_boxes(inline_base, boxes) as ~Flow;
|
||||||
self.layout_context.flow_leaf_set.access(|leaf_set| inline_flow.mark_as_leaf(leaf_set));
|
inline_flow.mark_as_leaf(self.layout_context.flow_leaf_set.get());
|
||||||
TextRunScanner::new().scan_for_runs(self.font_context, inline_flow);
|
TextRunScanner::new().scan_for_runs(self.font_context, inline_flow);
|
||||||
|
|
||||||
flow.add_new_child(inline_flow)
|
flow.add_new_child(inline_flow)
|
||||||
|
@ -380,7 +380,7 @@ impl<'fc> FlowConstructor<'fc> {
|
||||||
|
|
||||||
// The flow is done. If it ended up with no kids, add the flow to the leaf set.
|
// The flow is done. If it ended up with no kids, add the flow to the leaf set.
|
||||||
if flow.child_count() == 0 {
|
if flow.child_count() == 0 {
|
||||||
self.layout_context.flow_leaf_set.access(|leaf_set| flow.mark_as_leaf(leaf_set))
|
flow.mark_as_leaf(self.layout_context.flow_leaf_set.get())
|
||||||
} else {
|
} else {
|
||||||
flow.mark_as_nonleaf()
|
flow.mark_as_nonleaf()
|
||||||
}
|
}
|
||||||
|
@ -619,12 +619,10 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
|
||||||
// `display: none` contributes no flow construction result. Nuke the flow construction
|
// `display: none` contributes no flow construction result. Nuke the flow construction
|
||||||
// results of children.
|
// results of children.
|
||||||
(display::none, _, _) => {
|
(display::none, _, _) => {
|
||||||
self.layout_context.flow_leaf_set.access(|leaf_set| {
|
|
||||||
for child in node.children() {
|
for child in node.children() {
|
||||||
let mut old_result = child.swap_out_construction_result();
|
let mut old_result = child.swap_out_construction_result();
|
||||||
old_result.destroy(leaf_set)
|
old_result.destroy(self.layout_context.flow_leaf_set.get())
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline items contribute inline box construction results.
|
// Inline items contribute inline box construction results.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! Data needed by the layout task.
|
//! Data needed by the layout task.
|
||||||
|
|
||||||
use extra::arc::MutexArc;
|
use extra::arc::{Arc, MutexArc};
|
||||||
use green::task::GreenTask;
|
use green::task::GreenTask;
|
||||||
use layout::flow::FlowLeafSet;
|
use layout::flow::FlowLeafSet;
|
||||||
use layout::util::OpaqueNode;
|
use layout::util::OpaqueNode;
|
||||||
|
@ -39,13 +39,13 @@ pub struct LayoutContext {
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
|
|
||||||
/// The set of leaf DOM nodes.
|
/// The set of leaf DOM nodes.
|
||||||
dom_leaf_set: MutexArc<DomLeafSet>,
|
dom_leaf_set: Arc<DomLeafSet>,
|
||||||
|
|
||||||
/// A channel up to the layout task.
|
/// A channel up to the layout task.
|
||||||
layout_chan: LayoutChan,
|
layout_chan: LayoutChan,
|
||||||
|
|
||||||
/// The set of leaf flows.
|
/// The set of leaf flows.
|
||||||
flow_leaf_set: MutexArc<FlowLeafSet>,
|
flow_leaf_set: Arc<FlowLeafSet>,
|
||||||
|
|
||||||
/// Information needed to construct a font context.
|
/// Information needed to construct a font context.
|
||||||
font_context_info: FontContextInfo,
|
font_context_info: FontContextInfo,
|
||||||
|
|
|
@ -44,10 +44,10 @@ use geom::rect::Rect;
|
||||||
use gfx::display_list::{ClipDisplayItemClass, DisplayList};
|
use gfx::display_list::{ClipDisplayItemClass, DisplayList};
|
||||||
use layout::display_list_builder::ToGfxColor;
|
use layout::display_list_builder::ToGfxColor;
|
||||||
use gfx::color::Color;
|
use gfx::color::Color;
|
||||||
|
use servo_util::concurrentmap::{ConcurrentHashMap, ConcurrentHashMapIterator};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::hashmap::{HashSet, HashSetIterator};
|
|
||||||
use std::sync::atomics::Relaxed;
|
use std::sync::atomics::Relaxed;
|
||||||
use style::ComputedValues;
|
use style::ComputedValues;
|
||||||
use style::computed_values::text_align;
|
use style::computed_values::text_align;
|
||||||
|
@ -216,13 +216,13 @@ pub trait MutableOwnedFlowUtils {
|
||||||
|
|
||||||
/// Marks the flow as a leaf. The flow must not have children and must not be marked as a
|
/// Marks the flow as a leaf. The flow must not have children and must not be marked as a
|
||||||
/// nonleaf.
|
/// nonleaf.
|
||||||
fn mark_as_leaf(&mut self, leaf_set: &mut FlowLeafSet);
|
fn mark_as_leaf(&mut self, leaf_set: &FlowLeafSet);
|
||||||
|
|
||||||
/// Marks the flow as a nonleaf. The flow must not be marked as a leaf.
|
/// Marks the flow as a nonleaf. The flow must not be marked as a leaf.
|
||||||
fn mark_as_nonleaf(&mut self);
|
fn mark_as_nonleaf(&mut self);
|
||||||
|
|
||||||
/// Destroys the flow.
|
/// Destroys the flow.
|
||||||
fn destroy(&mut self, leaf_set: &mut FlowLeafSet);
|
fn destroy(&mut self, leaf_set: &FlowLeafSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FlowClass {
|
pub enum FlowClass {
|
||||||
|
@ -756,7 +756,7 @@ impl MutableOwnedFlowUtils for ~Flow {
|
||||||
|
|
||||||
/// Marks the flow as a leaf. The flow must not have children and must not be marked as a
|
/// Marks the flow as a leaf. The flow must not have children and must not be marked as a
|
||||||
/// nonleaf.
|
/// nonleaf.
|
||||||
fn mark_as_leaf(&mut self, leaf_set: &mut FlowLeafSet) {
|
fn mark_as_leaf(&mut self, leaf_set: &FlowLeafSet) {
|
||||||
{
|
{
|
||||||
let base = mut_base(*self);
|
let base = mut_base(*self);
|
||||||
if base.flags_info.flags.is_nonleaf() {
|
if base.flags_info.flags.is_nonleaf() {
|
||||||
|
@ -781,7 +781,7 @@ impl MutableOwnedFlowUtils for ~Flow {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destroys the flow.
|
/// Destroys the flow.
|
||||||
fn destroy(&mut self, leaf_set: &mut FlowLeafSet) {
|
fn destroy(&mut self, leaf_set: &FlowLeafSet) {
|
||||||
let is_leaf = {
|
let is_leaf = {
|
||||||
let base = mut_base(*self);
|
let base = mut_base(*self);
|
||||||
base.children.len() == 0
|
base.children.len() == 0
|
||||||
|
@ -802,27 +802,26 @@ impl MutableOwnedFlowUtils for ~Flow {
|
||||||
|
|
||||||
/// Keeps track of the leaves of the flow tree. This is used to efficiently start bottom-up
|
/// Keeps track of the leaves of the flow tree. This is used to efficiently start bottom-up
|
||||||
/// parallel traversals.
|
/// parallel traversals.
|
||||||
#[deriving(Clone)]
|
|
||||||
pub struct FlowLeafSet {
|
pub struct FlowLeafSet {
|
||||||
priv set: HashSet<UnsafeFlow>,
|
priv set: ConcurrentHashMap<UnsafeFlow,()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowLeafSet {
|
impl FlowLeafSet {
|
||||||
/// Creates a new flow leaf set.
|
/// Creates a new flow leaf set.
|
||||||
pub fn new() -> FlowLeafSet {
|
pub fn new() -> FlowLeafSet {
|
||||||
FlowLeafSet {
|
FlowLeafSet {
|
||||||
set: HashSet::new(),
|
set: ConcurrentHashMap::with_locks_and_buckets(64, 256),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a newly-created flow into the leaf set.
|
/// Inserts a newly-created flow into the leaf set.
|
||||||
fn insert(&mut self, flow: &~Flow) {
|
fn insert(&self, flow: &~Flow) {
|
||||||
self.set.insert(parallel::owned_flow_to_unsafe_flow(flow));
|
self.set.insert(parallel::owned_flow_to_unsafe_flow(flow), ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a flow from the leaf set. Asserts that the flow was indeed in the leaf set. (This
|
/// Removes a flow from the leaf set. Asserts that the flow was indeed in the leaf set. (This
|
||||||
/// invariant is needed for memory safety, as there must always be exactly one leaf set.)
|
/// invariant is needed for memory safety, as there must always be exactly one leaf set.)
|
||||||
fn remove(&mut self, flow: &~Flow) {
|
fn remove(&self, flow: &~Flow) {
|
||||||
if !self.contains(flow) {
|
if !self.contains(flow) {
|
||||||
fail!("attempted to remove a flow from the leaf set that wasn't in the set!")
|
fail!("attempted to remove a flow from the leaf set that wasn't in the set!")
|
||||||
}
|
}
|
||||||
|
@ -830,16 +829,16 @@ impl FlowLeafSet {
|
||||||
self.set.remove(&flow);
|
self.set.remove(&flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains(&mut self, flow: &~Flow) -> bool {
|
pub fn contains(&self, flow: &~Flow) -> bool {
|
||||||
let flow = parallel::owned_flow_to_unsafe_flow(flow);
|
let flow = parallel::owned_flow_to_unsafe_flow(flow);
|
||||||
self.set.contains(&flow)
|
self.set.contains_key(&flow)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&self) {
|
||||||
self.set.clear()
|
self.set.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter<'a>(&'a self) -> HashSetIterator<'a,UnsafeFlow> {
|
pub fn iter<'a>(&'a self) -> ConcurrentHashMapIterator<'a,UnsafeFlow,()> {
|
||||||
self.set.iter()
|
self.set.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,10 +83,10 @@ pub struct LayoutTask {
|
||||||
local_image_cache: MutexArc<LocalImageCache>,
|
local_image_cache: MutexArc<LocalImageCache>,
|
||||||
|
|
||||||
/// The set of leaves in the DOM tree.
|
/// The set of leaves in the DOM tree.
|
||||||
dom_leaf_set: MutexArc<DomLeafSet>,
|
dom_leaf_set: Arc<DomLeafSet>,
|
||||||
|
|
||||||
/// The set of leaves in the flow tree.
|
/// The set of leaves in the flow tree.
|
||||||
flow_leaf_set: MutexArc<FlowLeafSet>,
|
flow_leaf_set: Arc<FlowLeafSet>,
|
||||||
|
|
||||||
/// The size of the viewport.
|
/// The size of the viewport.
|
||||||
screen_size: Size2D<Au>,
|
screen_size: Size2D<Au>,
|
||||||
|
@ -292,8 +292,8 @@ impl LayoutTask {
|
||||||
image_cache_task: image_cache_task.clone(),
|
image_cache_task: image_cache_task.clone(),
|
||||||
local_image_cache: local_image_cache,
|
local_image_cache: local_image_cache,
|
||||||
screen_size: screen_size,
|
screen_size: screen_size,
|
||||||
dom_leaf_set: MutexArc::new(DomLeafSet::new()),
|
dom_leaf_set: Arc::new(DomLeafSet::new()),
|
||||||
flow_leaf_set: MutexArc::new(FlowLeafSet::new()),
|
flow_leaf_set: Arc::new(FlowLeafSet::new()),
|
||||||
|
|
||||||
display_list: None,
|
display_list: None,
|
||||||
stylist: ~new_stylist(),
|
stylist: ~new_stylist(),
|
||||||
|
@ -666,7 +666,7 @@ impl LayoutTask {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.flow_leaf_set.access(|leaf_set| layout_root.destroy(leaf_set));
|
layout_root.destroy(self.flow_leaf_set.get());
|
||||||
|
|
||||||
// Tell script that we're done.
|
// Tell script that we're done.
|
||||||
//
|
//
|
||||||
|
|
|
@ -15,7 +15,7 @@ use layout::layout_task::{AssignHeightsAndStoreOverflowTraversal, BubbleWidthsTr
|
||||||
use layout::util::{LayoutDataAccess, OpaqueNode};
|
use layout::util::{LayoutDataAccess, OpaqueNode};
|
||||||
use layout::wrapper::{layout_node_to_unsafe_layout_node, LayoutNode, UnsafeLayoutNode};
|
use layout::wrapper::{layout_node_to_unsafe_layout_node, LayoutNode, UnsafeLayoutNode};
|
||||||
|
|
||||||
use extra::arc::MutexArc;
|
use extra::arc::Arc;
|
||||||
use servo_util::time::{ProfilerChan, profile};
|
use servo_util::time::{ProfilerChan, profile};
|
||||||
use servo_util::time;
|
use servo_util::time;
|
||||||
use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
|
use servo_util::workqueue::{WorkQueue, WorkUnit, WorkerProxy};
|
||||||
|
@ -167,7 +167,7 @@ fn match_and_cascade_node(unsafe_layout_node: UnsafeLayoutNode,
|
||||||
if child_count == 0 {
|
if child_count == 0 {
|
||||||
// We don't need set the `child_count` field here since that's only used by kids during
|
// We don't need set the `child_count` field here since that's only used by kids during
|
||||||
// bottom-up traversals, and since this node is a leaf it has no kids.
|
// bottom-up traversals, and since this node is a leaf it has no kids.
|
||||||
layout_context.dom_leaf_set.access(|dom_leaf_set| dom_leaf_set.insert(&node));
|
layout_context.dom_leaf_set.get().insert(&node);
|
||||||
} else {
|
} else {
|
||||||
let mut layout_data_ref = node.mutate_layout_data();
|
let mut layout_data_ref = node.mutate_layout_data();
|
||||||
match *layout_data_ref.get() {
|
match *layout_data_ref.get() {
|
||||||
|
@ -220,7 +220,7 @@ pub fn match_and_cascade_subtree(root_node: &LayoutNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn traverse_flow_tree(kind: TraversalKind,
|
pub fn traverse_flow_tree(kind: TraversalKind,
|
||||||
leaf_set: &MutexArc<FlowLeafSet>,
|
leaf_set: &Arc<FlowLeafSet>,
|
||||||
profiler_chan: ProfilerChan,
|
profiler_chan: ProfilerChan,
|
||||||
layout_context: &mut LayoutContext,
|
layout_context: &mut LayoutContext,
|
||||||
queue: &mut WorkQueue<*mut LayoutContext,UnsafeFlow>) {
|
queue: &mut WorkQueue<*mut LayoutContext,UnsafeFlow>) {
|
||||||
|
@ -234,14 +234,12 @@ pub fn traverse_flow_tree(kind: TraversalKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
profile(time::LayoutParallelWarmupCategory, profiler_chan, || {
|
profile(time::LayoutParallelWarmupCategory, profiler_chan, || {
|
||||||
leaf_set.access(|leaf_set| {
|
for (flow, _) in leaf_set.get().iter() {
|
||||||
for &flow in leaf_set.iter() {
|
|
||||||
queue.push(WorkUnit {
|
queue.push(WorkUnit {
|
||||||
fun: fun,
|
fun: fun,
|
||||||
data: flow,
|
data: *flow,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
queue.run();
|
queue.run();
|
||||||
|
|
|
@ -22,10 +22,10 @@ use script::dom::htmlimageelement::HTMLImageElement;
|
||||||
use script::dom::node::{AbstractNode, DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId};
|
use script::dom::node::{AbstractNode, DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId};
|
||||||
use script::dom::text::Text;
|
use script::dom::text::Text;
|
||||||
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{PipelineId, SubpageId};
|
||||||
|
use servo_util::concurrentmap::{ConcurrentHashMap, ConcurrentHashMapIterator};
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
use servo_util::namespace::Namespace;
|
use servo_util::namespace::Namespace;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::hashmap::{HashMap, HashMapIterator};
|
|
||||||
use style::{PropertyDeclarationBlock, TElement, TNode, AttrSelector};
|
use style::{PropertyDeclarationBlock, TElement, TNode, AttrSelector};
|
||||||
|
|
||||||
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
|
||||||
|
@ -439,29 +439,29 @@ pub fn layout_node_to_unsafe_layout_node(node: &LayoutNode) -> UnsafeLayoutNode
|
||||||
|
|
||||||
/// Keeps track of the leaves of the DOM. This is used to efficiently start bottom-up traversals.
|
/// Keeps track of the leaves of the DOM. This is used to efficiently start bottom-up traversals.
|
||||||
pub struct DomLeafSet {
|
pub struct DomLeafSet {
|
||||||
priv set: HashMap<UnsafeLayoutNode,()>,
|
priv set: ConcurrentHashMap<UnsafeLayoutNode,()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DomLeafSet {
|
impl DomLeafSet {
|
||||||
/// Creates a new DOM leaf set.
|
/// Creates a new DOM leaf set.
|
||||||
pub fn new() -> DomLeafSet {
|
pub fn new() -> DomLeafSet {
|
||||||
DomLeafSet {
|
DomLeafSet {
|
||||||
set: HashMap::new(),
|
set: ConcurrentHashMap::with_locks_and_buckets(64, 256),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a DOM node into the leaf set.
|
/// Inserts a DOM node into the leaf set.
|
||||||
pub fn insert(&mut self, node: &LayoutNode) {
|
pub fn insert(&self, node: &LayoutNode) {
|
||||||
self.set.insert(layout_node_to_unsafe_layout_node(node), ());
|
self.set.insert(layout_node_to_unsafe_layout_node(node), ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all DOM nodes from the set.
|
/// Removes all DOM nodes from the set.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&self) {
|
||||||
self.set.clear()
|
self.set.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the DOM nodes in the leaf set.
|
/// Iterates over the DOM nodes in the leaf set.
|
||||||
pub fn iter<'a>(&'a self) -> HashMapIterator<'a,UnsafeLayoutNode,()> {
|
pub fn iter<'a>(&'a self) -> ConcurrentHashMapIterator<'a,UnsafeLayoutNode,()> {
|
||||||
self.set.iter()
|
self.set.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue