зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #3668 - Removes duplicate CSS selector matching logic (from cgaebel:sequential-reflow); r=pcwalton
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/ This passes reftests with both default arguments, and with `-y 1`. r? @pcwalton Source-Repo: https://github.com/servo/servo Source-Revision: 7eaeaeeb217e7cbd083fe318863e7de4b9f38e2b
This commit is contained in:
Родитель
ab3dd48482
Коммит
f081b5599e
|
@ -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<T:PreorderFlowTraversal>(&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<T:PostorderFlowTraversal>(&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)
|
||||
|
|
|
@ -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<Box<BloomFilter>>,
|
||||
applicable_declarations: &mut ApplicableDeclarations,
|
||||
parent: Option<LayoutNode>);
|
||||
|
||||
fn match_node(&self,
|
||||
stylist: &Stylist,
|
||||
parent_bf: &Option<Box<BloomFilter>>,
|
||||
|
@ -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<Box<BloomFilter>>,
|
||||
applicable_declarations: &mut ApplicableDeclarations,
|
||||
parent: Option<LayoutNode>) {
|
||||
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<LayoutNode>,
|
||||
applicable_declarations: &ApplicableDeclarations,
|
||||
|
|
|
@ -411,10 +411,10 @@ pub trait MutableFlowUtils {
|
|||
// Traversals
|
||||
|
||||
/// Traverses the tree in preorder.
|
||||
fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool;
|
||||
fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &T);
|
||||
|
||||
/// Traverses the tree in postorder.
|
||||
fn traverse_postorder<T:PostorderFlowTraversal>(self, traversal: &mut T) -> bool;
|
||||
fn traverse_postorder<T:PostorderFlowTraversal>(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<T:PreorderFlowTraversal>(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<T:PreorderFlowTraversal>(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<T:PostorderFlowTraversal>(self, traversal: &mut T) -> bool {
|
||||
if traversal.should_prune(self) {
|
||||
return true
|
||||
}
|
||||
|
||||
fn traverse_postorder<T:PostorderFlowTraversal>(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.
|
||||
|
|
|
@ -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;
|
||||
|
@ -515,31 +512,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.
|
||||
|
@ -552,12 +528,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"),
|
||||
|
@ -649,17 +620,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,8 +666,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.
|
||||
|
@ -724,20 +687,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
})
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче