mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Update style of flow and remove its reliance on tree
`tree` is an old API that predates the use of traits. It should be redone. This commit breaks the dependency on it.
This commit is contained in:
parent
c74249aee5
commit
fddf4ca30e
5 changed files with 223 additions and 147 deletions
|
@ -4,15 +4,14 @@
|
||||||
|
|
||||||
// Block layout.
|
// Block layout.
|
||||||
|
|
||||||
use core::cell::Cell;
|
|
||||||
|
|
||||||
use layout::box::{RenderBox};
|
use layout::box::{RenderBox};
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
|
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
|
||||||
use layout::flow::{FlowContext, FlowTree, InlineBlockFlow, BlockFlow, RootFlow};
|
use layout::flow::{BlockFlow, FlowContext, InlineBlockFlow, RootFlow};
|
||||||
use layout::inline::InlineLayout;
|
use layout::inline::InlineLayout;
|
||||||
|
|
||||||
use au = gfx::geometry;
|
use au = gfx::geometry;
|
||||||
|
use core::cell::Cell;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
|
@ -82,7 +81,7 @@ impl BlockLayout for FlowContext {
|
||||||
let mut pref_width = Au(0);
|
let mut pref_width = Au(0);
|
||||||
|
|
||||||
/* find max width from child block contexts */
|
/* find max width from child block contexts */
|
||||||
for FlowTree.each_child(self) |child_ctx| {
|
for self.each_child |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.d().min_width);
|
min_width = au::max(min_width, child_ctx.d().min_width);
|
||||||
|
@ -122,7 +121,7 @@ impl BlockLayout for FlowContext {
|
||||||
remaining_width -= left_used.add(&right_used);
|
remaining_width -= left_used.add(&right_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
for FlowTree.each_child(self) |child_ctx| {
|
for self.each_child |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.d().position.origin.x = left_used;
|
child_ctx.d().position.origin.x = left_used;
|
||||||
child_ctx.d().position.size.width = remaining_width;
|
child_ctx.d().position.size.width = remaining_width;
|
||||||
|
@ -134,7 +133,7 @@ impl BlockLayout for FlowContext {
|
||||||
|
|
||||||
let mut cur_y = Au(0);
|
let mut cur_y = Au(0);
|
||||||
|
|
||||||
for FlowTree.each_child(self) |child_ctx| {
|
for self.each_child |child_ctx| {
|
||||||
child_ctx.d().position.origin.y = cur_y;
|
child_ctx.d().position.origin.y = cur_y;
|
||||||
cur_y += child_ctx.d().position.size.height;
|
cur_y += child_ctx.d().position.size.height;
|
||||||
}
|
}
|
||||||
|
@ -164,7 +163,7 @@ impl BlockLayout for FlowContext {
|
||||||
// TODO: handle any out-of-flow elements
|
// TODO: handle any out-of-flow elements
|
||||||
|
|
||||||
// go deeper into the flow tree
|
// go deeper into the flow tree
|
||||||
for FlowTree.each_child(self) |child| {
|
for self.each_child |child| {
|
||||||
self.build_display_list_for_child(builder, child, dirty, offset, list)
|
self.build_display_list_for_child(builder, child, dirty, offset, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ use layout::debug::{BoxedMutDebugMethods, DebugMethods};
|
||||||
use layout::flow::*;
|
use layout::flow::*;
|
||||||
use layout::inline::{InlineFlowData, InlineLayout};
|
use layout::inline::{InlineFlowData, InlineLayout};
|
||||||
use layout::root::RootFlowData;
|
use layout::root::RootFlowData;
|
||||||
use util::tree;
|
|
||||||
|
|
||||||
use gfx::image::holder::ImageHolder;
|
use gfx::image::holder::ImageHolder;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
|
@ -223,9 +222,8 @@ impl BuilderContext {
|
||||||
priv fn attach_child_flow(&self, child: @mut FlowContext) {
|
priv fn attach_child_flow(&self, child: @mut FlowContext) {
|
||||||
let d = self.default_collector.flow.d(); // FIXME: borrow checker workaround
|
let d = self.default_collector.flow.d(); // FIXME: borrow checker workaround
|
||||||
let cd = child.d(); // FIXME: borrow checker workaround
|
let cd = child.d(); // FIXME: borrow checker workaround
|
||||||
debug!("BuilderContext: Adding child flow f%? of f%?",
|
debug!("BuilderContext: Adding child flow f%? of f%?", d.id, cd.id);
|
||||||
d.id, cd.id);
|
self.default_collector.flow.add_child(child);
|
||||||
tree::add_child(&FlowTree, self.default_collector.flow, child);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
priv fn create_child_flow_of_type(&self,
|
priv fn create_child_flow_of_type(&self,
|
||||||
|
@ -332,10 +330,10 @@ pub impl LayoutTreeBuilder {
|
||||||
// eventually be elided or split, but the mapping between
|
// eventually be elided or split, but the mapping between
|
||||||
// nodes and FlowContexts should not change during layout.
|
// nodes and FlowContexts should not change during layout.
|
||||||
let flow = &mut this_ctx.default_collector.flow;
|
let flow = &mut this_ctx.default_collector.flow;
|
||||||
for tree::each_child(&FlowTree, flow) |child_flow: &@mut FlowContext| {
|
for flow.each_child |child_flow: @mut FlowContext| {
|
||||||
let node = child_flow.d().node;
|
let node = child_flow.d().node;
|
||||||
assert!(node.has_layout_data());
|
assert!(node.has_layout_data());
|
||||||
node.layout_data().flow = Some(*child_flow);
|
node.layout_data().flow = Some(child_flow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,8 +353,8 @@ pub impl LayoutTreeBuilder {
|
||||||
let mut found_child_block = false;
|
let mut found_child_block = false;
|
||||||
|
|
||||||
let flow = &mut parent_ctx.default_collector.flow;
|
let flow = &mut parent_ctx.default_collector.flow;
|
||||||
for tree::each_child(&FlowTree, flow) |child_ctx: &@mut FlowContext| {
|
for flow.each_child |child_ctx: @mut FlowContext| {
|
||||||
match **child_ctx {
|
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,
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -371,24 +369,36 @@ pub impl LayoutTreeBuilder {
|
||||||
// FIXME: this will create refcounted cycles between the removed flow and any
|
// FIXME: this will create refcounted cycles between the removed flow and any
|
||||||
// of its RenderBox or FlowContext children, and possibly keep alive other junk
|
// of its RenderBox or FlowContext children, and possibly keep alive other junk
|
||||||
let parent_flow = parent_ctx.default_collector.flow;
|
let parent_flow = parent_ctx.default_collector.flow;
|
||||||
|
|
||||||
|
// FIXME: Workaround for the borrow check.
|
||||||
|
let (first_child, last_child) = {
|
||||||
|
let parent_flow: &mut FlowContext = parent_flow;
|
||||||
|
let parent_flow_data = parent_flow.d();
|
||||||
|
(parent_flow_data.first_child, parent_flow_data.last_child)
|
||||||
|
};
|
||||||
|
|
||||||
// check first/last child for whitespace-ness
|
// check first/last child for whitespace-ness
|
||||||
for tree::first_child(&FlowTree, &parent_flow).each |first_flow: &@mut FlowContext| {
|
for first_child.each |first_flow: &@mut FlowContext| {
|
||||||
if first_flow.starts_inline_flow() {
|
if first_flow.starts_inline_flow() {
|
||||||
let boxes = &mut first_flow.inline().boxes;
|
let boxes = &mut first_flow.inline().boxes;
|
||||||
if boxes.len() == 1 && boxes[0].is_whitespace_only() {
|
if boxes.len() == 1 && boxes[0].is_whitespace_only() {
|
||||||
debug!("LayoutTreeBuilder: pruning whitespace-only first child flow f%d from parent f%d",
|
debug!("LayoutTreeBuilder: pruning whitespace-only first child flow \
|
||||||
first_flow.d().id, parent_flow.d().id);
|
f%d from parent f%d",
|
||||||
tree::remove_child(&FlowTree, parent_flow, *first_flow);
|
first_flow.d().id,
|
||||||
|
parent_flow.d().id);
|
||||||
|
parent_flow.remove_child(*first_flow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for tree::last_child(&FlowTree, &parent_flow).each |last_flow: &@mut FlowContext| {
|
for last_child.each |last_flow: &@mut FlowContext| {
|
||||||
if last_flow.starts_inline_flow() {
|
if last_flow.starts_inline_flow() {
|
||||||
let boxes = &mut last_flow.inline().boxes;
|
let boxes = &mut last_flow.inline().boxes;
|
||||||
if boxes.len() == 1 && boxes.last().is_whitespace_only() {
|
if boxes.len() == 1 && boxes.last().is_whitespace_only() {
|
||||||
debug!("LayoutTreeBuilder: pruning whitespace-only last child flow f%d from parent f%d",
|
debug!("LayoutTreeBuilder: pruning whitespace-only last child flow \
|
||||||
last_flow.d().id, parent_flow.d().id);
|
f%d from parent f%d",
|
||||||
tree::remove_child(&FlowTree, parent_flow, *last_flow);
|
last_flow.d().id,
|
||||||
|
parent_flow.d().id);
|
||||||
|
parent_flow.remove_child(*last_flow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -416,7 +426,7 @@ pub impl LayoutTreeBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_flow(&mut self, ty: FlowContextType, node: AbstractNode) -> @mut FlowContext {
|
fn make_flow(&mut self, ty: FlowContextType, node: AbstractNode) -> @mut FlowContext {
|
||||||
let data = FlowData(self.next_flow_id(), node);
|
let data = FlowData::new(self.next_flow_id(), node);
|
||||||
let ret = match ty {
|
let ret = match ty {
|
||||||
Flow_Absolute => @mut AbsoluteFlow(data),
|
Flow_Absolute => @mut AbsoluteFlow(data),
|
||||||
Flow_Block => @mut BlockFlow(data, BlockFlowData()),
|
Flow_Block => @mut BlockFlow(data, BlockFlowData()),
|
||||||
|
|
|
@ -2,8 +2,28 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use core;
|
//! Servo's experimental layout system builds a tree of `FlowContext` and `RenderBox` objects and
|
||||||
use core::cell::Cell;
|
/// solves layout constraints to obtain positions and display attributes of tree nodes. Positions
|
||||||
|
/// are computed in several tree traversals driven by the fundamental data dependencies required by
|
||||||
|
/// inline and block layout.
|
||||||
|
///
|
||||||
|
/// Flows 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 auxiliary 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 (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()` and
|
||||||
|
/// similar methods.
|
||||||
|
|
||||||
use dom::node::AbstractNode;
|
use dom::node::AbstractNode;
|
||||||
use layout::block::{BlockFlowData, BlockLayout};
|
use layout::block::{BlockFlowData, BlockLayout};
|
||||||
use layout::box::RenderBox;
|
use layout::box::RenderBox;
|
||||||
|
@ -12,41 +32,16 @@ use layout::debug::BoxedMutDebugMethods;
|
||||||
use layout::display_list_builder::DisplayListBuilder;
|
use layout::display_list_builder::DisplayListBuilder;
|
||||||
use layout::inline::{InlineFlowData, InlineLayout};
|
use layout::inline::{InlineFlowData, InlineLayout};
|
||||||
use layout::root::{RootFlowData, RootLayout};
|
use layout::root::{RootFlowData, RootLayout};
|
||||||
use util::tree;
|
|
||||||
use geom::rect::Rect;
|
use core::cell::Cell;
|
||||||
|
use core::ptr;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
|
use geom::rect::Rect;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use gfx::geometry::Au;
|
use gfx::geometry::Au;
|
||||||
|
|
||||||
/** Servo's experimental layout system builds a tree of FlowContexts
|
/// The type of the formatting context and data specific to each context, such as line box
|
||||||
and RenderBoxes, and figures out positions and display attributes of
|
/// structures or float lists.
|
||||||
tree nodes. Positions are computed in several tree traversals driven
|
|
||||||
by fundamental data dependencies of inline and block layout.
|
|
||||||
|
|
||||||
Flows 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()`.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The type of the formatting context, and data specific to each
|
|
||||||
context, such as linebox structures or float lists */
|
|
||||||
pub enum FlowContext {
|
pub enum FlowContext {
|
||||||
AbsoluteFlow(FlowData),
|
AbsoluteFlow(FlowData),
|
||||||
BlockFlow(FlowData, BlockFlowData),
|
BlockFlow(FlowData, BlockFlowData),
|
||||||
|
@ -71,8 +66,13 @@ pub enum FlowContextType {
|
||||||
render boxes within the context. */
|
render boxes within the context. */
|
||||||
pub struct FlowData {
|
pub struct FlowData {
|
||||||
node: AbstractNode,
|
node: AbstractNode,
|
||||||
/* reference to parent, children flow contexts */
|
|
||||||
tree: tree::Tree<@mut FlowContext>,
|
parent: Option<@mut FlowContext>,
|
||||||
|
first_child: Option<@mut FlowContext>,
|
||||||
|
last_child: Option<@mut FlowContext>,
|
||||||
|
prev_sibling: Option<@mut FlowContext>,
|
||||||
|
next_sibling: Option<@mut FlowContext>,
|
||||||
|
|
||||||
/* TODO (Issue #87): debug only */
|
/* TODO (Issue #87): debug only */
|
||||||
id: int,
|
id: int,
|
||||||
|
|
||||||
|
@ -84,55 +84,131 @@ pub struct FlowData {
|
||||||
position: Rect<Au>,
|
position: Rect<Au>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn FlowData(id: int, node: AbstractNode) -> FlowData {
|
impl FlowData {
|
||||||
FlowData {
|
pub fn new(id: int, node: AbstractNode) -> FlowData {
|
||||||
node: node,
|
FlowData {
|
||||||
tree: tree::empty(),
|
node: node,
|
||||||
id: id,
|
|
||||||
|
|
||||||
min_width: Au(0),
|
parent: None,
|
||||||
pref_width: Au(0),
|
first_child: None,
|
||||||
position: Au::zero_rect()
|
last_child: None,
|
||||||
|
prev_sibling: None,
|
||||||
|
next_sibling: None,
|
||||||
|
|
||||||
|
id: id,
|
||||||
|
|
||||||
|
min_width: Au(0),
|
||||||
|
pref_width: Au(0),
|
||||||
|
position: Au::zero_rect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl<'self> FlowContext {
|
impl<'self> FlowContext {
|
||||||
fn d(&'self mut self) -> &'self mut FlowData {
|
pub fn d(&'self mut self) -> &'self mut FlowData {
|
||||||
unsafe {
|
unsafe {
|
||||||
match *self {
|
match *self {
|
||||||
AbsoluteFlow(ref d) => cast::transmute(d),
|
AbsoluteFlow(ref d) => cast::transmute(d),
|
||||||
BlockFlow(ref d, _) => cast::transmute(d),
|
BlockFlow(ref d, _) => cast::transmute(d),
|
||||||
FloatFlow(ref d) => cast::transmute(d),
|
FloatFlow(ref d) => cast::transmute(d),
|
||||||
InlineBlockFlow(ref d) => cast::transmute(d),
|
InlineBlockFlow(ref d) => cast::transmute(d),
|
||||||
InlineFlow(ref d, _) => cast::transmute(d),
|
InlineFlow(ref d, _) => cast::transmute(d),
|
||||||
RootFlow(ref d, _) => cast::transmute(d),
|
RootFlow(ref d, _) => cast::transmute(d),
|
||||||
TableFlow(ref d) => cast::transmute(d)
|
TableFlow(ref d) => cast::transmute(d)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inline(&'self mut self) -> &'self mut InlineFlowData {
|
/// Iterates over the immediate children of this flow.
|
||||||
|
///
|
||||||
|
/// TODO: Fold me into `util::tree`.
|
||||||
|
pub fn each_child(@mut self, f: &fn(@mut FlowContext) -> bool) {
|
||||||
|
let mut current_opt = self.d().first_child;
|
||||||
|
while !current_opt.is_none() {
|
||||||
|
let current = current_opt.get();
|
||||||
|
if !f(current) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current_opt = current.d().next_sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds the given flow to the end of the list of this flow's children. The new child must be
|
||||||
|
/// detached from the tree before calling this method.
|
||||||
|
///
|
||||||
|
/// TODO: Fold me into `util::tree`.
|
||||||
|
pub fn add_child(@mut self, child: @mut FlowContext) {
|
||||||
|
let self_data = self.d(), child_data = child.d();
|
||||||
|
|
||||||
|
assert!(child_data.parent.is_none());
|
||||||
|
assert!(child_data.prev_sibling.is_none());
|
||||||
|
assert!(child_data.next_sibling.is_none());
|
||||||
|
|
||||||
|
match self_data.last_child {
|
||||||
|
None => {
|
||||||
|
self_data.first_child = Some(child);
|
||||||
|
}
|
||||||
|
Some(last_child) => {
|
||||||
|
assert!(last_child.d().next_sibling.is_none());
|
||||||
|
last_child.d().next_sibling = Some(child);
|
||||||
|
child_data.prev_sibling = Some(last_child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self_data.last_child = Some(child);
|
||||||
|
child_data.parent = Some(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the given flow from the tree.
|
||||||
|
///
|
||||||
|
/// TODO: Fold me into `util::tree`.
|
||||||
|
pub fn remove_child(@mut self, child: @mut FlowContext) {
|
||||||
|
let self_data = self.d(), child_data = child.d();
|
||||||
|
|
||||||
|
assert!(child_data.parent.is_some());
|
||||||
|
assert!(ptr::ref_eq(&*child_data.parent.get(), self));
|
||||||
|
|
||||||
|
match child_data.prev_sibling {
|
||||||
|
None => self_data.first_child = child_data.next_sibling,
|
||||||
|
Some(prev_sibling) => {
|
||||||
|
prev_sibling.d().next_sibling = child_data.next_sibling;
|
||||||
|
child_data.prev_sibling = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match child_data.next_sibling {
|
||||||
|
None => self_data.last_child = child.d().prev_sibling,
|
||||||
|
Some(next_sibling) => {
|
||||||
|
next_sibling.d().prev_sibling = Some(next_sibling);
|
||||||
|
child_data.next_sibling = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
child_data.parent = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inline(&'self mut self) -> &'self mut InlineFlowData {
|
||||||
match self {
|
match self {
|
||||||
&InlineFlow(_, ref i) => unsafe { cast::transmute(i) },
|
&InlineFlow(_, ref i) => unsafe { cast::transmute(i) },
|
||||||
_ => fail!(fmt!("Tried to access inline data of non-inline: f%d", self.d().id))
|
_ => fail!(fmt!("Tried to access inline data of non-inline: f%d", self.d().id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block(&'self mut self) -> &'self mut BlockFlowData {
|
pub fn block(&'self mut self) -> &'self mut BlockFlowData {
|
||||||
match self {
|
match self {
|
||||||
&BlockFlow(_, ref mut b) => unsafe { cast::transmute(b) },
|
&BlockFlow(_, ref mut b) => unsafe { cast::transmute(b) },
|
||||||
_ => fail!(fmt!("Tried to access block data of non-block: f%d", self.d().id))
|
_ => fail!(fmt!("Tried to access block data of non-block: f%d", self.d().id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root(&'self mut self) -> &'self mut RootFlowData {
|
pub fn root(&'self mut self) -> &'self mut RootFlowData {
|
||||||
match self {
|
match self {
|
||||||
&RootFlow(_, ref r) => unsafe { cast::transmute(r) },
|
&RootFlow(_, ref r) => unsafe { cast::transmute(r) },
|
||||||
_ => fail!(fmt!("Tried to access root data of non-root: f%d", self.d().id))
|
_ => fail!(fmt!("Tried to access root data of non-root: f%d", self.d().id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bubble_widths(@mut self, ctx: &mut LayoutContext) {
|
pub fn bubble_widths(@mut self, ctx: &mut LayoutContext) {
|
||||||
match self {
|
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),
|
||||||
|
@ -141,7 +217,7 @@ pub impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_widths(@mut self, ctx: &mut LayoutContext) {
|
pub fn assign_widths(@mut self, ctx: &mut LayoutContext) {
|
||||||
match self {
|
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),
|
||||||
|
@ -150,7 +226,7 @@ pub impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_height(@mut self, ctx: &mut LayoutContext) {
|
pub fn assign_height(@mut self, ctx: &mut LayoutContext) {
|
||||||
match self {
|
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),
|
||||||
|
@ -159,8 +235,11 @@ pub impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_recurse(@mut self, builder: &DisplayListBuilder, dirty: &Rect<Au>,
|
pub fn build_display_list_recurse(@mut self,
|
||||||
offset: &Point2D<Au>, list: &Cell<DisplayList>) {
|
builder: &DisplayListBuilder,
|
||||||
|
dirty: &Rect<Au>,
|
||||||
|
offset: &Point2D<Au>,
|
||||||
|
list: &Cell<DisplayList>) {
|
||||||
let d = self.d(); // FIXME: borrow checker workaround
|
let d = self.d(); // FIXME: borrow checker workaround
|
||||||
debug!("FlowContext::build_display_list at %?: %s", d.position, self.debug_str());
|
debug!("FlowContext::build_display_list at %?: %s", d.position, self.debug_str());
|
||||||
|
|
||||||
|
@ -173,9 +252,10 @@ pub impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual methods that do not require much flow-specific logic
|
// Actual methods that do not require much flow-specific logic
|
||||||
fn foldl_all_boxes<B: Copy>(&mut self,
|
pub fn foldl_all_boxes<B:Copy>(&mut self,
|
||||||
seed: B,
|
seed: B,
|
||||||
cb: &fn(a: B, b: @mut RenderBox) -> B) -> B {
|
cb: &fn(a: B, b: @mut RenderBox) -> B)
|
||||||
|
-> B {
|
||||||
match self {
|
match self {
|
||||||
&RootFlow(*) => {
|
&RootFlow(*) => {
|
||||||
let root = self.root(); // FIXME: borrow checker workaround
|
let root = self.root(); // FIXME: borrow checker workaround
|
||||||
|
@ -193,85 +273,67 @@ pub impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foldl_boxes_for_node<B: Copy>(&mut self,
|
pub fn foldl_boxes_for_node<B:Copy>(&mut self,
|
||||||
node: AbstractNode,
|
node: AbstractNode,
|
||||||
seed: B,
|
seed: B,
|
||||||
cb: &fn(a: B,@mut RenderBox) -> B)
|
cb: &fn(a: B, @mut RenderBox) -> B)
|
||||||
-> B {
|
-> B {
|
||||||
do self.foldl_all_boxes(seed) |acc, box| {
|
do self.foldl_all_boxes(seed) |acc, box| {
|
||||||
if box.d().node == node { cb(acc, box) }
|
if box.d().node == node { cb(acc, box) }
|
||||||
else { acc }
|
else { acc }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_all_boxes<T>(&mut self, cb: &fn(@mut RenderBox) -> T) {
|
pub fn iter_all_boxes(&mut self, cb: &fn(@mut RenderBox) -> bool) {
|
||||||
match self {
|
match self {
|
||||||
&RootFlow(*) => {
|
&RootFlow(*) => {
|
||||||
let root = self.root(); // FIXME: borrow checker workaround
|
let root = self.root(); // FIXME: borrow checker workaround
|
||||||
for root.box.each |box| { cb(*box); }
|
for root.box.each |box| {
|
||||||
|
if !cb(*box) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&BlockFlow(*) => {
|
&BlockFlow(*) => {
|
||||||
let block = self.block(); // FIXME: borrow checker workaround
|
let block = self.block(); // FIXME: borrow checker workaround
|
||||||
for block.box.each |box| { cb(*box); }
|
for block.box.each |box| {
|
||||||
|
if !cb(*box) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&InlineFlow(*) => {
|
&InlineFlow(*) => {
|
||||||
let inline = self.inline(); // FIXME: borrow checker workaround
|
let inline = self.inline(); // FIXME: borrow checker workaround
|
||||||
for inline.boxes.each |box| { cb(*box); }
|
for inline.boxes.each |box| {
|
||||||
|
if !cb(*box) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self))
|
_ => fail!(fmt!("Don't know how to iterate node's RenderBoxes for %?", self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_boxes_for_node<T>(&mut self,
|
pub fn iter_boxes_for_node(&mut self, node: AbstractNode, cb: &fn(@mut RenderBox) -> bool) {
|
||||||
node: AbstractNode,
|
for self.iter_all_boxes |box| {
|
||||||
cb: &fn(@mut RenderBox) -> T) {
|
if box.d().node == node {
|
||||||
do self.iter_all_boxes |box| {
|
if !cb(box) {
|
||||||
if box.d().node == node { cb(box); }
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The tree holding FlowContexts */
|
|
||||||
pub enum FlowTree { FlowTree }
|
|
||||||
|
|
||||||
impl FlowTree {
|
|
||||||
fn each_child(&self, ctx: @mut FlowContext, f: &fn(box: @mut FlowContext) -> bool) {
|
|
||||||
tree::each_child(self, &ctx, |box| f(*box) )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl tree::ReadMethods<@mut FlowContext> for FlowTree {
|
|
||||||
fn with_tree_fields<R>(&self, box: &@mut FlowContext, f: &fn(&mut tree::Tree<@mut FlowContext>) -> R) -> R {
|
|
||||||
let tree = &mut box.d().tree;
|
|
||||||
f(tree)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlowTree {
|
|
||||||
fn add_child(self, parent: @mut FlowContext, child: @mut FlowContext) {
|
|
||||||
tree::add_child(&self, parent, child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl tree::WriteMethods<@mut FlowContext> for FlowTree {
|
|
||||||
fn tree_eq(&self, a: &@mut FlowContext, b: &@mut FlowContext) -> bool { core::managed::mut_ptr_eq(*a, *b) }
|
|
||||||
|
|
||||||
fn with_tree_fields<R>(&self, box: &@mut FlowContext, f: &fn(&mut tree::Tree<@mut FlowContext>) -> R) -> R {
|
|
||||||
let tree = &mut box.d().tree;
|
|
||||||
f(tree)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl BoxedMutDebugMethods for FlowContext {
|
impl BoxedMutDebugMethods for FlowContext {
|
||||||
fn dump(@mut self) {
|
fn dump(@mut self) {
|
||||||
self.dump_indent(0u);
|
self.dump_indent(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Dumps the flow tree, for debugging, with indentation. */
|
/// Dumps the flow tree, for debugging, with indentation.
|
||||||
fn dump_indent(@mut self, indent: uint) {
|
fn dump_indent(@mut self, indent: uint) {
|
||||||
let mut s = ~"|";
|
let mut s = ~"|";
|
||||||
for uint::range(0u, indent) |_i| {
|
for uint::range(0, indent) |_i| {
|
||||||
s += ~"---- ";
|
s += ~"---- ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,8 +341,8 @@ impl BoxedMutDebugMethods for FlowContext {
|
||||||
debug!("%s", s);
|
debug!("%s", s);
|
||||||
|
|
||||||
// FIXME: this should have a pure/const version?
|
// FIXME: this should have a pure/const version?
|
||||||
for FlowTree.each_child(self) |child| {
|
for self.each_child |child| {
|
||||||
child.dump_indent(indent + 1u)
|
child.dump_indent(indent + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,3 +375,4 @@ impl BoxedMutDebugMethods for FlowContext {
|
||||||
fmt!("f%? %?", d.id, repr)
|
fmt!("f%? %?", d.id, repr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use gfx::geometry::Au;
|
||||||
use layout::block::BlockLayout;
|
use layout::block::BlockLayout;
|
||||||
use layout::box::RenderBox;
|
use layout::box::RenderBox;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::flow::{FlowContext, FlowTree, RootFlow};
|
use layout::flow::{FlowContext, RootFlow};
|
||||||
use layout::display_list_builder::DisplayListBuilder;
|
use layout::display_list_builder::DisplayListBuilder;
|
||||||
|
|
||||||
pub struct RootFlowData {
|
pub struct RootFlowData {
|
||||||
|
@ -63,7 +63,7 @@ impl RootLayout for FlowContext {
|
||||||
// the root adjusts self height to at least cover the viewport.
|
// the root adjusts self height to at least cover the viewport.
|
||||||
let mut cur_y = Au(0);
|
let mut cur_y = Au(0);
|
||||||
|
|
||||||
for FlowTree.each_child(self) |child_ctx| {
|
for self.each_child |child_ctx| {
|
||||||
child_ctx.d().position.origin.y = cur_y;
|
child_ctx.d().position.origin.y = cur_y;
|
||||||
cur_y += child_ctx.d().position.size.height;
|
cur_y += child_ctx.d().position.size.height;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use layout::flow::{FlowContext, FlowTree};
|
use layout::flow::FlowContext;
|
||||||
|
|
||||||
/** Trait for running tree-based traversals over layout contexts */
|
/// A trait for running tree-based traversals over flows contexts.
|
||||||
pub trait FlowContextTraversals {
|
pub trait FlowContextTraversals {
|
||||||
fn traverse_preorder(@mut self, preorder_cb: &fn(@mut FlowContext));
|
fn traverse_preorder(@mut self, preorder_cb: &fn(@mut FlowContext));
|
||||||
fn traverse_postorder(@mut self, postorder_cb: &fn(@mut FlowContext));
|
fn traverse_postorder(@mut self, postorder_cb: &fn(@mut FlowContext));
|
||||||
|
@ -13,11 +13,15 @@ pub trait FlowContextTraversals {
|
||||||
impl FlowContextTraversals for FlowContext {
|
impl FlowContextTraversals for FlowContext {
|
||||||
fn traverse_preorder(@mut self, preorder_cb: &fn(@mut FlowContext)) {
|
fn traverse_preorder(@mut self, preorder_cb: &fn(@mut FlowContext)) {
|
||||||
preorder_cb(self);
|
preorder_cb(self);
|
||||||
do FlowTree.each_child(self) |child| { child.traverse_preorder(preorder_cb); true }
|
for self.each_child |child| {
|
||||||
|
child.traverse_preorder(preorder_cb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn traverse_postorder(@mut self, postorder_cb: &fn(@mut FlowContext)) {
|
fn traverse_postorder(@mut self, postorder_cb: &fn(@mut FlowContext)) {
|
||||||
do FlowTree.each_child(self) |child| { child.traverse_postorder(postorder_cb); true }
|
for self.each_child |child| {
|
||||||
|
child.traverse_postorder(postorder_cb);
|
||||||
|
}
|
||||||
postorder_cb(self);
|
postorder_cb(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue