mirror of
https://github.com/servo/servo.git
synced 2025-08-09 07:25:35 +01:00
Add comments on overall design; move display list building to Flows and Boxes; create a DisplayListBuilder context; rename Box to RenderBox
This commit is contained in:
parent
4e9e679547
commit
da7ae8a280
14 changed files with 362 additions and 195 deletions
|
@ -1 +1 @@
|
|||
Subproject commit e1ec99049c193aaedbb603e4ceb675251e5814b3
|
||||
Subproject commit 01de30b15bfb3ecdfb921b7571ff98e63c0d4483
|
|
@ -1,7 +1,7 @@
|
|||
#[doc="Applies the appropriate CSS style to boxes."]
|
||||
|
||||
use au = gfx::geometry;
|
||||
use layout::base::{Box, SpecifiedStyle, BoxTree};
|
||||
use layout::base::{RenderBox, SpecifiedStyle, RenderBoxTree};
|
||||
use layout::context::LayoutContext;
|
||||
use layout::traverse_parallel::top_down_traversal;
|
||||
use image::ImageHolder;
|
||||
|
@ -32,12 +32,12 @@ impl CSSValue<CSSFontSize> : ResolveMethods<CSSFontSize> {
|
|||
|
||||
|
||||
struct StyleApplicator {
|
||||
box: @Box,
|
||||
box: @RenderBox,
|
||||
reflow: fn~(),
|
||||
}
|
||||
|
||||
// TODO: normalize this into a normal preorder tree traversal function
|
||||
fn apply_style(layout_ctx: &LayoutContext, box: @Box, reflow: fn~()) {
|
||||
fn apply_style(layout_ctx: &LayoutContext, box: @RenderBox, reflow: fn~()) {
|
||||
let applicator = StyleApplicator {
|
||||
box: box,
|
||||
reflow: reflow
|
||||
|
@ -50,7 +50,7 @@ fn apply_style(layout_ctx: &LayoutContext, box: @Box, reflow: fn~()) {
|
|||
|
||||
#[doc="A wrapper around a set of functions that can be applied as a top-down traversal of layout
|
||||
boxes."]
|
||||
fn inheritance_wrapper(layout_ctx: &LayoutContext, box : @Box, reflow: fn~()) {
|
||||
fn inheritance_wrapper(layout_ctx: &LayoutContext, box : @RenderBox, reflow: fn~()) {
|
||||
let applicator = StyleApplicator {
|
||||
box: box,
|
||||
reflow: reflow
|
||||
|
@ -59,12 +59,12 @@ fn inheritance_wrapper(layout_ctx: &LayoutContext, box : @Box, reflow: fn~()) {
|
|||
}
|
||||
|
||||
/*
|
||||
fn resolve_fontsize(box : @Box) {
|
||||
fn resolve_fontsize(box : @RenderBox) {
|
||||
// TODO: complete this
|
||||
return
|
||||
}
|
||||
|
||||
fn resolve_height(box : @Box) -> au {
|
||||
fn resolve_height(box : @RenderBox) -> au {
|
||||
let style = box.node.get_style();
|
||||
let inherit_val = match box.tree.parent {
|
||||
None => au(0),
|
||||
|
@ -81,7 +81,7 @@ fn resolve_height(box : @Box) -> au {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_width(box : @Box) {
|
||||
fn resolve_width(box : @RenderBox) {
|
||||
let style = box.node.get_specified_style();
|
||||
let inherit_val = match box.tree.parent {
|
||||
None => style.height.initial(),
|
||||
|
@ -102,7 +102,7 @@ impl StyleApplicator {
|
|||
fn apply_css_style(layout_ctx: &LayoutContext) {
|
||||
let reflow = copy self.reflow;
|
||||
|
||||
do BoxTree.each_child(self.box) |child| {
|
||||
do RenderBoxTree.each_child(self.box) |child| {
|
||||
inheritance_wrapper(layout_ctx, child, reflow); true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use js::glue::bindgen::RUST_OBJECT_TO_JSVAL;
|
|||
use js::jsapi::{JSClass, JSObject, JSPropertySpec, JSContext, jsid, jsval, JSBool};
|
||||
use js::rust::{bare_compartment, compartment, methods};
|
||||
use js::{JSPROP_ENUMERATE, JSPROP_SHARED};
|
||||
use layout::base::Box;
|
||||
use layout::base::RenderBox;
|
||||
use layout::debug::DebugMethods;
|
||||
use ptr::null;
|
||||
use std::arc::ARC;
|
||||
|
@ -193,12 +193,12 @@ enum ElementKind {
|
|||
|
||||
/** The RCU rd_aux data is a (weak) pointer to the layout data,
|
||||
defined by this `LayoutData` enum. It contains the CSS style object
|
||||
as well as the primary `Box`.
|
||||
as well as the primary `RenderBox`.
|
||||
|
||||
Note that there may be multiple boxes per DOM node. */
|
||||
enum LayoutData = {
|
||||
mut style: ~SpecifiedStyle,
|
||||
mut box: Option<@Box>
|
||||
mut box: Option<@RenderBox>
|
||||
};
|
||||
|
||||
type Node = rcu::Handle<NodeData, LayoutData>;
|
||||
|
|
|
@ -9,6 +9,8 @@ use std::arc::{ARC, clone};
|
|||
use dvec::DVec;
|
||||
use text::glyph::Glyph;
|
||||
|
||||
pub use layout::display_list_builder::DisplayListBuilder;
|
||||
|
||||
struct DisplayItem {
|
||||
draw: ~fn((&DisplayItem), (&RenderContext)),
|
||||
bounds : Rect<au>, // TODO: whose coordinate system should this use?
|
||||
|
@ -88,7 +90,7 @@ trait DisplayListMethods {
|
|||
impl DisplayList : DisplayListMethods {
|
||||
fn draw(ctx: &RenderContext) {
|
||||
for self.each |item| {
|
||||
debug!["drawing %?", item];
|
||||
debug!("drawing %?", item);
|
||||
item.draw(item, ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
/* Fundamental layout structures and algorithms. */
|
||||
|
||||
use arc = std::arc;
|
||||
use arc::ARC;
|
||||
use au = gfx::geometry;
|
||||
use au::au;
|
||||
use core::dvec::DVec;
|
||||
use core::to_str::ToStr;
|
||||
use core::rand;
|
||||
use css::styles::SpecifiedStyle;
|
||||
use css::values::{BoxSizing, Length, Px, CSSDisplay};
|
||||
use css::values::{BoxSizing, Length, Px, CSSDisplay, Specified, BgColor, BgTransparent};
|
||||
use dl = gfx::display_list;
|
||||
use dom::base::{Element, ElementKind, HTMLDivElement, HTMLImageElement};
|
||||
use dom::base::{Node, NodeData, NodeKind, NodeTree};
|
||||
use dom::rcu;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use gfx::geometry::au;
|
||||
use geom::point::Point2D;
|
||||
use image::{Image, ImageHolder};
|
||||
use layout::block::BlockFlowData;
|
||||
use layout::context::LayoutContext;
|
||||
|
@ -20,14 +24,73 @@ use layout::inline::InlineFlowData;
|
|||
use layout::root::RootFlowData;
|
||||
use layout::text::TextBoxData;
|
||||
use servo_text::text_run::TextRun;
|
||||
use std::arc::{ARC, clone};
|
||||
use std::net::url::Url;
|
||||
use task::spawn;
|
||||
use util::color::Color;
|
||||
use util::tree;
|
||||
use vec::{push, push_all};
|
||||
|
||||
|
||||
/** Servo's experimental layout system builds a tree of FlowContexts
|
||||
and RenderBoxes, and figures out positions and display attributes of
|
||||
tree nodes. Positions are computed in several tree traversals driven
|
||||
by fundamental data dependencies of inline and block layout.
|
||||
|
||||
Render boxes (`struct RenderBox`) are the leafs of the layout
|
||||
tree. They cannot position themselves. In general, render boxes do not
|
||||
have a simple correspondence with CSS boxes as in the specification:
|
||||
|
||||
* Several render boxes may correspond to the same CSS box or DOM
|
||||
node. For example, a CSS text box broken across two lines is
|
||||
represented by two render boxes.
|
||||
|
||||
* Some CSS boxes are not created at all, such as some anonymous block
|
||||
boxes induced by inline boxes with block-level sibling boxes. In
|
||||
that case, Servo uses an InlineFlow with BlockFlow siblings; the
|
||||
InlineFlow is block-level, but not a block container. It is
|
||||
positioned as if it were a block box, but its children are
|
||||
positioned according to inline flow.
|
||||
|
||||
Fundamental box types include:
|
||||
|
||||
* GenericBox: an empty box that contributes only borders, margins,
|
||||
padding, backgrounds. It is analogous to a CSS nonreplaced content box.
|
||||
|
||||
* ImageBox: a box that represents a (replaced content) image and its
|
||||
accompanying borders, shadows, etc.
|
||||
|
||||
* TextBox: a box representing a single run of text with a distinct
|
||||
style. A TextBox may be split into two or more render boxes across
|
||||
line breaks. Several TextBoxes may correspond to a single DOM text
|
||||
node. Split text boxes are implemented by referring to subsets of a
|
||||
master TextRun object.
|
||||
|
||||
|
||||
Flows (`struct FlowContext`) are interior nodes in the layout tree,
|
||||
and correspond closely to flow contexts in the CSS
|
||||
specification. Flows are responsible for positioning their child flow
|
||||
contexts and render boxes. Flows have purpose-specific fields, such as
|
||||
auxilliary line box structs, out-of-flow child lists, and so on.
|
||||
|
||||
Currently, the important types of flows are:
|
||||
|
||||
* BlockFlow: a flow that establishes a block context. It has several
|
||||
child flows, each of which are positioned according to block
|
||||
formatting context rules (as if child flows CSS block boxes). Block
|
||||
flows also contain a single GenericBox to represent their rendered
|
||||
borders, padding, etc. (In the future, this render box may be
|
||||
folded into BlockFlow to save space.)
|
||||
|
||||
* InlineFlow: a flow that establishes an inline context. It has a
|
||||
flat list of child boxes/flows that are subject to inline layout
|
||||
and line breaking, and structs to represent line breaks and mapping
|
||||
to CSS boxes, for the purpose of handling `getClientRects()`.
|
||||
|
||||
*/
|
||||
|
||||
struct FlowLayoutData {
|
||||
// TODO: min/pref and position are used during disjoint phases of
|
||||
// layout; maybe combine into a single enum to save space.
|
||||
mut min_width: au,
|
||||
mut pref_width: au,
|
||||
mut position: Rect<au>,
|
||||
|
@ -42,7 +105,7 @@ fn FlowLayoutData() -> FlowLayoutData {
|
|||
}
|
||||
|
||||
/* The type of the formatting context, and data specific to each
|
||||
context, such as lineboxes or float lists */
|
||||
context, such as linebox structures or float lists */
|
||||
enum FlowContextData {
|
||||
AbsoluteFlow,
|
||||
BlockFlow(BlockFlowData),
|
||||
|
@ -54,14 +117,7 @@ enum FlowContextData {
|
|||
}
|
||||
|
||||
/* A particular kind of layout context. It manages the positioning of
|
||||
layout boxes within the context.
|
||||
|
||||
Flow contexts form a tree that is induced by the structure of the
|
||||
box tree. Each context is responsible for laying out one or more
|
||||
boxes, according to the flow type. The number of flow contexts should
|
||||
be much fewer than the number of boxes. The context maintains a vector
|
||||
of its constituent boxes in their document order.
|
||||
*/
|
||||
render boxes within the context. */
|
||||
struct FlowContext {
|
||||
kind: FlowContextData,
|
||||
data: FlowLayoutData,
|
||||
|
@ -85,6 +141,8 @@ impl @FlowContext : cmp::Eq {
|
|||
pure fn ne(&&other: @FlowContext) -> bool { !box::ptr_eq(self, other) }
|
||||
}
|
||||
|
||||
|
||||
/* Flow context disambiguation methods: the verbose alternative to virtual methods */
|
||||
impl @FlowContext {
|
||||
fn bubble_widths(ctx: &LayoutContext) {
|
||||
match self.kind {
|
||||
|
@ -112,6 +170,16 @@ impl @FlowContext {
|
|||
_ => fail fmt!("Tried to assign_height of flow: %?", self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_recurse(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||
match self.kind {
|
||||
RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
|
||||
BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
|
||||
InlineFlow(*) => self.build_display_list_inline(builder, dirty, offset, list),
|
||||
_ => fail fmt!("Tried to build_display_list_recurse of flow: %?", self.kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The tree holding FlowContexts */
|
||||
|
@ -166,9 +234,9 @@ enum BoxData {
|
|||
TextBox(TextBoxData)
|
||||
}
|
||||
|
||||
struct Box {
|
||||
struct RenderBox {
|
||||
/* references to children, parent */
|
||||
tree : tree::Tree<@Box>,
|
||||
tree : tree::Tree<@RenderBox>,
|
||||
/* originating DOM node */
|
||||
node : Node,
|
||||
/* reference to containing flow context, which this box
|
||||
|
@ -182,8 +250,8 @@ struct Box {
|
|||
mut id: int
|
||||
}
|
||||
|
||||
fn Box(id: int, node: Node, ctx: @FlowContext, kind: BoxData) -> Box {
|
||||
Box {
|
||||
fn RenderBox(id: int, node: Node, ctx: @FlowContext, kind: BoxData) -> RenderBox {
|
||||
RenderBox {
|
||||
/* will be set when box is parented */
|
||||
tree : tree::empty(),
|
||||
node : node,
|
||||
|
@ -194,7 +262,7 @@ fn Box(id: int, node: Node, ctx: @FlowContext, kind: BoxData) -> Box {
|
|||
}
|
||||
}
|
||||
|
||||
impl @Box {
|
||||
impl @RenderBox {
|
||||
pure fn is_replaced() -> bool {
|
||||
match self.kind {
|
||||
ImageBox(*) => true, // TODO: form elements, etc
|
||||
|
@ -210,14 +278,12 @@ impl @Box {
|
|||
// FlowContext will combine the width of this element and
|
||||
// that of its children to arrive at the context width.
|
||||
GenericBox => au(0),
|
||||
// TODO: consult CSS 'width', margin, border.
|
||||
// TODO: If image isn't available, consult Node
|
||||
// attrs, etc. to determine intrinsic dimensions. These
|
||||
// dimensions are not defined by CSS 2.1, but are defined
|
||||
// by the HTML5 spec in Section 4.8.1
|
||||
ImageBox(size) => size.width,
|
||||
// TODO: account for line breaks, etc. The run should know
|
||||
// how to compute its own min and pref widths, and should
|
||||
// probably cache them.
|
||||
TextBox(d) => d.runs.foldl(au(0), |sum, run| {
|
||||
au::max(sum, run.min_break_width())
|
||||
})
|
||||
|
@ -282,30 +348,99 @@ impl @Box {
|
|||
|
||||
image
|
||||
}
|
||||
|
||||
// TODO: to implement stacking contexts correctly, we need to
|
||||
// create a set of display lists, one per each layer of a stacking
|
||||
// context. (CSS 2.1, Section 9.9.1). Each box is passed the list
|
||||
// set representing the box's stacking context. When asked to
|
||||
// construct its constituent display items, each box puts its
|
||||
// DisplayItems into the correct stack layer (according to CSS 2.1
|
||||
// Appendix E). and then builder flattens the list at the end.
|
||||
|
||||
/* Methods for building a display list. This is a good candidate
|
||||
for a function pointer as the number of boxes explodes.
|
||||
|
||||
# Arguments
|
||||
|
||||
* `builder` - the display list builder which manages the coordinate system and options.
|
||||
* `dirty` - Dirty rectangle, in the coordinate system of the owning flow (self.ctx)
|
||||
* `origin` - Total offset from display list root flow to this box's owning flow
|
||||
* `list` - List to which items should be appended
|
||||
*/
|
||||
fn build_display_list(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||
if !self.data.position.intersects(dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
let bounds : Rect<au> = Rect(self.data.position.origin.add(offset),
|
||||
copy self.data.position.size);
|
||||
|
||||
match self.kind {
|
||||
TextBox(d) => {
|
||||
let mut runs = d.runs;
|
||||
// TODO: don't paint background for text boxes
|
||||
list.push(~dl::SolidColor(bounds, 255u8, 255u8, 255u8));
|
||||
|
||||
let mut bounds = bounds;
|
||||
for uint::range(0, runs.len()) |i| {
|
||||
bounds.size.height = runs[i].size().height;
|
||||
let glyph_run = make_glyph_run(&runs[i]);
|
||||
list.push(~dl::Glyphs(bounds, glyph_run));
|
||||
bounds.origin.y += bounds.size.height;
|
||||
}
|
||||
return;
|
||||
|
||||
pure fn make_glyph_run(text_run: &TextRun) -> dl::GlyphRun {
|
||||
dl::GlyphRun {
|
||||
glyphs: copy text_run.glyphs
|
||||
}
|
||||
}
|
||||
},
|
||||
// TODO: items for background, border, outline
|
||||
GenericBox(*) => { },
|
||||
ImageBox(*) => {
|
||||
match self.get_image() {
|
||||
Some(image) => list.push(~dl::Image(bounds, image)),
|
||||
/* No image data at all? Okay, add some fallback content instead. */
|
||||
None => {
|
||||
// TODO: shouldn't need to unbox CSSValue by now
|
||||
let boxed_color = self.node.style().background_color;
|
||||
let color = match boxed_color {
|
||||
Specified(BgColor(c)) => c,
|
||||
Specified(BgTransparent) | _ => util::color::rgba(0,0,0,0.0)
|
||||
};
|
||||
list.push(~dl::SolidColor(bounds, color.red, color.green, color.blue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Why do these have to be redefined for each node type?
|
||||
|
||||
/* The tree holding boxes */
|
||||
enum BoxTree { BoxTree }
|
||||
/* The tree holding render box relations. (This should only be used
|
||||
for painting nested inlines, AFAIK-- everything else depends on Flow tree) */
|
||||
enum RenderBoxTree { RenderBoxTree }
|
||||
|
||||
impl BoxTree : tree::ReadMethods<@Box> {
|
||||
fn each_child(node: @Box, f: fn(&&@Box) -> bool) {
|
||||
impl RenderBoxTree : tree::ReadMethods<@RenderBox> {
|
||||
fn each_child(node: @RenderBox, f: fn(&&@RenderBox) -> bool) {
|
||||
tree::each_child(self, node, f)
|
||||
}
|
||||
|
||||
fn with_tree_fields<R>(&&b: @Box, f: fn(tree::Tree<@Box>) -> R) -> R {
|
||||
fn with_tree_fields<R>(&&b: @RenderBox, f: fn(tree::Tree<@RenderBox>) -> R) -> R {
|
||||
f(b.tree)
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxTree : tree::WriteMethods<@Box> {
|
||||
fn add_child(parent: @Box, child: @Box) {
|
||||
impl RenderBoxTree : tree::WriteMethods<@RenderBox> {
|
||||
fn add_child(parent: @RenderBox, child: @RenderBox) {
|
||||
assert !box::ptr_eq(parent, child);
|
||||
tree::add_child(self, parent, child)
|
||||
}
|
||||
|
||||
fn with_tree_fields<R>(&&b: @Box, f: fn(tree::Tree<@Box>) -> R) -> R {
|
||||
fn with_tree_fields<R>(&&b: @RenderBox, f: fn(tree::Tree<@RenderBox>) -> R) -> R {
|
||||
f(b.tree)
|
||||
}
|
||||
}
|
||||
|
@ -354,7 +489,7 @@ impl @FlowContext : DebugMethods {
|
|||
}
|
||||
}
|
||||
|
||||
impl @Box : DebugMethods {
|
||||
impl @RenderBox : DebugMethods {
|
||||
fn dump() {
|
||||
self.dump_indent(0u);
|
||||
}
|
||||
|
@ -369,7 +504,7 @@ impl @Box : DebugMethods {
|
|||
s += self.debug_str();
|
||||
debug!("%s", s);
|
||||
|
||||
for BoxTree.each_child(self) |kid| {
|
||||
for RenderBoxTree.each_child(self) |kid| {
|
||||
kid.dump_indent(indent + 1u)
|
||||
}
|
||||
}
|
||||
|
@ -412,9 +547,9 @@ mod test {
|
|||
}
|
||||
*/
|
||||
|
||||
fn flat_bounds(root: @Box) -> ~[Rect<au>] {
|
||||
fn flat_bounds(root: @RenderBox) -> ~[Rect<au>] {
|
||||
let mut r = ~[];
|
||||
for tree::each_child(BoxTree, root) |c| {
|
||||
for tree::each_child(RenderBoxTree, root) |c| {
|
||||
push_all(r, flat_bounds(c));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
use au = gfx::geometry;
|
||||
use css::values::*;
|
||||
use dl = gfx::display_list;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use gfx::geometry::au;
|
||||
use layout::base::{Box, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
|
||||
use layout::base::{RenderBox, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
|
||||
use layout::context::LayoutContext;
|
||||
use util::tree;
|
||||
|
||||
struct BlockFlowData {
|
||||
mut box: Option<@Box>
|
||||
mut box: Option<@RenderBox>
|
||||
}
|
||||
|
||||
fn BlockFlowData() -> BlockFlowData {
|
||||
|
@ -20,11 +22,14 @@ fn BlockFlowData() -> BlockFlowData {
|
|||
trait BlockLayout {
|
||||
pure fn starts_block_flow() -> bool;
|
||||
pure fn access_block<T>(fn(&&BlockFlowData) -> T) -> T;
|
||||
pure fn with_block_box(fn(&&@Box) -> ()) -> ();
|
||||
pure fn with_block_box(fn(&&@RenderBox) -> ()) -> ();
|
||||
|
||||
fn bubble_widths_block(ctx: &LayoutContext);
|
||||
fn assign_widths_block(ctx: &LayoutContext);
|
||||
fn assign_height_block(ctx: &LayoutContext);
|
||||
|
||||
fn build_display_list_block(a: &dl::DisplayListBuilder, b: &Rect<au>,
|
||||
c: &Point2D<au>, d: &dl::DisplayList);
|
||||
}
|
||||
|
||||
impl @FlowContext : BlockLayout {
|
||||
|
@ -45,7 +50,7 @@ impl @FlowContext : BlockLayout {
|
|||
|
||||
/* Get the current flow's corresponding block box, if it exists, and do something with it.
|
||||
This works on both BlockFlow and RootFlow, since they are mostly the same. */
|
||||
pure fn with_block_box(cb:fn(&&@Box) -> ()) -> () {
|
||||
pure fn with_block_box(cb:fn(&&@RenderBox) -> ()) -> () {
|
||||
match self.kind {
|
||||
BlockFlow(*) => {
|
||||
do self.access_block |d| {
|
||||
|
@ -147,4 +152,22 @@ impl @FlowContext : BlockLayout {
|
|||
let (used_top, used_bot) = box.get_used_height();
|
||||
}
|
||||
}
|
||||
|
||||
fn build_display_list_block(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||
|
||||
assert self.starts_block_flow();
|
||||
|
||||
// add box that starts block context
|
||||
do self.with_block_box |box| {
|
||||
box.build_display_list(builder, dirty, offset, list)
|
||||
}
|
||||
|
||||
// TODO: handle any out-of-flow elements
|
||||
|
||||
// go deeper into the flow tree
|
||||
for FlowTree.each_child(self) |child| {
|
||||
self.build_display_list_for_child(builder, child, dirty, offset, list)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use css::values::{CSSDisplay, DisplayBlock, DisplayInline, DisplayInlineBlock, D
|
|||
use css::values::{Inherit, Initial, Specified};
|
||||
use dom::base::{ElementData, HTMLDivElement, HTMLImageElement};
|
||||
use dom::base::{Element, Text, Node, Doctype, Comment, NodeTree};
|
||||
use layout::base::{Box, BoxData, GenericBox, ImageBox, TextBox, BoxTree};
|
||||
use layout::base::{RenderBox, BoxData, GenericBox, ImageBox, TextBox, RenderBoxTree};
|
||||
use layout::base::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
|
||||
use layout::block::BlockFlowData;
|
||||
use layout::context::LayoutContext;
|
||||
|
@ -20,7 +20,7 @@ use servo_text::font_cache::FontCache;
|
|||
export LayoutTreeBuilder;
|
||||
|
||||
struct LayoutTreeBuilder {
|
||||
mut root_box: Option<@Box>,
|
||||
mut root_box: Option<@RenderBox>,
|
||||
mut root_ctx: Option<@FlowContext>,
|
||||
mut next_bid: int,
|
||||
mut next_cid: int
|
||||
|
@ -42,7 +42,7 @@ impl LayoutTreeBuilder {
|
|||
|
||||
/** Creates necessary box(es) and flow context(s) for the current DOM node,
|
||||
and recurses on its children. */
|
||||
fn construct_recursively(layout_ctx: &LayoutContext, cur_node: Node, parent_ctx: @FlowContext, parent_box: @Box) {
|
||||
fn construct_recursively(layout_ctx: &LayoutContext, cur_node: Node, parent_ctx: @FlowContext, parent_box: @RenderBox) {
|
||||
let style = cur_node.style();
|
||||
|
||||
// DEBUG
|
||||
|
@ -109,7 +109,7 @@ impl LayoutTreeBuilder {
|
|||
|
||||
// connect the box to its parent box
|
||||
debug!("Adding child box b%? of b%?", parent_box.id, new_box.id);
|
||||
BoxTree.add_child(parent_box, new_box);
|
||||
RenderBoxTree.add_child(parent_box, new_box);
|
||||
|
||||
if (!next_ctx.eq(parent_ctx)) {
|
||||
debug!("Adding child flow f%? of f%?", parent_ctx.id, next_ctx.id);
|
||||
|
@ -146,7 +146,7 @@ impl LayoutTreeBuilder {
|
|||
|
||||
/** entry point for box creation. Should only be
|
||||
called on root DOM element. */
|
||||
fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@Box, ()> {
|
||||
fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@RenderBox, ()> {
|
||||
self.root_ctx = Some(self.make_ctx(RootFlow(RootFlowData()), tree::empty()));
|
||||
self.root_box = Some(self.make_box(root, self.root_ctx.get(), GenericBox));
|
||||
|
||||
|
@ -160,8 +160,8 @@ impl LayoutTreeBuilder {
|
|||
ret
|
||||
}
|
||||
|
||||
fn make_box(node : Node, ctx: @FlowContext, data: BoxData) -> @Box {
|
||||
let ret = @Box(self.next_box_id(), node, ctx, data);
|
||||
fn make_box(node : Node, ctx: @FlowContext, data: BoxData) -> @RenderBox {
|
||||
let ret = @RenderBox(self.next_box_id(), node, ctx, data);
|
||||
debug!("Created box: %s", ret.debug_str());
|
||||
ret
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export build_display_list;
|
||||
export DisplayListBuilder;
|
||||
|
||||
use au = gfx::geometry;
|
||||
use base::Box;
|
||||
use base::{RenderBox, RenderBoxTree};
|
||||
use css::values::{BgColor, BgTransparent, Specified};
|
||||
use dl = gfx::display_list;
|
||||
use dom::base::{Text, NodeScope};
|
||||
|
@ -13,118 +13,51 @@ use geom::rect::Rect;
|
|||
use geom::size::Size2D;
|
||||
use gfx::geometry::au;
|
||||
use layout::text::TextBoxData;
|
||||
use layout::base::{TextBox, BoxTree};
|
||||
use layout::base::{LayoutContext, FlowContext, TextBox};
|
||||
use servo_text::text_run::TextRun;
|
||||
use util::tree;
|
||||
use vec::push;
|
||||
|
||||
/**
|
||||
Builds a display list for a box and all its children
|
||||
*/
|
||||
fn build_display_list(box : @Box) -> dl::DisplayList {
|
||||
let list = DVec();
|
||||
build_display_list_from_origin(list, box, Point2D(au(0), au(0)));
|
||||
return list;
|
||||
/** A builder object that manages display list builder should mainly
|
||||
hold information about the initial request and desired result---for
|
||||
example, whether the DisplayList to be used for painting or hit
|
||||
testing. This can affect which boxes are created.
|
||||
|
||||
Right now, the builder isn't used for much, but it establishes the
|
||||
pattern we'll need once we support DL-based hit testing &c. */
|
||||
struct DisplayListBuilder {
|
||||
ctx: &LayoutContext,
|
||||
}
|
||||
|
||||
/**
|
||||
Builds a display list for a box and all its children.
|
||||
|
||||
# Arguments
|
||||
trait FlowDisplayListBuilderMethods {
|
||||
fn build_display_list(a: &DisplayListBuilder, b: &Rect<au>, c: &dl::DisplayList);
|
||||
|
||||
* `box` - The box to build the display list for.
|
||||
* `origin` - The coordinates of upper-left corner of the box containing the
|
||||
passed-in box.
|
||||
|
||||
*/
|
||||
fn build_display_list_from_origin(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {
|
||||
let box_origin = Point2D(
|
||||
au::from_px(au::to_px(origin.x) + au::to_px(box.data.position.origin.x)),
|
||||
au::from_px(au::to_px(origin.y) + au::to_px(box.data.position.origin.y)));
|
||||
debug!("Handed origin %?, box has bounds %?, starting with origin %?", origin, box.data.position.size, box_origin);
|
||||
|
||||
box_to_display_items(list, box, box_origin);
|
||||
|
||||
for BoxTree.each_child(box) |c| {
|
||||
debug!("Recursively building display list with origin %?", box_origin);
|
||||
build_display_list_from_origin(list, c, box_origin);
|
||||
}
|
||||
fn build_display_list_for_child(a: &DisplayListBuilder, b: @FlowContext,
|
||||
c: &Rect<au>, d: &Point2D<au>, e: &dl::DisplayList);
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a display list item for a single block.
|
||||
impl @FlowContext: FlowDisplayListBuilderMethods {
|
||||
|
||||
# Arguments
|
||||
|
||||
* `box` - The box to build the display list for
|
||||
* `origin` - The coordinates of upper-left corner of the passed in box.
|
||||
|
||||
*/
|
||||
#[allow(non_implicitly_copyable_typarams)]
|
||||
fn box_to_display_items(list: dl::DisplayList, box: @Box, origin: Point2D<au>) {
|
||||
|
||||
// TODO: each box should know how to make its own display items.
|
||||
// The display list builder should mainly hold information about
|
||||
// the initial request and desired result---for example, is the
|
||||
// DisplayList to be used for painting or hit testing. This can
|
||||
// influence which boxes are created.
|
||||
|
||||
// TODO: to implement stacking contexts correctly, we need to
|
||||
// create a set of display lists, one per each layer of a stacking
|
||||
// context. (CSS 2.1, Section 9.9.1). Each box is passed the list
|
||||
// set representing the box's stacking context. When asked to
|
||||
// construct its constituent display items, each box puts its
|
||||
// DisplayItems into the correct stack layer (according to CSS 2.1
|
||||
// Appendix E). and then builder flattens the list at the end.
|
||||
|
||||
debug!("request to display a box from origin %?", origin);
|
||||
|
||||
let bounds : Rect<au> = Rect(origin, copy box.data.position.size);
|
||||
|
||||
match box.kind {
|
||||
TextBox(d) => {
|
||||
let mut runs = d.runs;
|
||||
list.push(~dl::SolidColor(bounds, 255u8, 255u8, 255u8));
|
||||
|
||||
let mut bounds = bounds;
|
||||
for uint::range(0, runs.len()) |i| {
|
||||
bounds.size.height = runs[i].size().height;
|
||||
let glyph_run = text_run_to_dl_glyph_run(& runs[i]);
|
||||
list.push(~dl::Glyphs(bounds, glyph_run));
|
||||
bounds.origin.y += bounds.size.height;
|
||||
fn build_display_list(builder: &DisplayListBuilder, dirty: &Rect<au>, list: &dl::DisplayList) {
|
||||
let zero = au::zero_point();
|
||||
self.build_display_list_recurse(builder, dirty, &zero, list);
|
||||
}
|
||||
return;
|
||||
|
||||
pure fn text_run_to_dl_glyph_run(text_run: &TextRun) ->
|
||||
dl::GlyphRun {
|
||||
dl::GlyphRun {
|
||||
glyphs: copy text_run.glyphs
|
||||
fn build_display_list_for_child(builder: &DisplayListBuilder, child: @FlowContext,
|
||||
dirty: &Rect<au>, offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||
|
||||
// adjust the dirty rect to child flow context coordinates
|
||||
let adj_dirty = dirty.translate(&child.data.position.origin);
|
||||
let adj_offset = offset.add(&child.data.position.origin);
|
||||
|
||||
if (adj_dirty.intersects(&child.data.position)) {
|
||||
child.build_display_list_recurse(builder, &adj_dirty, &adj_offset, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Fall through
|
||||
}
|
||||
};
|
||||
|
||||
// Check if there is a background image, if not set the background color.
|
||||
let image = box.get_image();
|
||||
|
||||
if image.is_some() {
|
||||
list.push(~dl::Image(bounds, option::unwrap(image)))
|
||||
} else {
|
||||
// DAC
|
||||
// TODO: shouldn't need to unbox CSSValue by now
|
||||
let boxed_color = box.node.style().background_color;
|
||||
let color = match boxed_color {
|
||||
Specified(BgColor(c)) => c,
|
||||
Specified(BgTransparent) | _ => util::color::rgba(0,0,0,0.0)
|
||||
};
|
||||
debug!("Assigning color %? to box with bounds %?", color, bounds);
|
||||
list.push(~dl::SolidColor(bounds, color.red, color.green, color.blue));
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: redo unit tests, if possible?gn
|
||||
|
||||
fn should_convert_text_boxes_to_solid_color_background_items() {
|
||||
#[test];
|
||||
|
@ -212,3 +145,4 @@ fn should_calculate_the_bounds_of_the_text_items() {
|
|||
|
||||
do list.borrow |l| { assert l[1].bounds == expected; }
|
||||
}
|
||||
*/
|
|
@ -1,18 +1,44 @@
|
|||
use au = gfx::geometry;
|
||||
use base::Box;
|
||||
use base::RenderBox;
|
||||
use core::dvec::DVec;
|
||||
use css::values::{BoxAuto, BoxLength, Px};
|
||||
use dl = gfx::display_list;
|
||||
use dom::rcu;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use gfx::geometry::au;
|
||||
use layout::context::LayoutContext;
|
||||
use layout::base::{FlowContext, InlineFlow, BoxTree, ImageBox, TextBox, GenericBox};
|
||||
use layout::base::{FlowContext, InlineFlow, RenderBoxTree, ImageBox, TextBox, GenericBox};
|
||||
use num::Num;
|
||||
use util::tree;
|
||||
|
||||
/*
|
||||
Tentative design: (may not line up with reality)
|
||||
|
||||
Lineboxes are represented as offsets into the child list, rather than
|
||||
as an object that "owns" boxes. Choosing a different set of line
|
||||
breaks requires a new list of offsets, and possibly some splitting and
|
||||
merging of TextBoxes.
|
||||
|
||||
A similar list will keep track of the mapping between CSS boxes and
|
||||
the corresponding render boxes in the inline flow.
|
||||
|
||||
After line breaks are determined, lender boxes in the inline flow may
|
||||
overlap visually. For example, in the case of nested inline CSS boxes,
|
||||
outer inlines must be at least as large as the inner inlines, for
|
||||
purposes of drawing noninherited things like backgrounds, borders,
|
||||
outlines.
|
||||
|
||||
N.B. roc has an alternative design where the list instead consists of
|
||||
things like "start outer box, text, start inner box, text, end inner
|
||||
box, text, end outer box, text". This seems a little complicated to
|
||||
serve as the starting point, but the current design doesn't make it
|
||||
hard to try out that alternative.
|
||||
*/
|
||||
|
||||
struct InlineFlowData {
|
||||
boxes: ~DVec<@Box>
|
||||
boxes: ~DVec<@RenderBox>
|
||||
}
|
||||
|
||||
fn InlineFlowData() -> InlineFlowData {
|
||||
|
@ -28,6 +54,7 @@ trait InlineLayout {
|
|||
fn bubble_widths_inline(ctx: &LayoutContext);
|
||||
fn assign_widths_inline(ctx: &LayoutContext);
|
||||
fn assign_height_inline(ctx: &LayoutContext);
|
||||
fn build_display_list_inline(a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
|
||||
}
|
||||
|
||||
impl @FlowContext : InlineLayout {
|
||||
|
@ -116,4 +143,27 @@ impl @FlowContext : InlineLayout {
|
|||
// during inline flowing.
|
||||
}
|
||||
|
||||
fn build_display_list_inline(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||
|
||||
assert self.starts_inline_flow();
|
||||
|
||||
// TODO: if the CSS box introducing this inline context is *not* anonymous,
|
||||
// we need to draw it too, in a way similar to BlowFlowContext
|
||||
|
||||
// TODO: once we form line boxes and have their cached bounds, we can be
|
||||
// smarter and not recurse on a line if nothing in it can intersect dirty
|
||||
do self.access_inline |d| {
|
||||
for d.boxes.each |box| {
|
||||
box.build_display_list(builder, dirty, offset, list)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should inline-block elements have flows as children
|
||||
// of the inline flow, or should the flow be nested inside the
|
||||
// box somehow? Maybe it's best to unify flows and boxes into
|
||||
// the same enum, so inline-block flows are normal
|
||||
// (indivisible) children in the inline flow child list.
|
||||
}
|
||||
|
||||
} // @FlowContext : InlineLayout
|
||||
|
|
|
@ -6,16 +6,17 @@
|
|||
use au = gfx::geometry;
|
||||
use au::au;
|
||||
use content::content_task;
|
||||
use core::dvec::DVec;
|
||||
use css::resolve::apply::apply_style;
|
||||
use css::values::Stylesheet;
|
||||
use display_list_builder::build_display_list;
|
||||
use dl = gfx::display_list;
|
||||
use dom::base::Node;
|
||||
use dom::event::{Event, ReflowEvent};
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use gfx::render_task;
|
||||
use layout::base::Box;
|
||||
use layout::base::RenderBox;
|
||||
use layout::box_builder::LayoutTreeBuilder;
|
||||
use layout::context::LayoutContext;
|
||||
use render_task::RenderTask;
|
||||
|
@ -67,14 +68,15 @@ fn LayoutTask(render_task: RenderTask, image_cache_task: ImageCacheTask) -> Layo
|
|||
layout_data_refs += node.initialize_style_for_subtree();
|
||||
node.recompute_style_for_subtree(&layout_ctx, styles);
|
||||
|
||||
let root_box: @Box;
|
||||
// TODO: this should care about root flow, not root box.
|
||||
let root_box: @RenderBox;
|
||||
let builder = LayoutTreeBuilder();
|
||||
match builder.construct_trees(&layout_ctx, node) {
|
||||
Ok(root) => root_box = root,
|
||||
Err(*) => fail ~"Root node should always exist"
|
||||
}
|
||||
|
||||
debug!("layout: constructed Box tree");
|
||||
debug!("layout: constructed RenderBox tree");
|
||||
root_box.dump();
|
||||
|
||||
debug!("layout: constructed Flow tree");
|
||||
|
@ -90,7 +92,13 @@ fn LayoutTask(render_task: RenderTask, image_cache_task: ImageCacheTask) -> Layo
|
|||
do root_flow.traverse_preorder |f| { f.assign_widths(&layout_ctx) }
|
||||
do root_flow.traverse_postorder |f| { f.assign_height(&layout_ctx) }
|
||||
|
||||
let dlist = build_display_list(root_box);
|
||||
let dlist = DVec();
|
||||
let builder = dl::DisplayListBuilder {
|
||||
ctx: &layout_ctx,
|
||||
};
|
||||
// TODO: set options on the builder before building
|
||||
// TODO: be smarter about what needs painting
|
||||
root_flow.build_display_list(&builder, © root_flow.data.position, &dlist);
|
||||
render_task.send(render_task::RenderMsg(dlist));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
use au = gfx::geometry;
|
||||
use css::values::*;
|
||||
use dl = gfx::display_list;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use gfx::geometry::au;
|
||||
use layout::base::{Box, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
|
||||
use layout::base::{RenderBox, FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
|
||||
use layout::context::LayoutContext;
|
||||
use util::tree;
|
||||
|
||||
struct RootFlowData {
|
||||
mut box: Option<@Box>
|
||||
mut box: Option<@RenderBox>
|
||||
}
|
||||
|
||||
fn RootFlowData() -> RootFlowData {
|
||||
|
@ -22,6 +25,8 @@ trait RootLayout {
|
|||
fn bubble_widths_root(ctx: &LayoutContext);
|
||||
fn assign_widths_root(ctx: &LayoutContext);
|
||||
fn assign_height_root(ctx: &LayoutContext);
|
||||
|
||||
fn build_display_list_root(a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
|
||||
}
|
||||
|
||||
impl @FlowContext : RootLayout {
|
||||
|
@ -58,4 +63,11 @@ impl @FlowContext : RootLayout {
|
|||
|
||||
self.assign_height_block(ctx);
|
||||
}
|
||||
|
||||
fn build_display_list_root(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||
assert self.starts_root_flow();
|
||||
|
||||
self.build_display_list_block(builder, dirty, offset, list);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use geom::size::Size2D;
|
|||
use gfx::geometry::au;
|
||||
use servo_text::text_run::TextRun;
|
||||
use servo_text::font_cache::FontCache;
|
||||
use layout::base::{TextBox, Box};
|
||||
use layout::base::{TextBox, RenderBox};
|
||||
use layout::context::LayoutContext;
|
||||
|
||||
struct TextBoxData {
|
||||
|
@ -25,7 +25,7 @@ trait TextLayout {
|
|||
}
|
||||
|
||||
#[doc="The main reflow routine for text layout."]
|
||||
impl @Box : TextLayout {
|
||||
impl @RenderBox : TextLayout {
|
||||
fn reflow_text(ctx: &LayoutContext) {
|
||||
let d = match self.kind {
|
||||
TextBox(d) => { d }
|
||||
|
@ -78,6 +78,7 @@ impl @Box : TextLayout {
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO: new unit tests for TextBox splitting, etc
|
||||
fn should_calculate_the_size_of_the_text_box() {
|
||||
#[test];
|
||||
#[ignore(cfg(target_os = "macos"))];
|
||||
|
@ -97,3 +98,4 @@ fn should_calculate_the_size_of_the_text_box() {
|
|||
let expected = Size2D(au::from_px(84), au::from_px(20));
|
||||
assert b.data.position.size == expected;
|
||||
}
|
||||
*/
|
|
@ -1,16 +1,17 @@
|
|||
/** Interface for running tree-based traversals over layout boxes and contextsg */
|
||||
|
||||
use layout::base::{Box, BoxTree};
|
||||
use layout::base::{RenderBox, RenderBoxTree};
|
||||
use layout::base::{FlowContext, FlowTree};
|
||||
|
||||
trait BoxTraversals {
|
||||
fn traverse_preorder(preorder_cb: &fn(@Box));
|
||||
/* TODO: we shouldn't need render box traversals */
|
||||
trait RenderBoxTraversals {
|
||||
fn traverse_preorder(preorder_cb: &fn(@RenderBox));
|
||||
}
|
||||
|
||||
impl @Box : BoxTraversals {
|
||||
fn traverse_preorder(preorder_cb: &fn(@Box)) {
|
||||
impl @RenderBox : RenderBoxTraversals {
|
||||
fn traverse_preorder(preorder_cb: &fn(@RenderBox)) {
|
||||
preorder_cb(self);
|
||||
do BoxTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
|
||||
do RenderBoxTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
#[doc = "Interface for running tree-based traversals over layout boxes"]
|
||||
use base::{Box, BoxTree};
|
||||
use base::{RenderBox, RenderBoxTree};
|
||||
use intrinsic::TyDesc;
|
||||
|
||||
export full_traversal;
|
||||
|
@ -22,14 +22,14 @@ type shared_box<T> = {
|
|||
};
|
||||
|
||||
#[doc="Transform and @ into its underlying representation. The reference count stays constant."]
|
||||
fn unwrap_box(-b : @Box) -> *shared_box<Box> unsafe {
|
||||
let new_box : *shared_box<Box> = unsafe::transmute(b);
|
||||
fn unwrap_box(-b : @RenderBox) -> *shared_box<RenderBox> unsafe {
|
||||
let new_box : *shared_box<RenderBox> = unsafe::transmute(b);
|
||||
return new_box;
|
||||
}
|
||||
|
||||
#[doc="Transform an underlying representation back to an @. The reference count stays constant."]
|
||||
fn rewrap_box(-b : *shared_box<Box>) -> @Box unsafe {
|
||||
let new_box : @Box = unsafe::transmute(b);
|
||||
fn rewrap_box(-b : *shared_box<RenderBox>) -> @RenderBox unsafe {
|
||||
let new_box : @RenderBox = unsafe::transmute(b);
|
||||
return new_box;
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,8 @@ finish, and then applies the second function to the current box.
|
|||
applied to that node's children
|
||||
|
||||
"]
|
||||
fn traverse_helper<T : Copy Send>(-root : @Box, returned : T, -top_down : fn~(+T, @Box) -> T,
|
||||
-bottom_up : fn~(@Box)) {
|
||||
fn traverse_helper<T : Copy Send>(-root : @RenderBox, returned : T, -top_down : fn~(+T, @RenderBox) -> T,
|
||||
-bottom_up : fn~(@RenderBox)) {
|
||||
let returned = top_down(returned, root);
|
||||
|
||||
do listen |ack_chan| {
|
||||
|
@ -67,21 +67,21 @@ fn traverse_helper<T : Copy Send>(-root : @Box, returned : T, -top_down : fn~(+T
|
|||
// current task will block until all of it's children return,
|
||||
// so the original owner of the @-box will not exit while the
|
||||
// children are still live.
|
||||
for BoxTree.each_child(root) |kid| {
|
||||
for RenderBoxTree.each_child(root) |kid| {
|
||||
count += 1;
|
||||
|
||||
// Unwrap the box so we can send it out of this task
|
||||
let unwrapped = unwrap_box(copy kid);
|
||||
// Hide the box in an option so we can get it across the
|
||||
// task boundary without copying it
|
||||
let swappable : ~mut Option<*shared_box<Box>> = ~mut Some(unwrapped);
|
||||
let swappable : ~mut Option<*shared_box<RenderBox>> = ~mut Some(unwrapped);
|
||||
|
||||
do task::spawn |copy top_down, copy bottom_up| {
|
||||
// Get the box out of the option and into the new task
|
||||
let mut swapped_in = None;
|
||||
swapped_in <-> *swappable;
|
||||
|
||||
// Retrieve the original @Box and recurse
|
||||
// Retrieve the original @RenderBox and recurse
|
||||
let new_kid = rewrap_box(option::unwrap(swapped_in));
|
||||
traverse_helper(new_kid, copy returned, copy top_down, copy bottom_up);
|
||||
|
||||
|
@ -97,7 +97,7 @@ fn traverse_helper<T : Copy Send>(-root : @Box, returned : T, -top_down : fn~(+T
|
|||
}
|
||||
|
||||
#[doc="A noneffectful function to be used if only one pass is required."]
|
||||
fn nop(_box : @Box) {
|
||||
fn nop(_box : @RenderBox) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -105,15 +105,15 @@ fn nop(_box : @Box) {
|
|||
A wrapper to change a function that only acts on a box to one that
|
||||
threasds a unit through to match travserse_helper
|
||||
"]
|
||||
fn unit_wrapper(-fun : fn~(@Box)) -> fn~(+(), @Box) {
|
||||
fn~(+_u : (), box : @Box) { fun(box); }
|
||||
fn unit_wrapper(-fun : fn~(@RenderBox)) -> fn~(+(), @RenderBox) {
|
||||
fn~(+_u : (), box : @RenderBox) { fun(box); }
|
||||
}
|
||||
|
||||
#[doc="
|
||||
Iterate in parallel over the boxes in a tree, applying one function
|
||||
to a parent before recursing on its children and one after.
|
||||
"]
|
||||
fn full_traversal(+root : @Box, -top_down : fn~(@Box), -bottom_up : fn~(@Box)) {
|
||||
fn full_traversal(+root : @RenderBox, -top_down : fn~(@RenderBox), -bottom_up : fn~(@RenderBox)) {
|
||||
traverse_helper(root, (), unit_wrapper(top_down), bottom_up);
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ fn full_traversal(+root : @Box, -top_down : fn~(@Box), -bottom_up : fn~(@Box)) {
|
|||
Iterate in parallel over the boxes in a tree, applying the given
|
||||
function to a parent before its children.
|
||||
"]
|
||||
fn top_down_traversal(+root : @Box, -top_down : fn~(@Box)) {
|
||||
fn top_down_traversal(+root : @RenderBox, -top_down : fn~(@RenderBox)) {
|
||||
traverse_helper(root, (), unit_wrapper(top_down), nop);
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ fn top_down_traversal(+root : @Box, -top_down : fn~(@Box)) {
|
|||
Iterate in parallel over the boxes in a tree, applying the given
|
||||
function to a parent after its children.
|
||||
"]
|
||||
fn bottom_up_traversal(+root : @Box, -bottom_up : fn~(@Box)) {
|
||||
fn bottom_up_traversal(+root : @RenderBox, -bottom_up : fn~(@RenderBox)) {
|
||||
traverse_helper(root, (), unit_wrapper(nop), bottom_up);
|
||||
}
|
||||
|
||||
|
@ -140,9 +140,9 @@ fn bottom_up_traversal(+root : @Box, -bottom_up : fn~(@Box)) {
|
|||
the recursion unwinds, the second function is applied to first the
|
||||
children in parallel, and then the parent.
|
||||
"]
|
||||
fn extended_full_traversal<T : Copy Send>(+root : @Box, first_val : T,
|
||||
-top_down : fn~(+T, @Box) -> T,
|
||||
-bottom_up : fn~(@Box)) {
|
||||
fn extended_full_traversal<T : Copy Send>(+root : @RenderBox, first_val : T,
|
||||
-top_down : fn~(+T, @RenderBox) -> T,
|
||||
-bottom_up : fn~(@RenderBox)) {
|
||||
traverse_helper(root, first_val, top_down, bottom_up);
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ fn extended_full_traversal<T : Copy Send>(+root : @Box, first_val : T,
|
|||
function to a parent before its children, the value returned by the
|
||||
function is passed to each child when they are recursed upon.
|
||||
"]
|
||||
fn extended_top_down_traversal<T : Copy Send>(+root : @Box, first_val : T,
|
||||
-top_down : fn~(+T, @Box) -> T) {
|
||||
fn extended_top_down_traversal<T : Copy Send>(+root : @RenderBox, first_val : T,
|
||||
-top_down : fn~(+T, @RenderBox) -> T) {
|
||||
traverse_helper(root, first_val, top_down, nop);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue