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.rs164
1 files changed, 94 insertions, 70 deletions
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index 64b833fc55b..e21cd7a52c8 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -11,21 +11,21 @@ use css::select::new_stylist;
use css::node_style::StyledNode;
use layout::construct::{FlowConstructionResult, NoConstructionResult};
use layout::context::LayoutContext;
-use layout::display_list_builder::{DisplayListBuilder, DisplayListBuildingInfo, ToGfxColor};
use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use layout::flow::{PreorderFlowTraversal, PostorderFlowTraversal};
use layout::flow;
use layout::incremental::RestyleDamage;
use layout::parallel::PaddedUnsafeFlow;
use layout::parallel;
-use layout::util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods};
+use layout::util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor};
use layout::wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
+use collections::dlist::DList;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
-use gfx::display_list::{ClipDisplayItemClass, DisplayItem, DisplayItemIterator, DisplayList};
-use gfx::display_list::{OpaqueNode, StackingContext};
+use gfx::display_list::{ClipDisplayItemClass, ContentStackingLevel, DisplayItem};
+use gfx::display_list::{DisplayItemIterator, DisplayList, OpaqueNode};
use gfx::font_context::{FontContext, FontContextInfo};
use gfx::render_task::{RenderMsg, RenderChan, RenderLayer};
use gfx::{render_task, color};
@@ -48,7 +48,7 @@ use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
use servo_util::geometry::Au;
use servo_util::geometry;
use servo_util::opts::Opts;
-use servo_util::smallvec::{SmallVec, SmallVec0, SmallVec1};
+use servo_util::smallvec::{SmallVec, SmallVec1};
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
use servo_util::task::send_on_failure;
@@ -107,7 +107,11 @@ pub struct LayoutTask {
/// The channel on which messages can be sent to the profiler.
pub profiler_chan: ProfilerChan,
- pub opts: Opts
+ /// The command-line options.
+ pub opts: Opts,
+
+ /// The dirty rect. Used during display list construction.
+ pub dirty: Rect<Au>,
}
/// The damage computation traversal.
@@ -225,7 +229,31 @@ impl<'a> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {
#[inline]
fn should_process(&mut self, flow: &mut Flow) -> bool {
- !flow::base(flow).flags.inorder()
+ !flow::base(flow).flags.impacted_by_floats()
+ }
+}
+
+/// The display list construction traversal.
+pub struct BuildDisplayListTraversal<'a> {
+ layout_context: &'a LayoutContext,
+}
+
+impl<'a> BuildDisplayListTraversal<'a> {
+ #[inline]
+ fn process(&mut self, flow: &mut Flow) {
+ flow.compute_absolute_position();
+
+ for kid in flow::mut_base(flow).child_iter() {
+ if !kid.is_absolutely_positioned() {
+ self.process(kid)
+ }
+ }
+
+ for absolute_descendant_link in flow::mut_base(flow).abs_descendants.iter() {
+ self.process(absolute_descendant_link.resolve().unwrap())
+ }
+
+ flow.build_display_list(self.layout_context)
}
}
@@ -319,7 +347,8 @@ impl LayoutTask {
initial_css_values: Arc::new(style::initial_values()),
parallel_traversal: parallel_traversal,
profiler_chan: profiler_chan,
- opts: opts.clone()
+ opts: opts.clone(),
+ dirty: Rect::zero(),
}
}
@@ -349,6 +378,7 @@ impl LayoutTask {
url: (*url).clone(),
reflow_root: OpaqueNodeMethods::from_layout_node(reflow_root),
opts: self.opts.clone(),
+ dirty: Rect::zero(),
}
}
@@ -634,23 +664,26 @@ impl LayoutTask {
// Build the display list if necessary, and send it to the renderer.
if data.goal == ReflowForDisplay {
profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone(), || {
- let mut root_stacking_context = StackingContext::new();
- let mut display_list_builder = DisplayListBuilder {
- ctx: &layout_ctx,
- layers: SmallVec0::new(),
- dirty: flow::base(layout_root).position.clone(),
- };
- let display_list_building_info = DisplayListBuildingInfo {
- relative_containing_block_size: flow::base(layout_root).position.size,
- absolute_containing_block_position: Point2D(Au(0), Au(0)),
- layers_needed_for_positioned_flows: false,
- };
+ layout_ctx.dirty = flow::base(layout_root).position.clone();
- layout_root.build_display_list(&mut root_stacking_context,
- &mut display_list_builder,
- &display_list_building_info);
+ match self.parallel_traversal {
+ None => {
+ let mut traversal = BuildDisplayListTraversal {
+ layout_context: &layout_ctx,
+ };
+ traversal.process(layout_root);
+ }
+ Some(ref mut traversal) => {
+ parallel::build_display_list_for_subtree(&mut layout_root,
+ self.profiler_chan.clone(),
+ &mut layout_ctx,
+ traversal);
+ }
+ }
- let display_list = Arc::new(root_stacking_context.flatten());
+ let root_display_list = mem::replace(&mut flow::mut_base(layout_root).display_list,
+ DisplayList::new());
+ let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel));
// FIXME(pcwalton): This is really ugly and can't handle overflow: scroll. Refactor
// it with extreme prejudice.
@@ -677,12 +710,9 @@ impl LayoutTask {
}
}
- let root_size = Size2D(display_list_building_info.relative_containing_block_size
- .width
- .to_nearest_px() as uint,
- display_list_building_info.relative_containing_block_size
- .height
- .to_nearest_px() as uint);
+ let root_size = flow::base(layout_root).position.size;
+ let root_size = Size2D(root_size.width.to_nearest_px() as uint,
+ root_size.height.to_nearest_px() as uint);
let render_layer = RenderLayer {
id: layout_root.layer_id(0),
display_list: display_list.clone(),
@@ -693,13 +723,15 @@ impl LayoutTask {
self.display_list = Some(display_list.clone());
+ // TODO(pcwalton): Eventually, when we have incremental reflow, this will have to
+ // be smarter in order to handle retained layer contents properly from reflow to
+ // reflow.
let mut layers = SmallVec1::new();
layers.push(render_layer);
- let DisplayListBuilder {
- layers: sublayers,
- ..
- } = display_list_builder;
- layers.push_all_move(sublayers);
+ for layer in mem::replace(&mut flow::mut_base(layout_root).layers,
+ DList::new()).move_iter() {
+ layers.push(layer)
+ }
debug!("Layout done!");
@@ -726,7 +758,6 @@ impl LayoutTask {
// need to compare nodes for equality. Thus we can safely work only with `OpaqueNode`.
ContentBoxQuery(node, reply_chan) => {
let node: OpaqueNode = OpaqueNodeMethods::from_script_node(node);
-
fn union_boxes_for_node(accumulator: &mut Option<Rect<Au>>,
mut iter: DisplayItemIterator,
node: OpaqueNode) {
@@ -774,28 +805,22 @@ impl LayoutTask {
reply_chan.send(ContentBoxesResponse(boxes))
}
HitTestQuery(_, point, reply_chan) => {
- fn hit_test(x: Au, y: Au, list: &[DisplayItem])
+ fn hit_test<'a,I:Iterator<&'a DisplayItem>>(x: Au, y: Au, mut iterator: I)
-> Option<HitTestResponse> {
- for item in list.rev_iter() {
+ for item in iterator {
match *item {
ClipDisplayItemClass(ref cc) => {
- if !cc.need_clip || geometry::rect_contains_point(cc.base.bounds,
- Point2D(x, y)) {
- let ret = hit_test(x, y, cc.child_list.as_slice());
+ if geometry::rect_contains_point(cc.base.bounds, Point2D(x, y)) {
+ let ret = hit_test(x, y, cc.children.list.rev_iter());
if !ret.is_none() {
return ret
}
}
+ continue
}
_ => {}
}
- }
- for item in list.rev_iter() {
- match *item {
- ClipDisplayItemClass(_) => continue,
- _ => {}
- }
let bounds = item.bounds();
// TODO(tikue): This check should really be performed by a method of
@@ -816,7 +841,7 @@ impl LayoutTask {
Au::from_frac_px(point.y as f64));
let resp = match self.display_list {
None => fail!("no display list!"),
- Some(ref display_list) => hit_test(x, y, display_list.list.as_slice()),
+ Some(ref display_list) => hit_test(x, y, display_list.list.rev_iter()),
};
if resp.is_some() {
reply_chan.send(Ok(resp.unwrap()));
@@ -826,44 +851,43 @@ impl LayoutTask {
}
MouseOverQuery(_, point, reply_chan) => {
- fn mouse_over_test(x: Au,
+ fn mouse_over_test<'a,
+ I:Iterator<&'a DisplayItem>>(
+ x: Au,
y: Au,
- list: &[DisplayItem],
+ mut iterator: I,
result: &mut Vec<UntrustedNodeAddress>) {
- for item in list.rev_iter() {
+ for item in iterator {
match *item {
ClipDisplayItemClass(ref cc) => {
- mouse_over_test(x, y, cc.child_list.as_slice(), result);
+ mouse_over_test(x, y, cc.children.list.rev_iter(), result);
+ }
+ _ => {
+ let bounds = item.bounds();
+
+ // TODO(tikue): This check should really be performed by a method
+ // of DisplayItem.
+ if x < bounds.origin.x + bounds.size.width &&
+ bounds.origin.x <= x &&
+ y < bounds.origin.y + bounds.size.height &&
+ bounds.origin.y <= y {
+ result.push(item.base()
+ .node
+ .to_untrusted_node_address());
+ }
}
- _ => {}
- }
- }
-
- for item in list.rev_iter() {
- let bounds = item.bounds();
-
- // TODO(tikue): This check should really be performed by a method of
- // DisplayItem.
- if x < bounds.origin.x + bounds.size.width &&
- bounds.origin.x <= x &&
- y < bounds.origin.y + bounds.size.height &&
- bounds.origin.y <= y {
- result.push(item.base()
- .node
- .to_untrusted_node_address());
}
}
}
let mut mouse_over_list: Vec<UntrustedNodeAddress> = vec!();
- let (x, y) = (Au::from_frac_px(point.x as f64),
- Au::from_frac_px(point.y as f64));
+ let (x, y) = (Au::from_frac_px(point.x as f64), Au::from_frac_px(point.y as f64));
match self.display_list {
None => fail!("no display list!"),
Some(ref display_list) => {
mouse_over_test(x,
y,
- display_list.list.as_slice(),
+ display_list.list.rev_iter(),
&mut mouse_over_list);
}
};