aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEric Atkinson <eatkinson@mozilla.com>2013-06-23 15:48:02 -0700
committerEric Atkinson <eatkinson@mozilla.com>2013-06-24 16:07:02 -0700
commit94e7a86b7efe8b8c8d8ede0f3104c3893ff9a37a (patch)
tree30fb844e697e144127e978489a4d1a94f445b494 /src
parentd3fe4f4e3ad2f627b1de0d6f50c8866edc5a5451 (diff)
downloadservo-94e7a86b7efe8b8c8d8ede0f3104c3893ff9a37a.tar.gz
servo-94e7a86b7efe8b8c8d8ede0f3104c3893ff9a37a.zip
Added floats to the flow tree
Diffstat (limited to 'src')
-rw-r--r--src/components/main/layout/block.rs38
-rw-r--r--src/components/main/layout/box.rs36
-rw-r--r--src/components/main/layout/box_builder.rs21
-rw-r--r--src/components/main/layout/float.rs223
-rw-r--r--src/components/main/layout/float_context.rs (renamed from src/components/main/layout/floats.rs)41
-rw-r--r--src/components/main/layout/flow.rs22
-rw-r--r--src/components/main/layout/inline.rs55
-rw-r--r--src/components/main/layout/layout_task.rs6
-rw-r--r--src/components/main/layout/model.rs4
-rwxr-xr-xsrc/components/main/servo.rc3
10 files changed, 398 insertions, 51 deletions
diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs
index f7f07b14df2..175ee60073e 100644
--- a/src/components/main/layout/block.rs
+++ b/src/components/main/layout/block.rs
@@ -8,9 +8,10 @@ use layout::box::{RenderBox};
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::display_list_builder::{FlowDisplayListBuilderMethods};
-use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow};
+use layout::flow::{BlockFlow, FlowContext, FlowData, InlineBlockFlow, FloatFlow};
use layout::inline::InlineLayout;
use layout::model::{MaybeAuto, Specified, Auto};
+use layout::float_context::FloatContext;
use core::cell::Cell;
use geom::point::Point2D;
@@ -72,7 +73,7 @@ impl BlockLayout for FlowContext {
fn starts_block_flow(&self) -> bool {
match *self {
- BlockFlow(*) | InlineBlockFlow(*) => true,
+ BlockFlow(*) | InlineBlockFlow(*) | FloatFlow(*) => true,
_ => false
}
}
@@ -91,14 +92,17 @@ impl BlockFlowData {
pub fn bubble_widths_block(@mut self, ctx: &LayoutContext) {
let mut min_width = Au(0);
let mut pref_width = Au(0);
+ let mut num_floats = 0;
/* find max width from child block contexts */
for BlockFlow(self).each_child |child_ctx| {
assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
- do child_ctx.with_base |child_node| {
+ do child_ctx.with_mut_base |child_node| {
min_width = geometry::max(min_width, child_node.min_width);
pref_width = geometry::max(pref_width, child_node.pref_width);
+
+ num_floats = num_floats + child_node.num_floats;
}
}
@@ -116,6 +120,7 @@ impl BlockFlowData {
self.common.min_width = min_width;
self.common.pref_width = pref_width;
+ self.common.num_floats = num_floats;
}
/// Computes left and right margins and width based on CSS 2.1 secion 10.3.3.
@@ -180,6 +185,7 @@ impl BlockFlowData {
debug!("Setting root position");
self.common.position.origin = Au::zero_point();
self.common.position.size.width = ctx.screen_size.size.width;
+ self.common.floats_in = FloatContext::new(self.common.num_floats);
}
//position was set to the containing block by the flow's parent
@@ -240,7 +246,7 @@ impl BlockFlowData {
}
}
- pub fn assign_height_block(@mut self, ctx: &LayoutContext) {
+ pub fn assign_height_block(@mut self, ctx: &mut LayoutContext) {
let mut cur_y = Au(0);
let mut top_offset = Au(0);
@@ -251,6 +257,28 @@ impl BlockFlowData {
}
}
+ // TODO(eatkinson): the translation here is probably
+ // totally wrong. We need to do it right or pages
+ // with floats will look very strange.
+
+ // Floats for blocks work like this:
+ // self.floats_in -> child[0].floats_in
+ // visit child[0]
+ // child[i-1].floats_out -> child[i].floats_in
+ // visit child[i]
+ // repeat until all children are visited.
+ // last_child.floats_out -> self.floats_out (done at the end of this function)
+ let mut float_ctx = self.common.floats_in.clone();
+ for BlockFlow(self).each_child |kid| {
+ do kid.with_mut_base |child_node| {
+ child_node.floats_in = float_ctx.clone();
+ }
+ kid.assign_height(ctx);
+ do kid.with_mut_base |child_node| {
+ float_ctx = child_node.floats_out.translate(Point2D(Au(0), -child_node.position.size.height));
+ }
+
+ }
for BlockFlow(self).each_child |kid| {
do kid.with_mut_base |child_node| {
child_node.position.origin.y = cur_y;
@@ -281,6 +309,8 @@ impl BlockFlowData {
//TODO(eatkinson): compute heights using the 'height' property.
self.common.position.size.height = height + noncontent_height;
+
+ self.common.floats_out = float_ctx.translate(Point2D(Au(0), self.common.position.size.height));
}
pub fn build_display_list_block<E:ExtraDisplayListData>(@mut self,
diff --git a/src/components/main/layout/box.rs b/src/components/main/layout/box.rs
index 141425c30ed..7d7db5410bc 100644
--- a/src/components/main/layout/box.rs
+++ b/src/components/main/layout/box.rs
@@ -8,7 +8,7 @@ use css::node_style::StyledNode;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor};
use layout::flow::FlowContext;
-use layout::model::BoxModel;
+use layout::model::{BoxModel, MaybeAuto};
use layout::text;
use core::cell::Cell;
@@ -370,11 +370,41 @@ pub impl RenderBox {
}
}
+ /// Guess the intrinsic width of this box for
+ /// computation of min and preferred widths.
+ //
+ // TODO(eatkinson): this is unspecified in
+ // CSS 2.1, but we need to do something reasonable
+ // here. What this function does currently is
+ // NOT reasonable.
+ //
+ // TODO(eatkinson): integrate with
+ // get_min_width and get_pref_width?
+ priv fn guess_width (&self) -> Au {
+ do self.with_base |base| {
+ if(!base.node.is_element()) {
+ Au(0)
+ } else {
+
+ let w = MaybeAuto::from_width(self.style().width(), Au(0)).spec_or_default(Au(0));
+ let ml = MaybeAuto::from_margin(self.style().margin_left(), Au(0)).spec_or_default(Au(0));
+ let mr = MaybeAuto::from_margin(self.style().margin_right(), Au(0)).spec_or_default(Au(0));
+ let pl = base.model.compute_padding_length(self.style().padding_left(), Au(0));
+ let pr = base.model.compute_padding_length(self.style().padding_right(), Au(0));
+ let bl = base.model.compute_border_width(self.style().border_left_width());
+ let br = base.model.compute_border_width(self.style().border_right_width());
+
+ w + ml + mr + pl + pr + bl + br
+ }
+ }
+ }
+
/// Returns the *minimum width* of this render box as defined by the CSS specification.
fn get_min_width(&self, _: &LayoutContext) -> Au {
// FIXME(pcwalton): I think we only need to calculate this if the damage says that CSS
// needs to be restyled.
- match *self {
+
+ self.guess_width() + match *self {
// TODO: This should account for the minimum width of the box element in isolation.
// That includes borders, margins, and padding, but not child widths. The block
// `FlowContext` will combine the width of this element and that of its children to
@@ -397,7 +427,7 @@ pub impl RenderBox {
/// Returns the *preferred width* of this render box as defined by the CSS specification.
fn get_pref_width(&self, _: &LayoutContext) -> Au {
- match *self {
+ self.guess_width() + match *self {
// TODO: This should account for the preferred width of the box element in isolation.
// That includes borders, margins, and padding, but not child widths. The block
// `FlowContext` will combine the width of this element and that of its children to
diff --git a/src/components/main/layout/box_builder.rs b/src/components/main/layout/box_builder.rs
index b446f8a7172..6ec2092af99 100644
--- a/src/components/main/layout/box_builder.rs
+++ b/src/components/main/layout/box_builder.rs
@@ -6,6 +6,7 @@
use layout::aux::LayoutAuxMethods;
use layout::block::BlockFlowData;
+use layout::float::FloatFlowData;
use layout::box::{GenericRenderBoxClass, ImageRenderBox, ImageRenderBoxClass, RenderBox};
use layout::box::{RenderBoxBase, RenderBoxType, RenderBox_Generic, RenderBox_Image};
use layout::box::{RenderBox_Text, UnscannedTextRenderBox, UnscannedTextRenderBoxClass};
@@ -22,6 +23,7 @@ use newcss::values::{CSSDisplayTableRowGroup, CSSDisplayTableHeaderGroup, CSSDis
use newcss::values::{CSSDisplayTableRow, CSSDisplayTableColumnGroup, CSSDisplayTableColumn};
use newcss::values::{CSSDisplayTableCell, CSSDisplayTableCaption};
use newcss::values::{CSSDisplayNone};
+use newcss::values::{CSSFloatNone};
use script::dom::element::*;
use script::dom::node::{AbstractNode, CommentNodeTypeId, DoctypeNodeTypeId};
use script::dom::node::{ElementNodeTypeId, LayoutView, TextNodeTypeId};
@@ -349,8 +351,23 @@ pub impl LayoutTreeBuilder {
None => None,
Some(gen) => Some(gen.flow)
};
+
+ // TODO(eatkinson): use the value of the float property to
+ // determine whether to float left or right.
+ let is_float = if (node.is_element()) {
+ match node.style().float() {
+ CSSFloatNone => false,
+ _ => true
+ }
+ } else {
+ false
+ };
+
let new_generator = match (display, parent_generator.flow, sibling_flow) {
+ (CSSDisplayBlock, BlockFlow(_), _) if is_float => {
+ self.create_child_generator(node, parent_generator, Flow_Float)
+ },
(CSSDisplayBlock, BlockFlow(info), _) => match (info.is_root, node.parent_node()) {
// If this is the root node, then use the root flow's
// context. Otherwise, make a child block context.
@@ -383,8 +400,6 @@ pub impl LayoutTreeBuilder {
// TODO(eatkinson): blocks that are children of inlines need
// to split their parent flows.
- //
- // TODO(eatkinson): floats and positioned elements.
_ => parent_generator
};
@@ -520,7 +535,7 @@ pub impl LayoutTreeBuilder {
let result = match ty {
Flow_Absolute => AbsoluteFlow(@mut info),
Flow_Block => BlockFlow(@mut BlockFlowData::new(info)),
- Flow_Float => FloatFlow(@mut info),
+ Flow_Float => FloatFlow(@mut FloatFlowData::new(info)),
Flow_InlineBlock => InlineBlockFlow(@mut info),
Flow_Inline => InlineFlow(@mut InlineFlowData::new(info)),
Flow_Root => BlockFlow(@mut BlockFlowData::new_root(info)),
diff --git a/src/components/main/layout/float.rs b/src/components/main/layout/float.rs
new file mode 100644
index 00000000000..5bd25784424
--- /dev/null
+++ b/src/components/main/layout/float.rs
@@ -0,0 +1,223 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+use layout::box::{RenderBox};
+use layout::context::LayoutContext;
+use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
+use layout::display_list_builder::{FlowDisplayListBuilderMethods};
+use layout::flow::{FloatFlow, FlowData};
+use layout::model::{MaybeAuto};
+use layout::float_context::{FloatContext, PlacementInfo, FloatLeft};
+
+use core::cell::Cell;
+use geom::point::Point2D;
+use geom::rect::Rect;
+use gfx::display_list::DisplayList;
+use gfx::geometry::Au;
+use gfx::geometry;
+use servo_util::tree::{TreeNodeRef, TreeUtils};
+
+pub struct FloatFlowData {
+ /// Data common to all flows.
+ common: FlowData,
+
+ /// The associated render box.
+ box: Option<RenderBox>,
+
+ containing_width: Au,
+
+
+ /// Index into the box list for inline floats
+ index: Option<uint>,
+
+}
+
+impl FloatFlowData {
+ pub fn new(common: FlowData) -> FloatFlowData {
+ FloatFlowData {
+ common: common,
+ containing_width: Au(0),
+ box: None,
+ index: None,
+ }
+ }
+
+ pub fn teardown(&mut self) {
+ self.common.teardown();
+ for self.box.each |box| {
+ box.teardown();
+ }
+ self.box = None;
+ self.index = None;
+ }
+}
+
+impl FloatFlowData {
+ pub fn bubble_widths_float(@mut self, ctx: &LayoutContext) {
+ let mut min_width = Au(0);
+ let mut pref_width = Au(0);
+
+ self.common.num_floats = 1;
+
+ for FloatFlow(self).each_child |child_ctx| {
+ //assert!(child_ctx.starts_block_flow() || child_ctx.starts_inline_flow());
+
+ do child_ctx.with_mut_base |child_node| {
+ min_width = geometry::max(min_width, child_node.min_width);
+ pref_width = geometry::max(pref_width, child_node.pref_width);
+ child_node.floats_in = FloatContext::new(child_node.num_floats);
+ }
+ }
+
+ self.box.map(|&box| {
+ let style = box.style();
+ do box.with_model |model| {
+ model.compute_borders(style)
+ }
+
+ min_width = min_width.add(&box.get_min_width(ctx));
+ pref_width = pref_width.add(&box.get_pref_width(ctx));
+ });
+
+ self.common.min_width = min_width;
+ self.common.pref_width = pref_width;
+ }
+
+ pub fn assign_widths_float(@mut self, _: &LayoutContext) {
+ debug!("assign_widths_block: assigning width for flow %?", self.common.id);
+ // position.size.width is set by parent even though we don't know
+ // position.origin yet.
+ let mut remaining_width = self.common.position.size.width;
+ self.containing_width = remaining_width;
+ let mut x_offset = Au(0);
+
+ for self.box.each |&box| {
+ let style = box.style();
+ do box.with_model |model| {
+ // Can compute padding here since we know containing block width.
+ model.compute_padding(style, remaining_width);
+
+ // Margins for floats are 0 if auto.
+ let margin_top = MaybeAuto::from_margin(style.margin_top(),
+ remaining_width).spec_or_default(Au(0));
+ let margin_bottom = MaybeAuto::from_margin(style.margin_bottom(),
+ remaining_width).spec_or_default(Au(0));
+ let margin_left = MaybeAuto::from_margin(style.margin_left(),
+ remaining_width).spec_or_default(Au(0));
+ let margin_right = MaybeAuto::from_margin(style.margin_right(),
+ remaining_width).spec_or_default(Au(0));
+
+
+
+ let shrink_to_fit = geometry::min(self.common.pref_width,
+ geometry::max(self.common.min_width,
+ remaining_width));
+
+
+ let width = MaybeAuto::from_width(style.width(),
+ remaining_width).spec_or_default(shrink_to_fit);
+
+ model.margin.top = margin_top;
+ model.margin.right = margin_right;
+ model.margin.bottom = margin_bottom;
+ model.margin.left = margin_left;
+
+ self.common.position.size.width = width;
+ x_offset = model.offset();
+ remaining_width = width;
+ }
+
+ do box.with_mut_base |base| {
+ //The associated box is the border box of this flow
+ base.position.origin.x = base.model.margin.left;
+
+ let pb = base.model.padding.left + base.model.padding.right +
+ base.model.border.left + base.model.border.right;
+ base.position.size.width = remaining_width + pb;
+ }
+ }
+
+ for FloatFlow(self).each_child |kid| {
+ //assert!(kid.starts_block_flow() || kid.starts_inline_flow());
+
+ do kid.with_mut_base |child_node| {
+ child_node.position.origin.x = x_offset;
+ child_node.position.size.width = remaining_width;
+ }
+ }
+ }
+
+ pub fn assign_height_float(@mut self, ctx: &mut LayoutContext) {
+ for FloatFlow(self).each_child |kid| {
+ kid.assign_height(ctx);
+ }
+
+ let mut cur_y = Au(0);
+ let mut top_offset = Au(0);
+
+ for self.box.each |&box| {
+ do box.with_model |model| {
+ top_offset = model.margin.top + model.border.top + model.padding.top;
+ cur_y += top_offset;
+ }
+ }
+
+ for FloatFlow(self).each_child |kid| {
+ do kid.with_mut_base |child_node| {
+ child_node.position.origin.y = cur_y;
+ cur_y += child_node.position.size.height;
+ }
+ }
+
+ let height = cur_y - top_offset;
+
+ let mut noncontent_height = Au(0);
+ self.box.map(|&box| {
+ do box.with_mut_base |base| {
+ //The associated box is the border box of this flow
+ base.position.origin.y = base.model.margin.top;
+
+ noncontent_height = base.model.padding.top + base.model.padding.bottom +
+ base.model.border.top + base.model.border.bottom;
+ base.position.size.height = height + noncontent_height;
+
+ noncontent_height += base.model.margin.top + base.model.margin.bottom;
+ }
+ });
+
+ //TODO(eatkinson): compute heights using the 'height' property.
+ self.common.position.size.height = height + noncontent_height;
+
+ let info = PlacementInfo {
+ width: self.common.position.size.width,
+ height: self.common.position.size.height,
+ ceiling: Au(0),
+ max_width: self.containing_width,
+ f_type: FloatLeft,
+ };
+
+ self.common.floats_out = self.common.floats_in.add_float(&info);
+
+
+
+ }
+
+ pub fn build_display_list_float<E:ExtraDisplayListData>(@mut self,
+ builder: &DisplayListBuilder,
+ dirty: &Rect<Au>,
+ offset: &Point2D<Au>,
+ list: &Cell<DisplayList<E>>) {
+ self.box.map(|&box| {
+ box.build_display_list(builder, dirty, offset, list)
+ });
+
+
+ // go deeper into the flow tree
+ let flow = FloatFlow(self);
+ for flow.each_child |child| {
+ flow.build_display_list_for_child(builder, child, dirty, offset, list)
+ }
+ }
+}
+
diff --git a/src/components/main/layout/floats.rs b/src/components/main/layout/float_context.rs
index 4b4bce7596b..dd35b4f91cb 100644
--- a/src/components/main/layout/floats.rs
+++ b/src/components/main/layout/float_context.rs
@@ -1,28 +1,32 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
use geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
use gfx::geometry::{Au, max, min};
use core::util::replace;
-enum FloatType{
+pub enum FloatType{
FloatLeft,
FloatRight
}
-priv struct FloatContextBase{
+struct FloatContextBase{
float_data: ~[Option<FloatData>],
floats_used: uint,
max_y : Au,
offset: Point2D<Au>
}
-priv struct FloatData{
+struct FloatData{
bounds: Rect<Au>,
f_type: FloatType
}
/// All information necessary to place a float
-struct PlacementInfo{
+pub struct PlacementInfo{
width: Au, // The dimensions of the float
height: Au,
ceiling: Au, // The minimum top of the float, as determined by earlier elements
@@ -32,18 +36,26 @@ struct PlacementInfo{
/// Wrappers around float methods. To avoid allocating data we'll never use,
/// destroy the context on modification.
-enum FloatContext {
+pub enum FloatContext {
Invalid,
Valid(FloatContextBase)
}
impl FloatContext {
- fn new(num_floats: uint) -> FloatContext {
+ pub fn new(num_floats: uint) -> FloatContext {
Valid(FloatContextBase::new(num_floats))
}
#[inline(always)]
- priv fn with_base<R>(&mut self, callback: &fn(&mut FloatContextBase) -> R) -> R {
+ pub fn clone(&mut self) -> FloatContext {
+ match *self {
+ Invalid => fail!("Can't clone an invalid float context"),
+ Valid(_) => replace(self, Invalid)
+ }
+ }
+
+ #[inline(always)]
+ fn with_base<R>(&mut self, callback: &fn(&mut FloatContextBase) -> R) -> R {
match *self {
Invalid => fail!("Float context no longer available"),
Valid(ref mut base) => callback(base)
@@ -51,7 +63,7 @@ impl FloatContext {
}
#[inline(always)]
- fn with_base<R>(&self, callback: &fn(&FloatContextBase) -> R) -> R {
+ pub fn with_base<R>(&self, callback: &fn(&FloatContextBase) -> R) -> R {
match *self {
Invalid => fail!("Float context no longer available"),
Valid(ref base) => callback(base)
@@ -59,7 +71,7 @@ impl FloatContext {
}
#[inline(always)]
- fn translate(&mut self, trans: Point2D<Au>) -> FloatContext {
+ pub fn translate(&mut self, trans: Point2D<Au>) -> FloatContext {
do self.with_base |base| {
base.translate(trans);
}
@@ -67,14 +79,14 @@ impl FloatContext {
}
#[inline(always)]
- fn available_rect(&mut self, top: Au, height: Au, max_x: Au) -> Option<Rect<Au>> {
+ pub fn available_rect(&mut self, top: Au, height: Au, max_x: Au) -> Option<Rect<Au>> {
do self.with_base |base| {
base.available_rect(top, height, max_x)
}
}
#[inline(always)]
- fn add_float(&mut self, info: &PlacementInfo) -> FloatContext{
+ pub fn add_float(&mut self, info: &PlacementInfo) -> FloatContext{
do self.with_base |base| {
base.add_float(info);
}
@@ -84,9 +96,8 @@ impl FloatContext {
impl FloatContextBase{
fn new(num_floats: uint) -> FloatContextBase {
- let new_data = do vec::build_sized(num_floats) |push_fun| {
- push_fun(None);
- };
+ debug!("Creating float context of size %?", num_floats);
+ let new_data = vec::from_elem(num_floats, None);
FloatContextBase {
float_data: new_data,
floats_used: 0,
@@ -166,6 +177,7 @@ impl FloatContextBase{
}
fn add_float(&mut self, info: &PlacementInfo) {
+ debug!("Floats_used: %?, Floats available: %?", self.floats_used, self.float_data.len());
assert!(self.floats_used < self.float_data.len() &&
self.float_data[self.floats_used].is_none());
@@ -177,6 +189,7 @@ impl FloatContextBase{
f_type: info.f_type
};
self.float_data[self.floats_used] = Some(new_float);
+ self.floats_used += 1;
}
/// Given necessary info, finds the position of the float in
diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs
index 900a7b0a130..0d60eb117a6 100644
--- a/src/components/main/layout/flow.rs
+++ b/src/components/main/layout/flow.rs
@@ -26,10 +26,12 @@
/// similar methods.
use layout::block::BlockFlowData;
+use layout::float::FloatFlowData;
use layout::box::RenderBox;
use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::inline::{InlineFlowData};
+use layout::float_context::{FloatContext, Invalid};
use core::cell::Cell;
use geom::point::Point2D;
@@ -44,7 +46,7 @@ use servo_util::tree::{TreeNode, TreeNodeRef, TreeUtils};
pub enum FlowContext {
AbsoluteFlow(@mut FlowData),
BlockFlow(@mut BlockFlowData),
- FloatFlow(@mut FlowData),
+ FloatFlow(@mut FloatFlowData),
InlineBlockFlow(@mut FlowData),
InlineFlow(@mut InlineFlowData),
TableFlow(@mut FlowData),
@@ -70,10 +72,10 @@ impl FlowContext {
pub fn teardown(&self) {
match *self {
AbsoluteFlow(data) |
- FloatFlow(data) |
InlineBlockFlow(data) |
TableFlow(data) => data.teardown(),
BlockFlow(data) => data.teardown(),
+ FloatFlow(data) => data.teardown(),
InlineFlow(data) => data.teardown()
}
}
@@ -110,7 +112,7 @@ impl TreeNodeRef<FlowData> for FlowContext {
BlockFlow(info) => {
callback(&info.common)
}
- FloatFlow(info) => callback(info),
+ FloatFlow(info) => callback(&info.common),
InlineBlockFlow(info) => callback(info),
InlineFlow(info) => {
callback(&info.common)
@@ -124,7 +126,7 @@ impl TreeNodeRef<FlowData> for FlowContext {
BlockFlow(info) => {
callback(&mut info.common)
}
- FloatFlow(info) => callback(info),
+ FloatFlow(info) => callback(&mut info.common),
InlineBlockFlow(info) => callback(info),
InlineFlow(info) => {
callback(&mut info.common)
@@ -156,6 +158,9 @@ pub struct FlowData {
min_width: Au,
pref_width: Au,
position: Rect<Au>,
+ floats_in: FloatContext,
+ floats_out: FloatContext,
+ num_floats: uint,
}
impl TreeNode<FlowContext> for FlowData {
@@ -216,6 +221,9 @@ impl FlowData {
min_width: Au(0),
pref_width: Au(0),
position: Au::zero_rect(),
+ floats_in: Invalid,
+ floats_out: Invalid,
+ num_floats: 0,
}
}
}
@@ -264,6 +272,7 @@ impl<'self> FlowContext {
match *self {
BlockFlow(info) => info.bubble_widths_block(ctx),
InlineFlow(info) => info.bubble_widths_inline(ctx),
+ FloatFlow(info) => info.bubble_widths_float(ctx),
_ => fail!(fmt!("Tried to bubble_widths of flow: f%d", self.id()))
}
}
@@ -272,6 +281,7 @@ impl<'self> FlowContext {
match *self {
BlockFlow(info) => info.assign_widths_block(ctx),
InlineFlow(info) => info.assign_widths_inline(ctx),
+ FloatFlow(info) => info.assign_widths_float(ctx),
_ => fail!(fmt!("Tried to assign_widths of flow: f%d", self.id()))
}
}
@@ -280,6 +290,7 @@ impl<'self> FlowContext {
match *self {
BlockFlow(info) => info.assign_height_block(ctx),
InlineFlow(info) => info.assign_height_inline(ctx),
+ FloatFlow(info) => info.assign_height_float(ctx),
_ => fail!(fmt!("Tried to assign_height of flow: f%d", self.id()))
}
}
@@ -296,6 +307,7 @@ impl<'self> FlowContext {
match *self {
BlockFlow(info) => info.build_display_list_block(builder, dirty, offset, list),
InlineFlow(info) => info.build_display_list_inline(builder, dirty, offset, list),
+ FloatFlow(info) => info.build_display_list_float(builder, dirty, offset, list),
_ => fail!(fmt!("Tried to build_display_list_recurse of flow: %?", self))
}
}
@@ -412,7 +424,7 @@ impl<'self> FlowContext {
};
do self.with_base |base| {
- fmt!("f%? %? size %?", base.id, repr, base.position)
+ fmt!("f%? %? floats %?", base.id, repr, base.num_floats)
}
}
}
diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs
index 1e14c36dec9..4894da2fb1c 100644
--- a/src/components/main/layout/inline.rs
+++ b/src/components/main/layout/inline.rs
@@ -10,6 +10,7 @@ use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::flow::{FlowContext, FlowData, InlineFlow};
use layout::text::{UnscannedMethods, adapt_textbox_with_range};
+use layout::float_context::FloatContext;
use core::util;
use geom::{Point2D, Rect, Size2D};
@@ -25,6 +26,7 @@ use newcss::values::{CSSLineHeightNormal, CSSLineHeightNumber, CSSLineHeightLeng
use servo_util::range::Range;
use std::deque::Deque;
+use servo_util::tree::{TreeNodeRef, TreeUtils};
/*
Lineboxes are represented as offsets into the child list, rather than
@@ -394,7 +396,7 @@ impl TextRunScanner {
struct PendingLine {
range: Range,
- width: Au
+ bounds: Rect<Au>
}
struct LineboxScanner {
@@ -413,8 +415,8 @@ impl LineboxScanner {
flow: inline,
new_boxes: ~[],
work_list: @mut Deque::new(),
- pending_line: PendingLine {mut range: Range::empty(), mut width: Au(0)},
- line_spans: ~[]
+ pending_line: PendingLine {mut range: Range::empty(), mut bounds: Rect(Point2D(Au(0), Au(0)), Size2D(Au(0), Au(0)))},
+ line_spans: ~[],
}
}
@@ -427,7 +429,7 @@ impl LineboxScanner {
fn reset_linebox(&mut self) {
self.pending_line.range.reset(0,0);
- self.pending_line.width = Au(0);
+ self.pending_line.bounds = Rect(Point2D(Au(0), Au(0)), Size2D(Au(0), Au(0)));
}
pub fn scan_for_lines(&mut self, ctx: &LayoutContext) {
@@ -508,7 +510,7 @@ impl LineboxScanner {
linebox_align = CSSTextAlignLeft;
}
- let slack_width = self.flow.position().size.width - self.pending_line.width;
+ let slack_width = self.flow.position().size.width - self.pending_line.bounds.size.width;
match linebox_align {
// So sorry, but justified text is more complicated than shuffling linebox coordinates.
// TODO(Issue #213): implement `text-align: justify`
@@ -548,7 +550,7 @@ impl LineboxScanner {
// return value: whether any box was appended.
fn try_append_to_line(&mut self, ctx: &LayoutContext, in_box: RenderBox) -> bool {
- let remaining_width = self.flow.position().size.width - self.pending_line.width;
+ let remaining_width = self.flow.position().size.width - self.pending_line.bounds.size.width;
let in_box_width = in_box.position().size.width;
let line_is_empty: bool = self.pending_line.range.length() == 0;
@@ -639,7 +641,7 @@ impl LineboxScanner {
self.pending_line.range.reset(self.new_boxes.len(), 0);
}
self.pending_line.range.extend_by(1);
- self.pending_line.width += box.position().size.width;
+ self.pending_line.bounds.size.width += box.position().size.width;
self.new_boxes.push(box);
}
}
@@ -696,6 +698,15 @@ impl InlineFlowData {
pub fn bubble_widths_inline(@mut self, ctx: &mut LayoutContext) {
let mut scanner = TextRunScanner::new();
scanner.scan_for_runs(ctx, InlineFlow(self));
+ let mut num_floats = 0;
+
+ for InlineFlow(self).each_child |kid| {
+ do kid.with_mut_base |base| {
+ num_floats += base.num_floats;
+ base.floats_in = FloatContext::new(base.num_floats);
+ }
+ }
+
{
let this = &mut *self;
@@ -711,12 +722,13 @@ impl InlineFlowData {
this.common.min_width = min_width;
this.common.pref_width = pref_width;
+ this.common.num_floats = num_floats;
}
}
/// 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.
- pub fn assign_widths_inline(@mut self, ctx: &mut LayoutContext) {
+ pub fn assign_widths_inline(@mut self, _: &mut LayoutContext) {
// 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
@@ -745,9 +757,11 @@ impl InlineFlowData {
} // End of for loop.
}
- let mut scanner = LineboxScanner::new(InlineFlow(self));
- scanner.scan_for_lines(ctx);
-
+ for InlineFlow(self).each_child |kid| {
+ do kid.with_mut_base |base| {
+ base.position.size.width = self.common.position.size.width;
+ }
+ }
// There are no child contexts, so stop here.
// TODO(Issue #225): once there are 'inline-block' elements, this won't be
@@ -757,7 +771,18 @@ impl InlineFlowData {
// 'inline-block' box that created this flow before recursing.
}
- pub fn assign_height_inline(&mut self, _: &mut LayoutContext) {
+ pub fn assign_height_inline(@mut self, ctx: &mut LayoutContext) {
+
+ for InlineFlow(self).each_child |kid| {
+ kid.assign_height(ctx);
+ }
+
+
+ // TODO(eatkinson): line boxes need to shrink if there are floats
+ let mut scanner = LineboxScanner::new(InlineFlow(self));
+ scanner.scan_for_lines(ctx);
+ self.common.floats_out = self.common.floats_in.clone();
+
// TODO(#226): Get the CSS `line-height` property from the containing block's style to
// determine minimum linebox height.
//
@@ -774,10 +799,8 @@ impl InlineFlowData {
let mut linebox_height = Au(0);
let mut baseline_offset = Au(0);
- let boxes = &mut self.boxes;
-
for line_span.eachi |box_i| {
- let cur_box = boxes[box_i]; // FIXME: borrow checker workaround
+ let cur_box = self.boxes[box_i];
// Compute the height and bounding box of each box.
let bounding_box = match cur_box {
@@ -849,7 +872,7 @@ impl InlineFlowData {
// Now go back and adjust the Y coordinates to match the baseline we determined.
for line_span.eachi |box_i| {
- let cur_box = boxes[box_i];
+ let cur_box = self.boxes[box_i];
// TODO(#226): This is completely wrong. We need to use the element's `line-height`
// when calculating line box height. Then we should go back over and set Y offsets
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index 0389f7135ce..0d683ec25f4 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -225,9 +225,9 @@ impl Layout {
for layout_root.traverse_preorder |flow| {
flow.assign_widths(&mut layout_ctx);
};
- for layout_root.traverse_postorder |flow| {
- flow.assign_height(&mut layout_ctx);
- };
+
+ // For now, this is an inorder traversal
+ layout_root.assign_height(&mut layout_ctx);
}
// Build the display list if necessary, and send it to the renderer.
diff --git a/src/components/main/layout/model.rs b/src/components/main/layout/model.rs
index 37195aa757e..44bf3417a89 100644
--- a/src/components/main/layout/model.rs
+++ b/src/components/main/layout/model.rs
@@ -112,7 +112,7 @@ impl BoxModel {
}
/// Helper function to compute the border width in app units from the CSS border width.
- priv fn compute_border_width(&self, width: CSSBorderWidth) -> Au {
+ pub fn compute_border_width(&self, width: CSSBorderWidth) -> Au {
match width {
CSSBorderWidthLength(Px(v)) |
CSSBorderWidthLength(Em(v)) |
@@ -126,7 +126,7 @@ impl BoxModel {
}
}
- fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au) -> Au {
+ pub fn compute_padding_length(&self, padding: CSSPadding, content_box_width: Au) -> Au {
match padding {
CSSPaddingLength(Px(v)) |
CSSPaddingLength(Pt(v)) |
diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc
index 3e123796073..4cdfb710ee5 100755
--- a/src/components/main/servo.rc
+++ b/src/components/main/servo.rc
@@ -73,7 +73,8 @@ pub mod layout {
pub mod inline;
pub mod model;
pub mod text;
- pub mod floats;
+ pub mod float_context;
+ pub mod float;
mod aux;
}