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) } 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 { fn set_aux(p: @A) unsafe {
let p2 = p;
unsafe::forget(p2); // Bump the reference count.
(**self).rd_aux = ptr::addr_of(*p); (**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 { impl layout_methods for @box {
#[doc="The main reflow routine."] #[doc="The main reflow routine."]
fn reflow(available_width: au) { fn reflow(available_width: au) {
@ -77,6 +93,36 @@ impl layout_methods for @box {
#debug["reflow_intrinsic size=%?", self.bounds]; #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)] #[cfg(test)]

View file

@ -3,13 +3,27 @@
import dom::base::{nk_div, nk_img, node}; import dom::base::{nk_div, nk_img, node};
import dom::rcu::reader_methods; import dom::rcu::reader_methods;
import gfx::geom; import gfx::geom;
import /*layout::*/base::{bk_block, bk_intrinsic, box, box_kind, btree, ntree}; import /*layout::*/base::{bk_block, bk_inline, bk_intrinsic, box, box_kind};
import /*layout::*/base::{rd_tree_ops, wr_tree_ops}; import /*layout::*/base::{btree, node_methods, ntree, rd_tree_ops};
import /*layout::*/style::style::{di_block, di_inline}; import /*layout::*/base::wr_tree_ops;
import /*layout::*/style::style::{di_block, di_inline, style_methods};
import util::tree; import util::tree;
export box_builder_methods; 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 { fn new_box(n: node, kind: box_kind) -> @box {
@box({tree: tree::empty(), @box({tree: tree::empty(),
node: n, node: n,
@ -17,13 +31,87 @@ fn new_box(n: node, kind: box_kind) -> @box {
kind: kind }) kind: kind })
} }
impl box_builder_priv_methods for node { fn create_context(parent_node: node, parent_box: @box) -> ctxt {
fn construct_boxes() -> @box { ret ctxt({
let b = new_box(self, self.determine_box_kind()); parent_node: parent_node,
self.aux::<()>({ |a| a.box = some(b); }); parent_box: parent_box,
ret b; 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=" #[doc="
Determines the kind of box that this node needs. Also, for images, Determines the kind of box that this node needs. Also, for images,
computes the intrinsic size. computes the intrinsic size.
@ -37,15 +125,15 @@ impl box_builder_priv_methods for node {
} }
impl box_builder_methods for node { impl box_builder_methods for node {
#[doc="Creates boxes for a subtree. This is the entry point."] #[doc="Creates boxes for this node. This is the entry point."]
fn construct_boxes_for_subtree() -> @box { fn construct_boxes() -> @box {
let p_box = self.construct_boxes(); let box_kind = self.determine_box_kind();
for ntree.each_child(self) { let my_box = new_box(self, box_kind);
|c| if box_kind == bk_block {
let c_box = c.construct_boxes_for_subtree(); let cx = create_context(self, my_box);
btree.add_child(p_box, c_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 gfx::renderer;
import dom::base::node; import dom::base::node;
import dom::rcu::scope; import dom::rcu::scope;
import /*layout::*/base::*;
import /*layout::*/style::style::style_methods; import /*layout::*/style::style::style_methods;
import base::*;
import box_builder::box_builder_methods; import box_builder::box_builder_methods;
import dl = display_list; import dl = display_list;
@ -29,9 +29,14 @@ fn layout(to_renderer: chan<renderer::msg>) -> chan<msg> {
ping(ch) { ch.send(content::pong); } ping(ch) { ch.send(content::pong); }
exit { break; } exit { break; }
build(node) { build(node) {
#debug("layout: received layout request"); #debug("layout: received layout request for:");
node.dump();
node.recompute_style_for_subtree(); 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)); this_box.reflow(geom::px_to_au(800));
let dlist = build_display_list(this_box); let dlist = build_display_list(this_box);
to_renderer.send(renderer::render(dlist)); to_renderer.send(renderer::render(dlist));

View file

@ -32,10 +32,17 @@ impl style_priv for node {
fn recompute_style() { fn recompute_style() {
let default_style: computed_style = let default_style: computed_style =
default_style_for_node_kind(self.rd { |n| n.kind }); default_style_for_node_kind(self.rd { |n| n.kind });
#debug("recomputing style; parent node:");
self.dump();
let the_layout_data = @layout_data({ let the_layout_data = @layout_data({
mut computed_style: default_style, mut computed_style: default_style,
mut box: none mut box: none
}); });
#debug("layout data: %?", the_layout_data);
self.set_aux(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>