From 7368d42225b94f3ac821058800350d7c541f1a3f Mon Sep 17 00:00:00 2001 From: Clark Gaebel Date: Mon, 13 Oct 2014 00:07:03 -0400 Subject: [PATCH] Removes duplicate CSS selector matching logic. Now that DOM/Flow traversals have been refactored out, the `recalc_style_for_subtree` function in `css/matching.rs` can be removed, in lieu of just running the standard `recalc_style_for_node` and `construct_flows` traversals sequentially. Now we no longer have the maintenance headache of duplicating selector matching logic in two places! \o/ r? @pcwalton --- components/layout/block.rs | 36 ++------ components/layout/css/matching.rs | 74 +---------------- components/layout/flow.rs | 62 ++++---------- components/layout/layout_task.rs | 76 +++++------------ components/layout/lib.rs | 1 + components/layout/parallel.rs | 131 ++++++++++++------------------ components/layout/sequential.rs | 89 ++++++++++++++++++++ components/layout/traversal.rs | 44 ++++------ 8 files changed, 201 insertions(+), 312 deletions(-) create mode 100644 components/layout/sequential.rs diff --git a/components/layout/block.rs b/components/layout/block.rs index d5352d622dc..62c40da0672 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -431,18 +431,17 @@ struct AbsoluteAssignBSizesTraversal<'a>(&'a LayoutContext<'a>); impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> { #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { + fn process(&self, flow: &mut Flow) { let block_flow = flow.as_block(); // The root of the absolute flow tree is definitely not absolutely // positioned. Nothing to process here. if block_flow.is_root_of_absolute_flow_tree() { - return true; + return; } let AbsoluteAssignBSizesTraversal(ref ctx) = *self; block_flow.calculate_abs_block_size_and_margins(*ctx); - true } } @@ -458,14 +457,13 @@ struct AbsoluteStoreOverflowTraversal<'a>{ impl<'a> PostorderFlowTraversal for AbsoluteStoreOverflowTraversal<'a> { #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { + fn process(&self, flow: &mut Flow) { // This will be taken care of by the normal store-overflow traversal. if flow.is_root_of_absolute_flow_tree() { - return true; + return; } flow.store_overflow(self.layout_context); - true } } @@ -711,16 +709,10 @@ impl BlockFlow { /// /// Return true if the traversal is to continue or false to stop. fn traverse_preorder_absolute_flows(&mut self, - traversal: &mut T) - -> bool { + traversal: &mut T) { let flow = self as &mut Flow; - if traversal.should_prune(flow) { - return true - } - if !traversal.process(flow) { - return false - } + traversal.process(flow); let cb_block_start_edge_offset = flow.generated_containing_block_rect().start.b; let mut descendant_offset_iter = mut_base(flow).abs_descendants.iter_with_offset(); @@ -730,30 +722,20 @@ impl BlockFlow { // The stored y_offset is wrt to the flow box. // Translate it to the CB (which is the padding box). block.static_b_offset = **y_offset - cb_block_start_edge_offset; - if !block.traverse_preorder_absolute_flows(traversal) { - return false - } + block.traverse_preorder_absolute_flows(traversal); } - - true } /// Traverse the Absolute flow tree in postorder. /// /// Return true if the traversal is to continue or false to stop. fn traverse_postorder_absolute_flows(&mut self, - traversal: &mut T) - -> bool { + traversal: &mut T) { let flow = self as &mut Flow; - if traversal.should_prune(flow) { - return true - } for descendant_link in mut_base(flow).abs_descendants.iter() { let block = descendant_link.as_block(); - if !block.traverse_postorder_absolute_flows(traversal) { - return false - } + block.traverse_postorder_absolute_flows(traversal); } traversal.process(flow) diff --git a/components/layout/css/matching.rs b/components/layout/css/matching.rs index d3ea0b48b7f..7783c04aa0a 100644 --- a/components/layout/css/matching.rs +++ b/components/layout/css/matching.rs @@ -5,10 +5,8 @@ // High-level interface to CSS selector matching. use css::node_style::StyledNode; -use construct::FlowConstructor; -use context::LayoutContext; use util::{LayoutDataAccess, LayoutDataWrapper}; -use wrapper::{LayoutElement, LayoutNode, PostorderNodeMutTraversal, ThreadSafeLayoutNode}; +use wrapper::{LayoutElement, LayoutNode}; use wrapper::{TLayoutNode}; use script::dom::node::{TextNodeTypeId}; @@ -295,15 +293,6 @@ pub trait MatchMethods { /// called to reset the bloom filter after an `insert`. fn remove_from_bloom_filter(&self, bf: &mut BloomFilter); - /// Performs aux initialization, selector matching, cascading, and flow construction - /// sequentially. - fn recalc_style_for_subtree(&self, - stylist: &Stylist, - layout_context: &LayoutContext, - parent_bf: &mut Option>, - applicable_declarations: &mut ApplicableDeclarations, - parent: Option); - fn match_node(&self, stylist: &Stylist, parent_bf: &Option>, @@ -524,67 +513,6 @@ impl<'ln> MatchMethods for LayoutNode<'ln> { element.each_class(|class| bf.remove(class)); } - fn recalc_style_for_subtree(&self, - stylist: &Stylist, - layout_context: &LayoutContext, - parent_bf: &mut Option>, - applicable_declarations: &mut ApplicableDeclarations, - parent: Option) { - self.initialize_layout_data(layout_context.shared.layout_chan.clone()); - - // First, check to see whether we can share a style with someone. - let sharing_result = unsafe { - self.share_style_if_possible(layout_context.style_sharing_candidate_cache(), - parent.clone()) - }; - - // Otherwise, match and cascade selectors. - match sharing_result { - CannotShare(mut shareable) => { - if self.is_element() { - self.match_node(stylist, &*parent_bf, applicable_declarations, &mut shareable); - } - - unsafe { - self.cascade_node(parent, - applicable_declarations, - layout_context.applicable_declarations_cache()) - } - - applicable_declarations.clear(); - - // Add ourselves to the LRU cache. - if shareable { - layout_context.style_sharing_candidate_cache().insert_if_possible(self) - } - } - StyleWasShared(index) => layout_context.style_sharing_candidate_cache().touch(index), - } - - match *parent_bf { - None => {}, - Some(ref mut pbf) => self.insert_into_bloom_filter(&mut **pbf), - } - - for kid in self.children() { - kid.recalc_style_for_subtree(stylist, - layout_context, - parent_bf, - applicable_declarations, - Some(self.clone())); - } - - match *parent_bf { - None => {}, - Some(ref mut pbf) => self.remove_from_bloom_filter(&mut **pbf), - } - - // Construct flows. - let layout_node = ThreadSafeLayoutNode::new(self); - let mut flow_constructor = FlowConstructor::new(layout_context); - flow_constructor.process(&layout_node); - } - unsafe fn cascade_node(&self, parent: Option, applicable_declarations: &ApplicableDeclarations, diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 5aca4c11bb3..25984fe70ff 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -411,10 +411,10 @@ pub trait MutableFlowUtils { // Traversals /// Traverses the tree in preorder. - fn traverse_preorder(self, traversal: &mut T) -> bool; + fn traverse_preorder(self, traversal: &T); /// Traverses the tree in postorder. - fn traverse_postorder(self, traversal: &mut T) -> bool; + fn traverse_postorder(self, traversal: &T); // Mutators @@ -464,41 +464,27 @@ pub enum FlowClass { /// A top-down traversal. pub trait PreorderFlowTraversal { /// The operation to perform. Return true to continue or false to stop. - fn process(&mut self, flow: &mut Flow) -> bool; + fn process(&self, flow: &mut Flow); /// Returns true if this node must be processed in-order. If this returns false, /// we skip the operation for this node, but continue processing the descendants. /// This is called *after* parent nodes are visited. - fn should_process(&mut self, _flow: &mut Flow) -> bool { + fn should_process(&self, _flow: &mut Flow) -> bool { true } - - /// Returns true if this node should be pruned. If this returns true, we skip the operation - /// entirely and do not process any descendant nodes. This is called *before* child nodes are - /// visited. The default implementation never prunes any nodes. - fn should_prune(&mut self, _flow: &mut Flow) -> bool { - false - } } /// A bottom-up traversal, with a optional in-order pass. pub trait PostorderFlowTraversal { /// The operation to perform. Return true to continue or false to stop. - fn process(&mut self, flow: &mut Flow) -> bool; + fn process(&self, flow: &mut Flow); /// Returns false if this node must be processed in-order. If this returns false, we skip the /// operation for this node, but continue processing the ancestors. This is called *after* /// child nodes are visited. - fn should_process(&mut self, _flow: &mut Flow) -> bool { + fn should_process(&self, _flow: &mut Flow) -> bool { true } - - /// Returns true if this node should be pruned. If this returns true, we skip the operation - /// entirely and do not process any descendant nodes. This is called *before* child nodes are - /// visited. The default implementation never prunes any nodes. - fn should_prune(&mut self, _flow: &mut Flow) -> bool { - false - } } /// Flags used in flows, tightly packed to save space. @@ -1043,45 +1029,25 @@ impl<'a> ImmutableFlowUtils for &'a Flow + 'a { impl<'a> MutableFlowUtils for &'a mut Flow + 'a { /// Traverses the tree in preorder. - fn traverse_preorder(self, traversal: &mut T) -> bool { - if traversal.should_prune(self) { - return true - } - - if !traversal.should_process(self) { - return true - } - - if !traversal.process(self) { - return false + fn traverse_preorder(self, traversal: &T) { + if traversal.should_process(self) { + traversal.process(self); } for kid in child_iter(self) { - if !kid.traverse_preorder(traversal) { - return false - } + kid.traverse_preorder(traversal); } - - true } /// Traverses the tree in postorder. - fn traverse_postorder(self, traversal: &mut T) -> bool { - if traversal.should_prune(self) { - return true - } - + fn traverse_postorder(self, traversal: &T) { for kid in child_iter(self) { - if !kid.traverse_postorder(traversal) { - return false - } + kid.traverse_postorder(traversal); } - if !traversal.should_process(self) { - return true + if traversal.should_process(self) { + traversal.process(self) } - - traversal.process(self) } /// Calculate and set overflow for current flow. diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 2ff6d921490..598afa0aa9b 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -5,18 +5,16 @@ //! The layout task. Performs layout on the DOM, builds display lists and sends them to be //! rendered. -use css::matching::{ApplicableDeclarations, MatchMethods}; use css::node_style::StyledNode; use construct::FlowConstructionResult; use context::{LayoutContext, SharedLayoutContext}; use flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; -use flow::{PreorderFlowTraversal, PostorderFlowTraversal}; use flow; use flow_ref::FlowRef; use layout_debug; use parallel::UnsafeFlow; use parallel; -use traversal; +use sequential; use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor}; use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode}; @@ -48,7 +46,6 @@ use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, Failu use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg}; use gfx::font_cache_task::{FontCacheTask}; use servo_net::local_image_cache::{ImageResponder, LocalImageCache}; -use servo_util::bloom::BloomFilter; use servo_net::resource_task::{ResourceTask, load_bytes_iter}; use servo_util::geometry::Au; use servo_util::geometry; @@ -508,31 +505,10 @@ impl LayoutTask { /// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling. #[inline(never)] fn solve_constraints<'a>(&self, - layout_root: &mut Flow, - layout_context: &'a LayoutContext<'a>) { + layout_root: &mut FlowRef, + shared_layout_context: &SharedLayoutContext) { let _scope = layout_debug_scope!("solve_constraints"); - - if layout_context.shared.opts.bubble_inline_sizes_separately { - let mut traversal = traversal::BubbleISizes { - layout_context: layout_context, - }; - layout_root.traverse_postorder(&mut traversal); - } - - // FIXME(pcwalton): Prune these two passes. - { - let mut traversal = traversal::AssignISizes { - layout_context: layout_context, - }; - layout_root.traverse_preorder(&mut traversal); - } - - { - let mut traversal = traversal::AssignBSizesAndStoreOverflow { - layout_context: layout_context, - }; - layout_root.traverse_postorder(&mut traversal); - } + sequential::traverse_flow_tree_preorder(layout_root, shared_layout_context); } /// Performs layout constraint solving in parallel. @@ -545,12 +521,7 @@ impl LayoutTask { rw_data: &mut LayoutTaskData, layout_root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) { - if shared_layout_context.opts.bubble_inline_sizes_separately { - let mut traversal = traversal::BubbleISizes { - layout_context: &LayoutContext::new(shared_layout_context), - }; - layout_root.get_mut().traverse_postorder(&mut traversal); - } + let _scope = layout_debug_scope!("solve_constraints_parallel"); match rw_data.parallel_traversal { None => fail!("solve_contraints_parallel() called with no parallel traversal ready"), @@ -642,17 +613,10 @@ impl LayoutTask { let rw_data = rw_data.deref_mut(); match rw_data.parallel_traversal { None => { - let layout_ctx = LayoutContext::new(&shared_layout_ctx); - let mut applicable_declarations = ApplicableDeclarations::new(); - let mut parent_bf = Some(box BloomFilter::new()); - node.recalc_style_for_subtree(&*rw_data.stylist, - &layout_ctx, - &mut parent_bf, - &mut applicable_declarations, - None) + sequential::traverse_dom_preorder(*node, &shared_layout_ctx); } Some(ref mut traversal) => { - parallel::traverse_dom_preorder(*node, &mut shared_layout_ctx, traversal) + parallel::traverse_dom_preorder(*node, &shared_layout_ctx, traversal) } } @@ -695,8 +659,7 @@ impl LayoutTask { match rw_data.parallel_traversal { None => { // Sequential mode. - let layout_ctx = LayoutContext::new(&shared_layout_ctx); - self.solve_constraints(layout_root.get_mut(), &layout_ctx) + self.solve_constraints(&mut layout_root, &shared_layout_ctx) } Some(_) => { // Parallel mode. @@ -717,20 +680,19 @@ impl LayoutTask { let rw_data = rw_data.deref_mut(); match rw_data.parallel_traversal { None => { - let layout_ctx = LayoutContext::new(&shared_layout_ctx); - let mut traversal = traversal::BuildDisplayList { - layout_context: &layout_ctx, - }; - traversal.process(layout_root.get_mut()); + sequential::build_display_list_for_subtree( + &mut layout_root, + &shared_layout_ctx); } Some(ref mut traversal) => { - parallel::build_display_list_for_subtree(&mut layout_root, - &data.url, - data.iframe, - self.first_reflow.get(), - self.time_profiler_chan.clone(), - &mut shared_layout_ctx, - traversal); + parallel::build_display_list_for_subtree( + &mut layout_root, + &data.url, + data.iframe, + self.first_reflow.get(), + self.time_profiler_chan.clone(), + &shared_layout_ctx, + traversal); } } diff --git a/components/layout/lib.rs b/components/layout/lib.rs index 336b47476d8..0e7eb9434d2 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -55,6 +55,7 @@ pub mod layout_task; pub mod inline; pub mod model; pub mod parallel; +pub mod sequential; pub mod table_wrapper; pub mod table; pub mod table_caption; diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index fbb95ac8123..d55420d2f7e 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -11,7 +11,8 @@ use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal use flow; use flow_ref::FlowRef; use traversal::{RecalcStyleForNode, ConstructFlows}; -use traversal::{AssignBSizesAndStoreOverflow, AssignISizes, BubbleISizes}; +use traversal::{BubbleISizes, AssignISizes, AssignBSizesAndStoreOverflow}; +use traversal::{ComputeAbsolutePositions, BuildDisplayList}; use url::Url; use util::{LayoutDataAccess, LayoutDataWrapper}; use wrapper::{layout_node_to_unsafe_layout_node, layout_node_from_unsafe_layout_node, LayoutNode}; @@ -79,12 +80,12 @@ impl DomParallelInfo { /// A parallel top-down DOM traversal. pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { - fn run_parallel(&mut self, + fn run_parallel(&self, node: UnsafeLayoutNode, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeLayoutNode>); #[inline(always)] - fn run_parallel_helper(&mut self, + fn run_parallel_helper(&self, unsafe_node: UnsafeLayoutNode, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeLayoutNode>, top_down_func: extern "Rust" fn(UnsafeFlow, @@ -139,7 +140,7 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal { /// /// The only communication between siblings is that they both /// fetch-and-subtract the parent's children count. - fn run_parallel(&mut self, + fn run_parallel(&self, mut unsafe_node: UnsafeLayoutNode, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeLayoutNode>) { loop { @@ -214,7 +215,7 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal { /// /// The only communication between siblings is that they both /// fetch-and-subtract the parent's children count. - fn run_parallel(&mut self, + fn run_parallel(&self, mut unsafe_flow: UnsafeFlow, _: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { loop { @@ -259,12 +260,12 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal { /// A parallel top-down flow traversal. trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { - fn run_parallel(&mut self, + fn run_parallel(&self, unsafe_flow: UnsafeFlow, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>); #[inline(always)] - fn run_parallel_helper(&mut self, + fn run_parallel_helper(&self, unsafe_flow: UnsafeFlow, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>, top_down_func: extern "Rust" fn(UnsafeFlow, @@ -304,7 +305,7 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal { impl<'a> ParallelPostorderFlowTraversal for BubbleISizes<'a> {} impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> { - fn run_parallel(&mut self, + fn run_parallel(&self, unsafe_flow: UnsafeFlow, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { self.run_parallel_helper(unsafe_flow, @@ -316,10 +317,23 @@ impl<'a> ParallelPreorderFlowTraversal for AssignISizes<'a> { impl<'a> ParallelPostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> {} +impl<'a> ParallelPreorderFlowTraversal for ComputeAbsolutePositions<'a> { + fn run_parallel(&self, + unsafe_flow: UnsafeFlow, + proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeFlow>) { + self.run_parallel_helper(unsafe_flow, + proxy, + compute_absolute_positions, + build_display_list) + } +} + +impl<'a> ParallelPostorderFlowTraversal for BuildDisplayList<'a> {} + impl<'a> ParallelPostorderDomTraversal for ConstructFlows<'a> {} impl <'a> ParallelPreorderDomTraversal for RecalcStyleForNode<'a> { - fn run_parallel(&mut self, + fn run_parallel(&self, unsafe_node: UnsafeLayoutNode, proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeLayoutNode>) { self.run_parallel_helper(unsafe_node, @@ -333,7 +347,7 @@ fn recalc_style(unsafe_node: UnsafeLayoutNode, proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeLayoutNode>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); - let mut recalc_style_for_node_traversal = RecalcStyleForNode { + let recalc_style_for_node_traversal = RecalcStyleForNode { layout_context: &layout_context, }; recalc_style_for_node_traversal.run_parallel(unsafe_node, proxy) @@ -343,7 +357,7 @@ fn construct_flows(unsafe_node: UnsafeLayoutNode, proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeLayoutNode>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); - let mut construct_flows_traversal = ConstructFlows { + let construct_flows_traversal = ConstructFlows { layout_context: &layout_context, }; construct_flows_traversal.run_parallel(unsafe_node, proxy) @@ -353,91 +367,40 @@ fn assign_inline_sizes(unsafe_flow: UnsafeFlow, proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); - let mut assign_inline_sizes_traversal = AssignISizes { + let assign_inline_sizes_traversal = AssignISizes { layout_context: &layout_context, }; assign_inline_sizes_traversal.run_parallel(unsafe_flow, proxy) } fn assign_block_sizes_and_store_overflow(unsafe_flow: UnsafeFlow, - proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { + proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); - let mut assign_block_sizes_traversal = AssignBSizesAndStoreOverflow { + let assign_block_sizes_traversal = AssignBSizesAndStoreOverflow { layout_context: &layout_context, }; assign_block_sizes_traversal.run_parallel(unsafe_flow, proxy) } -fn compute_absolute_position(unsafe_flow: UnsafeFlow, - proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { - let mut had_descendants = false; - unsafe { - // Get a real flow. - let flow: &mut FlowRef = mem::transmute(&unsafe_flow); - - // Compute the absolute position for the flow. - flow.get_mut().compute_absolute_position(); - - // Enqueue all children. - for kid in flow::child_iter(flow.get_mut()) { - had_descendants = true; - proxy.push(WorkUnit { - fun: compute_absolute_position, - data: borrowed_flow_to_unsafe_flow(kid), - }); - } - - // If there were no more descendants, start building the display list. - if !had_descendants { - build_display_list(mut_owned_flow_to_unsafe_flow(flow), proxy) - } - } -} - -fn build_display_list(mut unsafe_flow: UnsafeFlow, - proxy: &mut WorkerProxy<*const SharedLayoutContext,UnsafeFlow>) { +fn compute_absolute_positions(unsafe_flow: UnsafeFlow, + proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeFlow>) { let shared_layout_context = unsafe { &**proxy.user_data() }; let layout_context = LayoutContext::new(shared_layout_context); + let compute_absolute_positions_traversal = ComputeAbsolutePositions { + layout_context: &layout_context, + }; + compute_absolute_positions_traversal.run_parallel(unsafe_flow, proxy); +} - loop { - unsafe { - // Get a real flow. - let flow: &mut FlowRef = mem::transmute(&unsafe_flow); - - // Build display lists. - flow.get_mut().build_display_list(&layout_context); - - { - let base = flow::mut_base(flow.get_mut()); - - // Reset the count of children for the next layout traversal. - base.parallel.children_count.store(base.children.len() as int, Relaxed); - } - - // Possibly enqueue the parent. - let unsafe_parent = flow::mut_base(flow.get_mut()).parallel.parent; - if unsafe_parent == null_unsafe_flow() { - // We're done! - break - } - - // No, we're not at the root yet. Then are we the last child - // of our parent to finish processing? If so, we can continue - // on with our parent; otherwise, we've gotta wait. - let parent: &mut FlowRef = mem::transmute(&unsafe_parent); - let parent_base = flow::mut_base(parent.get_mut()); - if parent_base.parallel - .children_count - .fetch_sub(1, SeqCst) == 1 { - // We were the last child of our parent. Build display lists for our parent. - unsafe_flow = unsafe_parent - } else { - // Stop. - break - } - } - } +fn build_display_list(unsafe_flow: UnsafeFlow, + proxy: &mut WorkerProxy<*const SharedLayoutContext, UnsafeFlow>) { + let shared_layout_context = unsafe { &**proxy.user_data() }; + let layout_context = LayoutContext::new(shared_layout_context); + let build_display_list_traversal = BuildDisplayList { + layout_context: &layout_context, + }; + build_display_list_traversal.run_parallel(unsafe_flow, proxy); } pub fn traverse_dom_preorder(root: LayoutNode, @@ -462,6 +425,12 @@ pub fn traverse_flow_tree_preorder(root: &mut FlowRef, time_profiler_chan: TimeProfilerChan, shared_layout_context: &SharedLayoutContext, queue: &mut WorkQueue<*const SharedLayoutContext,UnsafeFlow>) { + if shared_layout_context.opts.bubble_inline_sizes_separately { + let layout_context = LayoutContext::new(shared_layout_context); + let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context }; + root.get_mut().traverse_postorder(&bubble_inline_sizes); + } + queue.data = shared_layout_context as *const _; profile(time::LayoutParallelWarmupCategory, Some((url, iframe, first_reflow)), time_profiler_chan, || { @@ -487,7 +456,7 @@ pub fn build_display_list_for_subtree(root: &mut FlowRef, profile(time::LayoutParallelWarmupCategory, Some((url, iframe, first_reflow)), time_profiler_chan, || { queue.push(WorkUnit { - fun: compute_absolute_position, + fun: compute_absolute_positions, data: mut_owned_flow_to_unsafe_flow(root), }) }); diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs new file mode 100644 index 00000000000..1cd8216f760 --- /dev/null +++ b/components/layout/sequential.rs @@ -0,0 +1,89 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Implements sequential traversals over the DOM and flow trees. + +use context::{LayoutContext, SharedLayoutContext}; +use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal}; +use flow; +use flow_ref::FlowRef; +use traversal::{BubbleISizes, RecalcStyleForNode, ConstructFlows}; +use traversal::{AssignBSizesAndStoreOverflow, AssignISizes}; +use traversal::{ComputeAbsolutePositions, BuildDisplayList}; +use wrapper::LayoutNode; +use wrapper::{PostorderNodeMutTraversal}; +use wrapper::{PreorderDomTraversal, PostorderDomTraversal}; + +pub fn traverse_dom_preorder(root: LayoutNode, + shared_layout_context: &SharedLayoutContext) { + fn doit(node: LayoutNode, recalc_style: RecalcStyleForNode, construct_flows: ConstructFlows) { + recalc_style.process(node); + + for kid in node.children() { + doit(kid, recalc_style, construct_flows); + } + + construct_flows.process(node); + } + + let layout_context = LayoutContext::new(shared_layout_context); + let recalc_style = RecalcStyleForNode { layout_context: &layout_context }; + let construct_flows = ConstructFlows { layout_context: &layout_context }; + + doit(root, recalc_style, construct_flows); +} + +pub fn traverse_flow_tree_preorder(root: &mut FlowRef, + shared_layout_context: &SharedLayoutContext) { + fn doit(flow: &mut Flow, assign_inline_sizes: AssignISizes, assign_block_sizes: AssignBSizesAndStoreOverflow) { + if assign_inline_sizes.should_process(flow) { + assign_inline_sizes.process(flow); + } + + for kid in flow::child_iter(flow) { + doit(kid, assign_inline_sizes, assign_block_sizes); + } + + if assign_block_sizes.should_process(flow) { + assign_block_sizes.process(flow); + } + } + + let layout_context = LayoutContext::new(shared_layout_context); + + let root = root.get_mut(); + + if layout_context.shared.opts.bubble_inline_sizes_separately { + let bubble_inline_sizes = BubbleISizes { layout_context: &layout_context }; + root.traverse_postorder(&bubble_inline_sizes); + } + + let assign_inline_sizes = AssignISizes { layout_context: &layout_context }; + let assign_block_sizes = AssignBSizesAndStoreOverflow { layout_context: &layout_context }; + + doit(root, assign_inline_sizes, assign_block_sizes); +} + +pub fn build_display_list_for_subtree(root: &mut FlowRef, + shared_layout_context: &SharedLayoutContext) { + fn doit(flow: &mut Flow, compute_absolute_positions: ComputeAbsolutePositions, build_display_list: BuildDisplayList) { + if compute_absolute_positions.should_process(flow) { + compute_absolute_positions.process(flow); + } + + for kid in flow::mut_base(flow).child_iter() { + doit(kid, compute_absolute_positions, build_display_list); + } + + if build_display_list.should_process(flow) { + build_display_list.process(flow); + } + } + + let layout_context = LayoutContext::new(shared_layout_context); + let compute_absolute_positions = ComputeAbsolutePositions { layout_context: &layout_context }; + let build_display_list = BuildDisplayList { layout_context: &layout_context }; + + doit(root.get_mut(), compute_absolute_positions, build_display_list); +} diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index b9686e84276..c05e67b4dc0 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -261,14 +261,13 @@ struct FlowTreeVerification; #[cfg(debug)] impl PreorderFlow for FlowTreeVerification { #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { + fn process(&mut self, flow: &mut Flow) { let base = flow::base(flow); if !base.flags.is_leaf() && !base.flags.is_nonleaf() { println("flow tree verification failed: flow wasn't a leaf or a nonleaf!"); flow.dump(); fail!("flow tree verification failed") } - true } } @@ -280,18 +279,9 @@ pub struct BubbleISizes<'a> { impl<'a> PostorderFlowTraversal for BubbleISizes<'a> { #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { + fn process(&self, flow: &mut Flow) { flow.bubble_inline_sizes(); - true } - - // FIXME: We can't prune until we start reusing flows - /* - #[inline] - fn should_prune(&mut self, flow: &mut Flow) -> bool { - flow::mut_base(flow).restyle_damage.lacks(BubbleISizes) - } - */ } /// The assign-inline-sizes traversal. In Gecko this corresponds to `Reflow`. @@ -301,9 +291,8 @@ pub struct AssignISizes<'a> { impl<'a> PreorderFlowTraversal for AssignISizes<'a> { #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { + fn process(&self, flow: &mut Flow) { flow.assign_inline_sizes(self.layout_context); - true } } @@ -317,36 +306,39 @@ pub struct AssignBSizesAndStoreOverflow<'a> { impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> { #[inline] - fn process(&mut self, flow: &mut Flow) -> bool { + fn process(&self, flow: &mut Flow) { flow.assign_block_size(self.layout_context); // Skip store-overflow for absolutely positioned flows. That will be // done in a separate traversal. if !flow.is_store_overflow_delayed() { flow.store_overflow(self.layout_context); } - true } #[inline] - fn should_process(&mut self, flow: &mut Flow) -> bool { + fn should_process(&self, flow: &mut Flow) -> bool { !flow::base(flow).flags.impacted_by_floats() } } -/// The display list construction traversal. +pub struct ComputeAbsolutePositions<'a> { + pub layout_context: &'a LayoutContext<'a>, +} + +impl<'a> PreorderFlowTraversal for ComputeAbsolutePositions<'a> { + #[inline] + fn process(&self, flow: &mut Flow) { + flow.compute_absolute_position() + } +} + pub struct BuildDisplayList<'a> { pub layout_context: &'a LayoutContext<'a>, } -impl<'a> BuildDisplayList<'a> { +impl<'a> PostorderFlowTraversal for BuildDisplayList<'a> { #[inline] - pub fn process(&mut self, flow: &mut Flow) { - flow.compute_absolute_position(); - - for kid in flow::mut_base(flow).child_iter() { - self.process(kid) - } - + fn process(&self, flow: &mut Flow) { flow.build_display_list(self.layout_context) } }