diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs index ff06f05dd62..c73cbb2a494 100644 --- a/src/components/main/layout/block.rs +++ b/src/components/main/layout/block.rs @@ -7,7 +7,6 @@ use layout::box::{RenderBox}; use layout::context::LayoutContext; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; -use layout::display_list_builder::{FlowDisplayListBuilderMethods}; use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow, FloatFlow}; use layout::inline::InlineLayout; use layout::model::{MaybeAuto, Specified, Auto}; @@ -327,11 +326,17 @@ impl BlockFlowData { pub fn build_display_list_block(@mut self, builder: &DisplayListBuilder, dirty: &Rect, - offset: &Point2D, - list: &Cell>) { + list: &Cell>) + -> bool { + + let abs_rect = Rect(self.common.abs_position, self.common.position.size); + if !abs_rect.intersects(dirty) { + return false; + } + // add box that starts block context self.box.map(|&box| { - box.build_display_list(builder, dirty, offset, list) + box.build_display_list(builder, dirty, &self.common.abs_position, list) }); @@ -340,8 +345,12 @@ impl BlockFlowData { // go deeper into the flow tree let flow = BlockFlow(self); for flow.each_child |child| { - flow.build_display_list_for_child(builder, child, dirty, offset, list) + do child.with_mut_base |base| { + base.abs_position = self.common.abs_position + base.position.origin; + } } + + true } } diff --git a/src/components/main/layout/display_list_builder.rs b/src/components/main/layout/display_list_builder.rs index 5009c1452b1..c992a32fc69 100644 --- a/src/components/main/layout/display_list_builder.rs +++ b/src/components/main/layout/display_list_builder.rs @@ -6,16 +6,9 @@ use layout::box::RenderBox; use layout::context::LayoutContext; -use layout::flow::FlowContext; -use std::cell::Cell; -use geom::point::Point2D; -use geom::rect::Rect; -use gfx::display_list::DisplayList; -use gfx::geometry::Au; use gfx; use newcss; -use servo_util::tree::TreeNodeRef; /// Extra display list data is either nothing (if the display list is to be rendered) or the /// originating render box (if the display list is generated for hit testing). @@ -49,54 +42,6 @@ pub struct DisplayListBuilder<'self> { ctx: &'self LayoutContext, } -pub trait FlowDisplayListBuilderMethods { - fn build_display_list(&self, - a: &DisplayListBuilder, - b: &Rect, - c: &Cell>); - fn build_display_list_for_child(&self, - a: &DisplayListBuilder, - b: FlowContext, - c: &Rect, - d: &Point2D, - e: &Cell>); -} - -impl FlowDisplayListBuilderMethods for FlowContext { - fn build_display_list(&self, - builder: &DisplayListBuilder, - dirty: &Rect, - list: &Cell>) { - let zero = gfx::geometry::zero_point(); - self.build_display_list_recurse(builder, dirty, &zero, list); - } - - fn build_display_list_for_child(&self, - builder: &DisplayListBuilder, - child_flow: FlowContext, - dirty: &Rect, - offset: &Point2D, - list: &Cell>) { - // Adjust the dirty rect to child flow context coordinates. - do child_flow.with_base |child_node| { - let abs_flow_bounds = child_node.position.translate(offset); - let adj_offset = offset.add(&child_node.position.origin); - - debug!("build_display_list_for_child: rel=%?, abs=%?", - child_node.position, - abs_flow_bounds); - debug!("build_display_list_for_child: dirty=%?, offset=%?", dirty, offset); - - if dirty.intersects(&abs_flow_bounds) { - debug!("build_display_list_for_child: intersected. recursing into child flow..."); - child_flow.build_display_list_recurse(builder, dirty, &adj_offset, list); - } else { - debug!("build_display_list_for_child: Did not intersect..."); - } - } - } -} - // // Miscellaneous useful routines // diff --git a/src/components/main/layout/float.rs b/src/components/main/layout/float.rs index 2c23b90138d..898ce9ebfe2 100644 --- a/src/components/main/layout/float.rs +++ b/src/components/main/layout/float.rs @@ -5,7 +5,6 @@ use layout::box::{RenderBox}; use layout::context::LayoutContext; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; -use layout::display_list_builder::{FlowDisplayListBuilderMethods}; use layout::flow::{FloatFlow, FlowData}; use layout::model::{MaybeAuto}; use layout::float_context::{FloatContext, PlacementInfo, FloatType}; @@ -226,20 +225,33 @@ impl FloatFlowData { pub fn build_display_list_float(@mut self, builder: &DisplayListBuilder, dirty: &Rect, - offset: &Point2D, - list: &Cell>) { + list: &Cell>) + -> bool { - let offset = *offset + self.rel_pos; + let abs_rect = Rect(self.common.abs_position, self.common.position.size); + if !abs_rect.intersects(dirty) { + return false; + } + + + let offset = self.common.abs_position + self.rel_pos; + // add box that starts block context self.box.map(|&box| { box.build_display_list(builder, dirty, &offset, list) }); + // TODO: handle any out-of-flow elements + // go deeper into the flow tree let flow = FloatFlow(self); for flow.each_child |child| { - flow.build_display_list_for_child(builder, child, dirty, &offset, list) + do child.with_mut_base |base| { + base.abs_position = offset; + } } + + true } } diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs index d6bc65d73c0..d0da205275a 100644 --- a/src/components/main/layout/flow.rs +++ b/src/components/main/layout/flow.rs @@ -80,6 +80,19 @@ impl FlowContext { InlineFlow(data) => data.teardown() } } + + /// Like traverse_preorder, but don't end the whole traversal if the callback + /// returns false. + fn partially_traverse_preorder(&self, callback: &fn(FlowContext) -> bool) { + if !callback((*self).clone()) { + return; + } + + for self.each_child |kid| { + // FIXME: Work around rust#2202. We should be able to pass the callback directly. + kid.partially_traverse_preorder(|a| callback(a)); + } + } } impl FlowData { @@ -162,6 +175,7 @@ pub struct FlowData { floats_in: FloatContext, floats_out: FloatContext, num_floats: uint, + abs_position: Point2D } impl TreeNode for FlowData { @@ -225,6 +239,7 @@ impl FlowData { floats_in: Invalid, floats_out: Invalid, num_floats: 0, + abs_position: Point2D(Au(0), Au(0)) } } } @@ -296,21 +311,22 @@ impl<'self> FlowContext { } } - pub fn build_display_list_recurse(&self, - builder: &DisplayListBuilder, - dirty: &Rect, - offset: &Point2D, - list: &Cell>) { - do self.with_base |info| { - debug!("FlowContext::build_display_list at %?: %s", info.position, self.debug_str()); + pub fn build_display_list(&self, + builder: &DisplayListBuilder, + dirty: &Rect, + list: &Cell>) + -> bool { + + + match *self { + BlockFlow(info) => info.build_display_list_block(builder, dirty, list), + InlineFlow(info) => info.build_display_list_inline(builder, dirty, list), + FloatFlow(info) => info.build_display_list_float(builder, dirty, list), + _ => { + fail!("Tried to build_display_list_recurse of flow: %?", self) + } } - match *self { - BlockFlow(info) => info.build_display_list_block(builder, dirty, offset, list), - InlineFlow(info) => info.build_display_list_inline(builder, dirty, offset, list), - FloatFlow(info) => info.build_display_list_float(builder, dirty, offset, list), - _ => fail!(fmt!("Tried to build_display_list_recurse of flow: %?", self)) - } } // Actual methods that do not require much flow-specific logic diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs index 16ad686e14e..9d8f5cfbb4f 100644 --- a/src/components/main/layout/inline.rs +++ b/src/components/main/layout/inline.rs @@ -745,8 +745,14 @@ impl InlineFlowData { pub fn build_display_list_inline(&self, builder: &DisplayListBuilder, dirty: &Rect, - offset: &Point2D, - list: &Cell>) { + list: &Cell>) + -> bool { + + let abs_rect = Rect(self.common.abs_position, self.common.position.size); + if !abs_rect.intersects(dirty) { + return false; + } + // TODO(#228): Once we form line boxes and have their cached bounds, we can be smarter and // not recurse on a line if nothing in it can intersect the dirty region. debug!("FlowContext[%d]: building display list for %u inline boxes", @@ -754,11 +760,12 @@ impl InlineFlowData { self.boxes.len()); for self.boxes.iter().advance |box| { - box.build_display_list(builder, dirty, offset, list) + box.build_display_list(builder, dirty, &self.common.abs_position, list) } // TODO(#225): Should `inline-block` elements have flows as children of the inline flow or // should the flow be nested inside the box somehow? + true } } diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 0f93798af10..5d0a78d6b94 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -11,7 +11,7 @@ use layout::aux::{LayoutData, LayoutAuxMethods}; use layout::box::RenderBox; use layout::box_builder::LayoutTreeBuilder; use layout::context::LayoutContext; -use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods}; +use layout::display_list_builder::{DisplayListBuilder}; use layout::flow::FlowContext; use std::cast::transmute; @@ -241,7 +241,9 @@ impl LayoutTask { // TODO: Set options on the builder before building. // TODO: Be smarter about what needs painting. - layout_root.build_display_list(&builder, &layout_root.position(), display_list); + for layout_root.traverse_preorder |flow| { + flow.build_display_list(&builder, &layout_root.position(), display_list); + } let root_size = do layout_root.with_base |base| { base.position.size