Skip to content

Commit

Permalink
Implement toy inline layout
Browse files Browse the repository at this point in the history
  • Loading branch information
pcwalton committed May 17, 2012
1 parent 1cab10d commit dccee99
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/servo/dom/base.rs
Expand Up @@ -52,3 +52,4 @@ impl of tree::wr_tree_ops<node> for node_scope {
self.wr(node) { |n| f(n.tree) }
}
}

3 changes: 3 additions & 0 deletions src/servo/dom/rcu.rs
Expand Up @@ -52,6 +52,9 @@ impl reader_methods<T:send,A> for handle<T,A> {
}

fn set_aux(p: @A) unsafe {
let p2 = p;
unsafe::forget(p2); // Bump the reference count.

(**self).rd_aux = ptr::addr_of(*p);
}

Expand Down
46 changes: 46 additions & 0 deletions src/servo/layout/base.rs
Expand Up @@ -61,6 +61,22 @@ impl of tree::wr_tree_ops<@box> for btree {
}
}

impl layout_methods_priv for @box {
#[doc="Dumps the box tree, for debugging, with indentation."]
fn dump_indent(indent: uint) {
let mut s = "";
uint::range(0u, indent) {
|_i|
s += " ";
}

s += #fmt("%?", self.kind);
#debug["%s", s];

for btree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
}
}

impl layout_methods for @box {
#[doc="The main reflow routine."]
fn reflow(available_width: au) {
Expand All @@ -77,6 +93,36 @@ impl layout_methods for @box {

#debug["reflow_intrinsic size=%?", self.bounds];
}

#[doc="Dumps the box tree, for debugging."]
fn dump() {
self.dump_indent(0u);
}
}

// Debugging

impl node_methods_priv for node {
#[doc="Dumps the node tree, for debugging, with indentation."]
fn dump_indent(indent: uint) {
let mut s = "";
uint::range(0u, indent) {
|_i|
s += " ";
}

s += #fmt("%?", self.rd({ |n| n.kind }));
#debug["%s", s];

for ntree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
}
}

impl node_methods for node {
#[doc="Dumps the subtree rooted at this node, for debugging."]
fn dump() {
self.dump_indent(0u);
}
}

#[cfg(test)]
Expand Down
120 changes: 104 additions & 16 deletions src/servo/layout/box_builder.rs
Expand Up @@ -3,27 +3,115 @@
import dom::base::{nk_div, nk_img, node};
import dom::rcu::reader_methods;
import gfx::geom;
import /*layout::*/base::{bk_block, bk_intrinsic, box, box_kind, btree, ntree};
import /*layout::*/base::{rd_tree_ops, wr_tree_ops};
import /*layout::*/style::style::{di_block, di_inline};
import /*layout::*/base::{bk_block, bk_inline, bk_intrinsic, box, box_kind};
import /*layout::*/base::{btree, node_methods, ntree, rd_tree_ops};
import /*layout::*/base::wr_tree_ops;
import /*layout::*/style::style::{di_block, di_inline, style_methods};
import util::tree;

export box_builder_methods;

enum ctxt = {
// The parent node that we're scanning.
parent_node: node,
// The parent box that these boxes will be added to.
parent_box: @box,

// The current anonymous box that we're currently appending inline nodes
// to.
//
// See CSS2 9.2.1.1.
mut anon_box: option<@box>
};

fn new_box(n: node, kind: box_kind) -> @box {
@box({tree: tree::empty(),
node: n,
mut bounds: geom::zero_rect_au(),
kind: kind })
}

impl box_builder_priv_methods for node {
fn construct_boxes() -> @box {
let b = new_box(self, self.determine_box_kind());
self.aux::<()>({ |a| a.box = some(b); });
ret b;
fn create_context(parent_node: node, parent_box: @box) -> ctxt {
ret ctxt({
parent_node: parent_node,
parent_box: parent_box,
mut anon_box: none
});
}

impl methods for ctxt {
#[doc="
Constructs boxes for the parent's children, when the parent's 'display'
attribute is 'block'.
"]
fn construct_boxes_for_block_children() {
for ntree.each_child(self.parent_node) {
|kid|

// Create boxes for the child. Get its primary box.
let kid_box = kid.construct_boxes();

// Determine the child's display.
let disp = kid.get_computed_style().display;
if disp != di_inline {
self.finish_anonymous_box_if_necessary();
}

// Add the child's box to the current enclosing box or the current
// anonymous box.
alt kid.get_computed_style().display {
di_block { btree.add_child(self.parent_box, kid_box); }
di_inline {
let anon_box = alt self.anon_box {
none {
let b = new_box(kid, bk_inline);
self.anon_box = some(b);
b
}
some(b) { b }
};
btree.add_child(anon_box, kid_box);
}
}
}
}

#[doc="
Constructs boxes for the parent's children, when the parent's 'display'
attribute is 'inline'.
"]
fn construct_boxes_for_inline_children() {
// TODO
}

#[doc="Constructs boxes for the parent's children."]
fn construct_boxes_for_children() {
#debug("parent node:");
self.parent_node.dump();

alt self.parent_node.get_computed_style().display {
di_block { self.construct_boxes_for_block_children(); }
di_inline { self.construct_boxes_for_inline_children(); }
}

self.finish_anonymous_box_if_necessary();
assert self.anon_box.is_none();
}

#[doc="
Flushes the anonymous box we're creating if it exists. This appends the
anonymous box to the block.
"]
fn finish_anonymous_box_if_necessary() {
alt self.anon_box {
none { /* Nothing to do. */ }
some(b) { btree.add_child(self.parent_box, b); }
}
self.anon_box = none;
}
}

impl box_builder_priv for node {
#[doc="
Determines the kind of box that this node needs. Also, for images,
computes the intrinsic size.
Expand All @@ -37,15 +125,15 @@ impl box_builder_priv_methods for node {
}

impl box_builder_methods for node {
#[doc="Creates boxes for a subtree. This is the entry point."]
fn construct_boxes_for_subtree() -> @box {
let p_box = self.construct_boxes();
for ntree.each_child(self) {
|c|
let c_box = c.construct_boxes_for_subtree();
btree.add_child(p_box, c_box);
#[doc="Creates boxes for this node. This is the entry point."]
fn construct_boxes() -> @box {
let box_kind = self.determine_box_kind();
let my_box = new_box(self, box_kind);
if box_kind == bk_block {
let cx = create_context(self, my_box);
cx.construct_boxes_for_children();
}
ret p_box;
ret my_box;
}
}

11 changes: 8 additions & 3 deletions src/servo/layout/layout.rs
Expand Up @@ -11,8 +11,8 @@ import gfx::geom;
import gfx::renderer;
import dom::base::node;
import dom::rcu::scope;
import /*layout::*/base::*;
import /*layout::*/style::style::style_methods;
import base::*;
import box_builder::box_builder_methods;
import dl = display_list;

Expand All @@ -29,9 +29,14 @@ fn layout(to_renderer: chan<renderer::msg>) -> chan<msg> {
ping(ch) { ch.send(content::pong); }
exit { break; }
build(node) {
#debug("layout: received layout request");
#debug("layout: received layout request for:");
node.dump();

node.recompute_style_for_subtree();
let this_box = node.construct_boxes_for_subtree();

let this_box = node.construct_boxes();
this_box.dump();

this_box.reflow(geom::px_to_au(800));
let dlist = build_display_list(this_box);
to_renderer.send(renderer::render(dlist));
Expand Down
7 changes: 7 additions & 0 deletions src/servo/layout/style/style.rs
Expand Up @@ -32,10 +32,17 @@ impl style_priv for node {
fn recompute_style() {
let default_style: computed_style =
default_style_for_node_kind(self.rd { |n| n.kind });

#debug("recomputing style; parent node:");
self.dump();

let the_layout_data = @layout_data({
mut computed_style: default_style,
mut box: none
});

#debug("layout data: %?", the_layout_data);

self.set_aux(the_layout_data);
}
}
Expand Down
6 changes: 6 additions & 0 deletions test-inline.html
@@ -0,0 +1,6 @@
<div>
<img></img>
<div>
<img></img><img></img><img></img>
</div>
</div>

0 comments on commit dccee99

Please sign in to comment.