aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/main/layout/layout_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/main/layout/layout_task.rs')
-rw-r--r--src/components/main/layout/layout_task.rs175
1 files changed, 84 insertions, 91 deletions
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index f9856724659..2f70d0ea499 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -9,18 +9,17 @@ use css::matching::{ApplicableDeclarations, ApplicableDeclarationsCache, MatchMe
use css::matching::{StyleSharingCandidateCache};
use css::select::new_stylist;
use css::node_style::StyledNode;
-use layout::construct::{FlowConstructionResult, FlowConstructor, NoConstructionResult};
+use layout::construct::{FlowConstructionResult, NoConstructionResult};
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ToGfxColor};
-use layout::flow::{Flow, FlowLeafSet, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
+use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use layout::flow::{PreorderFlowTraversal, PostorderFlowTraversal};
use layout::flow;
use layout::incremental::RestyleDamage;
-use layout::parallel::{AssignHeightsAndStoreOverflowTraversalKind, BubbleWidthsTraversalKind};
-use layout::parallel::{UnsafeFlow};
+use layout::parallel::PaddedUnsafeFlow;
use layout::parallel;
use layout::util::{LayoutDataAccess, OpaqueNode, LayoutDataWrapper};
-use layout::wrapper::{DomLeafSet, LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
+use layout::wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
use extra::url::Url;
use extra::arc::{Arc, MutexArc};
@@ -28,24 +27,25 @@ use geom::rect::Rect;
use geom::size::Size2D;
use gfx::display_list::{ClipDisplayItemClass, DisplayItem, DisplayItemIterator};
use gfx::display_list::{DisplayList, DisplayListCollection};
-use gfx::font_context::FontContextInfo;
-use gfx::opts::Opts;
+use gfx::font_context::{FontContext, FontContextInfo};
use gfx::render_task::{RenderMsg, RenderChan, RenderLayer};
use gfx::{render_task, color};
+use script::dom::bindings::js::JS;
use script::dom::event::ReflowEvent;
-use script::dom::node::{ElementNodeTypeId, LayoutDataRef};
+use script::dom::node::{ElementNodeTypeId, LayoutDataRef, Node};
use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId};
use script::layout_interface::{AddStylesheetMsg, ContentBoxQuery};
use script::layout_interface::{ContentBoxesQuery, ContentBoxesResponse, ExitNowMsg, LayoutQuery};
use script::layout_interface::{HitTestQuery, ContentBoxResponse, HitTestResponse, MouseOverQuery, MouseOverResponse};
use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, PrepareToExitMsg};
-use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage, UntrustedNodeAddress};
+use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, UntrustedNodeAddress};
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, FailureMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
use servo_util::geometry::Au;
+use servo_util::opts::Opts;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
use servo_util::task::send_on_failure;
@@ -86,12 +86,6 @@ pub struct LayoutTask {
/// The local image cache.
local_image_cache: MutexArc<LocalImageCache>,
- /// The set of leaves in the DOM tree.
- dom_leaf_set: Arc<DomLeafSet>,
-
- /// The set of leaves in the flow tree.
- flow_leaf_set: Arc<FlowLeafSet>,
-
/// The size of the viewport.
screen_size: Size2D<Au>,
@@ -104,7 +98,7 @@ pub struct LayoutTask {
initial_css_values: Arc<ComputedValues>,
/// The workers that we use for parallel operation.
- parallel_traversal: Option<WorkQueue<*mut LayoutContext,UnsafeFlow>>,
+ parallel_traversal: Option<WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>>,
/// The channel on which messages can be sent to the profiler.
profiler_chan: ProfilerChan,
@@ -194,12 +188,14 @@ impl<'a> PostorderFlowTraversal for BubbleWidthsTraversal<'a> {
}
/// The assign-widths traversal. In Gecko this corresponds to `Reflow`.
-struct AssignWidthsTraversal<'a>(&'a mut LayoutContext);
+pub struct AssignWidthsTraversal<'a> {
+ layout_context: &'a mut LayoutContext,
+}
impl<'a> PreorderFlowTraversal for AssignWidthsTraversal<'a> {
#[inline]
fn process(&mut self, flow: &mut Flow) -> bool {
- flow.assign_widths(**self);
+ flow.assign_widths(self.layout_context);
true
}
}
@@ -303,8 +299,6 @@ impl LayoutTask {
image_cache_task: image_cache_task.clone(),
local_image_cache: local_image_cache,
screen_size: screen_size,
- dom_leaf_set: Arc::new(DomLeafSet::new()),
- flow_leaf_set: Arc::new(FlowLeafSet::new()),
display_list_collection: None,
stylist: ~new_stylist(),
@@ -323,7 +317,7 @@ impl LayoutTask {
}
// Create a layout context for use in building display lists, hit testing, &c.
- fn build_layout_context(&self, reflow_root: &LayoutNode) -> LayoutContext {
+ fn build_layout_context(&self, reflow_root: &LayoutNode, url: &Url) -> LayoutContext {
let font_context_info = FontContextInfo {
backend: self.opts.render_backend,
needs_font_list: true,
@@ -334,13 +328,13 @@ impl LayoutTask {
image_cache: self.local_image_cache.clone(),
screen_size: self.screen_size.clone(),
constellation_chan: self.constellation_chan.clone(),
- dom_leaf_set: self.dom_leaf_set.clone(),
- flow_leaf_set: self.flow_leaf_set.clone(),
layout_chan: self.chan.clone(),
font_context_info: font_context_info,
stylist: &*self.stylist,
initial_css_values: self.initial_css_values.clone(),
+ url: (*url).clone(),
reflow_root: OpaqueNode::from_layout_node(reflow_root),
+ opts: self.opts.clone(),
}
}
@@ -422,17 +416,8 @@ impl LayoutTask {
self.stylist.add_stylesheet(sheet, AuthorOrigin)
}
- /// Builds the flow tree.
- ///
- /// This corresponds to the various `nsCSSFrameConstructor` methods in Gecko or
- /// `createRendererIfNeeded` in WebKit. Note, however that in WebKit `createRendererIfNeeded`
- /// is intertwined with selector matching, making it difficult to compare directly. It is
- /// marked `#[inline(never)]` to aid benchmarking in sampling profilers.
- #[inline(never)]
- fn construct_flow_tree(&self, layout_context: &mut LayoutContext, node: LayoutNode, url: &Url) -> ~Flow {
- let node = ThreadSafeLayoutNode::new(node);
- node.traverse_postorder_mut(&mut FlowConstructor::init(layout_context, url));
-
+ /// Retrieves the flow tree root from the root node.
+ fn get_layout_root(&self, node: LayoutNode) -> ~Flow {
let mut layout_data_ref = node.mutate_layout_data();
let result = match *layout_data_ref.get() {
Some(ref mut layout_data) => {
@@ -456,7 +441,7 @@ impl LayoutTask {
fn solve_constraints(&mut self,
layout_root: &mut Flow,
layout_context: &mut LayoutContext) {
- {
+ if layout_context.opts.bubble_widths_separately {
let mut traversal = BubbleWidthsTraversal {
layout_context: layout_context,
};
@@ -468,7 +453,12 @@ impl LayoutTask {
// recompute them every time.
// NOTE: this currently computes borders, so any pruning should separate that operation
// out.
- layout_root.traverse_preorder(&mut AssignWidthsTraversal(layout_context));
+ {
+ let mut traversal = AssignWidthsTraversal {
+ layout_context: layout_context,
+ };
+ layout_root.traverse_preorder(&mut traversal);
+ }
// FIXME(pcwalton): Prune this pass as well.
{
@@ -485,28 +475,24 @@ impl LayoutTask {
/// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling.
#[inline(never)]
fn solve_constraints_parallel(&mut self,
- layout_root: &mut Flow,
+ layout_root: &mut ~Flow,
layout_context: &mut LayoutContext) {
+ if layout_context.opts.bubble_widths_separately {
+ let mut traversal = BubbleWidthsTraversal {
+ layout_context: layout_context,
+ };
+ layout_root.traverse_postorder(&mut traversal);
+ }
+
match self.parallel_traversal {
None => fail!("solve_contraints_parallel() called with no parallel traversal ready"),
Some(ref mut traversal) => {
- parallel::traverse_flow_tree(BubbleWidthsTraversalKind,
- &self.flow_leaf_set,
- self.profiler_chan.clone(),
- layout_context,
- traversal);
-
// NOTE: this currently computes borders, so any pruning should separate that
// operation out.
- // TODO(pcwalton): Run this in parallel as well. This will require a bit more work
- // because this is a top-down traversal, unlike the others.
- layout_root.traverse_preorder(&mut AssignWidthsTraversal(layout_context));
-
- parallel::traverse_flow_tree(AssignHeightsAndStoreOverflowTraversalKind,
- &self.flow_leaf_set,
- self.profiler_chan.clone(),
- layout_context,
- traversal);
+ parallel::traverse_flow_tree_preorder(layout_root,
+ self.profiler_chan.clone(),
+ layout_context,
+ traversal);
}
}
}
@@ -527,8 +513,9 @@ impl LayoutTask {
/// The high-level routine that performs layout tasks.
fn handle_reflow(&mut self, data: &Reflow) {
// FIXME: Isolate this transmutation into a "bridge" module.
- let node: &LayoutNode = unsafe {
- transmute(&data.document_root)
+ let node: &mut LayoutNode = unsafe {
+ let mut node: JS<Node> = JS::from_trusted_node_address(data.document_root);
+ transmute(&mut node)
};
debug!("layout: received layout request for: {:s}", data.url.to_str());
@@ -558,45 +545,51 @@ impl LayoutTask {
self.screen_size = current_screen_size;
// Create a layout context for use throughout the following passes.
- let mut layout_ctx = self.build_layout_context(node);
+ let mut layout_ctx = self.build_layout_context(node, &data.url);
+
+ // Create a font context, if this is sequential.
+ //
+ // FIXME(pcwalton): This is a pretty bogus thing to do. Essentially this is a workaround
+ // for libgreen having slow TLS.
+ let mut font_context_opt = if self.parallel_traversal.is_none() {
+ Some(~FontContext::new(layout_ctx.font_context_info.clone()))
+ } else {
+ None
+ };
+
+ // Create a font context, if this is sequential.
+ //
+ // FIXME(pcwalton): This is a pretty bogus thing to do. Essentially this is a workaround
+ // for libgreen having slow TLS.
+ let mut font_context_opt = if self.parallel_traversal.is_none() {
+ Some(~FontContext::new(layout_ctx.font_context_info.clone()))
+ } else {
+ None
+ };
let mut layout_root = profile(time::LayoutStyleRecalcCategory,
self.profiler_chan.clone(),
|| {
- // Perform CSS selector matching if necessary.
- match data.damage.level {
- ReflowDocumentDamage => {}
- _ => {
- profile(time::LayoutSelectorMatchCategory, self.profiler_chan.clone(), || {
- match self.parallel_traversal {
- None => {
- let mut applicable_declarations = ApplicableDeclarations::new();
- let mut applicable_declarations_cache =
- ApplicableDeclarationsCache::new();
- let mut style_sharing_candidate_cache =
- StyleSharingCandidateCache::new();
- node.match_and_cascade_subtree(self.stylist,
- &layout_ctx.layout_chan,
- &mut applicable_declarations,
- layout_ctx.initial_css_values.get(),
- &mut applicable_declarations_cache,
- &mut style_sharing_candidate_cache,
- None)
- }
- Some(ref mut traversal) => {
- parallel::match_and_cascade_subtree(node,
- &mut layout_ctx,
- traversal)
- }
- }
- })
+ // Perform CSS selector matching and flow construction.
+ match self.parallel_traversal {
+ None => {
+ let mut applicable_declarations = ApplicableDeclarations::new();
+ let mut applicable_declarations_cache = ApplicableDeclarationsCache::new();
+ let mut style_sharing_candidate_cache = StyleSharingCandidateCache::new();
+ drop(node.recalc_style_for_subtree(self.stylist,
+ &mut layout_ctx,
+ font_context_opt.take_unwrap(),
+ &mut applicable_declarations,
+ &mut applicable_declarations_cache,
+ &mut style_sharing_candidate_cache,
+ None))
+ }
+ Some(ref mut traversal) => {
+ parallel::recalc_style_for_subtree(node, &mut layout_ctx, traversal)
}
}
- // Construct the flow tree.
- profile(time::LayoutTreeBuilderCategory,
- self.profiler_chan.clone(),
- || self.construct_flow_tree(&mut layout_ctx, *node, &data.url))
+ self.get_layout_root((*node).clone())
});
// Verification of the flow tree, which ensures that all nodes were either marked as leaves
@@ -622,7 +615,7 @@ impl LayoutTask {
}
Some(_) => {
// Parallel mode.
- self.solve_constraints_parallel(layout_root, &mut layout_ctx)
+ self.solve_constraints_parallel(&mut layout_root, &mut layout_ctx)
}
}
});
@@ -648,7 +641,7 @@ impl LayoutTask {
if child.type_id() == ElementNodeTypeId(HTMLHtmlElementTypeId) ||
child.type_id() == ElementNodeTypeId(HTMLBodyElementTypeId) {
let element_bg_color = {
- let thread_safe_child = ThreadSafeLayoutNode::new(child);
+ let thread_safe_child = ThreadSafeLayoutNode::new(&child);
thread_safe_child.style()
.get()
.resolve_color(thread_safe_child.style()
@@ -683,7 +676,7 @@ impl LayoutTask {
});
}
- layout_root.destroy(self.flow_leaf_set.get());
+ layout_root.destroy();
// Tell script that we're done.
//
@@ -700,7 +693,7 @@ impl LayoutTask {
// The neat thing here is that in order to answer the following two queries we only
// need to compare nodes for equality. Thus we can safely work only with `OpaqueNode`.
ContentBoxQuery(node, reply_chan) => {
- let node = OpaqueNode::from_script_node(&node);
+ let node = OpaqueNode::from_script_node(node);
fn union_boxes_for_node<'a>(
accumulator: &mut Option<Rect<Au>>,
@@ -724,7 +717,7 @@ impl LayoutTask {
reply_chan.send(ContentBoxResponse(rect.unwrap_or(Au::zero_rect())))
}
ContentBoxesQuery(node, reply_chan) => {
- let node = OpaqueNode::from_script_node(&node);
+ let node = OpaqueNode::from_script_node(node);
fn add_boxes_for_node<'a>(
accumulator: &mut ~[Rect<Au>],