diff options
author | Eric Atkinson <eatkinson@mozilla.com> | 2013-06-23 15:48:02 -0700 |
---|---|---|
committer | Eric Atkinson <eatkinson@mozilla.com> | 2013-06-24 16:07:02 -0700 |
commit | 94e7a86b7efe8b8c8d8ede0f3104c3893ff9a37a (patch) | |
tree | 30fb844e697e144127e978489a4d1a94f445b494 /src/components/main/layout/float.rs | |
parent | d3fe4f4e3ad2f627b1de0d6f50c8866edc5a5451 (diff) | |
download | servo-94e7a86b7efe8b8c8d8ede0f3104c3893ff9a37a.tar.gz servo-94e7a86b7efe8b8c8d8ede0f3104c3893ff9a37a.zip |
Added floats to the flow tree
Diffstat (limited to 'src/components/main/layout/float.rs')
-rw-r--r-- | src/components/main/layout/float.rs | 223 |
1 files changed, 223 insertions, 0 deletions
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) + } + } +} + |