diff options
-rw-r--r-- | src/components/main/layout/block.rs | 38 | ||||
-rw-r--r-- | src/components/main/layout/box.rs | 36 | ||||
-rw-r--r-- | src/components/main/layout/box_builder.rs | 21 | ||||
-rw-r--r-- | src/components/main/layout/float.rs | 223 | ||||
-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.rs | 22 | ||||
-rw-r--r-- | src/components/main/layout/inline.rs | 55 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 6 | ||||
-rw-r--r-- | src/components/main/layout/model.rs | 4 | ||||
-rwxr-xr-x | src/components/main/servo.rc | 3 |
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; } |