mirror of
https://github.com/servo/servo.git
synced 2025-07-16 11:53:39 +01:00
Switch flow tree to owned pointers
This commit is contained in:
parent
eb58e4f5d1
commit
9b08fd8d18
9 changed files with 525 additions and 499 deletions
|
@ -19,7 +19,6 @@ use geom::rect::Rect;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use gfx::geometry::{Au, to_frac_px};
|
use gfx::geometry::{Au, to_frac_px};
|
||||||
use gfx::geometry;
|
use gfx::geometry;
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
|
|
||||||
pub struct BlockFlowData {
|
pub struct BlockFlowData {
|
||||||
/// Data common to all flows.
|
/// Data common to all flows.
|
||||||
|
@ -50,7 +49,6 @@ impl BlockFlowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn teardown(&mut self) {
|
pub fn teardown(&mut self) {
|
||||||
self.common.teardown();
|
|
||||||
for box in self.box.iter() {
|
for box in self.box.iter() {
|
||||||
box.teardown();
|
box.teardown();
|
||||||
}
|
}
|
||||||
|
@ -66,7 +64,7 @@ pub trait BlockLayout {
|
||||||
impl BlockLayout for FlowContext {
|
impl BlockLayout for FlowContext {
|
||||||
fn starts_root_flow(&self) -> bool {
|
fn starts_root_flow(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) => info.is_root,
|
BlockFlow(ref info) => info.is_root,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,13 +87,13 @@ impl BlockFlowData {
|
||||||
/* TODO: floats */
|
/* TODO: floats */
|
||||||
/* TODO: absolute contexts */
|
/* TODO: absolute contexts */
|
||||||
/* TODO: inline-blocks */
|
/* TODO: inline-blocks */
|
||||||
pub fn bubble_widths_block(@mut self, ctx: &LayoutContext) {
|
pub fn bubble_widths_block(&mut self, ctx: &LayoutContext) {
|
||||||
let mut min_width = Au(0);
|
let mut min_width = Au(0);
|
||||||
let mut pref_width = Au(0);
|
let mut pref_width = Au(0);
|
||||||
let mut num_floats = 0;
|
let mut num_floats = 0;
|
||||||
|
|
||||||
/* find max width from child block contexts */
|
/* find max width from child block contexts */
|
||||||
for child_ctx in BlockFlow(self).children() {
|
for child_ctx in self.common.child_iter() {
|
||||||
assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
|
assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
|
||||||
|
|
||||||
do child_ctx.with_mut_base |child_node| {
|
do child_ctx.with_mut_base |child_node| {
|
||||||
|
@ -179,7 +177,7 @@ impl BlockFlowData {
|
||||||
///
|
///
|
||||||
/// Dual boxes consume some width first, and the remainder is assigned to all child (block)
|
/// Dual boxes consume some width first, and the remainder is assigned to all child (block)
|
||||||
/// contexts.
|
/// contexts.
|
||||||
pub fn assign_widths_block(@mut self, ctx: &LayoutContext) {
|
pub fn assign_widths_block(&mut self, ctx: &LayoutContext) {
|
||||||
debug!("assign_widths_block: assigning width for flow %?", self.common.id);
|
debug!("assign_widths_block: assigning width for flow %?", self.common.id);
|
||||||
if self.is_root {
|
if self.is_root {
|
||||||
debug!("Setting root position");
|
debug!("Setting root position");
|
||||||
|
@ -240,7 +238,7 @@ impl BlockFlowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_inorder_children = self.common.is_inorder || self.common.num_floats > 0;
|
let has_inorder_children = self.common.is_inorder || self.common.num_floats > 0;
|
||||||
for kid in BlockFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
assert!(kid.starts_block_flow() || kid.starts_inline_flow());
|
assert!(kid.starts_block_flow() || kid.starts_inline_flow());
|
||||||
|
|
||||||
do kid.with_mut_base |child_node| {
|
do kid.with_mut_base |child_node| {
|
||||||
|
@ -255,12 +253,12 @@ impl BlockFlowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height_inorder_block(@mut self, ctx: &mut LayoutContext) {
|
pub fn assign_height_inorder_block(&mut self, ctx: &mut LayoutContext) {
|
||||||
debug!("assign_height_inorder_block: assigning height for block %?", self.common.id);
|
debug!("assign_height_inorder_block: assigning height for block %?", self.common.id);
|
||||||
self.assign_height_block_base(ctx, true);
|
self.assign_height_block_base(ctx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height_block(@mut self, ctx: &mut LayoutContext) {
|
pub fn assign_height_block(&mut self, ctx: &mut LayoutContext) {
|
||||||
debug!("assign_height_block: assigning height for block %?", self.common.id);
|
debug!("assign_height_block: assigning height for block %?", self.common.id);
|
||||||
// This is the only case in which a block flow can start an inorder
|
// This is the only case in which a block flow can start an inorder
|
||||||
// subtraversal.
|
// subtraversal.
|
||||||
|
@ -271,7 +269,7 @@ impl BlockFlowData {
|
||||||
self.assign_height_block_base(ctx, false);
|
self.assign_height_block_base(ctx, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_height_block_base(@mut self, ctx: &mut LayoutContext, inorder: bool) {
|
fn assign_height_block_base(&mut self, ctx: &mut LayoutContext, inorder: bool) {
|
||||||
let mut cur_y = Au(0);
|
let mut cur_y = Au(0);
|
||||||
let mut clearance = Au(0);
|
let mut clearance = Au(0);
|
||||||
let mut top_offset = Au(0);
|
let mut top_offset = Au(0);
|
||||||
|
@ -304,7 +302,7 @@ impl BlockFlowData {
|
||||||
// repeat until all children are visited.
|
// repeat until all children are visited.
|
||||||
// last_child.floats_out -> self.floats_out (done at the end of this method)
|
// last_child.floats_out -> self.floats_out (done at the end of this method)
|
||||||
float_ctx = self.common.floats_in.translate(Point2D(-left_offset, -top_offset));
|
float_ctx = self.common.floats_in.translate(Point2D(-left_offset, -top_offset));
|
||||||
for kid in BlockFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
do kid.with_mut_base |child_node| {
|
do kid.with_mut_base |child_node| {
|
||||||
child_node.floats_in = float_ctx.clone();
|
child_node.floats_in = float_ctx.clone();
|
||||||
}
|
}
|
||||||
|
@ -314,7 +312,7 @@ impl BlockFlowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for kid in BlockFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
do kid.with_mut_base |child_node| {
|
do kid.with_mut_base |child_node| {
|
||||||
child_node.position.origin.y = cur_y;
|
child_node.position.origin.y = cur_y;
|
||||||
cur_y = cur_y + child_node.position.size.height;
|
cur_y = cur_y + child_node.position.size.height;
|
||||||
|
@ -359,7 +357,7 @@ impl BlockFlowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_display_list_block<E:ExtraDisplayListData>(@mut self,
|
pub fn build_display_list_block<E:ExtraDisplayListData>(&mut self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &Cell<DisplayList<E>>)
|
||||||
|
@ -388,9 +386,11 @@ impl BlockFlowData {
|
||||||
|
|
||||||
let abs_rect = Rect(self.common.abs_position, self.common.position.size);
|
let abs_rect = Rect(self.common.abs_position, self.common.position.size);
|
||||||
if !abs_rect.intersects(dirty) {
|
if !abs_rect.intersects(dirty) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("build_display_list_block: adding display element");
|
||||||
|
|
||||||
// add box that starts block context
|
// add box that starts block context
|
||||||
self.box.map(|&box| {
|
self.box.map(|&box| {
|
||||||
box.build_display_list(builder, dirty, &self.common.abs_position, list)
|
box.build_display_list(builder, dirty, &self.common.abs_position, list)
|
||||||
|
@ -398,16 +398,14 @@ impl BlockFlowData {
|
||||||
|
|
||||||
|
|
||||||
// TODO: handle any out-of-flow elements
|
// TODO: handle any out-of-flow elements
|
||||||
|
let this_position = self.common.abs_position;
|
||||||
// go deeper into the flow tree
|
for child in self.common.child_iter() {
|
||||||
let flow = BlockFlow(self);
|
|
||||||
for child in flow.children() {
|
|
||||||
do child.with_mut_base |base| {
|
do child.with_mut_base |base| {
|
||||||
base.abs_position = self.common.abs_position + base.position.origin;
|
base.abs_position = this_position + base.position.origin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,9 +153,6 @@ pub struct RenderBoxBase {
|
||||||
/// The DOM node that this `RenderBox` originates from.
|
/// The DOM node that this `RenderBox` originates from.
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
|
|
||||||
/// The reference to the containing flow context which this box participates in.
|
|
||||||
ctx: FlowContext,
|
|
||||||
|
|
||||||
/// The position of this box relative to its owning flow.
|
/// The position of this box relative to its owning flow.
|
||||||
position: Rect<Au>,
|
position: Rect<Au>,
|
||||||
|
|
||||||
|
@ -170,11 +167,10 @@ pub struct RenderBoxBase {
|
||||||
|
|
||||||
impl RenderBoxBase {
|
impl RenderBoxBase {
|
||||||
/// Constructs a new `RenderBoxBase` instance.
|
/// Constructs a new `RenderBoxBase` instance.
|
||||||
pub fn new(node: AbstractNode<LayoutView>, flow_context: FlowContext, id: int)
|
pub fn new(node: AbstractNode<LayoutView>, id: int)
|
||||||
-> RenderBoxBase {
|
-> RenderBoxBase {
|
||||||
RenderBoxBase {
|
RenderBoxBase {
|
||||||
node: node,
|
node: node,
|
||||||
ctx: flow_context,
|
|
||||||
position: Au::zero_rect(),
|
position: Au::zero_rect(),
|
||||||
model: Zero::zero(),
|
model: Zero::zero(),
|
||||||
id: id,
|
id: id,
|
||||||
|
|
|
@ -30,9 +30,10 @@ use script::dom::node::{AbstractNode, CommentNodeTypeId, DoctypeNodeTypeId};
|
||||||
use script::dom::node::{ElementNodeTypeId, LayoutView, TextNodeTypeId};
|
use script::dom::node::{ElementNodeTypeId, LayoutView, TextNodeTypeId};
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use servo_util::tree::{TreeNodeRef, TreeNode};
|
use servo_util::tree::{TreeNodeRef, TreeNode};
|
||||||
|
use std::util;
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
pub struct LayoutTreeBuilder {
|
pub struct LayoutTreeBuilder {
|
||||||
root_flow: Option<FlowContext>,
|
|
||||||
next_cid: int,
|
next_cid: int,
|
||||||
next_bid: int,
|
next_bid: int,
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,6 @@ pub struct LayoutTreeBuilder {
|
||||||
impl LayoutTreeBuilder {
|
impl LayoutTreeBuilder {
|
||||||
pub fn new() -> LayoutTreeBuilder {
|
pub fn new() -> LayoutTreeBuilder {
|
||||||
LayoutTreeBuilder {
|
LayoutTreeBuilder {
|
||||||
root_flow: None,
|
|
||||||
next_cid: -1,
|
next_cid: -1,
|
||||||
next_bid: -1,
|
next_bid: -1,
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,9 @@ impl LayoutTreeBuilder {
|
||||||
|
|
||||||
// helper object for building the initial box list and making the
|
// helper object for building the initial box list and making the
|
||||||
// mapping between DOM nodes and boxes.
|
// mapping between DOM nodes and boxes.
|
||||||
struct BoxGenerator {
|
struct BoxGenerator<'self> {
|
||||||
flow: FlowContext,
|
flow: &'self mut FlowContext,
|
||||||
range_stack: ~[uint],
|
range_stack: @mut ~[uint],
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InlineSpacerSide {
|
enum InlineSpacerSide {
|
||||||
|
@ -93,25 +93,32 @@ fn simulate_UA_display_rules(node: AbstractNode<LayoutView>) -> CSSDisplay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxGenerator {
|
impl<'self> BoxGenerator<'self> {
|
||||||
/* Debug ids only */
|
/* Debug ids only */
|
||||||
|
|
||||||
fn new(flow: FlowContext) -> BoxGenerator {
|
fn new(flow: &'self mut FlowContext) -> BoxGenerator<'self> {
|
||||||
debug!("Creating box generator for flow: %s", flow.debug_str());
|
debug!("Creating box generator for flow: %s", flow.debug_str());
|
||||||
BoxGenerator {
|
BoxGenerator {
|
||||||
flow: flow,
|
flow: flow,
|
||||||
range_stack: ~[]
|
range_stack: @mut ~[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_clone<R> (&mut self, cb: &fn(BoxGenerator<'self>) -> R) -> R {
|
||||||
|
let gen = BoxGenerator {
|
||||||
|
flow: &mut *self.flow,
|
||||||
|
range_stack: self.range_stack
|
||||||
|
};
|
||||||
|
cb(gen)
|
||||||
|
}
|
||||||
|
|
||||||
/* Whether "spacer" boxes are needed to stand in for this DOM node */
|
/* Whether "spacer" boxes are needed to stand in for this DOM node */
|
||||||
fn inline_spacers_needed_for_node(&self, _: AbstractNode<LayoutView>) -> bool {
|
fn inline_spacers_needed_for_node(_: AbstractNode<LayoutView>) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement this, generating spacer
|
// TODO: implement this, generating spacer
|
||||||
fn make_inline_spacer_for_node_side(&self,
|
fn make_inline_spacer_for_node_side(_: &LayoutContext,
|
||||||
_: &LayoutContext,
|
|
||||||
_: AbstractNode<LayoutView>,
|
_: AbstractNode<LayoutView>,
|
||||||
_: InlineSpacerSide)
|
_: InlineSpacerSide)
|
||||||
-> Option<RenderBox> {
|
-> Option<RenderBox> {
|
||||||
|
@ -131,28 +138,29 @@ impl BoxGenerator {
|
||||||
|
|
||||||
debug!("BoxGenerator[f%d]: point a", self.flow.id());
|
debug!("BoxGenerator[f%d]: point a", self.flow.id());
|
||||||
|
|
||||||
|
let range_stack = &mut self.range_stack;
|
||||||
// depending on flow, make a box for this node.
|
// depending on flow, make a box for this node.
|
||||||
match self.flow {
|
match *self.flow {
|
||||||
InlineFlow(inline) => {
|
InlineFlow(ref mut inline) => {
|
||||||
let node_range_start = inline.boxes.len();
|
let node_range_start = inline.boxes.len();
|
||||||
self.range_stack.push(node_range_start);
|
range_stack.push(node_range_start);
|
||||||
|
|
||||||
// if a leaf, make a box.
|
// if a leaf, make a box.
|
||||||
if node.is_leaf() {
|
if node.is_leaf() {
|
||||||
let new_box = self.make_box(ctx, box_type, node, self.flow, builder);
|
let new_box = BoxGenerator::make_box(ctx, box_type, node, builder);
|
||||||
inline.boxes.push(new_box);
|
inline.boxes.push(new_box);
|
||||||
} else if self.inline_spacers_needed_for_node(node) {
|
} else if BoxGenerator::inline_spacers_needed_for_node(node) {
|
||||||
// else, maybe make a spacer for "left" margin, border, padding
|
// else, maybe make a spacer for "left" margin, border, padding
|
||||||
let inline_spacer = self.make_inline_spacer_for_node_side(ctx, node, LogicalBefore);
|
let inline_spacer = BoxGenerator::make_inline_spacer_for_node_side(ctx, node, LogicalBefore);
|
||||||
for spacer in inline_spacer.iter() {
|
for spacer in inline_spacer.iter() {
|
||||||
inline.boxes.push(*spacer);
|
inline.boxes.push(*spacer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: cases for inline-block, etc.
|
// TODO: cases for inline-block, etc.
|
||||||
},
|
},
|
||||||
BlockFlow(block) => {
|
BlockFlow(ref mut block) => {
|
||||||
debug!("BoxGenerator[f%d]: point b", block.common.id);
|
debug!("BoxGenerator[f%d]: point b", block.common.id);
|
||||||
let new_box = self.make_box(ctx, box_type, node, self.flow, builder);
|
let new_box = BoxGenerator::make_box(ctx, box_type, node, builder);
|
||||||
|
|
||||||
debug!("BoxGenerator[f%d]: attaching box[b%d] to block flow (node: %s)",
|
debug!("BoxGenerator[f%d]: attaching box[b%d] to block flow (node: %s)",
|
||||||
block.common.id,
|
block.common.id,
|
||||||
|
@ -161,46 +169,20 @@ impl BoxGenerator {
|
||||||
|
|
||||||
assert!(block.box.is_none());
|
assert!(block.box.is_none());
|
||||||
block.box = Some(new_box);
|
block.box = Some(new_box);
|
||||||
},
|
}
|
||||||
FloatFlow(float) => {
|
FloatFlow(ref mut float) => {
|
||||||
debug!("BoxGenerator[f%d]: point b", float.common.id);
|
debug!("BoxGenerator[f%d]: point b", float.common.id);
|
||||||
|
|
||||||
let mut parent_flow = None;
|
let new_box = BoxGenerator::make_box(ctx, box_type, node, builder);
|
||||||
|
|
||||||
do self.flow.with_base |base| {
|
debug!("BoxGenerator[f%d]: attaching box[b%d] to float flow (node: %s)",
|
||||||
parent_flow = base.parent_node();
|
float.common.id,
|
||||||
}
|
new_box.id(),
|
||||||
|
node.debug_str());
|
||||||
|
|
||||||
match parent_flow {
|
assert!(float.box.is_none() && float.index.is_none());
|
||||||
None => fail!("Float flow as root node"),
|
float.box = Some(new_box);
|
||||||
Some(BlockFlow(*)) |
|
}
|
||||||
Some(FloatFlow(*)) => {
|
|
||||||
let new_box = self.make_box(ctx, box_type, node, self.flow, builder);
|
|
||||||
|
|
||||||
debug!("BoxGenerator[f%d]: attaching box[b%d] to float flow (node: %s)",
|
|
||||||
float.common.id,
|
|
||||||
new_box.id(),
|
|
||||||
node.debug_str());
|
|
||||||
|
|
||||||
assert!(float.box.is_none() && float.index.is_none());
|
|
||||||
float.box = Some(new_box);
|
|
||||||
}
|
|
||||||
Some(InlineFlow(inline)) => {
|
|
||||||
let new_box = self.make_box(ctx, box_type, node, self.flow, builder);
|
|
||||||
|
|
||||||
debug!("BoxGenerator[f%d]: attaching box[b%d] to float flow (node: %s)",
|
|
||||||
float.common.id,
|
|
||||||
new_box.id(),
|
|
||||||
node.debug_str());
|
|
||||||
|
|
||||||
|
|
||||||
assert!(float.box.is_none() && float.index.is_none());
|
|
||||||
inline.boxes.push(new_box);
|
|
||||||
float.index = Some(inline.boxes.len() - 1);
|
|
||||||
}
|
|
||||||
_ => warn!("push_node() not implemented for flow f%d", self.flow.id())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => warn!("push_node() not implemented for flow f%d", self.flow.id()),
|
_ => warn!("push_node() not implemented for flow f%d", self.flow.id()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,16 +192,16 @@ impl BoxGenerator {
|
||||||
node: AbstractNode<LayoutView>) {
|
node: AbstractNode<LayoutView>) {
|
||||||
debug!("BoxGenerator[f%d]: popping node: %s", self.flow.id(), node.debug_str());
|
debug!("BoxGenerator[f%d]: popping node: %s", self.flow.id(), node.debug_str());
|
||||||
|
|
||||||
match self.flow {
|
match *self.flow {
|
||||||
InlineFlow(inline) => {
|
InlineFlow(ref mut inline) => {
|
||||||
let inline = &mut *inline;
|
let inline = &mut *inline;
|
||||||
|
|
||||||
if self.inline_spacers_needed_for_node(node) {
|
if BoxGenerator::inline_spacers_needed_for_node(node) {
|
||||||
// If this non-leaf box generates extra horizontal spacing, add a SpacerBox for
|
// If this non-leaf box generates extra horizontal spacing, add a SpacerBox for
|
||||||
// it.
|
// it.
|
||||||
let result = self.make_inline_spacer_for_node_side(ctx, node, LogicalAfter);
|
let result = BoxGenerator::make_inline_spacer_for_node_side(ctx, node, LogicalAfter);
|
||||||
for spacer in result.iter() {
|
for spacer in result.iter() {
|
||||||
let boxes = &mut self.flow.inline().boxes;
|
let boxes = &mut inline.boxes;
|
||||||
boxes.push(*spacer);
|
boxes.push(*spacer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,31 +216,29 @@ impl BoxGenerator {
|
||||||
inline.elems.add_mapping(node, &node_range);
|
inline.elems.add_mapping(node, &node_range);
|
||||||
},
|
},
|
||||||
BlockFlow(*) => assert!(self.range_stack.len() == 0),
|
BlockFlow(*) => assert!(self.range_stack.len() == 0),
|
||||||
|
FloatFlow(*) => assert!(self.range_stack.len() == 0),
|
||||||
_ => warn!("pop_node() not implemented for flow %?", self.flow.id()),
|
_ => warn!("pop_node() not implemented for flow %?", self.flow.id()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Disambiguate between different methods here instead of inlining, since each case has very
|
/// Disambiguate between different methods here instead of inlining, since each case has very
|
||||||
/// different complexity.
|
/// different complexity.
|
||||||
fn make_box(&self,
|
fn make_box(layout_ctx: &LayoutContext,
|
||||||
layout_ctx: &LayoutContext,
|
|
||||||
ty: RenderBoxType,
|
ty: RenderBoxType,
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
flow_context: FlowContext,
|
|
||||||
builder: &mut LayoutTreeBuilder)
|
builder: &mut LayoutTreeBuilder)
|
||||||
-> RenderBox {
|
-> RenderBox {
|
||||||
let base = RenderBoxBase::new(node, flow_context, builder.next_box_id());
|
let base = RenderBoxBase::new(node, builder.next_box_id());
|
||||||
let result = match ty {
|
let result = match ty {
|
||||||
RenderBox_Generic => GenericRenderBoxClass(@mut base),
|
RenderBox_Generic => GenericRenderBoxClass(@mut base),
|
||||||
RenderBox_Text => UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox::new(base)),
|
RenderBox_Text => UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox::new(base)),
|
||||||
RenderBox_Image => self.make_image_box(layout_ctx, node, base),
|
RenderBox_Image => BoxGenerator::make_image_box(layout_ctx, node, base),
|
||||||
};
|
};
|
||||||
debug!("BoxGenerator: created box: %s", result.debug_str());
|
debug!("BoxGenerator: created box: %s", result.debug_str());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_image_box(&self,
|
fn make_image_box(layout_ctx: &LayoutContext,
|
||||||
layout_ctx: &LayoutContext,
|
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
base: RenderBoxBase)
|
base: RenderBoxBase)
|
||||||
-> RenderBox {
|
-> RenderBox {
|
||||||
|
@ -296,6 +276,13 @@ impl BoxGenerator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum BoxGenResult<'self> {
|
||||||
|
NoGenerator,
|
||||||
|
ParentGenerator,
|
||||||
|
SiblingGenerator,
|
||||||
|
NewGenerator(BoxGenerator<'self>),
|
||||||
|
Mixed(BoxGenerator<'self>, ~BoxGenResult<'self>),
|
||||||
|
}
|
||||||
|
|
||||||
impl LayoutTreeBuilder {
|
impl LayoutTreeBuilder {
|
||||||
/* Debug-only ids */
|
/* Debug-only ids */
|
||||||
|
@ -304,47 +291,74 @@ impl LayoutTreeBuilder {
|
||||||
|
|
||||||
/// Creates necessary box(es) and flow context(s) for the current DOM node,
|
/// Creates necessary box(es) and flow context(s) for the current DOM node,
|
||||||
/// and recurses on its children.
|
/// and recurses on its children.
|
||||||
pub fn construct_recursively(&mut self,
|
pub fn construct_recursively<'a>(&mut self,
|
||||||
layout_ctx: &LayoutContext,
|
layout_ctx: &LayoutContext,
|
||||||
cur_node: AbstractNode<LayoutView>,
|
cur_node: AbstractNode<LayoutView>,
|
||||||
parent_generator: @mut BoxGenerator,
|
mut parent_generator: BoxGenerator<'a>,
|
||||||
prev_sibling_generator: Option<@mut BoxGenerator>)
|
mut prev_sibling_generator: Option<BoxGenerator<'a>>)
|
||||||
-> Option<@mut BoxGenerator> {
|
-> Option<BoxGenerator<'a>> {
|
||||||
debug!("Considering node: %s", cur_node.debug_str());
|
debug!("Considering node: %s", cur_node.debug_str());
|
||||||
|
let box_gen_result = {
|
||||||
|
let sibling_gen_ref = match prev_sibling_generator {
|
||||||
|
Some(ref mut generator) => Some(generator),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
self.box_generator_for_node(cur_node, &mut parent_generator, sibling_gen_ref)
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("result from generator_for_node: %?", &box_gen_result);
|
||||||
// Skip over nodes that don't belong in the flow tree
|
// Skip over nodes that don't belong in the flow tree
|
||||||
let (this_generator, next_generator) =
|
let (this_generator, next_generator) =
|
||||||
match self.box_generator_for_node(cur_node, parent_generator, prev_sibling_generator) {
|
match box_gen_result {
|
||||||
|
NoGenerator => return prev_sibling_generator,
|
||||||
Some((gen, n_gen)) => (gen, n_gen),
|
ParentGenerator => (parent_generator, None),
|
||||||
None => { return prev_sibling_generator; }
|
SiblingGenerator => (prev_sibling_generator.take_unwrap(), None),
|
||||||
|
NewGenerator(gen) => (gen, None),
|
||||||
|
Mixed(gen, next_gen) => (gen, Some(match *next_gen {
|
||||||
|
ParentGenerator => parent_generator,
|
||||||
|
SiblingGenerator => prev_sibling_generator.take_unwrap(),
|
||||||
|
_ => fail!("Unexpect BoxGenResult")
|
||||||
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let mut this_generator = this_generator;
|
||||||
|
|
||||||
debug!("point a: %s", cur_node.debug_str());
|
debug!("point a: %s", cur_node.debug_str());
|
||||||
this_generator.push_node(layout_ctx, cur_node, self);
|
this_generator.push_node(layout_ctx, cur_node, self);
|
||||||
debug!("point b: %s", cur_node.debug_str());
|
debug!("point b: %s", cur_node.debug_str());
|
||||||
|
|
||||||
// recurse on child nodes.
|
// recurse on child nodes.
|
||||||
let mut prev_generator: Option<@mut BoxGenerator> = None;
|
let prev_gen_cell = Cell::new(None);
|
||||||
for child_node in cur_node.children() {
|
for child_node in cur_node.children() {
|
||||||
prev_generator = self.construct_recursively(layout_ctx, child_node, this_generator, prev_generator);
|
do this_generator.with_clone |clone| {
|
||||||
|
let mut prev_generator = prev_gen_cell.take();
|
||||||
|
prev_generator = self.construct_recursively(layout_ctx, child_node, clone, prev_generator);
|
||||||
|
prev_gen_cell.put_back(prev_generator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this_generator.pop_node(layout_ctx, cur_node);
|
this_generator.pop_node(layout_ctx, cur_node);
|
||||||
self.simplify_children_of_flow(layout_ctx, &mut this_generator.flow);
|
self.simplify_children_of_flow(layout_ctx, this_generator.flow);
|
||||||
|
|
||||||
Some(next_generator)
|
match next_generator {
|
||||||
|
Some(n_gen) => Some(n_gen),
|
||||||
|
None => Some(this_generator),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn box_generator_for_node(&mut self,
|
|
||||||
|
|
||||||
|
pub fn box_generator_for_node<'a>(&mut self,
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
parent_generator: @mut BoxGenerator,
|
parent_generator: &mut BoxGenerator<'a>,
|
||||||
sibling_generator: Option<@mut BoxGenerator>)
|
mut sibling_generator: Option<&mut BoxGenerator<'a>>)
|
||||||
-> Option<(@mut BoxGenerator, @mut BoxGenerator)> {
|
-> BoxGenResult<'a> {
|
||||||
|
|
||||||
let display = if node.is_element() {
|
let display = if node.is_element() {
|
||||||
match node.style().display(node.is_root()) {
|
match node.style().display(node.is_root()) {
|
||||||
CSSDisplayNone => return None, // tree ends here if 'display: none'
|
CSSDisplayNone => return NoGenerator, // tree ends here if 'display: none'
|
||||||
// TODO(eatkinson) these are hacks so that the code doesn't crash
|
// TODO(eatkinson) these are hacks so that the code doesn't crash
|
||||||
// when unsupported display values are used. They should be deleted
|
// when unsupported display values are used. They should be deleted
|
||||||
// as they are implemented.
|
// as they are implemented.
|
||||||
|
@ -355,8 +369,8 @@ impl LayoutTreeBuilder {
|
||||||
CSSDisplayTableHeaderGroup => CSSDisplayBlock,
|
CSSDisplayTableHeaderGroup => CSSDisplayBlock,
|
||||||
CSSDisplayTableFooterGroup => CSSDisplayBlock,
|
CSSDisplayTableFooterGroup => CSSDisplayBlock,
|
||||||
CSSDisplayTableRow => CSSDisplayBlock,
|
CSSDisplayTableRow => CSSDisplayBlock,
|
||||||
CSSDisplayTableColumnGroup => return None,
|
CSSDisplayTableColumnGroup => return NoGenerator,
|
||||||
CSSDisplayTableColumn => return None,
|
CSSDisplayTableColumn => return NoGenerator,
|
||||||
CSSDisplayTableCell => CSSDisplayBlock,
|
CSSDisplayTableCell => CSSDisplayBlock,
|
||||||
CSSDisplayTableCaption => CSSDisplayBlock,
|
CSSDisplayTableCaption => CSSDisplayBlock,
|
||||||
v => v
|
v => v
|
||||||
|
@ -366,11 +380,11 @@ impl LayoutTreeBuilder {
|
||||||
|
|
||||||
ElementNodeTypeId(_) => CSSDisplayInline,
|
ElementNodeTypeId(_) => CSSDisplayInline,
|
||||||
TextNodeTypeId => CSSDisplayInline,
|
TextNodeTypeId => CSSDisplayInline,
|
||||||
DoctypeNodeTypeId | CommentNodeTypeId => return None,
|
DoctypeNodeTypeId | CommentNodeTypeId => return NoGenerator,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let sibling_flow: Option<FlowContext> = sibling_generator.map(|gen| gen.flow);
|
let sibling_flow: Option<&mut FlowContext> = sibling_generator.map_mut(|gen| &mut *gen.flow);
|
||||||
|
|
||||||
// TODO(eatkinson): use the value of the float property to
|
// TODO(eatkinson): use the value of the float property to
|
||||||
// determine whether to float left or right.
|
// determine whether to float left or right.
|
||||||
|
@ -385,105 +399,91 @@ impl LayoutTreeBuilder {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let new_generator = match (display, parent_generator.flow, sibling_flow) {
|
let new_generator = match (display, &mut parent_generator.flow, sibling_flow) {
|
||||||
// Floats
|
// Floats
|
||||||
(CSSDisplayBlock, BlockFlow(_), _) |
|
(CSSDisplayBlock, & &BlockFlow(_), _) |
|
||||||
(CSSDisplayBlock, FloatFlow(_), _) if !is_float.is_none() => {
|
(CSSDisplayBlock, & &FloatFlow(_), _) if !is_float.is_none() => {
|
||||||
self.create_child_generator(node, parent_generator, Flow_Float(is_float.unwrap()))
|
self.create_child_generator(node, parent_generator, Flow_Float(is_float.unwrap()))
|
||||||
}
|
}
|
||||||
// If we're placing a float after an inline, append the float to the inline flow,
|
// If we're placing a float after an inline, append the float to the inline flow,
|
||||||
// then continue building from the inline flow in case there are more inlines
|
// then continue building from the inline flow in case there are more inlines
|
||||||
// afterward.
|
// afterward.
|
||||||
(CSSDisplayBlock, _, Some(InlineFlow(_))) if !is_float.is_none() => {
|
(CSSDisplayBlock, _, Some(&InlineFlow(_))) if !is_float.is_none() => {
|
||||||
let float_generator = self.create_child_generator(node,
|
let float_generator = self.create_child_generator(node,
|
||||||
sibling_generator.unwrap(),
|
sibling_generator.unwrap(),
|
||||||
Flow_Float(is_float.unwrap()));
|
Flow_Float(is_float.unwrap()));
|
||||||
return Some((float_generator, sibling_generator.unwrap()));
|
return Mixed(float_generator, ~SiblingGenerator);
|
||||||
}
|
}
|
||||||
// This is a catch-all case for when:
|
// This is a catch-all case for when:
|
||||||
// a) sibling_flow is None
|
// a) sibling_flow is None
|
||||||
// b) sibling_flow is a BlockFlow
|
// b) sibling_flow is a BlockFlow
|
||||||
(CSSDisplayBlock, InlineFlow(_), _) if !is_float.is_none() => {
|
(CSSDisplayBlock, & &InlineFlow(_), _) if !is_float.is_none() => {
|
||||||
self.create_child_generator(node, parent_generator, Flow_Float(is_float.unwrap()))
|
self.create_child_generator(node, parent_generator, Flow_Float(is_float.unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
(CSSDisplayBlock, BlockFlow(info), _) => match (info.is_root, node.parent_node()) {
|
(CSSDisplayBlock, & &BlockFlow(ref info), _) => match (info.is_root, node.parent_node().is_some()) {
|
||||||
// If this is the root node, then use the root flow's
|
// If this is the root node, then use the root flow's
|
||||||
// context. Otherwise, make a child block context.
|
// context. Otherwise, make a child block context.
|
||||||
(true, Some(_)) => { self.create_child_generator(node, parent_generator, Flow_Block) }
|
(true, true) => self.create_child_generator(node, parent_generator, Flow_Block),
|
||||||
(true, None) => { parent_generator }
|
(true, false) => { return ParentGenerator }
|
||||||
(false, _) => {
|
(false, _) => {
|
||||||
self.create_child_generator(node, parent_generator, Flow_Block)
|
self.create_child_generator(node, parent_generator, Flow_Block)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
(CSSDisplayBlock, FloatFlow(*), _) => {
|
(CSSDisplayBlock, & &FloatFlow(*), _) => {
|
||||||
self.create_child_generator(node, parent_generator, Flow_Block)
|
self.create_child_generator(node, parent_generator, Flow_Block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlines that are children of inlines are part of the same flow
|
// Inlines that are children of inlines are part of the same flow
|
||||||
(CSSDisplayInline, InlineFlow(*), _) => parent_generator,
|
(CSSDisplayInline, & &InlineFlow(*), _) => return ParentGenerator,
|
||||||
(CSSDisplayInlineBlock, InlineFlow(*), _) => parent_generator,
|
(CSSDisplayInlineBlock, & &InlineFlow(*), _) => return ParentGenerator,
|
||||||
|
|
||||||
// Inlines that are children of blocks create new flows if their
|
// Inlines that are children of blocks create new flows if their
|
||||||
// previous sibling was a block.
|
// previous sibling was a block.
|
||||||
(CSSDisplayInline, BlockFlow(*), Some(BlockFlow(*))) |
|
(CSSDisplayInline, & &BlockFlow(*), Some(&BlockFlow(*))) |
|
||||||
(CSSDisplayInlineBlock, BlockFlow(*), Some(BlockFlow(*))) => {
|
(CSSDisplayInlineBlock, & &BlockFlow(*), Some(&BlockFlow(*))) => {
|
||||||
self.create_child_generator(node, parent_generator, Flow_Inline)
|
self.create_child_generator(node, parent_generator, Flow_Inline)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The first two cases should only be hit when a FloatFlow
|
// The first two cases should only be hit when a FloatFlow
|
||||||
// is the first child of a BlockFlow. Other times, we will
|
// is the first child of a BlockFlow. Other times, we will
|
||||||
(CSSDisplayInline, _, Some(FloatFlow(*))) |
|
(CSSDisplayInline, _, Some(&FloatFlow(*))) |
|
||||||
(CSSDisplayInlineBlock, _, Some(FloatFlow(*))) |
|
(CSSDisplayInlineBlock, _, Some(&FloatFlow(*))) |
|
||||||
(CSSDisplayInline, FloatFlow(*), _) |
|
(CSSDisplayInline, & &FloatFlow(*), _) |
|
||||||
(CSSDisplayInlineBlock, FloatFlow(*), _) => {
|
(CSSDisplayInlineBlock, & &FloatFlow(*), _) => {
|
||||||
self.create_child_generator(node, parent_generator, Flow_Inline)
|
self.create_child_generator(node, parent_generator, Flow_Inline)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inlines whose previous sibling was not a block try to use their
|
// Inlines whose previous sibling was not a block try to use their
|
||||||
// sibling's flow context.
|
// sibling's flow context.
|
||||||
(CSSDisplayInline, BlockFlow(*), _) |
|
(CSSDisplayInline, & &BlockFlow(*), _) |
|
||||||
(CSSDisplayInlineBlock, BlockFlow(*), _) => {
|
(CSSDisplayInlineBlock, & &BlockFlow(*), _) => {
|
||||||
self.create_child_generator_if_needed(node,
|
return match sibling_generator {
|
||||||
parent_generator,
|
None => NewGenerator(self.create_child_generator(node,
|
||||||
sibling_generator,
|
parent_generator,
|
||||||
Flow_Inline)
|
Flow_Inline)),
|
||||||
|
Some(*) => SiblingGenerator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(eatkinson): blocks that are children of inlines need
|
// TODO(eatkinson): blocks that are children of inlines need
|
||||||
// to split their parent flows.
|
// to split their parent flows.
|
||||||
_ => parent_generator
|
_ => return ParentGenerator
|
||||||
};
|
};
|
||||||
|
|
||||||
// Usually, the node we add boxes to will be prev_sibling on the
|
NewGenerator(new_generator)
|
||||||
// next call to this function.
|
|
||||||
Some((new_generator, new_generator))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_child_generator(&mut self,
|
pub fn create_child_generator<'a>(&mut self,
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
parent_generator: @mut BoxGenerator,
|
parent_generator: &mut BoxGenerator<'a>,
|
||||||
ty: FlowContextType)
|
ty: FlowContextType)
|
||||||
-> @mut BoxGenerator {
|
-> BoxGenerator<'a> {
|
||||||
|
|
||||||
let new_flow = self.make_flow(ty, node);
|
let mut new_flow = self.make_flow(ty, node);
|
||||||
parent_generator.flow.add_child(new_flow);
|
parent_generator.flow.add_new_child(new_flow);
|
||||||
|
BoxGenerator::new(parent_generator.flow.last_child().unwrap())
|
||||||
@mut BoxGenerator::new(new_flow)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_child_generator_if_needed(&mut self,
|
|
||||||
node: AbstractNode<LayoutView>,
|
|
||||||
parent_generator: @mut BoxGenerator,
|
|
||||||
maybe_generator: Option<@mut BoxGenerator>,
|
|
||||||
ty: FlowContextType)
|
|
||||||
-> @mut BoxGenerator {
|
|
||||||
|
|
||||||
match maybe_generator {
|
|
||||||
None => self.create_child_generator(node, parent_generator, ty),
|
|
||||||
Some(gen) => gen
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fix up any irregularities such as:
|
/// Fix up any irregularities such as:
|
||||||
|
@ -500,74 +500,71 @@ impl LayoutTreeBuilder {
|
||||||
let mut found_child_inline = false;
|
let mut found_child_inline = false;
|
||||||
let mut found_child_block = false;
|
let mut found_child_block = false;
|
||||||
|
|
||||||
let flow = *parent_flow;
|
for child_ctx in parent_flow.child_iter() {
|
||||||
for child_ctx in flow.children() {
|
|
||||||
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,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if found_child_block && found_child_inline {
|
if found_child_block && found_child_inline {
|
||||||
self.fixup_split_inline(*parent_flow)
|
self.fixup_split_inline(parent_flow)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
BlockFlow(*) | FloatFlow(*) => {
|
BlockFlow(*) | FloatFlow(*) => {
|
||||||
// FIXME: this will create refcounted cycles between the removed flow and any
|
|
||||||
// of its RenderBox or FlowContext children, and possibly keep alive other junk
|
|
||||||
|
|
||||||
// check first/last child for whitespace-ness
|
// check first/last child for whitespace-ness
|
||||||
let first_child = do parent_flow.with_base |parent_node| {
|
let mut do_remove = false;
|
||||||
parent_node.first_child
|
let p_id = parent_flow.id();
|
||||||
};
|
do parent_flow.with_first_child |mut first_child| {
|
||||||
for &first_flow in first_child.iter() {
|
for first_flow in first_child.mut_iter() {
|
||||||
if first_flow.starts_inline_flow() {
|
if first_flow.starts_inline_flow() {
|
||||||
// FIXME: workaround for rust#6393
|
// FIXME: workaround for rust#6393
|
||||||
let mut do_remove = false;
|
{
|
||||||
{
|
let boxes = &first_flow.imm_inline().boxes;
|
||||||
let boxes = &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 \
|
||||||
debug!("LayoutTreeBuilder: pruning whitespace-only first child \
|
flow f%d from parent f%d",
|
||||||
flow f%d from parent f%d",
|
first_flow.id(),
|
||||||
first_flow.id(),
|
p_id);
|
||||||
parent_flow.id());
|
do_remove = true;
|
||||||
do_remove = true;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (do_remove) {
|
|
||||||
(*parent_flow).remove_child(first_flow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (do_remove) {
|
||||||
|
parent_flow.remove_first();
|
||||||
|
}
|
||||||
|
|
||||||
let last_child = do parent_flow.with_base |parent_node| {
|
|
||||||
parent_node.last_child
|
do_remove = false;
|
||||||
};
|
let p_id = parent_flow.id();
|
||||||
for &last_flow in last_child.iter() {
|
do parent_flow.with_last_child |mut last_child| {
|
||||||
if last_flow.starts_inline_flow() {
|
for last_flow in last_child.mut_iter() {
|
||||||
// FIXME: workaround for rust#6393
|
if last_flow.starts_inline_flow() {
|
||||||
let mut do_remove = false;
|
// FIXME: workaround for rust#6393
|
||||||
{
|
{
|
||||||
let boxes = &last_flow.inline().boxes;
|
let boxes = &last_flow.imm_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 \
|
debug!("LayoutTreeBuilder: pruning whitespace-only last child \
|
||||||
flow f%d from parent f%d",
|
flow f%d from parent f%d",
|
||||||
last_flow.id(),
|
last_flow.id(),
|
||||||
parent_flow.id());
|
p_id);
|
||||||
do_remove = true;
|
do_remove = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (do_remove) {
|
|
||||||
(*parent_flow).remove_child(last_flow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (do_remove) {
|
||||||
|
parent_flow.remove_last();
|
||||||
|
}
|
||||||
|
|
||||||
// Issue 543: We only need to do this if there are inline child
|
// Issue 543: We only need to do this if there are inline child
|
||||||
// flows, but there's not a quick way to check at the moment.
|
// flows, but there's not a quick way to check at the moment.
|
||||||
for child_flow in (*parent_flow).children() {
|
for child_flow in (*parent_flow).child_iter() {
|
||||||
match child_flow {
|
match *child_flow {
|
||||||
InlineFlow(*) | InlineBlockFlow(*) => {
|
InlineFlow(*) | InlineBlockFlow(*) => {
|
||||||
let mut scanner = TextRunScanner::new();
|
let mut scanner = TextRunScanner::new();
|
||||||
scanner.scan_for_runs(ctx, child_flow);
|
scanner.scan_for_runs(ctx, child_flow);
|
||||||
|
@ -580,7 +577,7 @@ impl LayoutTreeBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fixup_split_inline(&self, _: FlowContext) {
|
pub fn fixup_split_inline(&self, _: &mut FlowContext) {
|
||||||
// TODO: finish me.
|
// TODO: finish me.
|
||||||
fail!(~"TODO: handle case where an inline is split by a block")
|
fail!(~"TODO: handle case where an inline is split by a block")
|
||||||
}
|
}
|
||||||
|
@ -588,11 +585,14 @@ impl LayoutTreeBuilder {
|
||||||
/// Entry point for box creation. Should only be called on the root DOM element.
|
/// Entry point for box creation. Should only be called on the root DOM element.
|
||||||
pub fn construct_trees(&mut self, layout_ctx: &LayoutContext, root: AbstractNode<LayoutView>)
|
pub fn construct_trees(&mut self, layout_ctx: &LayoutContext, root: AbstractNode<LayoutView>)
|
||||||
-> Result<FlowContext, ()> {
|
-> Result<FlowContext, ()> {
|
||||||
let new_flow = self.make_flow(Flow_Root, root);
|
debug!("Constructing flow tree for DOM: ");
|
||||||
let new_generator = @mut BoxGenerator::new(new_flow);
|
root.dump();
|
||||||
|
|
||||||
self.root_flow = Some(new_flow);
|
let mut new_flow = self.make_flow(Flow_Root, root);
|
||||||
self.construct_recursively(layout_ctx, root, new_generator, None);
|
{
|
||||||
|
let mut new_generator = BoxGenerator::new(&mut new_flow);
|
||||||
|
self.construct_recursively(layout_ctx, root, new_generator, None);
|
||||||
|
}
|
||||||
return Ok(new_flow)
|
return Ok(new_flow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,13 +600,13 @@ impl LayoutTreeBuilder {
|
||||||
pub fn make_flow(&mut self, ty: FlowContextType, node: AbstractNode<LayoutView>) -> FlowContext {
|
pub fn make_flow(&mut self, ty: FlowContextType, node: AbstractNode<LayoutView>) -> FlowContext {
|
||||||
let info = FlowData::new(self.next_flow_id(), node);
|
let info = FlowData::new(self.next_flow_id(), node);
|
||||||
let result = match ty {
|
let result = match ty {
|
||||||
Flow_Absolute => AbsoluteFlow(@mut info),
|
Flow_Absolute => AbsoluteFlow(~info),
|
||||||
Flow_Block => BlockFlow(@mut BlockFlowData::new(info)),
|
Flow_Block => BlockFlow(~BlockFlowData::new(info)),
|
||||||
Flow_Float(f_type) => FloatFlow(@mut FloatFlowData::new(info, f_type)),
|
Flow_Float(f_type) => FloatFlow(~FloatFlowData::new(info, f_type)),
|
||||||
Flow_InlineBlock => InlineBlockFlow(@mut info),
|
Flow_InlineBlock => InlineBlockFlow(~info),
|
||||||
Flow_Inline => InlineFlow(@mut InlineFlowData::new(info)),
|
Flow_Inline => InlineFlow(~InlineFlowData::new(info)),
|
||||||
Flow_Root => BlockFlow(@mut BlockFlowData::new_root(info)),
|
Flow_Root => BlockFlow(~BlockFlowData::new_root(info)),
|
||||||
Flow_Table => TableFlow(@mut info),
|
Flow_Table => TableFlow(~info),
|
||||||
};
|
};
|
||||||
debug!("LayoutTreeBuilder: created flow: %s", result.debug_str());
|
debug!("LayoutTreeBuilder: created flow: %s", result.debug_str());
|
||||||
result
|
result
|
||||||
|
|
|
@ -15,7 +15,6 @@ use geom::rect::Rect;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use gfx::geometry::Au;
|
use gfx::geometry::Au;
|
||||||
use gfx::geometry;
|
use gfx::geometry;
|
||||||
use servo_util::tree::TreeNodeRef;
|
|
||||||
|
|
||||||
pub struct FloatFlowData {
|
pub struct FloatFlowData {
|
||||||
/// Data common to all flows.
|
/// Data common to all flows.
|
||||||
|
@ -54,7 +53,6 @@ impl FloatFlowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn teardown(&mut self) {
|
pub fn teardown(&mut self) {
|
||||||
self.common.teardown();
|
|
||||||
for box in self.box.iter() {
|
for box in self.box.iter() {
|
||||||
box.teardown();
|
box.teardown();
|
||||||
}
|
}
|
||||||
|
@ -64,12 +62,12 @@ impl FloatFlowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatFlowData {
|
impl FloatFlowData {
|
||||||
pub fn bubble_widths_float(@mut self, ctx: &LayoutContext) {
|
pub fn bubble_widths_float(&mut self, ctx: &LayoutContext) {
|
||||||
let mut min_width = Au(0);
|
let mut min_width = Au(0);
|
||||||
let mut pref_width = Au(0);
|
let mut pref_width = Au(0);
|
||||||
let mut num_floats = 0;
|
let mut num_floats = 0;
|
||||||
|
|
||||||
for child_ctx in FloatFlow(self).children() {
|
for child_ctx in self.common.child_iter() {
|
||||||
//assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
|
//assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
|
||||||
|
|
||||||
do child_ctx.with_mut_base |child_node| {
|
do child_ctx.with_mut_base |child_node| {
|
||||||
|
@ -97,7 +95,7 @@ impl FloatFlowData {
|
||||||
self.common.pref_width = pref_width;
|
self.common.pref_width = pref_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_widths_float(@mut self) {
|
pub fn assign_widths_float(&mut self) {
|
||||||
debug!("assign_widths_float: assigning width for flow %?", self.common.id);
|
debug!("assign_widths_float: assigning width for flow %?", self.common.id);
|
||||||
// position.size.width is set by parent even though we don't know
|
// position.size.width is set by parent even though we don't know
|
||||||
// position.origin yet.
|
// position.origin yet.
|
||||||
|
@ -162,7 +160,7 @@ impl FloatFlowData {
|
||||||
self.common.position.size.width = remaining_width;
|
self.common.position.size.width = remaining_width;
|
||||||
|
|
||||||
let has_inorder_children = self.common.num_floats > 0;
|
let has_inorder_children = self.common.num_floats > 0;
|
||||||
for kid in FloatFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
//assert!(kid.starts_block_flow() || kid.starts_inline_flow());
|
//assert!(kid.starts_block_flow() || kid.starts_inline_flow());
|
||||||
|
|
||||||
do kid.with_mut_base |child_node| {
|
do kid.with_mut_base |child_node| {
|
||||||
|
@ -177,7 +175,7 @@ impl FloatFlowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height_inorder_float(@mut self) {
|
pub fn assign_height_inorder_float(&mut self) {
|
||||||
debug!("assign_height_inorder_float: assigning height for float %?", self.common.id);
|
debug!("assign_height_inorder_float: assigning height for float %?", self.common.id);
|
||||||
// assign_height_float was already called by the traversal function
|
// assign_height_float was already called by the traversal function
|
||||||
// so this is well-defined
|
// so this is well-defined
|
||||||
|
@ -222,12 +220,12 @@ impl FloatFlowData {
|
||||||
self.rel_pos = self.common.floats_out.last_float_pos();
|
self.rel_pos = self.common.floats_out.last_float_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height_float(@mut self, ctx: &mut LayoutContext) {
|
pub fn assign_height_float(&mut self, ctx: &mut LayoutContext) {
|
||||||
debug!("assign_height_float: assigning height for float %?", self.common.id);
|
debug!("assign_height_float: assigning height for float %?", self.common.id);
|
||||||
let has_inorder_children = self.common.num_floats > 0;
|
let has_inorder_children = self.common.num_floats > 0;
|
||||||
if has_inorder_children {
|
if has_inorder_children {
|
||||||
let mut float_ctx = FloatContext::new(self.floated_children);
|
let mut float_ctx = FloatContext::new(self.floated_children);
|
||||||
for kid in FloatFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
do kid.with_mut_base |child_node| {
|
do kid.with_mut_base |child_node| {
|
||||||
child_node.floats_in = float_ctx.clone();
|
child_node.floats_in = float_ctx.clone();
|
||||||
}
|
}
|
||||||
|
@ -248,7 +246,7 @@ impl FloatFlowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for kid in FloatFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
do kid.with_mut_base |child_node| {
|
do kid.with_mut_base |child_node| {
|
||||||
child_node.position.origin.y = cur_y;
|
child_node.position.origin.y = cur_y;
|
||||||
cur_y = cur_y + child_node.position.size.height;
|
cur_y = cur_y + child_node.position.size.height;
|
||||||
|
@ -289,7 +287,7 @@ impl FloatFlowData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_display_list_float<E:ExtraDisplayListData>(@mut self,
|
pub fn build_display_list_float<E:ExtraDisplayListData>(&mut self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &Cell<DisplayList<E>>)
|
||||||
|
@ -301,7 +299,7 @@ impl FloatFlowData {
|
||||||
}
|
}
|
||||||
let abs_rect = Rect(self.common.abs_position, self.common.position.size);
|
let abs_rect = Rect(self.common.abs_position, self.common.position.size);
|
||||||
if !abs_rect.intersects(dirty) {
|
if !abs_rect.intersects(dirty) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -315,14 +313,13 @@ impl FloatFlowData {
|
||||||
// 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
|
||||||
let flow = FloatFlow(self);
|
for child in self.common.child_iter() {
|
||||||
for child in flow.children() {
|
|
||||||
do child.with_mut_base |base| {
|
do child.with_mut_base |base| {
|
||||||
base.abs_position = offset + base.position.origin;
|
base.abs_position = offset + base.position.origin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,12 +48,12 @@ pub struct PlacementInfo{
|
||||||
/// destroy the context on modification.
|
/// destroy the context on modification.
|
||||||
pub enum FloatContext {
|
pub enum FloatContext {
|
||||||
Invalid,
|
Invalid,
|
||||||
Valid(FloatContextBase)
|
Valid(~FloatContextBase)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatContext {
|
impl FloatContext {
|
||||||
pub fn new(num_floats: uint) -> FloatContext {
|
pub fn new(num_floats: uint) -> FloatContext {
|
||||||
Valid(FloatContextBase::new(num_floats))
|
Valid(~FloatContextBase::new(num_floats))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -68,7 +68,7 @@ impl FloatContext {
|
||||||
fn with_mut_base<R>(&mut self, callback: &fn(&mut FloatContextBase) -> R) -> R {
|
fn with_mut_base<R>(&mut self, callback: &fn(&mut FloatContextBase) -> R) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
Invalid => fail!("Float context no longer available"),
|
Invalid => fail!("Float context no longer available"),
|
||||||
Valid(ref mut base) => callback(base)
|
Valid(ref mut base) => callback(&mut **base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ impl FloatContext {
|
||||||
pub fn with_base<R>(&self, callback: &fn(&FloatContextBase) -> R) -> R {
|
pub fn with_base<R>(&self, callback: &fn(&FloatContextBase) -> R) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
Invalid => fail!("Float context no longer available"),
|
Invalid => fail!("Float context no longer available"),
|
||||||
Valid(ref base) => callback(base)
|
Valid(ref base) => callback(& **base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,8 @@ use layout::inline::{InlineFlowData};
|
||||||
use layout::float_context::{FloatContext, Invalid, FloatType};
|
use layout::float_context::{FloatContext, Invalid, FloatType};
|
||||||
use layout::incremental::RestyleDamage;
|
use layout::incremental::RestyleDamage;
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
|
use extra::dlist::{DList,MutDListIterator};
|
||||||
|
use extra::container::Deque;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::io::stderr;
|
use std::io::stderr;
|
||||||
|
@ -42,18 +44,16 @@ use geom::rect::Rect;
|
||||||
use gfx::display_list::DisplayList;
|
use gfx::display_list::DisplayList;
|
||||||
use gfx::geometry::Au;
|
use gfx::geometry::Au;
|
||||||
use script::dom::node::{AbstractNode, LayoutView};
|
use script::dom::node::{AbstractNode, LayoutView};
|
||||||
use servo_util::tree::{TreeNode, TreeNodeRef};
|
|
||||||
|
|
||||||
/// The type of the formatting context and data specific to each context, such as line box
|
/// The type of the formatting context and data specific to each context, such as line box
|
||||||
/// structures or float lists.
|
/// structures or float lists.
|
||||||
#[deriving(Clone)]
|
|
||||||
pub enum FlowContext {
|
pub enum FlowContext {
|
||||||
AbsoluteFlow(@mut FlowData),
|
AbsoluteFlow(~FlowData),
|
||||||
BlockFlow(@mut BlockFlowData),
|
BlockFlow(~BlockFlowData),
|
||||||
FloatFlow(@mut FloatFlowData),
|
FloatFlow(~FloatFlowData),
|
||||||
InlineBlockFlow(@mut FlowData),
|
InlineBlockFlow(~FlowData),
|
||||||
InlineFlow(@mut InlineFlowData),
|
InlineFlow(~InlineFlowData),
|
||||||
TableFlow(@mut FlowData),
|
TableFlow(~FlowData),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum FlowContextType {
|
pub enum FlowContextType {
|
||||||
|
@ -67,142 +67,161 @@ pub enum FlowContextType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowContext {
|
impl FlowContext {
|
||||||
pub fn teardown(&self) {
|
pub fn each_bu_sub_inorder (&mut self, callback: &fn(&mut FlowContext) -> bool) -> bool {
|
||||||
match *self {
|
for kid in self.child_iter() {
|
||||||
AbsoluteFlow(data) |
|
|
||||||
InlineBlockFlow(data) |
|
|
||||||
TableFlow(data) => data.teardown(),
|
|
||||||
BlockFlow(data) => data.teardown(),
|
|
||||||
FloatFlow(data) => data.teardown(),
|
|
||||||
InlineFlow(data) => data.teardown()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like traverse_preorder, but don't end the whole traversal if the callback
|
|
||||||
/// returns false.
|
|
||||||
//
|
|
||||||
// FIXME: Unify this with traverse_preorder_prune, which takes a separate
|
|
||||||
// 'prune' function.
|
|
||||||
pub fn partially_traverse_preorder(&self, callback: &fn(FlowContext) -> bool) {
|
|
||||||
if !callback((*self).clone()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for kid in self.children() {
|
|
||||||
// FIXME: Work around rust#2202. We should be able to pass the callback directly.
|
// FIXME: Work around rust#2202. We should be able to pass the callback directly.
|
||||||
kid.partially_traverse_preorder(|a| callback(a));
|
if !kid.each_bu_sub_inorder(|a| callback(a)) {
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn traverse_bu_sub_inorder (&self, callback: &fn(FlowContext)) {
|
|
||||||
for kid in self.children() {
|
|
||||||
// FIXME: Work around rust#2202. We should be able to pass the callback directly.
|
|
||||||
kid.traverse_bu_sub_inorder(|a| callback(a));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.is_inorder() {
|
if !self.is_inorder() {
|
||||||
callback((*self).clone())
|
callback(self)
|
||||||
|
} else {
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn each_preorder_prune(&mut self, prune: &fn(&mut FlowContext) -> bool,
|
||||||
|
callback: &fn(&mut FlowContext) -> bool)
|
||||||
|
-> bool {
|
||||||
|
if prune(self) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !callback(self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for kid in self.child_iter() {
|
||||||
|
// FIXME: Work around rust#2202. We should be able to pass the callback directly.
|
||||||
|
if !kid.each_preorder_prune(|a| prune(a), |a| callback(a)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn each_postorder_prune(&mut self, prune: &fn(&mut FlowContext) -> bool,
|
||||||
|
callback: &fn(&mut FlowContext) -> bool)
|
||||||
|
-> bool {
|
||||||
|
if prune(self) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for kid in self.child_iter() {
|
||||||
|
// FIXME: Work around rust#2202. We should be able to pass the callback directly.
|
||||||
|
if !kid.each_postorder_prune(|a| prune(a), |a| callback(a)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn each_preorder(&mut self, callback: &fn(&mut FlowContext) -> bool) -> bool {
|
||||||
|
self.each_preorder_prune(|_| false, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn each_postorder(&mut self, callback: &fn(&mut FlowContext) -> bool) -> bool {
|
||||||
|
self.each_postorder_prune(|_| false, callback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowData {
|
impl<'self> FlowContext {
|
||||||
pub fn teardown(&mut self) {
|
pub fn leaf(&self) -> bool {
|
||||||
// Under the assumption that all flows exist in a tree,
|
do self.with_base |base| {
|
||||||
// we must restrict ourselves to finalizing flows that
|
base.children.len() == 0
|
||||||
// are descendents and subsequent siblings to ourselves,
|
|
||||||
// or we risk dynamic borrow failures.
|
|
||||||
self.parent = None;
|
|
||||||
|
|
||||||
for flow in self.first_child.iter() {
|
|
||||||
flow.teardown();
|
|
||||||
}
|
}
|
||||||
self.first_child = None;
|
|
||||||
|
|
||||||
self.last_child = None;
|
|
||||||
|
|
||||||
for flow in self.next_sibling.iter() {
|
|
||||||
flow.teardown();
|
|
||||||
}
|
|
||||||
self.next_sibling = None;
|
|
||||||
|
|
||||||
self.prev_sibling = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_new_child(&mut self, new_child: FlowContext) {
|
||||||
|
let cell = Cell::new(new_child);
|
||||||
|
do self.with_mut_base |base| {
|
||||||
|
base.children.push_back(cell.take());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_first_child<R>(&mut self, cb: &fn(Option<&mut FlowContext>) -> R) -> R {
|
||||||
|
do self.with_mut_base |base| {
|
||||||
|
cb(base.children.front_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_last_child<R>(&mut self, cb: &fn(Option<&mut FlowContext>) -> R) -> R {
|
||||||
|
do self.with_mut_base |base| {
|
||||||
|
cb(base.children.back_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last_child(&'self mut self) -> Option<&'self mut FlowContext> {
|
||||||
|
self.mut_base().children.back_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_first(&mut self) {
|
||||||
|
do self.with_mut_base |base| {
|
||||||
|
base.children.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_last(&mut self) {
|
||||||
|
do self.with_mut_base |base| {
|
||||||
|
base.children.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn child_iter<'a>(&'a mut self) -> MutDListIterator<'a, FlowContext> {
|
||||||
|
self.mut_base().children.mut_iter()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeNodeRef<FlowData> for FlowContext {
|
impl<'self> FlowContext {
|
||||||
fn with_base<R>(&self, callback: &fn(&FlowData) -> R) -> R {
|
pub fn with_base<R>(&self, callback: &fn(&FlowData) -> R) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
AbsoluteFlow(info) => callback(info),
|
AbsoluteFlow(ref info) => callback(&**info),
|
||||||
BlockFlow(info) => {
|
BlockFlow(ref info) => {
|
||||||
callback(&info.common)
|
callback(&info.common)
|
||||||
}
|
}
|
||||||
FloatFlow(info) => callback(&info.common),
|
FloatFlow(ref info) => callback(&info.common),
|
||||||
InlineBlockFlow(info) => callback(info),
|
InlineBlockFlow(ref info) => callback(&**info),
|
||||||
InlineFlow(info) => {
|
InlineFlow(ref info) => {
|
||||||
callback(&info.common)
|
callback(&info.common)
|
||||||
}
|
}
|
||||||
TableFlow(info) => callback(info)
|
TableFlow(ref info) => callback(&**info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn with_mut_base<R>(&self, callback: &fn(&mut FlowData) -> R) -> R {
|
pub fn with_mut_base<R>(&mut self, callback: &fn(&mut FlowData) -> R) -> R {
|
||||||
match *self {
|
match *self {
|
||||||
AbsoluteFlow(info) => callback(info),
|
AbsoluteFlow(ref mut info) => callback(&mut **info),
|
||||||
BlockFlow(info) => {
|
BlockFlow(ref mut info) => {
|
||||||
callback(&mut info.common)
|
callback(&mut info.common)
|
||||||
}
|
}
|
||||||
FloatFlow(info) => callback(&mut info.common),
|
FloatFlow(ref mut info) => callback(&mut info.common),
|
||||||
InlineBlockFlow(info) => callback(info),
|
InlineBlockFlow(ref mut info) => callback(&mut **info),
|
||||||
InlineFlow(info) => {
|
InlineFlow(ref mut info) => {
|
||||||
callback(&mut info.common)
|
callback(&mut info.common)
|
||||||
}
|
}
|
||||||
TableFlow(info) => callback(info),
|
TableFlow(ref mut info) => callback(&mut **info),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn mut_base(&'self mut self) -> &'self mut FlowData {
|
||||||
fn parent_node(node: &FlowData) -> Option<FlowContext> {
|
match *self {
|
||||||
node.parent
|
AbsoluteFlow(ref mut info) => &mut(**info),
|
||||||
}
|
BlockFlow(ref mut info) => {
|
||||||
|
&mut info.common
|
||||||
fn first_child(node: &FlowData) -> Option<FlowContext> {
|
}
|
||||||
node.first_child
|
FloatFlow(ref mut info) => &mut info.common,
|
||||||
}
|
InlineBlockFlow(ref mut info) => &mut(**info),
|
||||||
|
InlineFlow(ref mut info) => {
|
||||||
fn last_child(node: &FlowData) -> Option<FlowContext> {
|
&mut info.common
|
||||||
node.last_child
|
}
|
||||||
}
|
TableFlow(ref mut info) => &mut(**info),
|
||||||
|
}
|
||||||
fn prev_sibling(node: &FlowData) -> Option<FlowContext> {
|
|
||||||
node.prev_sibling
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_sibling(node: &FlowData) -> Option<FlowContext> {
|
|
||||||
node.next_sibling
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_parent_node(node: &mut FlowData, new_parent_node: Option<FlowContext>) {
|
|
||||||
node.parent = new_parent_node
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_first_child(node: &mut FlowData, new_first_child: Option<FlowContext>) {
|
|
||||||
node.first_child = new_first_child
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_last_child(node: &mut FlowData, new_last_child: Option<FlowContext>) {
|
|
||||||
node.last_child = new_last_child
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_prev_sibling(node: &mut FlowData, new_prev_sibling: Option<FlowContext>) {
|
|
||||||
node.prev_sibling = new_prev_sibling
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_next_sibling(node: &mut FlowData, new_next_sibling: Option<FlowContext>) {
|
|
||||||
node.next_sibling = new_next_sibling
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeNode<FlowContext> for FlowData { }
|
|
||||||
|
|
||||||
/// Data common to all flows.
|
/// Data common to all flows.
|
||||||
///
|
///
|
||||||
/// FIXME: We need a naming convention for pseudo-inheritance like this. How about
|
/// FIXME: We need a naming convention for pseudo-inheritance like this. How about
|
||||||
|
@ -211,11 +230,7 @@ pub struct FlowData {
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
restyle_damage: RestyleDamage,
|
restyle_damage: RestyleDamage,
|
||||||
|
|
||||||
parent: Option<FlowContext>,
|
children: DList<FlowContext>,
|
||||||
first_child: Option<FlowContext>,
|
|
||||||
last_child: Option<FlowContext>,
|
|
||||||
prev_sibling: Option<FlowContext>,
|
|
||||||
next_sibling: Option<FlowContext>,
|
|
||||||
|
|
||||||
/* TODO (Issue #87): debug only */
|
/* TODO (Issue #87): debug only */
|
||||||
id: int,
|
id: int,
|
||||||
|
@ -237,7 +252,6 @@ pub struct BoxIterator {
|
||||||
priv boxes: ~[RenderBox],
|
priv boxes: ~[RenderBox],
|
||||||
priv index: uint,
|
priv index: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator<RenderBox> for BoxIterator {
|
impl Iterator<RenderBox> for BoxIterator {
|
||||||
fn next(&mut self) -> Option<RenderBox> {
|
fn next(&mut self) -> Option<RenderBox> {
|
||||||
if self.index >= self.boxes.len() {
|
if self.index >= self.boxes.len() {
|
||||||
|
@ -249,18 +263,13 @@ impl Iterator<RenderBox> for BoxIterator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowData {
|
impl FlowData {
|
||||||
pub fn new(id: int, node: AbstractNode<LayoutView>) -> FlowData {
|
pub fn new(id: int, node: AbstractNode<LayoutView>) -> FlowData {
|
||||||
FlowData {
|
FlowData {
|
||||||
node: node,
|
node: node,
|
||||||
restyle_damage: node.restyle_damage(),
|
restyle_damage: node.restyle_damage(),
|
||||||
|
|
||||||
parent: None,
|
children: DList::new(),
|
||||||
first_child: None,
|
|
||||||
last_child: None,
|
|
||||||
prev_sibling: None,
|
|
||||||
next_sibling: None,
|
|
||||||
|
|
||||||
id: id,
|
id: id,
|
||||||
|
|
||||||
|
@ -274,6 +283,11 @@ impl FlowData {
|
||||||
is_inorder: false
|
is_inorder: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn child_iter<'a>(&'a mut self) -> MutDListIterator<'a, FlowContext> {
|
||||||
|
self.children.mut_iter()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> FlowContext {
|
impl<'self> FlowContext {
|
||||||
|
@ -302,75 +316,88 @@ impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inline(&'self mut self) -> &'self mut InlineFlowData {
|
||||||
pub fn inline(&self) -> @mut InlineFlowData {
|
|
||||||
match *self {
|
match *self {
|
||||||
InlineFlow(info) => info,
|
InlineFlow(ref mut info) => &mut (**info),
|
||||||
_ => fail!(fmt!("Tried to access inline data of non-inline: f%d", self.id()))
|
_ => fail!(fmt!("Tried to access inline data of non-inline: f%d", self.id()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn block(&self) -> @mut BlockFlowData {
|
pub fn imm_inline(&'self self) -> &'self InlineFlowData {
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) => info,
|
InlineFlow(ref info) => &**info,
|
||||||
|
_ => fail!(fmt!("Tried to access inline data of non-inline: f%d", self.id()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block(&'self mut self) -> &'self mut BlockFlowData {
|
||||||
|
match *self {
|
||||||
|
BlockFlow(ref mut info) => &mut (**info),
|
||||||
_ => fail!(fmt!("Tried to access block data of non-block: f%d", self.id()))
|
_ => fail!(fmt!("Tried to access block data of non-block: f%d", self.id()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn root(&self) -> @mut BlockFlowData {
|
pub fn root(&'self mut self) -> &'self mut BlockFlowData {
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) if info.is_root => info,
|
BlockFlow(ref mut info) if info.is_root => &mut (**info),
|
||||||
_ => fail!(fmt!("Tried to access root block data of non-root: f%d", self.id()))
|
_ => fail!(fmt!("Tried to access root block data of non-root: f%d", self.id()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bubble_widths(&self, ctx: &mut LayoutContext) {
|
pub fn bubble_widths(&mut self, ctx: &mut LayoutContext) {
|
||||||
|
|
||||||
|
debug!("FlowContext: bubbling widths for f%?", self.id());
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) => info.bubble_widths_block(ctx),
|
BlockFlow(ref mut info) => info.bubble_widths_block(ctx),
|
||||||
InlineFlow(info) => info.bubble_widths_inline(ctx),
|
InlineFlow(ref mut info) => info.bubble_widths_inline(ctx),
|
||||||
FloatFlow(info) => info.bubble_widths_float(ctx),
|
FloatFlow(ref mut info) => info.bubble_widths_float(ctx),
|
||||||
_ => fail!(fmt!("Tried to bubble_widths of flow: f%d", self.id()))
|
_ => fail!(fmt!("Tried to bubble_widths of flow: f%d", self.id()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_widths(&self, ctx: &mut LayoutContext) {
|
pub fn assign_widths(&mut self, ctx: &mut LayoutContext) {
|
||||||
|
|
||||||
|
debug!("FlowContext: assigning widths for f%?", self.id());
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) => info.assign_widths_block(ctx),
|
BlockFlow(ref mut info) => info.assign_widths_block(ctx),
|
||||||
InlineFlow(info) => info.assign_widths_inline(ctx),
|
InlineFlow(ref mut info) => info.assign_widths_inline(ctx),
|
||||||
FloatFlow(info) => info.assign_widths_float(),
|
FloatFlow(ref mut info) => info.assign_widths_float(),
|
||||||
_ => fail!(fmt!("Tried to assign_widths of flow: f%d", self.id()))
|
_ => fail!(fmt!("Tried to assign_widths of flow: f%d", self.id()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height(&self, ctx: &mut LayoutContext) {
|
pub fn assign_height(&mut self, ctx: &mut LayoutContext) {
|
||||||
|
|
||||||
|
debug!("FlowContext: assigning height for f%?", self.id());
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) => info.assign_height_block(ctx),
|
BlockFlow(ref mut info) => info.assign_height_block(ctx),
|
||||||
InlineFlow(info) => info.assign_height_inline(ctx),
|
InlineFlow(ref mut info) => info.assign_height_inline(ctx),
|
||||||
FloatFlow(info) => info.assign_height_float(ctx),
|
FloatFlow(ref mut info) => info.assign_height_float(ctx),
|
||||||
_ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
|
_ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height_inorder(&self, ctx: &mut LayoutContext) {
|
pub fn assign_height_inorder(&mut self, ctx: &mut LayoutContext) {
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) => info.assign_height_inorder_block(ctx),
|
BlockFlow(ref mut info) => info.assign_height_inorder_block(ctx),
|
||||||
InlineFlow(info) => info.assign_height_inorder_inline(ctx),
|
InlineFlow(ref mut info) => info.assign_height_inorder_inline(ctx),
|
||||||
FloatFlow(info) => info.assign_height_inorder_float(),
|
FloatFlow(ref mut info) => info.assign_height_inorder_float(),
|
||||||
_ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
|
_ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_display_list<E:ExtraDisplayListData>(&self,
|
pub fn build_display_list<E:ExtraDisplayListData>(&mut self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
list: &Cell<DisplayList<E>>)
|
list: &Cell<DisplayList<E>>)
|
||||||
-> bool {
|
-> bool {
|
||||||
|
|
||||||
|
|
||||||
|
debug!("FlowContext: building display list for f%?", self.id());
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(info) => info.build_display_list_block(builder, dirty, list),
|
BlockFlow(ref mut info) => info.build_display_list_block(builder, dirty, list),
|
||||||
InlineFlow(info) => info.build_display_list_inline(builder, dirty, list),
|
InlineFlow(ref mut info) => info.build_display_list_inline(builder, dirty, list),
|
||||||
FloatFlow(info) => info.build_display_list_float(builder, dirty, list),
|
FloatFlow(ref mut info) => info.build_display_list_float(builder, dirty, list),
|
||||||
_ => {
|
_ => {
|
||||||
fail!("Tried to build_display_list_recurse of flow: %?", self)
|
fail!("Tried to build_display_list_recurse of flow: %?", self)
|
||||||
}
|
}
|
||||||
|
@ -388,16 +415,14 @@ impl<'self> FlowContext {
|
||||||
|
|
||||||
|
|
||||||
// Actual methods that do not require much flow-specific logic
|
// Actual methods that do not require much flow-specific logic
|
||||||
pub fn foldl_all_boxes<B:Clone>(&self, seed: B, cb: &fn(a: B, b: RenderBox) -> B) -> B {
|
pub fn foldl_all_boxes<B:Clone>(&mut self, seed: B, cb: &fn(a: B, b: RenderBox) -> B) -> B {
|
||||||
match *self {
|
match *self {
|
||||||
BlockFlow(block) => {
|
BlockFlow(ref mut block) => {
|
||||||
let block = &mut *block;
|
|
||||||
do block.box.map_default(seed.clone()) |box| {
|
do block.box.map_default(seed.clone()) |box| {
|
||||||
cb(seed.clone(), *box)
|
cb(seed.clone(), *box)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineFlow(inline) => {
|
InlineFlow(ref mut inline) => {
|
||||||
let inline = &mut *inline;
|
|
||||||
do inline.boxes.iter().fold(seed) |acc, box| {
|
do inline.boxes.iter().fold(seed) |acc, box| {
|
||||||
cb(acc.clone(), *box)
|
cb(acc.clone(), *box)
|
||||||
}
|
}
|
||||||
|
@ -406,7 +431,7 @@ impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn foldl_boxes_for_node<B:Clone>(&self,
|
pub fn foldl_boxes_for_node<B:Clone>(&mut self,
|
||||||
node: AbstractNode<LayoutView>,
|
node: AbstractNode<LayoutView>,
|
||||||
seed: B,
|
seed: B,
|
||||||
callback: &fn(a: B, RenderBox) -> B)
|
callback: &fn(a: B, RenderBox) -> B)
|
||||||
|
@ -420,11 +445,11 @@ impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_all_boxes(&self) -> BoxIterator {
|
pub fn iter_all_boxes(&mut self) -> BoxIterator {
|
||||||
BoxIterator {
|
BoxIterator {
|
||||||
boxes: match *self {
|
boxes: match *self {
|
||||||
BlockFlow (block) => block.box.map_default(~[], |&x| ~[x]),
|
BlockFlow (ref mut block) => block.box.map_default(~[], |&x| ~[x]),
|
||||||
InlineFlow(inline) => inline.boxes.clone(),
|
InlineFlow(ref mut inline) => inline.boxes.clone(),
|
||||||
_ => 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))
|
||||||
},
|
},
|
||||||
index: 0,
|
index: 0,
|
||||||
|
@ -432,12 +457,12 @@ impl<'self> FlowContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dumps the flow tree for debugging.
|
/// Dumps the flow tree for debugging.
|
||||||
pub fn dump(&self) {
|
pub fn dump(&mut self) {
|
||||||
self.dump_indent(0);
|
self.dump_indent(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dumps the flow tree, for debugging, with indentation.
|
/// Dumps the flow tree, for debugging, with indentation.
|
||||||
pub fn dump_indent(&self, indent: uint) {
|
pub fn dump_indent(&mut self, indent: uint) {
|
||||||
let mut s = ~"|";
|
let mut s = ~"|";
|
||||||
for _ in range(0, indent) {
|
for _ in range(0, indent) {
|
||||||
s.push_str("---- ");
|
s.push_str("---- ");
|
||||||
|
@ -447,27 +472,27 @@ impl<'self> FlowContext {
|
||||||
stderr().write_line(s);
|
stderr().write_line(s);
|
||||||
|
|
||||||
// FIXME: this should have a pure/const version?
|
// FIXME: this should have a pure/const version?
|
||||||
for child in self.children() {
|
for child in self.child_iter() {
|
||||||
child.dump_indent(indent + 1)
|
child.dump_indent(indent + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_str(&self) -> ~str {
|
pub fn debug_str(&self) -> ~str {
|
||||||
let repr = match *self {
|
let repr = match *self {
|
||||||
InlineFlow(inline) => {
|
InlineFlow(ref inline) => {
|
||||||
let mut s = inline.boxes.iter().fold(~"InlineFlow(children=", |s, box| {
|
let mut s = inline.boxes.iter().fold(~"InlineFlow(children=", |s, box| {
|
||||||
fmt!("%s b%d", s, box.id())
|
fmt!("%s b%d", s, box.id())
|
||||||
});
|
});
|
||||||
s.push_str(")");
|
s.push_str(")");
|
||||||
s
|
s
|
||||||
},
|
},
|
||||||
BlockFlow(block) => {
|
BlockFlow(ref block) => {
|
||||||
match block.box {
|
match block.box {
|
||||||
Some(box) => fmt!("BlockFlow(box=b%d)", box.id()),
|
Some(box) => fmt!("BlockFlow(box=b%d)", box.id()),
|
||||||
None => ~"BlockFlow",
|
None => ~"BlockFlow",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FloatFlow(float) => {
|
FloatFlow(ref float) => {
|
||||||
match float.box {
|
match float.box {
|
||||||
Some(box) => fmt!("FloatFlow(box=b%d)", box.id()),
|
Some(box) => fmt!("FloatFlow(box=b%d)", box.id()),
|
||||||
None => ~"FloatFlow",
|
None => ~"FloatFlow",
|
||||||
|
|
|
@ -60,7 +60,6 @@ struct LineBox {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LineboxScanner {
|
struct LineboxScanner {
|
||||||
flow: FlowContext,
|
|
||||||
floats: FloatContext,
|
floats: FloatContext,
|
||||||
new_boxes: ~[RenderBox],
|
new_boxes: ~[RenderBox],
|
||||||
work_list: @mut RingBuf<RenderBox>,
|
work_list: @mut RingBuf<RenderBox>,
|
||||||
|
@ -70,11 +69,8 @@ struct LineboxScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LineboxScanner {
|
impl LineboxScanner {
|
||||||
pub fn new(inline: FlowContext, float_ctx: FloatContext) -> LineboxScanner {
|
pub fn new(float_ctx: FloatContext) -> LineboxScanner {
|
||||||
assert!(inline.starts_inline_flow());
|
|
||||||
|
|
||||||
LineboxScanner {
|
LineboxScanner {
|
||||||
flow: inline,
|
|
||||||
floats: float_ctx,
|
floats: float_ctx,
|
||||||
new_boxes: ~[],
|
new_boxes: ~[],
|
||||||
work_list: @mut RingBuf::new(),
|
work_list: @mut RingBuf::new(),
|
||||||
|
@ -92,8 +88,8 @@ impl LineboxScanner {
|
||||||
self.floats.clone()
|
self.floats.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_scanner(&mut self) {
|
fn reset_scanner(&mut self, flow: &mut InlineFlowData) {
|
||||||
debug!("Resetting line box scanner's state for flow f%d.", self.flow.id());
|
debug!("Resetting line box scanner's state for flow f%d.", flow.common.id);
|
||||||
self.lines = ~[];
|
self.lines = ~[];
|
||||||
self.new_boxes = ~[];
|
self.new_boxes = ~[];
|
||||||
self.cur_y = Au(0);
|
self.cur_y = Au(0);
|
||||||
|
@ -106,60 +102,55 @@ impl LineboxScanner {
|
||||||
self.pending_line.green_zone = Size2D(Au(0), Au(0))
|
self.pending_line.green_zone = Size2D(Au(0), Au(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scan_for_lines(&mut self) {
|
pub fn scan_for_lines(&mut self, flow: &mut InlineFlowData) {
|
||||||
self.reset_scanner();
|
self.reset_scanner(flow);
|
||||||
|
|
||||||
{ // FIXME: manually control borrow length
|
let mut i = 0u;
|
||||||
let inline: &InlineFlowData = self.flow.inline();
|
|
||||||
let mut i = 0u;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// acquire the next box to lay out from work list or box list
|
// acquire the next box to lay out from work list or box list
|
||||||
let cur_box = if self.work_list.is_empty() {
|
let cur_box = if self.work_list.is_empty() {
|
||||||
if i == inline.boxes.len() {
|
if i == flow.boxes.len() {
|
||||||
break
|
break
|
||||||
}
|
|
||||||
let box = inline.boxes[i]; i += 1;
|
|
||||||
debug!("LineboxScanner: Working with box from box list: b%d", box.id());
|
|
||||||
box
|
|
||||||
} else {
|
|
||||||
let box = self.work_list.pop_front().unwrap();
|
|
||||||
debug!("LineboxScanner: Working with box from work list: b%d", box.id());
|
|
||||||
box
|
|
||||||
};
|
|
||||||
|
|
||||||
let box_was_appended = self.try_append_to_line(cur_box);
|
|
||||||
if !box_was_appended {
|
|
||||||
debug!("LineboxScanner: Box wasn't appended, because line %u was full.",
|
|
||||||
self.lines.len());
|
|
||||||
self.flush_current_line();
|
|
||||||
} else {
|
|
||||||
debug!("LineboxScanner: appended a box to line %u", self.lines.len());
|
|
||||||
}
|
}
|
||||||
}
|
let box = flow.boxes[i]; i += 1;
|
||||||
|
debug!("LineboxScanner: Working with box from box list: b%d", box.id());
|
||||||
|
box
|
||||||
|
} else {
|
||||||
|
let box = self.work_list.pop_front().unwrap();
|
||||||
|
debug!("LineboxScanner: Working with box from work list: b%d", box.id());
|
||||||
|
box
|
||||||
|
};
|
||||||
|
|
||||||
if self.pending_line.range.length() > 0 {
|
let box_was_appended = self.try_append_to_line(cur_box, flow);
|
||||||
debug!("LineboxScanner: Partially full linebox %u left at end of scanning.",
|
if !box_was_appended {
|
||||||
self.lines.len());
|
debug!("LineboxScanner: Box wasn't appended, because line %u was full.",
|
||||||
|
self.lines.len());
|
||||||
self.flush_current_line();
|
self.flush_current_line();
|
||||||
|
} else {
|
||||||
|
debug!("LineboxScanner: appended a box to line %u", self.lines.len());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // FIXME: scope the borrow
|
if self.pending_line.range.length() > 0 {
|
||||||
let inline: &mut InlineFlowData = self.flow.inline();
|
debug!("LineboxScanner: Partially full linebox %u left at end of scanning.",
|
||||||
inline.elems.repair_for_box_changes(inline.boxes, self.new_boxes);
|
self.lines.len());
|
||||||
|
self.flush_current_line();
|
||||||
}
|
}
|
||||||
self.swap_out_results();
|
|
||||||
|
|
||||||
|
flow.elems.repair_for_box_changes(flow.boxes, self.new_boxes);
|
||||||
|
|
||||||
|
self.swap_out_results(flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn swap_out_results(&mut self) {
|
fn swap_out_results(&mut self, flow: &mut InlineFlowData) {
|
||||||
debug!("LineboxScanner: Propagating scanned lines[n=%u] to inline flow f%d",
|
debug!("LineboxScanner: Propagating scanned lines[n=%u] to inline flow f%d",
|
||||||
self.lines.len(),
|
self.lines.len(),
|
||||||
self.flow.id());
|
flow.common.id);
|
||||||
|
|
||||||
let inline: &mut InlineFlowData = self.flow.inline();
|
util::swap(&mut flow.boxes, &mut self.new_boxes);
|
||||||
util::swap(&mut inline.boxes, &mut self.new_boxes);
|
util::swap(&mut flow.lines, &mut self.lines);
|
||||||
util::swap(&mut inline.lines, &mut self.lines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_current_line(&mut self) {
|
fn flush_current_line(&mut self) {
|
||||||
|
@ -222,7 +213,7 @@ impl LineboxScanner {
|
||||||
/// Computes the position of a line that has only the provided RenderBox.
|
/// Computes the position of a line that has only the provided RenderBox.
|
||||||
/// Returns: the bounding rect of the line's green zone (whose origin coincides
|
/// Returns: the bounding rect of the line's green zone (whose origin coincides
|
||||||
/// with the line's origin) and the actual width of the first box after splitting.
|
/// with the line's origin) and the actual width of the first box after splitting.
|
||||||
fn initial_line_placement (&self, first_box: RenderBox, ceiling: Au) -> (Rect<Au>, Au) {
|
fn initial_line_placement (&self, first_box: RenderBox, ceiling: Au, flow: &mut InlineFlowData) -> (Rect<Au>, Au) {
|
||||||
debug!("LineboxScanner: Trying to place first box of line %?", self.lines.len());
|
debug!("LineboxScanner: Trying to place first box of line %?", self.lines.len());
|
||||||
debug!("LineboxScanner: box size: %?", first_box.position().size);
|
debug!("LineboxScanner: box size: %?", first_box.position().size);
|
||||||
let splitable = first_box.can_split();
|
let splitable = first_box.can_split();
|
||||||
|
@ -241,7 +232,7 @@ impl LineboxScanner {
|
||||||
width: placement_width,
|
width: placement_width,
|
||||||
height: first_box.position().size.height,
|
height: first_box.position().size.height,
|
||||||
ceiling: ceiling,
|
ceiling: ceiling,
|
||||||
max_width: self.flow.position().size.width,
|
max_width: flow.common.position.size.width,
|
||||||
f_type: FloatLeft
|
f_type: FloatLeft
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -307,11 +298,11 @@ impl LineboxScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns false only if we should break the line.
|
/// Returns false only if we should break the line.
|
||||||
fn try_append_to_line(&mut self, in_box: RenderBox) -> bool {
|
fn try_append_to_line(&mut self, in_box: RenderBox, flow: &mut InlineFlowData) -> bool {
|
||||||
let line_is_empty: bool = self.pending_line.range.length() == 0;
|
let line_is_empty: bool = self.pending_line.range.length() == 0;
|
||||||
|
|
||||||
if line_is_empty {
|
if line_is_empty {
|
||||||
let (line_bounds, _) = self.initial_line_placement(in_box, self.cur_y);
|
let (line_bounds, _) = self.initial_line_placement(in_box, self.cur_y, flow);
|
||||||
self.pending_line.bounds.origin = line_bounds.origin;
|
self.pending_line.bounds.origin = line_bounds.origin;
|
||||||
self.pending_line.green_zone = line_bounds.size;
|
self.pending_line.green_zone = line_bounds.size;
|
||||||
}
|
}
|
||||||
|
@ -348,7 +339,7 @@ impl LineboxScanner {
|
||||||
|
|
||||||
// First predict where the next line is going to be
|
// First predict where the next line is going to be
|
||||||
let this_line_y = self.pending_line.bounds.origin.y;
|
let this_line_y = self.pending_line.bounds.origin.y;
|
||||||
let (next_line, first_box_width) = self.initial_line_placement(in_box, this_line_y);
|
let (next_line, first_box_width) = self.initial_line_placement(in_box, this_line_y, flow);
|
||||||
let next_green_zone = next_line.size;
|
let next_green_zone = next_line.size;
|
||||||
|
|
||||||
let new_width = self.pending_line.bounds.size.width + first_box_width;
|
let new_width = self.pending_line.bounds.size.width + first_box_width;
|
||||||
|
@ -490,7 +481,6 @@ impl InlineFlowData {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn teardown(&mut self) {
|
pub fn teardown(&mut self) {
|
||||||
self.common.teardown();
|
|
||||||
for box in self.boxes.iter() {
|
for box in self.boxes.iter() {
|
||||||
box.teardown();
|
box.teardown();
|
||||||
}
|
}
|
||||||
|
@ -512,10 +502,10 @@ impl InlineLayout for FlowContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InlineFlowData {
|
impl InlineFlowData {
|
||||||
pub fn bubble_widths_inline(@mut self, ctx: &mut LayoutContext) {
|
pub fn bubble_widths_inline(&mut self, ctx: &mut LayoutContext) {
|
||||||
let mut num_floats = 0;
|
let mut num_floats = 0;
|
||||||
|
|
||||||
for kid in InlineFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
do kid.with_mut_base |base| {
|
do kid.with_mut_base |base| {
|
||||||
num_floats += base.num_floats;
|
num_floats += base.num_floats;
|
||||||
base.floats_in = FloatContext::new(base.num_floats);
|
base.floats_in = FloatContext::new(base.num_floats);
|
||||||
|
@ -542,11 +532,13 @@ impl InlineFlowData {
|
||||||
|
|
||||||
/// Recursively (top-down) determines the actual width of child contexts and boxes. When called
|
/// Recursively (top-down) determines the actual width of child contexts and boxes. When called
|
||||||
/// on this context, the context has had its width set by the parent context.
|
/// on this context, the context has had its width set by the parent context.
|
||||||
pub fn assign_widths_inline(@mut self, _: &LayoutContext) {
|
pub fn assign_widths_inline(&mut self, _: &LayoutContext) {
|
||||||
// Initialize content box widths if they haven't been initialized already.
|
// Initialize content box widths if they haven't been initialized already.
|
||||||
//
|
//
|
||||||
// TODO: Combine this with `LineboxScanner`'s walk in the box list, or put this into
|
// TODO: Combine this with `LineboxScanner`'s walk in the box list, or put this into
|
||||||
// `RenderBox`.
|
// `RenderBox`.
|
||||||
|
|
||||||
|
debug!("assign_widths_inline: floats_in: %?", self.common.floats_in);
|
||||||
{
|
{
|
||||||
let this = &mut *self;
|
let this = &mut *self;
|
||||||
for &box in this.boxes.iter() {
|
for &box in this.boxes.iter() {
|
||||||
|
@ -571,7 +563,7 @@ impl InlineFlowData {
|
||||||
} // End of for loop.
|
} // End of for loop.
|
||||||
}
|
}
|
||||||
|
|
||||||
for kid in InlineFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
do kid.with_mut_base |base| {
|
do kid.with_mut_base |base| {
|
||||||
base.position.size.width = self.common.position.size.width;
|
base.position.size.width = self.common.position.size.width;
|
||||||
base.is_inorder = self.common.is_inorder;
|
base.is_inorder = self.common.is_inorder;
|
||||||
|
@ -586,14 +578,14 @@ impl InlineFlowData {
|
||||||
// 'inline-block' box that created this flow before recursing.
|
// 'inline-block' box that created this flow before recursing.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height_inorder_inline(@mut self, ctx: &mut LayoutContext) {
|
pub fn assign_height_inorder_inline(&mut self, ctx: &mut LayoutContext) {
|
||||||
for kid in InlineFlow(self).children() {
|
for kid in self.common.child_iter() {
|
||||||
kid.assign_height_inorder(ctx);
|
kid.assign_height_inorder(ctx);
|
||||||
}
|
}
|
||||||
self.assign_height_inline(ctx);
|
self.assign_height_inline(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign_height_inline(@mut self, _: &LayoutContext) {
|
pub fn assign_height_inline(&mut self, _: &LayoutContext) {
|
||||||
|
|
||||||
debug!("assign_height_inline: assigning height for flow %?", self.common.id);
|
debug!("assign_height_inline: assigning height for flow %?", self.common.id);
|
||||||
|
|
||||||
|
@ -603,8 +595,10 @@ impl InlineFlowData {
|
||||||
//
|
//
|
||||||
// TODO(#226): Get the CSS `line-height` property from each non-replaced inline element to
|
// TODO(#226): Get the CSS `line-height` property from each non-replaced inline element to
|
||||||
// determine its height for computing linebox height.
|
// determine its height for computing linebox height.
|
||||||
let mut scanner = LineboxScanner::new(InlineFlow(self), self.common.floats_in.clone());
|
debug!("assign_height_inline: floats_in: %?", self.common.floats_in);
|
||||||
scanner.scan_for_lines();
|
let scanner_floats = self.common.floats_in.clone();
|
||||||
|
let mut scanner = LineboxScanner::new(scanner_floats);
|
||||||
|
scanner.scan_for_lines(self);
|
||||||
|
|
||||||
// Now, go through each line and lay out the boxes inside
|
// Now, go through each line and lay out the boxes inside
|
||||||
for line in self.lines.iter() {
|
for line in self.lines.iter() {
|
||||||
|
@ -760,7 +754,7 @@ impl InlineFlowData {
|
||||||
|
|
||||||
let abs_rect = Rect(self.common.abs_position, self.common.position.size);
|
let abs_rect = Rect(self.common.abs_position, self.common.position.size);
|
||||||
if !abs_rect.intersects(dirty) {
|
if !abs_rect.intersects(dirty) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(#228): Once we form line boxes and have their cached bounds, we can be smarter and
|
// TODO(#228): Once we form line boxes and have their cached bounds, we can be smarter and
|
||||||
|
@ -777,7 +771,7 @@ impl InlineFlowData {
|
||||||
// should the flow be nested inside the box somehow?
|
// should the flow be nested inside the box somehow?
|
||||||
|
|
||||||
// For now, don't traverse the subtree rooted here
|
// For now, don't traverse the subtree rooted here
|
||||||
false
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -225,7 +225,7 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the flow tree.
|
// Construct the flow tree.
|
||||||
let layout_root: FlowContext = do profile(time::LayoutTreeBuilderCategory,
|
let mut layout_root: FlowContext = do profile(time::LayoutTreeBuilderCategory,
|
||||||
self.profiler_chan.clone()) {
|
self.profiler_chan.clone()) {
|
||||||
let mut builder = LayoutTreeBuilder::new();
|
let mut builder = LayoutTreeBuilder::new();
|
||||||
let layout_root: FlowContext = match builder.construct_trees(&layout_ctx, *node) {
|
let layout_root: FlowContext = match builder.construct_trees(&layout_ctx, *node) {
|
||||||
|
@ -238,7 +238,7 @@ impl LayoutTask {
|
||||||
|
|
||||||
// Propagate restyle damage up and down the tree, as appropriate.
|
// Propagate restyle damage up and down the tree, as appropriate.
|
||||||
// FIXME: Merge this with flow tree building and/or the other traversals.
|
// FIXME: Merge this with flow tree building and/or the other traversals.
|
||||||
for flow in layout_root.traverse_preorder() {
|
do layout_root.each_preorder |flow| {
|
||||||
// Also set any damage implied by resize.
|
// Also set any damage implied by resize.
|
||||||
if resized {
|
if resized {
|
||||||
do flow.with_mut_base |base| {
|
do flow.with_mut_base |base| {
|
||||||
|
@ -248,23 +248,29 @@ impl LayoutTask {
|
||||||
|
|
||||||
let prop = flow.with_base(|base| base.restyle_damage.propagate_down());
|
let prop = flow.with_base(|base| base.restyle_damage.propagate_down());
|
||||||
if prop.is_nonempty() {
|
if prop.is_nonempty() {
|
||||||
for kid_ctx in flow.children() {
|
for kid_ctx in flow.child_iter() {
|
||||||
do kid_ctx.with_mut_base |kid| {
|
do kid_ctx.with_mut_base |kid| {
|
||||||
kid.restyle_damage.union_in_place(prop);
|
kid.restyle_damage.union_in_place(prop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
true
|
||||||
|
};
|
||||||
|
|
||||||
for flow in layout_root.traverse_postorder() {
|
do layout_root.each_postorder |flow| {
|
||||||
for child in flow.children() {
|
let mut damage = do flow.with_base |base| {
|
||||||
|
base.restyle_damage
|
||||||
|
};
|
||||||
|
for child in flow.child_iter() {
|
||||||
do child.with_base |child_base| {
|
do child.with_base |child_base| {
|
||||||
do flow.with_mut_base |base| {
|
damage.union_in_place(child_base.restyle_damage);
|
||||||
base.restyle_damage.union_in_place(child_base.restyle_damage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
do flow.with_mut_base |base| {
|
||||||
|
base.restyle_damage = damage;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
debug!("layout: constructed Flow tree");
|
debug!("layout: constructed Flow tree");
|
||||||
debug!("%?", layout_root.dump());
|
debug!("%?", layout_root.dump());
|
||||||
|
@ -272,22 +278,27 @@ impl LayoutTask {
|
||||||
// Perform the primary layout passes over the flow tree to compute the locations of all
|
// Perform the primary layout passes over the flow tree to compute the locations of all
|
||||||
// the boxes.
|
// the boxes.
|
||||||
do profile(time::LayoutMainCategory, self.profiler_chan.clone()) {
|
do profile(time::LayoutMainCategory, self.profiler_chan.clone()) {
|
||||||
for flow in layout_root.traverse_postorder_prune(|f| f.restyle_damage().lacks(BubbleWidths)) {
|
do layout_root.each_postorder_prune(|f| f.restyle_damage().lacks(BubbleWidths)) |flow| {
|
||||||
flow.bubble_widths(&mut layout_ctx);
|
flow.bubble_widths(&mut layout_ctx);
|
||||||
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: We want to do
|
// FIXME: We want to do
|
||||||
// for flow in layout_root.traverse_preorder_prune(|f| f.restyle_damage().lacks(Reflow))
|
// for flow in layout_root.traverse_preorder_prune(|f| f.restyle_damage().lacks(Reflow))
|
||||||
// but FloatContext values can't be reused, so we need to recompute them every time.
|
// but FloatContext values can't be reused, so we need to recompute them every time.
|
||||||
for flow in layout_root.traverse_preorder() {
|
debug!("assigning widths");
|
||||||
|
do layout_root.each_preorder |flow| {
|
||||||
flow.assign_widths(&mut layout_ctx);
|
flow.assign_widths(&mut layout_ctx);
|
||||||
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
// For now, this is an inorder traversal
|
// For now, this is an inorder traversal
|
||||||
// FIXME: prune this traversal as well
|
// FIXME: prune this traversal as well
|
||||||
do layout_root.traverse_bu_sub_inorder |flow| {
|
debug!("assigning height");
|
||||||
|
do layout_root.each_bu_sub_inorder |flow| {
|
||||||
flow.assign_height(&mut layout_ctx);
|
flow.assign_height(&mut layout_ctx);
|
||||||
}
|
true
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the display list if necessary, and send it to the renderer.
|
// Build the display list if necessary, and send it to the renderer.
|
||||||
|
@ -301,9 +312,10 @@ impl LayoutTask {
|
||||||
|
|
||||||
// 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.
|
||||||
do layout_root.partially_traverse_preorder |flow| {
|
let root_pos = &layout_root.position().clone();
|
||||||
flow.build_display_list(&builder, &layout_root.position(), display_list)
|
layout_root.each_preorder_prune(|flow| {
|
||||||
}
|
flow.build_display_list(&builder, root_pos, display_list)
|
||||||
|
}, |_| { true } );
|
||||||
|
|
||||||
let root_size = do layout_root.with_base |base| {
|
let root_size = do layout_root.with_base |base| {
|
||||||
base.position.size
|
base.position.size
|
||||||
|
|
|
@ -66,16 +66,20 @@ impl TextRunScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scan_for_runs(&mut self, ctx: &LayoutContext, flow: FlowContext) {
|
pub fn scan_for_runs(&mut self, ctx: &LayoutContext, flow: &mut FlowContext) {
|
||||||
let inline = flow.inline();
|
{
|
||||||
assert!(inline.boxes.len() > 0);
|
let inline = flow.imm_inline();
|
||||||
debug!("TextRunScanner: scanning %u boxes for text runs...", inline.boxes.len());
|
// FIXME: this assertion fails on wikipedia, but doesn't seem
|
||||||
|
// to cause problems.
|
||||||
|
// assert!(inline.boxes.len() > 0);
|
||||||
|
debug!("TextRunScanner: scanning %u boxes for text runs...", inline.boxes.len());
|
||||||
|
}
|
||||||
|
|
||||||
let mut last_whitespace = true;
|
let mut last_whitespace = true;
|
||||||
let mut out_boxes = ~[];
|
let mut out_boxes = ~[];
|
||||||
for box_i in range(0, flow.inline().boxes.len()) {
|
for box_i in range(0, flow.imm_inline().boxes.len()) {
|
||||||
debug!("TextRunScanner: considering box: %?", flow.inline().boxes[box_i].debug_str());
|
debug!("TextRunScanner: considering box: %?", flow.imm_inline().boxes[box_i].debug_str());
|
||||||
if box_i > 0 && !can_coalesce_text_nodes(flow.inline().boxes, box_i-1, box_i) {
|
if box_i > 0 && !can_coalesce_text_nodes(flow.imm_inline().boxes, box_i-1, box_i) {
|
||||||
last_whitespace = self.flush_clump_to_list(ctx, flow, last_whitespace, &mut out_boxes);
|
last_whitespace = self.flush_clump_to_list(ctx, flow, last_whitespace, &mut out_boxes);
|
||||||
}
|
}
|
||||||
self.clump.extend_by(1);
|
self.clump.extend_by(1);
|
||||||
|
@ -118,10 +122,10 @@ impl TextRunScanner {
|
||||||
/// necessary.
|
/// necessary.
|
||||||
pub fn flush_clump_to_list(&mut self,
|
pub fn flush_clump_to_list(&mut self,
|
||||||
ctx: &LayoutContext,
|
ctx: &LayoutContext,
|
||||||
flow: FlowContext,
|
flow: &mut FlowContext,
|
||||||
last_whitespace: bool,
|
last_whitespace: bool,
|
||||||
out_boxes: &mut ~[RenderBox]) -> bool {
|
out_boxes: &mut ~[RenderBox]) -> bool {
|
||||||
let inline = &mut *flow.inline();
|
let inline = flow.inline();
|
||||||
let in_boxes = &inline.boxes;
|
let in_boxes = &inline.boxes;
|
||||||
|
|
||||||
fn has_underline(decoration: CSSTextDecoration) -> bool{
|
fn has_underline(decoration: CSSTextDecoration) -> bool{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue