Implement toy inline layout

This commit is contained in:
Patrick Walton 2012-05-17 12:27:11 -07:00
parent 1cab10d8ba
commit dccee997e8
7 changed files with 175 additions and 19 deletions

View file

@ -52,3 +52,4 @@ impl of tree::wr_tree_ops<node> for node_scope {
self.wr(node) { |n| f(n.tree) }
}
}

View file

@ -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);
}

View file

@ -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) {
@ -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)]

View file

@ -3,13 +3,27 @@
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,
@ -17,13 +31,87 @@ fn new_box(n: node, kind: box_kind) -> @box {
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.
@ -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;
}
}

View file

@ -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;
@ -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));

View file

@ -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);
}
}

6
test-inline.html Normal file
View file

@ -0,0 +1,6 @@
<div>
<img></img>
<div>
<img></img><img></img><img></img>
</div>
</div>