diff --git a/src/servo/layout/block.rs b/src/servo/layout/block.rs index 6d4cda5b31d..43864617714 100644 --- a/src/servo/layout/block.rs +++ b/src/servo/layout/block.rs @@ -16,6 +16,7 @@ use geom::point::Point2D; use geom::rect::Rect; use gfx::display_list::DisplayList; use gfx::geometry::Au; +use servo_util::tree::TreeUtils; pub struct BlockFlowData { /// Data common to all flows. diff --git a/src/servo/layout/box_builder.rs b/src/servo/layout/box_builder.rs index 8bc838b18d1..f7638e07c5d 100644 --- a/src/servo/layout/box_builder.rs +++ b/src/servo/layout/box_builder.rs @@ -19,6 +19,7 @@ use gfx::image::holder::ImageHolder; use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock}; use newcss::values::{CSSDisplayNone}; use servo_util::range::Range; +use servo_util::tree::TreeUtils; pub struct LayoutTreeBuilder { root_flow: Option, @@ -121,7 +122,6 @@ impl BoxGenerator { // depending on flow, make a box for this node. match self.flow { InlineFlow(inline) => { - use servo_util::tree::TreeUtils; // For `is_leaf()`. let mut inline = &mut *inline; let node_range_start = inline.boxes.len(); @@ -338,12 +338,8 @@ pub impl LayoutTreeBuilder { debug!("point b: %s", cur_node.debug_str()); // recurse on child nodes. - { - use servo_util::tree::TreeUtils; // For `each_child()`. - - for cur_node.each_child |child_node| { - self.construct_recursively(layout_ctx, child_node, &mut this_ctx); - } + for cur_node.each_child |child_node| { + self.construct_recursively(layout_ctx, child_node, &mut this_ctx); } this_ctx.default_collector.pop_node(layout_ctx, self, cur_node); @@ -354,6 +350,7 @@ pub impl LayoutTreeBuilder { // eventually be elided or split, but the mapping between // nodes and FlowContexts should not change during layout. let flow = &mut this_ctx.default_collector.flow; + let flow: &FlowContext = flow; for flow.each_child |child_flow| { do child_flow.with_common_info |child_flow_info| { let node = child_flow_info.node; @@ -379,6 +376,7 @@ pub impl LayoutTreeBuilder { let mut found_child_block = false; let flow = &mut parent_ctx.default_collector.flow; + let flow: &FlowContext = flow; for flow.each_child |child_ctx| { match child_ctx { InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true, diff --git a/src/servo/layout/flow.rs b/src/servo/layout/flow.rs index 67e9dc31964..6086b974660 100644 --- a/src/servo/layout/flow.rs +++ b/src/servo/layout/flow.rs @@ -41,6 +41,7 @@ use geom::point::Point2D; use geom::rect::Rect; use gfx::display_list::DisplayList; use gfx::geometry::Au; +use servo_util::tree::{TreeNode, TreeNodeRef, TreeUtils}; /// The type of the formatting context and data specific to each context, such as line box /// structures or float lists. @@ -64,6 +65,21 @@ pub enum FlowContextType { Flow_Table } +impl Clone for FlowContext { + fn clone(&self) -> FlowContext { + *self + } +} + +impl TreeNodeRef for FlowContext { + fn with_immutable_node(&self, callback: &fn(&FlowData) -> R) -> R { + self.with_common_imm_info(callback) + } + fn with_mutable_node(&self, callback: &fn(&mut FlowData) -> R) -> R { + self.with_common_info(callback) + } +} + /// Data common to all flows. /// /// FIXME: We need a naming convention for pseudo-inheritance like this. How about @@ -88,6 +104,48 @@ pub struct FlowData { position: Rect, } +impl TreeNode for FlowData { + fn parent_node(&self) -> Option { + self.parent + } + + fn first_child(&self) -> Option { + self.first_child + } + + fn last_child(&self) -> Option { + self.last_child + } + + fn prev_sibling(&self) -> Option { + self.prev_sibling + } + + fn next_sibling(&self) -> Option { + self.next_sibling + } + + fn set_parent_node(&mut self, new_parent_node: Option) { + self.parent = new_parent_node + } + + fn set_first_child(&mut self, new_first_child: Option) { + self.first_child = new_first_child + } + + fn set_last_child(&mut self, new_last_child: Option) { + self.last_child = new_last_child + } + + fn set_prev_sibling(&mut self, new_prev_sibling: Option) { + self.prev_sibling = new_prev_sibling + } + + fn set_next_sibling(&mut self, new_next_sibling: Option) { + self.next_sibling = new_next_sibling + } +} + impl FlowData { pub fn new(id: int, node: AbstractNode) -> FlowData { FlowData { @@ -109,6 +167,30 @@ impl FlowData { } impl<'self> FlowContext { + // FIXME: This method is a duplicate of `with_immutable_node`; fix this. + #[inline(always)] + pub fn with_common_imm_info(&self, block: &fn(&FlowData) -> R) -> R { + match *self { + AbsoluteFlow(info) => block(info), + BlockFlow(info) => { + let info = &*info; // FIXME: Borrow check workaround. + block(&info.common) + } + FloatFlow(info) => block(info), + InlineBlockFlow(info) => block(info), + InlineFlow(info) => { + let info = &*info; // FIXME: Borrow check workaround. + block(&info.common) + } + RootFlow(info) => { + let info = &*info; // FIXME: Borrow check workaround. + block(&info.common) + } + TableFlow(info) => block(info), + } + } + + // FIXME: This method is a duplicate of `with_mutable_node`; fix this. #[inline(always)] pub fn with_common_info(&self, block: &fn(&mut FlowData) -> R) -> R { match *self { @@ -145,87 +227,6 @@ impl<'self> FlowContext { } } - /// Iterates over the immediate children of this flow. - /// - /// TODO: Fold me into `util::tree`. - pub fn each_child(&self, f: &fn(FlowContext) -> bool) { - let mut current_opt = self.with_common_info(|info| info.first_child); - while !current_opt.is_none() { - let current = current_opt.get(); - if !f(current) { - break; - } - current_opt = current.with_common_info(|info| info.next_sibling); - } - } - - /// Adds the given flow to the end of the list of this flow's children. The new child must be - /// detached from the tree before calling this method. - /// - /// TODO: Fold me into `util::tree`. - pub fn add_child(&self, child: FlowContext) { - do self.with_common_info |self_info| { - do child.with_common_info |child_info| { - assert!(child_info.parent.is_none()); - assert!(child_info.prev_sibling.is_none()); - assert!(child_info.next_sibling.is_none()); - - match self_info.last_child { - None => { - self_info.first_child = Some(child); - } - Some(last_child) => { - do last_child.with_common_info |last_child_info| { - assert!(last_child_info.next_sibling.is_none()); - last_child_info.next_sibling = Some(child); - child_info.prev_sibling = Some(last_child); - } - } - } - - self_info.last_child = Some(child); - child_info.parent = Some(*self); - } - } - } - - /// Removes the given flow from the tree. - /// - /// TODO: Fold me into `util::tree`. - pub fn remove_child(&self, child: FlowContext) { - do self.with_common_info |self_info| { - do child.with_common_info |child_info| { - assert!(child_info.parent.is_some()); - - match child_info.prev_sibling { - None => self_info.first_child = child_info.next_sibling, - Some(prev_sibling) => { - do prev_sibling.with_common_info |prev_sibling_info| { - prev_sibling_info.next_sibling = child_info.next_sibling; - child_info.prev_sibling = None; - } - } - } - - match child_info.next_sibling { - None => { - do child.with_common_info |child_info| { - self_info.last_child = child_info.prev_sibling; - } - } - Some(next_sibling) => { - do next_sibling.with_common_info |next_sibling_info| { - next_sibling_info.prev_sibling = Some(next_sibling); - child_info.next_sibling = None; - } - } - } - - child_info.parent = None; - } - } - } - pub fn inline(&self) -> @mut InlineFlowData { match *self { InlineFlow(info) => info, diff --git a/src/servo/layout/layout_task.rs b/src/servo/layout/layout_task.rs index c8f7bf23708..c445c7fdbb2 100644 --- a/src/servo/layout/layout_task.rs +++ b/src/servo/layout/layout_task.rs @@ -15,7 +15,6 @@ use layout::context::LayoutContext; use layout::debug::{BoxedMutDebugMethods, DebugMethods}; use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods}; use layout::flow::FlowContext; -use layout::traverse::*; use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg}; use resource::local_image_cache::LocalImageCache; use util::task::spawn_listener; @@ -35,6 +34,7 @@ use gfx::render_task::{RenderMsg, RenderTask}; use newcss::select::SelectCtx; use newcss::stylesheet::Stylesheet; use newcss::types::OriginAuthor; +use servo_util::tree::TreeUtils; use std::net::url::Url; pub type LayoutTask = SharedChan; @@ -165,11 +165,12 @@ impl Layout { self.css_select_ctx.append_sheet(sheet.take(), OriginAuthor); } + /// The high-level routine that performs layout tasks. fn handle_build(&mut self, data: &BuildData) { let node = &data.node; - // FIXME: Bad copy + // FIXME: Bad copy! let doc_url = copy data.url; - // FIXME: Bad clone + // FIXME: Bad clone! let dom_event_chan = data.dom_event_chan.clone(); debug!("layout: received layout request for: %s", doc_url.to_str()); @@ -177,12 +178,13 @@ impl Layout { debug!("layout: parsed Node tree"); debug!("%?", node.dump()); - // Reset the image cache + // Reset the image cache. self.local_image_cache.next_round(self.make_on_image_available_cb(dom_event_chan)); let screen_size = Size2D(Au::from_px(data.window_size.width as int), Au::from_px(data.window_size.height as int)); + // Create a layout context for use throughout the following passes. let mut layout_ctx = LayoutContext { image_cache: self.local_image_cache, font_ctx: self.font_ctx, @@ -190,8 +192,10 @@ impl Layout { screen_size: Rect(Point2D(Au(0), Au(0)), screen_size) }; + // Initialize layout data for each node. + // + // FIXME: This is inefficient. We don't need an entire traversal to do this! do time("layout: aux initialization") { - // TODO: this is dumb. we don't need an entire traversal to do this node.initialize_style_for_subtree(&mut self.layout_refs); } @@ -205,6 +209,7 @@ impl Layout { } } + // Construct the flow tree. let layout_root: FlowContext = do time("layout: tree construction") { let mut builder = LayoutTreeBuilder::new(); let layout_root: FlowContext = match builder.construct_trees(&layout_ctx, *node) { @@ -218,13 +223,21 @@ impl Layout { layout_root }; + // Perform the primary layout passes over the flow tree to compute the locations of all + // the boxes. do time("layout: main layout") { - /* perform layout passes over the flow tree */ - do layout_root.traverse_postorder |f| { f.bubble_widths(&mut layout_ctx) } - do layout_root.traverse_preorder |f| { f.assign_widths(&mut layout_ctx) } - do layout_root.traverse_postorder |f| { f.assign_height(&mut layout_ctx) } + for layout_root.traverse_postorder |flow| { + flow.bubble_widths(&mut layout_ctx); + }; + for layout_root.traverse_preorder |flow| { + flow.assign_widths(&mut layout_ctx); + }; + for layout_root.traverse_postorder |flow| { + flow.assign_height(&mut layout_ctx); + }; } + // Build the display list, and send it to the renderer. do time("layout: display list building") { let builder = DisplayListBuilder { ctx: &layout_ctx, @@ -249,13 +262,13 @@ impl Layout { self.render_task.send(RenderMsg(render_layer)); } // time(layout: display list building) - // Tell content we're done + // Tell content that we're done. data.content_join_chan.send(()); } - - fn handle_query(&self, query: LayoutQuery, - reply_chan: Chan) { + /// Handles a query from the script task. This is the main routine that DOM functions like + /// `getClientRects()` or `getBoundingClientRect()` ultimately invoke. + fn handle_query(&self, query: LayoutQuery, reply_chan: Chan) { match query { ContentBox(node) => { let response = match node.layout_data().flow { diff --git a/src/servo/layout/root.rs b/src/servo/layout/root.rs index d74d8bb345b..46abe8489c6 100644 --- a/src/servo/layout/root.rs +++ b/src/servo/layout/root.rs @@ -13,6 +13,8 @@ use layout::context::LayoutContext; use layout::flow::{FlowContext, FlowData, RootFlow}; use layout::display_list_builder::DisplayListBuilder; +use servo_util::tree::TreeUtils; + pub struct RootFlowData { /// Data common to all flows. common: FlowData, diff --git a/src/servo/layout/traverse.rs b/src/servo/layout/traverse.rs deleted file mode 100644 index d242bcae4f5..00000000000 --- a/src/servo/layout/traverse.rs +++ /dev/null @@ -1,27 +0,0 @@ -/* 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/. */ - -use layout::flow::FlowContext; - -/// A trait for running tree-based traversals over flows contexts. -pub trait FlowContextTraversals { - fn traverse_preorder(&self, preorder_cb: &fn(FlowContext)); - fn traverse_postorder(&self, postorder_cb: &fn(FlowContext)); -} - -impl FlowContextTraversals for FlowContext { - fn traverse_preorder(&self, preorder_cb: &fn(FlowContext)) { - preorder_cb(*self); - for self.each_child |child| { - child.traverse_preorder(preorder_cb); - } - } - - fn traverse_postorder(&self, postorder_cb: &fn(FlowContext)) { - for self.each_child |child| { - child.traverse_postorder(postorder_cb); - } - postorder_cb(*self); - } -} diff --git a/src/servo/servo.rc b/src/servo/servo.rc index b2d6424cdae..d2d749d8c70 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -104,7 +104,6 @@ pub mod layout { pub mod inline; pub mod root; pub mod text; - pub mod traverse; mod aux; }