mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Refactor FlowContext to have the preferred nesting strategy of enum variants and structs.
This commit is contained in:
parent
e89d2fa782
commit
49de0a7fac
7 changed files with 207 additions and 190 deletions
|
@ -22,7 +22,6 @@ fn BlockFlowData() -> BlockFlowData {
|
||||||
|
|
||||||
trait BlockLayout {
|
trait BlockLayout {
|
||||||
pure fn starts_block_flow() -> bool;
|
pure fn starts_block_flow() -> bool;
|
||||||
pure fn access_block<T>(fn(&&BlockFlowData) -> T) -> T;
|
|
||||||
pure fn with_block_box(fn(&&@RenderBox) -> ()) -> ();
|
pure fn with_block_box(fn(&&@RenderBox) -> ()) -> ();
|
||||||
|
|
||||||
fn bubble_widths_block(ctx: &LayoutContext);
|
fn bubble_widths_block(ctx: &LayoutContext);
|
||||||
|
@ -36,36 +35,25 @@ trait BlockLayout {
|
||||||
impl FlowContext : BlockLayout {
|
impl FlowContext : BlockLayout {
|
||||||
|
|
||||||
pure fn starts_block_flow() -> bool {
|
pure fn starts_block_flow() -> bool {
|
||||||
match self.kind {
|
match self {
|
||||||
RootFlow(*) | BlockFlow(*) | InlineBlockFlow(*) => true,
|
RootFlow(*) | BlockFlow(*) | InlineBlockFlow(*) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pure fn access_block<T>(cb:fn(&&BlockFlowData) -> T) -> T {
|
|
||||||
match self.kind {
|
|
||||||
BlockFlow(d) => cb(d),
|
|
||||||
_ => fail fmt!("Tried to access() data of BlockFlow, but this is a %?", self.kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the current flow's corresponding block box, if it exists, and do something with it.
|
/* 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. */
|
This works on both BlockFlow and RootFlow, since they are mostly the same. */
|
||||||
pure fn with_block_box(cb:fn(&&@RenderBox) -> ()) -> () {
|
pure fn with_block_box(cb:fn(&&@RenderBox) -> ()) -> () {
|
||||||
match self.kind {
|
match self {
|
||||||
BlockFlow(*) => {
|
BlockFlow(*) => {
|
||||||
do self.access_block |d| {
|
let mut box = self.block().box;
|
||||||
let mut box = d.box;
|
box.iter(cb);
|
||||||
box.iter(cb)
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
RootFlow(*) => {
|
RootFlow(*) => {
|
||||||
do self.access_root |d| {
|
let mut box = self.root().box;
|
||||||
let mut box = d.box;
|
box.iter(cb);
|
||||||
box.iter(cb)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_ => fail fmt!("Tried to do something with_block_box(), but this is a %?", self.kind)
|
_ => fail fmt!("Tried to do something with_block_box(), but this is a %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,8 +76,8 @@ impl FlowContext : BlockLayout {
|
||||||
for FlowTree.each_child(@self) |child_ctx| {
|
for FlowTree.each_child(@self) |child_ctx| {
|
||||||
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
||||||
|
|
||||||
min_width = au::max(min_width, child_ctx.data.min_width);
|
min_width = au::max(min_width, child_ctx.d().min_width);
|
||||||
pref_width = au::max(pref_width, child_ctx.data.pref_width);
|
pref_width = au::max(pref_width, child_ctx.d().pref_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if not an anonymous block context, add in block box's widths.
|
/* if not an anonymous block context, add in block box's widths.
|
||||||
|
@ -99,8 +87,8 @@ impl FlowContext : BlockLayout {
|
||||||
pref_width = pref_width.add(box.get_pref_width());
|
pref_width = pref_width.add(box.get_pref_width());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.data.min_width = min_width;
|
self.d().min_width = min_width;
|
||||||
self.data.pref_width = pref_width;
|
self.d().pref_width = pref_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Recursively (top-down) determines the actual width of child
|
/* Recursively (top-down) determines the actual width of child
|
||||||
|
@ -113,7 +101,7 @@ impl FlowContext : BlockLayout {
|
||||||
fn assign_widths_block(_ctx: &LayoutContext) {
|
fn assign_widths_block(_ctx: &LayoutContext) {
|
||||||
assert self.starts_block_flow();
|
assert self.starts_block_flow();
|
||||||
|
|
||||||
let mut remaining_width = self.data.position.size.width;
|
let mut remaining_width = self.d().position.size.width;
|
||||||
let mut _right_used = au(0);
|
let mut _right_used = au(0);
|
||||||
let mut left_used = au(0);
|
let mut left_used = au(0);
|
||||||
|
|
||||||
|
@ -127,8 +115,8 @@ impl FlowContext : BlockLayout {
|
||||||
|
|
||||||
for FlowTree.each_child(@self) |child_ctx| {
|
for FlowTree.each_child(@self) |child_ctx| {
|
||||||
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
||||||
child_ctx.data.position.origin.x = left_used;
|
child_ctx.d().position.origin.x = left_used;
|
||||||
child_ctx.data.position.size.width = remaining_width;
|
child_ctx.d().position.size.width = remaining_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,11 +126,11 @@ impl FlowContext : BlockLayout {
|
||||||
let mut cur_y = au(0);
|
let mut cur_y = au(0);
|
||||||
|
|
||||||
for FlowTree.each_child(@self) |child_ctx| {
|
for FlowTree.each_child(@self) |child_ctx| {
|
||||||
child_ctx.data.position.origin.y = cur_y;
|
child_ctx.d().position.origin.y = cur_y;
|
||||||
cur_y = cur_y.add(child_ctx.data.position.size.height);
|
cur_y = cur_y.add(child_ctx.d().position.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.data.position.size.height = cur_y;
|
self.d().position.size.height = cur_y;
|
||||||
|
|
||||||
let _used_top = au(0);
|
let _used_top = au(0);
|
||||||
let _used_bot = au(0);
|
let _used_bot = au(0);
|
||||||
|
|
|
@ -7,10 +7,10 @@ use css::values::{Inherit, Initial, Specified};
|
||||||
use dom::element::*;
|
use dom::element::*;
|
||||||
use dom::node::{Comment, Doctype, Element, Text, Node, NodeTree, LayoutData};
|
use dom::node::{Comment, Doctype, Element, Text, Node, NodeTree, LayoutData};
|
||||||
use image::holder::ImageHolder;
|
use image::holder::ImageHolder;
|
||||||
use layout::flow::{FlowContext, FlowContextData, BlockFlow, InlineFlow, InlineBlockFlow, RootFlow, FlowTree};
|
|
||||||
use layout::box::*;
|
use layout::box::*;
|
||||||
use layout::block::BlockFlowData;
|
use layout::block::BlockFlowData;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
|
use layout::flow::*;
|
||||||
use layout::inline::InlineFlowData;
|
use layout::inline::InlineFlowData;
|
||||||
use layout::root::RootFlowData;
|
use layout::root::RootFlowData;
|
||||||
use layout::text::TextBoxData;
|
use layout::text::TextBoxData;
|
||||||
|
@ -69,7 +69,7 @@ impl LayoutTreeBuilder {
|
||||||
if (parent_ctx.starts_inline_flow()) {
|
if (parent_ctx.starts_inline_flow()) {
|
||||||
parent_ctx
|
parent_ctx
|
||||||
} else {
|
} else {
|
||||||
self.make_ctx(InlineFlow(InlineFlowData()), tree::empty())
|
self.make_ctx(Flow_Inline)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
RenderBox_Image | RenderBox_Generic => {
|
RenderBox_Image | RenderBox_Generic => {
|
||||||
|
@ -80,12 +80,12 @@ impl LayoutTreeBuilder {
|
||||||
if (parent_ctx.starts_inline_flow()) {
|
if (parent_ctx.starts_inline_flow()) {
|
||||||
parent_ctx
|
parent_ctx
|
||||||
} else {
|
} else {
|
||||||
self.make_ctx(InlineFlow(InlineFlowData()), tree::empty())
|
self.make_ctx(Flow_Inline)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/* block boxes always create a new context */
|
/* block boxes always create a new context */
|
||||||
DisplayBlock => {
|
DisplayBlock => {
|
||||||
self.make_ctx(BlockFlow(BlockFlowData()), tree::empty())
|
self.make_ctx(Flow_Block)
|
||||||
},
|
},
|
||||||
_ => fail fmt!("unsupported display type in box generation: %?", simulated_display)
|
_ => fail fmt!("unsupported display type in box generation: %?", simulated_display)
|
||||||
}
|
}
|
||||||
|
@ -101,25 +101,27 @@ impl LayoutTreeBuilder {
|
||||||
let mut new_box = self.make_box(layout_ctx, box_type, cur_node, parent_ctx);
|
let mut new_box = self.make_box(layout_ctx, box_type, cur_node, parent_ctx);
|
||||||
debug!("Assign ^box to flow: %?", next_ctx.debug_str());
|
debug!("Assign ^box to flow: %?", next_ctx.debug_str());
|
||||||
|
|
||||||
match next_ctx.kind {
|
match *next_ctx {
|
||||||
InlineFlow(d) => {
|
InlineFlow(*) => {
|
||||||
d.boxes.push(new_box);
|
next_ctx.inline().boxes.push(new_box);
|
||||||
|
|
||||||
if (parent_box.is_some()) {
|
if (parent_box.is_some()) {
|
||||||
let parent = parent_box.get();
|
let parent = parent_box.get();
|
||||||
|
|
||||||
// connect the box to its parent box
|
// connect the box to its parent box
|
||||||
debug!("In inline flow f%?, set child b%? of parent b%?", next_ctx.id, parent.d().id, new_box.d().id);
|
debug!("In inline flow f%?, set child b%? of parent b%?",
|
||||||
|
next_ctx.d().id, parent.d().id, new_box.d().id);
|
||||||
RenderBoxTree.add_child(parent, new_box);
|
RenderBoxTree.add_child(parent, new_box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BlockFlow(d) => { d.box = Some(new_box) }
|
BlockFlow(*) => next_ctx.block().box = Some(new_box),
|
||||||
_ => {} // TODO: float lists, etc.
|
_ => {} // TODO: float lists, etc.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if !core::box::ptr_eq(next_ctx, parent_ctx) {
|
if !core::box::ptr_eq(next_ctx, parent_ctx) {
|
||||||
debug!("Adding child flow f%? of f%?", parent_ctx.id, next_ctx.id);
|
debug!("Adding child flow f%? of f%?",
|
||||||
|
parent_ctx.d().id, next_ctx.d().id);
|
||||||
FlowTree.add_child(parent_ctx, next_ctx);
|
FlowTree.add_child(parent_ctx, next_ctx);
|
||||||
}
|
}
|
||||||
// recurse
|
// recurse
|
||||||
|
@ -134,8 +136,8 @@ impl LayoutTreeBuilder {
|
||||||
let mut found_child_block = false;
|
let mut found_child_block = false;
|
||||||
|
|
||||||
do FlowTree.each_child(next_ctx) |child_ctx| {
|
do FlowTree.each_child(next_ctx) |child_ctx| {
|
||||||
match child_ctx.kind {
|
match *child_ctx {
|
||||||
InlineFlow(*) | InlineBlockFlow => found_child_inline = true,
|
InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
|
||||||
BlockFlow(*) => found_child_block = true,
|
BlockFlow(*) => found_child_block = true,
|
||||||
_ => {}
|
_ => {}
|
||||||
}; true
|
}; true
|
||||||
|
@ -176,14 +178,22 @@ impl LayoutTreeBuilder {
|
||||||
/** entry point for box creation. Should only be
|
/** entry point for box creation. Should only be
|
||||||
called on root DOM element. */
|
called on root DOM element. */
|
||||||
fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@FlowContext, ()> {
|
fn construct_trees(layout_ctx: &LayoutContext, root: Node) -> Result<@FlowContext, ()> {
|
||||||
self.root_ctx = Some(self.make_ctx(RootFlow(RootFlowData()), tree::empty()));
|
self.root_ctx = Some(self.make_ctx(Flow_Root));
|
||||||
|
|
||||||
self.construct_recursively(layout_ctx, root, self.root_ctx.get(), None);
|
self.construct_recursively(layout_ctx, root, self.root_ctx.get(), None);
|
||||||
return Ok(self.root_ctx.get())
|
return Ok(self.root_ctx.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_ctx(kind : FlowContextData, tree: tree::Tree<@FlowContext>) -> @FlowContext {
|
fn make_ctx(ty : FlowContextType) -> @FlowContext {
|
||||||
let ret = @FlowContext(self.next_ctx_id(), kind, tree);
|
let data = FlowData(self.next_ctx_id());
|
||||||
|
let ret = match ty {
|
||||||
|
Flow_Absolute => @AbsoluteFlow(data),
|
||||||
|
Flow_Block => @BlockFlow(data, BlockFlowData()),
|
||||||
|
Flow_Float => @FloatFlow(data),
|
||||||
|
Flow_InlineBlock => @InlineBlockFlow(data),
|
||||||
|
Flow_Inline => @InlineFlow(data, InlineFlowData()),
|
||||||
|
Flow_Root => @RootFlow(data, RootFlowData()),
|
||||||
|
Flow_Table => @TableFlow(data)
|
||||||
|
};
|
||||||
debug!("Created context: %s", ret.debug_str());
|
debug!("Created context: %s", ret.debug_str());
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,10 +49,10 @@ impl FlowContext: FlowDisplayListBuilderMethods {
|
||||||
dirty: &Rect<au>, offset: &Point2D<au>, list: &dl::DisplayList) {
|
dirty: &Rect<au>, offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||||
|
|
||||||
// adjust the dirty rect to child flow context coordinates
|
// adjust the dirty rect to child flow context coordinates
|
||||||
let adj_dirty = dirty.translate(&child.data.position.origin);
|
let adj_dirty = dirty.translate(&child.d().position.origin);
|
||||||
let adj_offset = offset.add(&child.data.position.origin);
|
let adj_offset = offset.add(&child.d().position.origin);
|
||||||
|
|
||||||
if (adj_dirty.intersects(&child.data.position)) {
|
if (adj_dirty.intersects(&child.d().position)) {
|
||||||
child.build_display_list_recurse(builder, &adj_dirty, &adj_offset, list);
|
child.build_display_list_recurse(builder, &adj_dirty, &adj_offset, list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,74 @@ Currently, the important types of flows are:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* The type of the formatting context, and data specific to each
|
||||||
|
context, such as linebox structures or float lists */
|
||||||
|
enum FlowContext {
|
||||||
|
AbsoluteFlow(FlowData),
|
||||||
|
BlockFlow(FlowData, BlockFlowData),
|
||||||
|
FloatFlow(FlowData),
|
||||||
|
InlineBlockFlow(FlowData),
|
||||||
|
InlineFlow(FlowData, InlineFlowData),
|
||||||
|
RootFlow(FlowData, RootFlowData),
|
||||||
|
TableFlow(FlowData)
|
||||||
|
}
|
||||||
|
|
||||||
struct FlowLayoutData {
|
enum FlowContextType {
|
||||||
|
Flow_Absolute,
|
||||||
|
Flow_Block,
|
||||||
|
Flow_Float,
|
||||||
|
Flow_InlineBlock,
|
||||||
|
Flow_Inline,
|
||||||
|
Flow_Root,
|
||||||
|
Flow_Table
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowContext {
|
||||||
|
pure fn d(&self) -> &self/FlowData {
|
||||||
|
match *self {
|
||||||
|
AbsoluteFlow(ref d) => d,
|
||||||
|
BlockFlow(ref d, _) => d,
|
||||||
|
FloatFlow(ref d) => d,
|
||||||
|
InlineBlockFlow(ref d) => d,
|
||||||
|
InlineFlow(ref d, _) => d,
|
||||||
|
RootFlow(ref d, _) => d,
|
||||||
|
TableFlow(ref d) => d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn inline(&self) -> &self/InlineFlowData {
|
||||||
|
match *self {
|
||||||
|
InlineFlow(_, ref i) => i,
|
||||||
|
_ => fail fmt!("Tried to access inline data of non-inline: %?", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn block(&self) -> &self/BlockFlowData {
|
||||||
|
match *self {
|
||||||
|
BlockFlow(_, ref b) => b,
|
||||||
|
_ => fail fmt!("Tried to access block data of non-block: %?", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn root(&self) -> &self/RootFlowData {
|
||||||
|
match *self {
|
||||||
|
RootFlow(_, ref r) => r,
|
||||||
|
_ => fail fmt!("Tried to access root data of non-root: %?", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A particular kind of layout context. It manages the positioning of
|
||||||
|
render boxes within the context. */
|
||||||
|
struct FlowData {
|
||||||
|
mut node: Option<Node>,
|
||||||
|
/* reference to parent, children flow contexts */
|
||||||
|
tree: tree::Tree<@FlowContext>,
|
||||||
|
/* TODO (Issue #87): debug only */
|
||||||
|
mut id: int,
|
||||||
|
|
||||||
|
/* layout computations */
|
||||||
// TODO: min/pref and position are used during disjoint phases of
|
// TODO: min/pref and position are used during disjoint phases of
|
||||||
// layout; maybe combine into a single enum to save space.
|
// layout; maybe combine into a single enum to save space.
|
||||||
mut min_width: au,
|
mut min_width: au,
|
||||||
|
@ -49,85 +115,55 @@ struct FlowLayoutData {
|
||||||
mut position: Rect<au>,
|
mut position: Rect<au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn FlowLayoutData() -> FlowLayoutData {
|
|
||||||
FlowLayoutData {
|
fn FlowData(id: int) -> FlowData {
|
||||||
|
FlowData {
|
||||||
|
node: None,
|
||||||
|
tree: tree::empty(),
|
||||||
|
id: id,
|
||||||
|
|
||||||
min_width: au(0),
|
min_width: au(0),
|
||||||
pref_width: au(0),
|
pref_width: au(0),
|
||||||
position : au::zero_rect(),
|
position: au::zero_rect()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The type of the formatting context, and data specific to each
|
|
||||||
context, such as linebox structures or float lists */
|
|
||||||
enum FlowContextData {
|
|
||||||
AbsoluteFlow,
|
|
||||||
BlockFlow(BlockFlowData),
|
|
||||||
FloatFlow,
|
|
||||||
InlineBlockFlow,
|
|
||||||
InlineFlow(InlineFlowData),
|
|
||||||
RootFlow(RootFlowData),
|
|
||||||
TableFlow
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A particular kind of layout context. It manages the positioning of
|
|
||||||
render boxes within the context. */
|
|
||||||
struct FlowContext {
|
|
||||||
kind: FlowContextData,
|
|
||||||
data: FlowLayoutData,
|
|
||||||
mut node: Option<Node>,
|
|
||||||
/* reference to parent, children flow contexts */
|
|
||||||
tree: tree::Tree<@FlowContext>,
|
|
||||||
/* TODO (Issue #87): debug only */
|
|
||||||
mut id: int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn FlowContext(id: int, kind: FlowContextData, tree: tree::Tree<@FlowContext>) -> FlowContext {
|
|
||||||
FlowContext {
|
|
||||||
kind: kind,
|
|
||||||
data: FlowLayoutData(),
|
|
||||||
node: None,
|
|
||||||
tree: tree,
|
|
||||||
id: id
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flow context disambiguation methods: the verbose alternative to virtual methods */
|
/* Flow context disambiguation methods: the verbose alternative to virtual methods */
|
||||||
impl FlowContext {
|
impl FlowContext {
|
||||||
fn bubble_widths(ctx: &LayoutContext) {
|
fn bubble_widths(ctx: &LayoutContext) {
|
||||||
match self.kind {
|
match self {
|
||||||
BlockFlow(*) => self.bubble_widths_block(ctx),
|
BlockFlow(*) => self.bubble_widths_block(ctx),
|
||||||
InlineFlow(*) => self.bubble_widths_inline(ctx),
|
InlineFlow(*) => self.bubble_widths_inline(ctx),
|
||||||
RootFlow(*) => self.bubble_widths_root(ctx),
|
RootFlow(*) => self.bubble_widths_root(ctx),
|
||||||
_ => fail fmt!("Tried to bubble_widths of flow: %?", self.kind)
|
_ => fail fmt!("Tried to bubble_widths of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_widths(ctx: &LayoutContext) {
|
fn assign_widths(ctx: &LayoutContext) {
|
||||||
match self.kind {
|
match self {
|
||||||
BlockFlow(*) => self.assign_widths_block(ctx),
|
BlockFlow(*) => self.assign_widths_block(ctx),
|
||||||
InlineFlow(*) => self.assign_widths_inline(ctx),
|
InlineFlow(*) => self.assign_widths_inline(ctx),
|
||||||
RootFlow(*) => self.assign_widths_root(ctx),
|
RootFlow(*) => self.assign_widths_root(ctx),
|
||||||
_ => fail fmt!("Tried to assign_widths of flow: %?", self.kind)
|
_ => fail fmt!("Tried to assign_widths of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_height(ctx: &LayoutContext) {
|
fn assign_height(ctx: &LayoutContext) {
|
||||||
match self.kind {
|
match self {
|
||||||
BlockFlow(*) => self.assign_height_block(ctx),
|
BlockFlow(*) => self.assign_height_block(ctx),
|
||||||
InlineFlow(*) => self.assign_height_inline(ctx),
|
InlineFlow(*) => self.assign_height_inline(ctx),
|
||||||
RootFlow(*) => self.assign_height_root(ctx),
|
RootFlow(*) => self.assign_height_root(ctx),
|
||||||
_ => fail fmt!("Tried to assign_height of flow: %?", self.kind)
|
_ => fail fmt!("Tried to assign_height of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_recurse(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
fn build_display_list_recurse(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||||
match self.kind {
|
match self {
|
||||||
RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
|
RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
|
||||||
BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
|
BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
|
||||||
InlineFlow(*) => self.build_display_list_inline(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)
|
_ => fail fmt!("Tried to build_display_list_recurse of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,39 +171,39 @@ impl FlowContext {
|
||||||
// Actual methods that do not require much flow-specific logic
|
// Actual methods that do not require much flow-specific logic
|
||||||
impl FlowContext {
|
impl FlowContext {
|
||||||
pure fn foldl_boxes_for_node<B: Copy>(node: Node, seed: B, blk: pure fn&(B,@RenderBox) -> B) -> B {
|
pure fn foldl_boxes_for_node<B: Copy>(node: Node, seed: B, blk: pure fn&(B,@RenderBox) -> B) -> B {
|
||||||
match self.kind {
|
match self {
|
||||||
RootFlow(d) => match d.box {
|
RootFlow(*) => match self.root().box {
|
||||||
Some(box) if box.d().node == node => { blk(seed, box) },
|
Some(box) if box.d().node == node => { blk(seed, box) },
|
||||||
_ => seed
|
_ => seed
|
||||||
},
|
},
|
||||||
BlockFlow(d) => match d.box {
|
BlockFlow(*) => match self.block().box {
|
||||||
Some(box) if box.d().node == node => { blk(seed, box) },
|
Some(box) if box.d().node == node => { blk(seed, box) },
|
||||||
_ => seed
|
_ => seed
|
||||||
},
|
},
|
||||||
InlineFlow(d) => do d.boxes.foldl(seed) |acc, box| {
|
InlineFlow(*) => do self.inline().boxes.foldl(seed) |acc, box| {
|
||||||
if box.d().node == node { blk(acc, box) }
|
if box.d().node == node { blk(acc, box) }
|
||||||
else { acc }
|
else { acc }
|
||||||
},
|
},
|
||||||
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self.kind)
|
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pure fn iter_boxes_for_node<T>(node: Node, cb: pure fn&(@RenderBox) -> T) {
|
pure fn iter_boxes_for_node<T>(node: Node, cb: pure fn&(@RenderBox) -> T) {
|
||||||
match self.kind {
|
match self {
|
||||||
RootFlow(d) => match d.box {
|
RootFlow(*) => match self.root().box {
|
||||||
Some(box) if box.d().node == node => { cb(box); },
|
Some(box) if box.d().node == node => { cb(box); },
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
BlockFlow(d) => match d.box {
|
BlockFlow(*) => match self.block().box {
|
||||||
Some(box) if box.d().node == node => { cb(box); },
|
Some(box) if box.d().node == node => { cb(box); },
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
InlineFlow(d) => {
|
InlineFlow(*) => {
|
||||||
for d.boxes.each |box| {
|
for self.inline().boxes.each |box| {
|
||||||
if box.d().node == node { cb(*box); }
|
if box.d().node == node { cb(*box); }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self.kind)
|
_ => fail fmt!("Don't know how to iterate node's RenderBoxes for %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +218,7 @@ impl FlowTree : tree::ReadMethods<@FlowContext> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_tree_fields<R>(&&b: @FlowContext, f: fn(tree::Tree<@FlowContext>) -> R) -> R {
|
fn with_tree_fields<R>(&&b: @FlowContext, f: fn(tree::Tree<@FlowContext>) -> R) -> R {
|
||||||
f(b.tree)
|
f(b.d().tree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +229,7 @@ impl FlowTree : tree::WriteMethods<@FlowContext> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_tree_fields<R>(&&b: @FlowContext, f: fn(tree::Tree<@FlowContext>) -> R) -> R {
|
fn with_tree_fields<R>(&&b: @FlowContext, f: fn(tree::Tree<@FlowContext>) -> R) -> R {
|
||||||
f(b.tree)
|
f(b.d().tree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,22 +256,28 @@ impl FlowContext : BoxedDebugMethods {
|
||||||
|
|
||||||
/* TODO: we need a string builder. This is horribly inefficient */
|
/* TODO: we need a string builder. This is horribly inefficient */
|
||||||
fn debug_str(@self) -> ~str {
|
fn debug_str(@self) -> ~str {
|
||||||
let repr = match self.kind {
|
let repr = match *self {
|
||||||
InlineFlow(d) => {
|
InlineFlow(*) => {
|
||||||
let mut s = d.boxes.foldl(~"InlineFlow(children=", |s, box| {
|
let mut s = self.inline().boxes.foldl(~"InlineFlow(children=", |s, box| {
|
||||||
fmt!("%s %?", s, box.d().id)
|
fmt!("%s %?", s, box.d().id)
|
||||||
});
|
});
|
||||||
s += ~")"; s
|
s += ~")"; s
|
||||||
},
|
},
|
||||||
BlockFlow(d) => {
|
BlockFlow(*) => {
|
||||||
match d.box {
|
match self.block().box {
|
||||||
Some(_b) => fmt!("BlockFlow(box=b%?)", d.box.get().d().id),
|
Some(box) => fmt!("BlockFlow(box=b%?)", box.d().id),
|
||||||
None => ~"BlockFlow",
|
None => ~"BlockFlow",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => fmt!("%?", self.kind)
|
RootFlow(*) => {
|
||||||
|
match self.root().box {
|
||||||
|
Some(box) => fmt!("RootFlo(box=b%?)", box.d().id),
|
||||||
|
None => ~"RootFlow",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => ~"(Unknown flow)"
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt!("c%? %?", self.id, repr)
|
fmt!("c%? %?", self.d().id, repr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,6 @@ fn InlineFlowData() -> InlineFlowData {
|
||||||
trait InlineLayout {
|
trait InlineLayout {
|
||||||
pure fn starts_inline_flow() -> bool;
|
pure fn starts_inline_flow() -> bool;
|
||||||
|
|
||||||
pure fn access_inline<T>(fn(&&InlineFlowData) -> T) -> T;
|
|
||||||
fn bubble_widths_inline(ctx: &LayoutContext);
|
fn bubble_widths_inline(ctx: &LayoutContext);
|
||||||
fn assign_widths_inline(ctx: &LayoutContext);
|
fn assign_widths_inline(ctx: &LayoutContext);
|
||||||
fn assign_height_inline(ctx: &LayoutContext);
|
fn assign_height_inline(ctx: &LayoutContext);
|
||||||
|
@ -58,14 +57,7 @@ trait InlineLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowContext : InlineLayout {
|
impl FlowContext : InlineLayout {
|
||||||
pure fn starts_inline_flow() -> bool { match self.kind { InlineFlow(*) => true, _ => false } }
|
pure fn starts_inline_flow() -> bool { match self { InlineFlow(*) => true, _ => false } }
|
||||||
|
|
||||||
pure fn access_inline<T>(cb: fn(&&InlineFlowData) -> T) -> T {
|
|
||||||
match self.kind {
|
|
||||||
InlineFlow(d) => cb(d),
|
|
||||||
_ => fail fmt!("Tried to access() data of InlineFlow, but this is a %?", self.kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bubble_widths_inline(_ctx: &LayoutContext) {
|
fn bubble_widths_inline(_ctx: &LayoutContext) {
|
||||||
assert self.starts_inline_flow();
|
assert self.starts_inline_flow();
|
||||||
|
@ -73,15 +65,13 @@ impl FlowContext : InlineLayout {
|
||||||
let mut min_width = au(0);
|
let mut min_width = au(0);
|
||||||
let mut pref_width = au(0);
|
let mut pref_width = au(0);
|
||||||
|
|
||||||
do self.access_inline |d| {
|
for self.inline().boxes.each |box| {
|
||||||
for d.boxes.each |box| {
|
min_width = au::max(min_width, box.get_min_width());
|
||||||
min_width = au::max(min_width, box.get_min_width());
|
pref_width = au::max(pref_width, box.get_pref_width());
|
||||||
pref_width = au::max(pref_width, box.get_pref_width());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.data.min_width = min_width;
|
self.d().min_width = min_width;
|
||||||
self.data.pref_width = pref_width;
|
self.d().pref_width = pref_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Recursively (top-down) determines the actual width of child
|
/* Recursively (top-down) determines the actual width of child
|
||||||
|
@ -91,59 +81,56 @@ impl FlowContext : InlineLayout {
|
||||||
assert self.starts_inline_flow();
|
assert self.starts_inline_flow();
|
||||||
|
|
||||||
/* Perform inline flow with the available width. */
|
/* Perform inline flow with the available width. */
|
||||||
//let avail_width = self.data.position.size.width;
|
//let avail_width = self.d().position.size.width;
|
||||||
|
|
||||||
let line_height = au::from_px(20);
|
let line_height = au::from_px(20);
|
||||||
//let mut cur_x = au(0);
|
//let mut cur_x = au(0);
|
||||||
let mut cur_y = au(0);
|
let mut cur_y = au(0);
|
||||||
|
|
||||||
do self.access_inline |d| {
|
for self.inline().boxes.each |box| {
|
||||||
for d.boxes.each |box| {
|
/* TODO: actually do inline flow.
|
||||||
/* TODO: actually do inline flow.
|
- Create a working linebox, and successively put boxes
|
||||||
- Create a working linebox, and successively put boxes
|
into it, splitting if necessary.
|
||||||
into it, splitting if necessary.
|
|
||||||
|
- Set width and height for each positioned element based on
|
||||||
- Set width and height for each positioned element based on
|
where its chunks ended up.
|
||||||
where its chunks ended up.
|
|
||||||
|
|
||||||
- Save the dvec of this context's lineboxes. */
|
- Save the dvec of this context's lineboxes. */
|
||||||
|
|
||||||
/* hack: until text box splitting is hoisted into this
|
/* hack: until text box splitting is hoisted into this
|
||||||
function, force "reflow" on TextBoxes. */
|
function, force "reflow" on TextBoxes. */
|
||||||
match *box {
|
match *box {
|
||||||
@TextBox(*) => box.reflow_text(ctx),
|
@TextBox(*) => box.reflow_text(ctx),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
box.d().position.size.width = match *box {
|
box.d().position.size.width = match *box {
|
||||||
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).width),
|
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).width),
|
||||||
@TextBox(_,d) => d.runs[0].size().width,
|
@TextBox(_,d) => d.runs[0].size().width,
|
||||||
// TODO: this should be set to the extents of its children
|
// TODO: this should be set to the extents of its children
|
||||||
@GenericBox(*) => au(0)
|
@GenericBox(*) => au(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
box.d().position.size.height = match *box {
|
box.d().position.size.height = match *box {
|
||||||
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).height),
|
@ImageBox(_,img) => au::from_px(img.get_size().get_default(Size2D(0,0)).height),
|
||||||
@TextBox(_,d) => d.runs[0].size().height,
|
@TextBox(_,d) => d.runs[0].size().height,
|
||||||
// TODO: this should be set to the extents of its children
|
// TODO: this should be set to the extents of its children
|
||||||
@GenericBox(*) => au(0)
|
@GenericBox(*) => au(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
box.d().position.origin = Point2D(au(0), cur_y);
|
box.d().position.origin = Point2D(au(0), cur_y);
|
||||||
cur_y = cur_y.add(au::max(line_height, box.d().position.size.height));
|
cur_y = cur_y.add(au::max(line_height, box.d().position.size.height));
|
||||||
} // for boxes.each |box|
|
} // for boxes.each |box|
|
||||||
}
|
|
||||||
|
|
||||||
self.data.position.size.height = cur_y;
|
self.d().position.size.height = cur_y;
|
||||||
|
|
||||||
/* There are no child contexts, so stop here. */
|
/* There are no child contexts, so stop here. */
|
||||||
|
|
||||||
// TODO: once there are 'inline-block' elements, this won't be
|
// TODO: once there are 'inline-block' elements, this won't be
|
||||||
// true. In that case, perform inline flow, and then set the
|
// true. In that case, perform inline flow, and then set the
|
||||||
// block flow context's width as the width of the
|
// block flow context's width as the width of the
|
||||||
// 'inline-block' box that created this flow.
|
// 'inline-block' box that created this flow.
|
||||||
|
}
|
||||||
} // fn assign_widths_inline
|
|
||||||
|
|
||||||
fn assign_height_inline(_ctx: &LayoutContext) {
|
fn assign_height_inline(_ctx: &LayoutContext) {
|
||||||
// Don't need to set box or ctx heights, since that is done
|
// Don't need to set box or ctx heights, since that is done
|
||||||
|
@ -160,10 +147,8 @@ impl FlowContext : InlineLayout {
|
||||||
|
|
||||||
// TODO: once we form line boxes and have their cached bounds, we can be
|
// 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
|
// smarter and not recurse on a line if nothing in it can intersect dirty
|
||||||
do self.access_inline |d| {
|
for self.inline().boxes.each |box| {
|
||||||
for d.boxes.each |box| {
|
box.build_display_list(builder, dirty, offset, list)
|
||||||
box.build_display_list(builder, dirty, offset, list)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should inline-block elements have flows as children
|
// TODO: should inline-block elements have flows as children
|
||||||
|
|
|
@ -168,7 +168,7 @@ impl Layout {
|
||||||
};
|
};
|
||||||
// TODO: set options on the builder before building
|
// TODO: set options on the builder before building
|
||||||
// TODO: be smarter about what needs painting
|
// TODO: be smarter about what needs painting
|
||||||
layout_root.build_display_list(&builder, © layout_root.data.position, &dlist);
|
layout_root.build_display_list(&builder, © layout_root.d().position, &dlist);
|
||||||
self.render_task.send(render_task::RenderMsg(dlist));
|
self.render_task.send(render_task::RenderMsg(dlist));
|
||||||
} // time(layout)
|
} // time(layout)
|
||||||
} // BuildMsg
|
} // BuildMsg
|
||||||
|
|
|
@ -21,7 +21,6 @@ fn RootFlowData() -> RootFlowData {
|
||||||
|
|
||||||
trait RootLayout {
|
trait RootLayout {
|
||||||
pure fn starts_root_flow() -> bool;
|
pure fn starts_root_flow() -> bool;
|
||||||
pure fn access_root<T>(fn(&&RootFlowData) -> T) -> T;
|
|
||||||
|
|
||||||
fn bubble_widths_root(ctx: &LayoutContext);
|
fn bubble_widths_root(ctx: &LayoutContext);
|
||||||
fn assign_widths_root(ctx: &LayoutContext);
|
fn assign_widths_root(ctx: &LayoutContext);
|
||||||
|
@ -33,19 +32,12 @@ trait RootLayout {
|
||||||
impl FlowContext : RootLayout {
|
impl FlowContext : RootLayout {
|
||||||
|
|
||||||
pure fn starts_root_flow() -> bool {
|
pure fn starts_root_flow() -> bool {
|
||||||
match self.kind {
|
match self {
|
||||||
RootFlow(*) => true,
|
RootFlow(*) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pure fn access_root<T>(cb:fn(&&RootFlowData) -> T) -> T {
|
|
||||||
match self.kind {
|
|
||||||
RootFlow(d) => cb(d),
|
|
||||||
_ => fail fmt!("Tried to access() data of RootFlow, but this is a %?", self.kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* defer to the block algorithm */
|
/* defer to the block algorithm */
|
||||||
fn bubble_widths_root(ctx: &LayoutContext) {
|
fn bubble_widths_root(ctx: &LayoutContext) {
|
||||||
assert self.starts_root_flow();
|
assert self.starts_root_flow();
|
||||||
|
@ -55,7 +47,7 @@ impl FlowContext : RootLayout {
|
||||||
fn assign_widths_root(ctx: &LayoutContext) {
|
fn assign_widths_root(ctx: &LayoutContext) {
|
||||||
assert self.starts_root_flow();
|
assert self.starts_root_flow();
|
||||||
|
|
||||||
self.data.position = copy ctx.screen_size;
|
self.d().position = copy ctx.screen_size;
|
||||||
self.assign_widths_block(ctx)
|
self.assign_widths_block(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue