Skip to content

Commit

Permalink
auto merge of #542 : eric93/servo/floats, r=pcwalton
Browse files Browse the repository at this point in the history
I added the minimal amount of code needed to place left-floats on the screen (right floats should also be possible soon). Text does not wrap around floats yet.

One thing I'm curious about is whether some existing abstractions (like Cell) can be used instead of this weird overwriting thing done in float_context.rs.
  • Loading branch information
bors-servo committed Jun 25, 2013
2 parents 033af01 + 427328e commit a01f6b9
Show file tree
Hide file tree
Showing 10 changed files with 694 additions and 36 deletions.
40 changes: 36 additions & 4 deletions src/components/main/layout/block.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -72,7 +73,7 @@ impl BlockLayout for FlowContext {

fn starts_block_flow(&self) -> bool {
match *self {
BlockFlow(*) | InlineBlockFlow(*) => true,
BlockFlow(*) | InlineBlockFlow(*) | FloatFlow(*) => true,
_ => false
}
}
Expand All @@ -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;
}
}

Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -240,17 +246,41 @@ 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);
let mut left_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;
left_offset = model.offset();
}
}

// 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 method)
let mut float_ctx = self.common.floats_in.translate(Point2D(-left_offset, -top_offset));
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;
Expand Down Expand Up @@ -281,6 +311,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(left_offset, self.common.position.size.height));
}

pub fn build_display_list_block<E:ExtraDisplayListData>(@mut self,
Expand Down
36 changes: 33 additions & 3 deletions src/components/main/layout/box.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
48 changes: 45 additions & 3 deletions src/components/main/layout/box_builder.rs
Expand Up @@ -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};
Expand All @@ -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};
Expand Down Expand Up @@ -159,6 +161,18 @@ impl BoxGenerator {
assert!(block.box.is_none());
block.box = Some(new_box);
},
FloatFlow(float) => {
debug!("BoxGenerator[f%d]: point b", float.common.id);
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.box = Some(new_box);
},
_ => warn!("push_node() not implemented for flow f%d", self.flow.id()),
}
}
Expand Down Expand Up @@ -349,8 +363,24 @@ 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.
Expand All @@ -360,6 +390,11 @@ pub impl LayoutTreeBuilder {
self.create_child_generator(node, parent_generator, Flow_Block)
}
},

(CSSDisplayBlock, FloatFlow(*), _) => {
self.create_child_generator(node, parent_generator, Flow_Block)
}

// Inlines that are children of inlines are part of the same flow
(CSSDisplayInline, InlineFlow(*), _) => parent_generator,
(CSSDisplayInlineBlock, InlineFlow(*), _) => parent_generator,
Expand All @@ -371,6 +406,15 @@ pub impl LayoutTreeBuilder {
self.create_child_generator(node, parent_generator, Flow_Inline)
}

// FIXME(eatkinson): this is bogus. Floats should not be able to split
// inlines. They should be appended as children of the inline flow.
(CSSDisplayInline, _, Some(FloatFlow(*))) |
(CSSDisplayInlineBlock, _, Some(FloatFlow(*))) |
(CSSDisplayInline, FloatFlow(*), _) |
(CSSDisplayInlineBlock, FloatFlow(*), _) => {
self.create_child_generator(node, parent_generator, Flow_Inline)
}

// Inlines whose previous sibling was not a block try to use their
// sibling's flow context.
(CSSDisplayInline, BlockFlow(*), _) |
Expand All @@ -383,8 +427,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
};

Expand Down Expand Up @@ -520,7 +562,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)),
Expand Down

0 comments on commit a01f6b9

Please sign in to comment.