aboutsummaryrefslogtreecommitdiffstats
path: root/src/servo/layout/box_builder.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/servo/layout/box_builder.rs')
-rw-r--r--src/servo/layout/box_builder.rs286
1 files changed, 147 insertions, 139 deletions
diff --git a/src/servo/layout/box_builder.rs b/src/servo/layout/box_builder.rs
index f127efa03e7..d0fb0deb55d 100644
--- a/src/servo/layout/box_builder.rs
+++ b/src/servo/layout/box_builder.rs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-/** Creates CSS boxes from a DOM. */
+//! Creates CSS boxes from a DOM tree.
use dom::element::*;
use dom::node::{AbstractNode, CommentNodeTypeId, DoctypeNodeTypeId};
@@ -16,12 +16,12 @@ use layout::inline::{InlineFlowData, InlineLayout};
use layout::root::RootFlowData;
use gfx::image::holder::ImageHolder;
-use servo_util::range::Range;
use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock};
use newcss::values::{CSSDisplayNone};
+use servo_util::range::Range;
pub struct LayoutTreeBuilder {
- root_flow: Option<@mut FlowContext>,
+ root_flow: Option<FlowContext>,
next_bid: int,
next_cid: int
}
@@ -39,7 +39,7 @@ pub impl LayoutTreeBuilder {
// helper object for building the initial box list and making the
// mapping between DOM nodes and boxes.
struct BoxGenerator {
- flow: @mut FlowContext,
+ flow: FlowContext,
range_stack: ~[uint],
}
@@ -58,7 +58,9 @@ priv fn simulate_UA_display_rules(node: AbstractNode) -> CSSDisplay {
};*/
let resolved = CSSDisplayInline;
- if (resolved == CSSDisplayNone) { return resolved; }
+ if resolved == CSSDisplayNone {
+ return resolved;
+ }
match node.type_id() {
DoctypeNodeTypeId | CommentNodeTypeId => CSSDisplayNone,
@@ -81,7 +83,7 @@ priv fn simulate_UA_display_rules(node: AbstractNode) -> CSSDisplay {
}
impl BoxGenerator {
- fn new(flow: @mut FlowContext) -> BoxGenerator {
+ fn new(flow: FlowContext) -> BoxGenerator {
debug!("Creating box generator for flow: %s", flow.debug_str());
BoxGenerator {
flow: flow,
@@ -99,103 +101,110 @@ impl BoxGenerator {
_: &LayoutContext,
_: AbstractNode,
_: InlineSpacerSide)
- -> Option<@mut RenderBox> {
+ -> Option<@mut RenderBox> {
None
}
- pub fn push_node(@mut self, ctx: &LayoutContext, builder: &mut LayoutTreeBuilder, node: AbstractNode) {
- debug!("BoxGenerator[f%d]: pushing node: %s", self.flow.d().id, node.debug_str());
+ pub fn push_node(&mut self,
+ ctx: &LayoutContext,
+ builder: &mut LayoutTreeBuilder,
+ node: AbstractNode) {
+ debug!("BoxGenerator[f%d]: pushing node: %s", self.flow.id(), node.debug_str());
// first, determine the box type, based on node characteristics
let simulated_display = simulate_UA_display_rules(node);
// TODO: remove this once UA styles work
let box_type = builder.decide_box_type(node, simulated_display);
- debug!("BoxGenerator[f%d]: point a", self.flow.d().id);
+ debug!("BoxGenerator[f%d]: point a", self.flow.id());
// depending on flow, make a box for this node.
match self.flow {
- @InlineFlow(*) => {
- let node_range_start = match self.flow {
- @InlineFlow(*) => {
- let inline_flow = self.flow.inline();
- inline_flow.boxes.len()
- }
- _ => 0
- };
+ InlineFlow(inline) => {
+ let mut inline = &mut *inline;
+ let node_range_start = inline.boxes.len();
self.range_stack.push(node_range_start);
// if a leaf, make a box.
if node.is_leaf() {
let new_box = builder.make_box(ctx, box_type, node, self.flow);
- let boxes = &mut self.flow.inline().boxes;
- boxes.push(new_box);
+ inline.boxes.push(new_box);
} else if self.inline_spacers_needed_for_node(node) {
// else, maybe make a spacer for "left" margin, border, padding
for self.make_inline_spacer_for_node_side(ctx, node, LogicalBefore).each
|spacer: &@mut RenderBox| {
- let boxes = &mut self.flow.inline().boxes;
- boxes.push(*spacer);
+ inline.boxes.push(*spacer);
}
}
// TODO: cases for inline-block, etc.
},
- @BlockFlow(*) => {
- debug!("BoxGenerator[f%d]: point b", self.flow.d().id);
- let new_box = builder.make_box(ctx, box_type, node, self.flow);
- debug!("BoxGenerator[f%d]: attaching box[b%d] to block flow (node: %s)",
- self.flow.d().id, new_box.d().id, node.debug_str());
-
- assert!(self.flow.block().box.is_none());
- //XXXjdm We segfault when returning without this temporary.
- let block = self.flow.block();
- block.box = Some(new_box);
+ BlockFlow(*) => {
+ do self.flow.with_common_info |flow_info| {
+ debug!("BoxGenerator[f%d]: point b", flow_info.id);
+ let new_box = builder.make_box(ctx, box_type, node, self.flow);
+ debug!("BoxGenerator[f%d]: attaching box[b%d] to block flow (node: %s)",
+ flow_info.id,
+ new_box.d().id,
+ node.debug_str());
+
+ assert!(self.flow.block().box.is_none());
+ //XXXjdm We segfault when returning without this temporary.
+ let block = self.flow.block();
+ block.box = Some(new_box);
+ }
},
- @RootFlow(*) => {
- debug!("BoxGenerator[f%d]: point c", self.flow.d().id);
- let new_box = builder.make_box(ctx, box_type, node, self.flow);
- debug!("BoxGenerator[f%d]: (node is: %s)", self.flow.d().id, node.debug_str());
- debug!("BoxGenerator[f%d]: attaching box[b%d] to root flow (node: %s)",
- self.flow.d().id, new_box.d().id, node.debug_str());
-
- assert!(self.flow.root().box.is_none());
- //XXXjdm We segfault when returning without this temporary.
- let root = self.flow.root();
- root.box = Some(new_box);
+ RootFlow(*) => {
+ do self.flow.with_common_info |info| {
+ debug!("BoxGenerator[f%d]: point c", info.id);
+ let new_box = builder.make_box(ctx, box_type, node, self.flow);
+ debug!("BoxGenerator[f%d]: (node is: %s)", info.id, node.debug_str());
+ debug!("BoxGenerator[f%d]: attaching box[b%d] to root flow (node: %s)",
+ info.id,
+ new_box.d().id,
+ node.debug_str());
+
+ assert!(self.flow.root().box.is_none());
+ //XXXjdm We segfault when returning without this temporary.
+ let root = self.flow.root();
+ root.box = Some(new_box);
+ }
},
- _ => { warn!("push_node() not implemented for flow f%d", self.flow.d().id) }
+ _ => {
+ do self.flow.with_common_info |flow_info| {
+ warn!("push_node() not implemented for flow f%d", flow_info.id)
+ }
+ }
}
}
- pub fn pop_node(&mut self, ctx: &LayoutContext, _builder: &LayoutTreeBuilder, node: AbstractNode) {
- debug!("BoxGenerator[f%d]: popping node: %s", self.flow.d().id, node.debug_str());
+ pub fn pop_node(&mut self,
+ ctx: &LayoutContext,
+ _builder: &LayoutTreeBuilder,
+ node: AbstractNode) {
+ debug!("BoxGenerator[f%d]: popping node: %s", self.flow.id(), node.debug_str());
match self.flow {
- @InlineFlow(*) => {
+ InlineFlow(inline) => {
+ let inline = &mut *inline;
+
if self.inline_spacers_needed_for_node(node) {
- // if this non-leaf box generates extra horizontal
- // spacing, add a SpacerBox for it.
- for self.make_inline_spacer_for_node_side(ctx, node, LogicalAfter).each |spacer: &@mut RenderBox| {
+ // If this non-leaf box generates extra horizontal spacing, add a SpacerBox for
+ // it.
+ let result = self.make_inline_spacer_for_node_side(ctx, node, LogicalAfter);
+ for result.each |spacer| {
let boxes = &mut self.flow.inline().boxes;
boxes.push(*spacer);
}
}
let mut node_range: Range = Range::new(self.range_stack.pop(), 0);
- let inline_flow = self.flow.inline(); // FIXME: borrow checker workaround
- node_range.extend_to(inline_flow.boxes.len());
+ node_range.extend_to(inline.boxes.len());
assert!(node_range.length() > 0);
debug!("BoxGenerator: adding element range=%?", node_range);
- let elems = &mut inline_flow.elems;
- elems.add_mapping(node, &node_range);
- },
- @BlockFlow(*) | @RootFlow(*) => {
- assert!(self.range_stack.len() == 0);
+ inline.elems.add_mapping(node, &node_range);
},
- _ => {
- let d = self.flow.d(); // FIXME: borrow checker workaround
- warn!("pop_node() not implemented for flow %?", d.id)
- }
+ BlockFlow(*) | RootFlow(*) => assert!(self.range_stack.len() == 0),
+ _ => warn!("pop_node() not implemented for flow %?", self.flow.id()),
}
}
}
@@ -207,7 +216,11 @@ struct BuilderContext {
impl BuilderContext {
fn new(collector: @mut BoxGenerator) -> BuilderContext {
- debug!("Creating new BuilderContext for flow: %s", collector.flow.debug_str());
+ {
+ let collector = &mut *collector;
+ debug!("Creating new BuilderContext for flow: %s", collector.flow.debug_str());
+ }
+
BuilderContext {
default_collector: collector,
inline_collector: None,
@@ -219,11 +232,16 @@ impl BuilderContext {
copy self
}
- priv fn attach_child_flow(&self, child: @mut FlowContext) {
- let d = self.default_collector.flow.d(); // FIXME: borrow checker workaround
- let cd = child.d(); // FIXME: borrow checker workaround
- debug!("BuilderContext: Adding child flow f%? of f%?", d.id, cd.id);
- self.default_collector.flow.add_child(child);
+ priv fn attach_child_flow(&self, child: FlowContext) {
+ let default_collector = &mut *self.default_collector;
+ do default_collector.flow.with_common_info |flow_info| {
+ do child.with_common_info |child_flow_info| {
+ debug!("BuilderContext: Adding child flow f%? of f%?",
+ flow_info.id,
+ child_flow_info.id);
+ default_collector.flow.add_child(child);
+ }
+ }
}
priv fn create_child_flow_of_type(&self,
@@ -236,7 +254,8 @@ impl BuilderContext {
BuilderContext::new(@mut BoxGenerator::new(new_flow))
}
- priv fn make_inline_collector(&mut self, builder: &mut LayoutTreeBuilder, node: AbstractNode) -> BuilderContext {
+ priv fn make_inline_collector(&mut self, builder: &mut LayoutTreeBuilder, node: AbstractNode)
+ -> BuilderContext {
debug!("BuilderContext: making new inline collector flow");
let new_flow = builder.make_flow(Flow_Inline, node);
let new_generator = @mut BoxGenerator::new(new_flow);
@@ -247,7 +266,8 @@ impl BuilderContext {
BuilderContext::new(new_generator)
}
- priv fn get_inline_collector(&mut self, builder: &mut LayoutTreeBuilder, node: AbstractNode) -> BuilderContext {
+ priv fn get_inline_collector(&mut self, builder: &mut LayoutTreeBuilder, node: AbstractNode)
+ -> BuilderContext {
match copy self.inline_collector {
Some(collector) => BuilderContext::new(collector),
None => self.make_inline_collector(builder, node)
@@ -261,10 +281,8 @@ impl BuilderContext {
// returns a context for the current node, or None if the document subtree rooted
// by the node should not generate a layout tree. For example, nodes with style 'display:none'
// should just not generate any flows or boxes.
- fn containing_context_for_node(&mut self,
- node: AbstractNode,
- builder: &mut LayoutTreeBuilder)
- -> Option<BuilderContext> {
+ fn containing_context_for_node(&mut self, node: AbstractNode, builder: &mut LayoutTreeBuilder)
+ -> Option<BuilderContext> {
// TODO: remove this once UA styles work
// TODO: handle interactions with 'float', 'position' (CSS 2.1, Section 9.7)
let simulated_display = match simulate_UA_display_rules(node) {
@@ -273,7 +291,7 @@ impl BuilderContext {
};
let containing_context = match (simulated_display, self.default_collector.flow) {
- (CSSDisplayBlock, @RootFlow(*)) => {
+ (CSSDisplayBlock, RootFlow(*)) => {
// If this is the root node, then use the root flow's
// context. Otherwise, make a child block context.
match node.parent_node() {
@@ -281,14 +299,14 @@ impl BuilderContext {
None => { self.clone() },
}
},
- (CSSDisplayBlock, @BlockFlow(*)) => {
+ (CSSDisplayBlock, BlockFlow(*)) => {
self.clear_inline_collector();
self.create_child_flow_of_type(Flow_Block, builder, node)
},
- (CSSDisplayInline, @InlineFlow(*)) => self.clone(),
- (CSSDisplayInlineBlock, @InlineFlow(*)) => self.clone(),
- (CSSDisplayInline, @BlockFlow(*)) => self.get_inline_collector(builder, node),
- (CSSDisplayInlineBlock, @BlockFlow(*)) => self.get_inline_collector(builder, node),
+ (CSSDisplayInline, InlineFlow(*)) => self.clone(),
+ (CSSDisplayInlineBlock, InlineFlow(*)) => self.clone(),
+ (CSSDisplayInline, BlockFlow(*)) => self.get_inline_collector(builder, node),
+ (CSSDisplayInlineBlock, BlockFlow(*)) => self.get_inline_collector(builder, node),
_ => self.clone()
};
@@ -330,10 +348,12 @@ pub impl LayoutTreeBuilder {
// eventually be elided or split, but the mapping between
// nodes and FlowContexts should not change during layout.
let flow = &mut this_ctx.default_collector.flow;
- for flow.each_child |child_flow: @mut FlowContext| {
- let node = child_flow.d().node;
- assert!(node.has_layout_data());
- node.layout_data().flow = Some(child_flow);
+ for flow.each_child |child_flow| {
+ do child_flow.with_common_info |child_flow_info| {
+ let node = child_flow_info.node;
+ assert!(node.has_layout_data());
+ node.layout_data().flow = Some(child_flow);
+ }
}
}
@@ -347,14 +367,14 @@ pub impl LayoutTreeBuilder {
// beginning or end of a block flow. Otherwise, the whitespace
// might affect whitespace collapsing with adjacent text.
fn simplify_children_of_flow(&self, _: &LayoutContext, parent_ctx: &BuilderContext) {
- match *parent_ctx.default_collector.flow {
+ match parent_ctx.default_collector.flow {
InlineFlow(*) => {
let mut found_child_inline = false;
let mut found_child_block = false;
let flow = &mut parent_ctx.default_collector.flow;
- for flow.each_child |child_ctx: @mut FlowContext| {
- match *child_ctx {
+ for flow.each_child |child_ctx| {
+ match child_ctx {
InlineFlow(*) | InlineBlockFlow(*) => found_child_inline = true,
BlockFlow(*) => found_child_block = true,
_ => {}
@@ -370,34 +390,32 @@ pub impl LayoutTreeBuilder {
// of its RenderBox or FlowContext children, and possibly keep alive other junk
let parent_flow = parent_ctx.default_collector.flow;
- // FIXME: Workaround for the borrow check.
- let (first_child, last_child) = {
- let parent_flow: &mut FlowContext = parent_flow;
- let parent_flow_data = parent_flow.d();
- (parent_flow_data.first_child, parent_flow_data.last_child)
- };
+ let (first_child, last_child) =
+ do parent_flow.with_common_info |parent_flow_info| {
+ (parent_flow_info.first_child, parent_flow_info.last_child)
+ };
// check first/last child for whitespace-ness
- for first_child.each |first_flow: &@mut FlowContext| {
+ for first_child.each |first_flow| {
if first_flow.starts_inline_flow() {
let boxes = &mut first_flow.inline().boxes;
if boxes.len() == 1 && boxes[0].is_whitespace_only() {
debug!("LayoutTreeBuilder: pruning whitespace-only first child flow \
f%d from parent f%d",
- first_flow.d().id,
- parent_flow.d().id);
+ first_flow.id(),
+ parent_flow.id());
parent_flow.remove_child(*first_flow);
}
}
}
- for last_child.each |last_flow: &@mut FlowContext| {
+ for last_child.each |last_flow| {
if last_flow.starts_inline_flow() {
let boxes = &mut last_flow.inline().boxes;
if boxes.len() == 1 && boxes.last().is_whitespace_only() {
debug!("LayoutTreeBuilder: pruning whitespace-only last child flow \
f%d from parent f%d",
- last_flow.d().id,
- parent_flow.d().id);
+ last_flow.id(),
+ parent_flow.id());
parent_flow.remove_child(*last_flow);
}
}
@@ -407,15 +425,14 @@ pub impl LayoutTreeBuilder {
}
}
- fn fixup_split_inline(&self, _: @mut FlowContext) {
+ fn fixup_split_inline(&self, _: FlowContext) {
// TODO: finish me.
fail!(~"TODO: handle case where an inline is split by a block")
}
- /** entry point for box creation. Should only be
- called on root DOM element. */
+ /// Entry point for box creation. Should only be called on the root DOM element.
fn construct_trees(&mut self, layout_ctx: &LayoutContext, root: AbstractNode)
- -> Result<@mut FlowContext, ()> {
+ -> Result<FlowContext, ()> {
let new_flow = self.make_flow(Flow_Root, root);
let new_generator = @mut BoxGenerator::new(new_flow);
let mut root_ctx = BuilderContext::new(new_generator);
@@ -425,53 +442,46 @@ pub impl LayoutTreeBuilder {
return Ok(new_flow)
}
- fn make_flow(&mut self, ty: FlowContextType, node: AbstractNode) -> @mut FlowContext {
- let data = FlowData::new(self.next_flow_id(), node);
- let ret = match ty {
- Flow_Absolute => @mut AbsoluteFlow(data),
- Flow_Block => @mut BlockFlow(data, BlockFlowData()),
- Flow_Float => @mut FloatFlow(data),
- Flow_InlineBlock => @mut InlineBlockFlow(data),
- Flow_Inline => @mut InlineFlow(data, InlineFlowData()),
- Flow_Root => @mut RootFlow(data, RootFlowData()),
- Flow_Table => @mut TableFlow(data)
+ /// Creates a flow of the given type for the supplied node.
+ fn make_flow(&mut self, ty: FlowContextType, node: AbstractNode) -> FlowContext {
+ let info = FlowData::new(self.next_flow_id(), node);
+ let result = match ty {
+ Flow_Absolute => AbsoluteFlow(@mut info),
+ Flow_Block => BlockFlow(@mut BlockFlowData::new(info)),
+ Flow_Float => FloatFlow(@mut info),
+ Flow_InlineBlock => InlineBlockFlow(@mut info),
+ Flow_Inline => InlineFlow(@mut InlineFlowData::new(info)),
+ Flow_Root => RootFlow(@mut RootFlowData::new(info)),
+ Flow_Table => TableFlow(@mut info),
};
- debug!("LayoutTreeBuilder: created flow: %s", ret.debug_str());
- ret
+ debug!("LayoutTreeBuilder: created flow: %s", result.debug_str());
+ result
}
- /**
- disambiguate between different methods here instead of inlining, since each
- case has very different complexity
- */
+ /// Disambiguate between different methods here instead of inlining, since each case has very
+ /// different complexity.
fn make_box(&mut self,
layout_ctx: &LayoutContext,
ty: RenderBoxType,
node: AbstractNode,
- ctx: @mut FlowContext)
- -> @mut RenderBox {
- let ret = match ty {
+ ctx: FlowContext)
+ -> @mut RenderBox {
+ let result = match ty {
RenderBox_Generic => self.make_generic_box(layout_ctx, node, ctx),
RenderBox_Text => self.make_text_box(layout_ctx, node, ctx),
RenderBox_Image => self.make_image_box(layout_ctx, node, ctx),
};
- debug!("LayoutTreeBuilder: created box: %s", ret.debug_str());
- ret
+ debug!("LayoutTreeBuilder: created box: %s", result.debug_str());
+ result
}
- fn make_generic_box(&mut self,
- _: &LayoutContext,
- node: AbstractNode,
- ctx: @mut FlowContext)
- -> @mut RenderBox {
+ fn make_generic_box(&mut self, _: &LayoutContext, node: AbstractNode, ctx: FlowContext)
+ -> @mut RenderBox {
@mut GenericBox(RenderBoxData(copy node, ctx, self.next_box_id()))
}
- fn make_image_box(&mut self,
- layout_ctx: &LayoutContext,
- node: AbstractNode,
- ctx: @mut FlowContext)
- -> @mut RenderBox {
+ fn make_image_box(&mut self, layout_ctx: &LayoutContext, node: AbstractNode, ctx: FlowContext)
+ -> @mut RenderBox {
if !node.is_image_element() {
fail!(~"WAT error: why couldn't we make an image box?");
}
@@ -482,17 +492,15 @@ pub impl LayoutTreeBuilder {
layout_ctx.image_cache);
@mut ImageBox(RenderBoxData(node, ctx, self.next_box_id()), holder)
} else {
- info!("Tried to make image box, but couldn't find image. Made generic box instead.");
+ info!("Tried to make image box, but couldn't find image. Made generic box \
+ instead.");
self.make_generic_box(layout_ctx, node, ctx)
}
}
}
- fn make_text_box(&mut self,
- _: &LayoutContext,
- node: AbstractNode,
- ctx: @mut FlowContext)
- -> @mut RenderBox {
+ fn make_text_box(&mut self, _: &LayoutContext, node: AbstractNode, ctx: FlowContext)
+ -> @mut RenderBox {
if !node.is_text() {
fail!(~"WAT error: why couldn't we make a text box?");
}