Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor flow #416

Merged
merged 12 commits into from May 7, 2013

layout: Port the flow tree over to the new generic tree functions

  • Loading branch information
pcwalton committed May 7, 2013
commit fe36f1dccbbf1e5978057fbf10671c3a529457d4
@@ -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.
@@ -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<FlowContext>,
@@ -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,
@@ -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<FlowData> for FlowContext {
fn with_immutable_node<R>(&self, callback: &fn(&FlowData) -> R) -> R {
self.with_common_imm_info(callback)
}
fn with_mutable_node<R>(&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<Au>,
}

impl TreeNode<FlowContext> for FlowData {
fn parent_node(&self) -> Option<FlowContext> {
self.parent
}

fn first_child(&self) -> Option<FlowContext> {
self.first_child
}

fn last_child(&self) -> Option<FlowContext> {
self.last_child
}

fn prev_sibling(&self) -> Option<FlowContext> {
self.prev_sibling
}

fn next_sibling(&self) -> Option<FlowContext> {
self.next_sibling
}

fn set_parent_node(&mut self, new_parent_node: Option<FlowContext>) {
self.parent = new_parent_node
}

fn set_first_child(&mut self, new_first_child: Option<FlowContext>) {
self.first_child = new_first_child
}

fn set_last_child(&mut self, new_last_child: Option<FlowContext>) {
self.last_child = new_last_child
}

fn set_prev_sibling(&mut self, new_prev_sibling: Option<FlowContext>) {
self.prev_sibling = new_prev_sibling
}

fn set_next_sibling(&mut self, new_next_sibling: Option<FlowContext>) {
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<R>(&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<R>(&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,
@@ -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<Msg>;
@@ -165,33 +165,37 @@ 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());
debug!("layout: damage is %?", data.damage);
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,
doc_url: doc_url,
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<LayoutQueryResponse>) {
/// 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<LayoutQueryResponse>) {
match query {
ContentBox(node) => {
let response = match node.layout_data().flow {
@@ -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,

This file was deleted.

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.