auto merge of #1278 : saneyuki/servo/rm_box, r=pcwalton

This commit is contained in:
bors-servo 2013-11-18 10:18:02 -08:00
commit 37f9427b6c
5 changed files with 150 additions and 174 deletions

View file

@ -127,12 +127,10 @@ impl BlockFlow {
}
};
let mut model_ref = base.model.mutate();
let model = &mut model_ref.ptr;
top_offset = clearance + model.margin.top + model.border.top + model.padding.top;
top_offset = clearance + base.margin.top + base.border.top + base.padding.top;
cur_y = cur_y + top_offset;
bottom_offset = model.margin.bottom + model.border.bottom + model.padding.bottom;
left_offset = model.offset();
bottom_offset = base.margin.bottom + base.border.bottom + base.padding.bottom;
left_offset = base.offset();
}
if inorder {
@ -160,17 +158,15 @@ impl BlockFlow {
let mut first_in_flow = true;
for &box in self.box.iter() {
let base = box.base();
let mut model_ref = base.model.mutate();
let model = &mut model_ref.ptr;
if !self.is_root && model.border.top == Au::new(0) && model.padding.top == Au::new(0) {
collapsible = model.margin.top;
if !self.is_root && base.border.top == Au::new(0) && base.padding.top == Au::new(0) {
collapsible = base.margin.top;
top_margin_collapsible = true;
}
if !self.is_root && model.border.bottom == Au::new(0) && model.padding.bottom == Au::new(0) {
if !self.is_root && base.border.bottom == Au::new(0) && base.padding.bottom == Au::new(0) {
bottom_margin_collapsible = true;
}
margin_top = model.margin.top;
margin_bottom = model.margin.bottom;
margin_top = base.margin.top;
margin_bottom = base.margin.bottom;
}
for kid in self.base.child_iter() {
@ -220,23 +216,22 @@ impl BlockFlow {
let mut noncontent_height = Au::new(0);
for box in self.box.iter() {
let base = box.base();
let mut model_ref = base.model.mutate();
let base = box.mut_base();
let mut position_ref = base.position.mutate();
let (model, position) = (&mut model_ref.ptr, &mut position_ref.ptr);
let position = &mut position_ref.ptr;
// The associated box is the border box of this flow.
model.margin.top = margin_top;
model.margin.bottom = margin_bottom;
base.margin.top = margin_top;
base.margin.bottom = margin_bottom;
position.origin.y = clearance + model.margin.top;
position.origin.y = clearance + base.margin.top;
noncontent_height = model.padding.top + model.padding.bottom + model.border.top +
model.border.bottom;
noncontent_height = base.padding.top + base.padding.bottom + base.border.top +
base.border.bottom;
position.size.height = height + noncontent_height;
noncontent_height = noncontent_height + clearance + model.margin.top +
model.margin.bottom;
noncontent_height = noncontent_height + clearance + base.margin.top +
base.margin.bottom;
}
self.base.position.size.height = height + noncontent_height;
@ -257,18 +252,18 @@ impl BlockFlow {
-> bool {
if self.base.node.is_iframe_element() {
let x = self.base.abs_position.x + do self.box.map_default(Au::new(0)) |box| {
let model = box.base().model.get();
model.margin.left + model.border.left + model.padding.left
let base = box.base();
base.margin.left + base.border.left + base.padding.left
};
let y = self.base.abs_position.y + do self.box.map_default(Au::new(0)) |box| {
let model = box.base().model.get();
model.margin.top + model.border.top + model.padding.top
let base = box.base();
base.margin.top + base.border.top + base.padding.top
};
let w = self.base.position.size.width - do self.box.map_default(Au::new(0)) |box| {
box.base().model.get().noncontent_width()
box.base().noncontent_width()
};
let h = self.base.position.size.height - do self.box.map_default(Au::new(0)) |box| {
box.base().model.get().noncontent_height()
box.base().noncontent_height()
};
do self.base.node.with_mut_iframe_element |iframe_element| {
iframe_element.size.get_mut_ref().set_rect(Rect(Point2D(to_frac_px(x) as f32,
@ -339,9 +334,10 @@ impl FlowContext for BlockFlow {
these widths will not include child elements, just padding etc. */
for box in self.box.iter() {
{
// Can compute border width here since it doesn't depend on anything.
let mut_base = box.mut_base();
let base = box.base();
base.model.mutate().ptr.compute_borders(base.style())
// Can compute border width here since it doesn't depend on anything.
mut_base.compute_borders(base.style())
}
let (this_minimum_width, this_preferred_width) = box.minimum_and_preferred_widths();
@ -374,16 +370,14 @@ impl FlowContext for BlockFlow {
let mut x_offset = Au::new(0);
for &box in self.box.iter() {
let base = box.base();
let base = box.mut_base();
let style = base.style();
let mut model_ref = base.model.mutate();
let model = &mut model_ref.ptr;
// Can compute padding here since we know containing block width.
model.compute_padding(style, remaining_width);
base.compute_padding(style, remaining_width);
// Margins are 0 right now so model.noncontent_width() is just borders + padding.
let available_width = remaining_width - model.noncontent_width();
// Margins are 0 right now so base.noncontent_width() is just borders + padding.
let available_width = remaining_width - base.noncontent_width();
// Top and bottom margins for blocks are 0 if auto.
let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
@ -426,19 +420,19 @@ impl FlowContext for BlockFlow {
}
};
model.margin.top = margin_top;
model.margin.right = margin_right;
model.margin.bottom = margin_bottom;
model.margin.left = margin_left;
base.margin.top = margin_top;
base.margin.right = margin_right;
base.margin.bottom = margin_bottom;
base.margin.left = margin_left;
x_offset = model.offset();
x_offset = base.offset();
remaining_width = width;
//The associated box is the border box of this flow
let position_ref = base.position.mutate();
position_ref.ptr.origin.x = model.margin.left;
let padding_and_borders = model.padding.left + model.padding.right +
model.border.left + model.border.right;
position_ref.ptr.origin.x = base.margin.left;
let padding_and_borders = base.padding.left + base.padding.right +
base.border.left + base.border.right;
position_ref.ptr.size.width = remaining_width + padding_and_borders;
}
@ -482,26 +476,24 @@ impl FlowContext for BlockFlow {
collapsible: &mut Au) {
for &box in self.box.iter() {
let base = box.base();
let mut model_ref = base.model.mutate();
let model = &mut model_ref.ptr;
// The top margin collapses with its first in-flow block-level child's
// top margin if the parent has no top border, no top padding.
if *first_in_flow && top_margin_collapsible {
// If top-margin of parent is less than top-margin of its first child,
// the parent box goes down until its top is aligned with the child.
if *margin_top < model.margin.top {
if *margin_top < base.margin.top {
// TODO: The position of child floats should be updated and this
// would influence clearance as well. See #725
let extra_margin = model.margin.top - *margin_top;
let extra_margin = base.margin.top - *margin_top;
*top_offset = *top_offset + extra_margin;
*margin_top = model.margin.top;
*margin_top = base.margin.top;
}
}
// The bottom margin of an in-flow block-level element collapses
// with the top margin of its next in-flow block-level sibling.
*collapsing = geometry::min(model.margin.top, *collapsible);
*collapsible = model.margin.bottom;
*collapsing = geometry::min(base.margin.top, *collapsible);
*collapsible = base.margin.bottom;
}
*first_in_flow = false;

View file

@ -28,12 +28,12 @@ use std::unstable::raw::Box;
use style::ComputedValues;
use style::computed_values::{
border_style, clear, float, font_family, font_style, line_height,
position, text_align, text_decoration, vertical_align};
position, text_align, text_decoration, vertical_align, LengthOrPercentage};
use css::node_style::StyledNode;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor};
use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth};
use layout::model::{BoxModel, MaybeAuto};
use layout::model::{MaybeAuto, specified};
/// Boxes (`struct Box`) are the leaves of the layout tree. They cannot position themselves. In
/// general, boxes do not have a simple correspondence with CSS boxes in the specification:
@ -119,6 +119,8 @@ impl Clone for @RenderBox {
pub trait RenderBoxUtils {
fn base<'a>(&'a self) -> &'a RenderBoxBase;
fn mut_base<'a>(&'a self) -> &'a mut RenderBoxBase;
/// Returns true if this element is replaced content. This is true for images, form elements,
/// and so on.
fn is_replaced(&self) -> bool;
@ -172,6 +174,7 @@ pub trait RenderBoxUtils {
pub trait RenderBoxRefUtils<'self> {
fn base(self) -> &'self RenderBoxBase;
fn mut_base(self) -> &'self mut RenderBoxBase;
}
/// A box that represents a generic render box.
@ -618,13 +621,22 @@ pub struct RenderBoxBase {
/// The position of this box relative to its owning flow.
position: Slot<Rect<Au>>,
/// The core parameters (border, padding, margin) used by the box model.
model: Slot<BoxModel>,
/// A debug ID.
///
/// TODO(#87) Make this only present in debug builds.
id: int
id: int,
/// the border of the content box.
border: SideOffsets2D<Au>,
/// the padding of the content box.
padding: SideOffsets2D<Au>,
/// the margin of the content box.
margin: SideOffsets2D<Au>,
/// The width of the content box.
content_box_width: Au,
}
impl RenderBoxBase {
@ -634,8 +646,11 @@ impl RenderBoxBase {
RenderBoxBase {
node: node,
position: Slot::init(Au::zero_rect()),
model: Slot::init(Zero::zero()),
id: id,
border: Zero::zero(),
padding: Zero::zero(),
margin: Zero::zero(),
content_box_width: Zero::zero(),
}
}
@ -655,13 +670,11 @@ impl RenderBoxBase {
let margin_right = MaybeAuto::from_style(style.Margin.margin_right,
Au::new(0)).specified_or_zero();
let mut model_ref = self.model.mutate();
let model = &mut model_ref.ptr;
let padding_left = model.compute_padding_length(style.Padding.padding_left, Au::new(0));
let padding_right = model.compute_padding_length(style.Padding.padding_right, Au::new(0));
let padding_left = self.compute_padding_length(style.Padding.padding_left, Au::new(0));
let padding_right = self.compute_padding_length(style.Padding.padding_right, Au::new(0));
width + margin_left + margin_right + padding_left + padding_right + model.border.left +
model.border.right
width + margin_left + margin_right + padding_left + padding_right + self.border.left +
self.border.right
}
pub fn calculate_line_height(&self, font_size: Au) -> Au {
@ -672,23 +685,50 @@ impl RenderBoxBase {
}
}
pub fn compute_padding(&self, containing_block_width: Au) {
self.model.mutate().ptr.compute_padding(self.node.style(), containing_block_width);
/// Populates the box model border parameters from the given computed style.
pub fn compute_borders(&mut self, style: &ComputedValues) {
self.border.top = style.Border.border_top_width;
self.border.right = style.Border.border_right_width;
self.border.bottom = style.Border.border_bottom_width;
self.border.left = style.Border.border_left_width;
}
pub fn get_noncontent_width(&self) -> Au {
let model_ref = self.model.mutate();
model_ref.ptr.border.left + model_ref.ptr.padding.left + model_ref.ptr.border.right +
model_ref.ptr.padding.right
/// Populates the box model padding parameters from the given computed style.
pub fn compute_padding(&mut self, style: &ComputedValues, containing_block_width: Au) {
self.padding.top = self.compute_padding_length(style.Padding.padding_top,
containing_block_width);
self.padding.right = self.compute_padding_length(style.Padding.padding_right,
containing_block_width);
self.padding.bottom = self.compute_padding_length(style.Padding.padding_bottom,
containing_block_width);
self.padding.left = self.compute_padding_length(style.Padding.padding_left,
containing_block_width);
}
pub fn compute_padding_length(&self, padding: LengthOrPercentage, content_box_width: Au) -> Au {
specified(padding, content_box_width)
}
pub fn noncontent_width(&self) -> Au {
let left = self.margin.left + self.border.left + self.padding.left;
let right = self.margin.right + self.border.right + self.padding.right;
left + right
}
pub fn noncontent_height(&self) -> Au {
let top = self.margin.top + self.border.top + self.padding.top;
let bottom = self.margin.bottom + self.border.bottom + self.padding.bottom;
top + bottom
}
/// The box formed by the content edge as defined in CSS 2.1 § 8.1. Coordinates are relative to
/// the owning flow.
pub fn content_box(&self) -> Rect<Au> {
let (position, model) = (self.position.get(), self.model.get());
let origin = Point2D(position.origin.x + model.border.left + model.padding.left,
let position = self.position.get();
let origin = Point2D(position.origin.x + self.border.left + self.padding.left,
position.origin.y);
let size = Size2D(position.size.width - self.get_noncontent_width(), position.size.height);
let noncontent_width = self.border.left + self.padding.left + self.border.right + self.padding.right;
let size = Size2D(position.size.width - noncontent_width, position.size.height);
Rect(origin, size)
}
@ -824,6 +864,10 @@ impl RenderBoxBase {
get_propagated_text_decoration(self.nearest_ancestor_element())
}
pub fn offset(&self) -> Au {
self.margin.left + self.border.left + self.padding.left
}
}
impl RenderBoxUtils for @RenderBox {
@ -835,6 +879,13 @@ impl RenderBoxUtils for @RenderBox {
}
}
fn mut_base<'a>(&'a self) -> &'a mut RenderBoxBase {
unsafe {
let (_, box_ptr): (uint, *Box<RenderBoxBase>) = cast::transmute(*self);
cast::transmute_mut(&(*box_ptr).data)
}
}
fn is_replaced(&self) -> bool {
self.class() == ImageRenderBoxClass
}
@ -894,7 +945,7 @@ impl RenderBoxUtils for @RenderBox {
abs_bounds: &Rect<Au>) {
// Fast path.
let base = self.base();
let border = base.model.get().border;
let border = base.border;
if border.is_zero() {
return
}
@ -1115,5 +1166,13 @@ impl<'self> RenderBoxRefUtils<'self> for &'self RenderBox {
cast::transmute(box_ptr)
}
}
#[inline(always)]
fn mut_base(self) -> &'self mut RenderBoxBase {
unsafe {
let (_, box_ptr): (uint, *mut RenderBoxBase) = cast::transmute(self);
cast::transmute(box_ptr)
}
}
}

View file

@ -127,8 +127,7 @@ impl FlowContext for FloatFlow {
for box in self.box.iter() {
{
let base = box.base();
base.model.mutate().ptr.compute_borders(base.style());
box.mut_base().compute_borders(box.base().style());
}
let (this_minimum_width, this_preferred_width) = box.minimum_and_preferred_widths();
@ -153,13 +152,13 @@ impl FlowContext for FloatFlow {
for &box in self.box.iter() {
let base = box.base();
let mut_base = box.mut_base();
let style = base.style();
let mut position_ref = base.position.mutate();
let mut model_ref = base.model.mutate();
let (position, model) = (&mut position_ref.ptr, &mut model_ref.ptr);
let position = &mut position_ref.ptr;
// Can compute padding here since we know containing block width.
model.compute_padding(style, remaining_width);
mut_base.compute_padding(style, remaining_width);
// Margins for floats are 0 if auto.
let margin_top = MaybeAuto::from_style(style.Margin.margin_top,
@ -180,19 +179,19 @@ impl FlowContext for FloatFlow {
remaining_width).specified_or_default(shrink_to_fit);
debug!("assign_widths_float -- width: {}", width);
model.margin.top = margin_top;
model.margin.right = margin_right;
model.margin.bottom = margin_bottom;
model.margin.left = margin_left;
mut_base.margin.top = margin_top;
mut_base.margin.right = margin_right;
mut_base.margin.bottom = margin_bottom;
mut_base.margin.left = margin_left;
x_offset = model.offset();
x_offset = base.offset();
remaining_width = width;
// The associated box is the border box of this flow.
position.origin.x = model.margin.left;
position.origin.x = base.margin.left;
let padding_and_borders = model.padding.left + model.padding.right +
model.border.left + model.border.right;
let padding_and_borders = base.padding.left + base.padding.right +
base.border.left + base.border.right;
position.size.width = remaining_width + padding_and_borders;
}
@ -231,12 +230,11 @@ impl FlowContext for FloatFlow {
Some(clear) => self.base.floats_in.clearance(clear),
};
let model = base.model.get();
let noncontent_width = model.padding.left + model.padding.right + model.border.left +
model.border.right;
let noncontent_width = base.padding.left + base.padding.right + base.border.left +
base.border.right;
full_noncontent_width = noncontent_width + model.margin.left + model.margin.right;
margin_height = model.margin.top + model.margin.bottom;
full_noncontent_width = noncontent_width + base.margin.left + base.margin.right;
margin_height = base.margin.top + base.margin.bottom;
}
let info = PlacementInfo {
@ -270,9 +268,7 @@ impl FlowContext for FloatFlow {
for &box in self.box.iter() {
let base = box.base();
let model_ref = base.model.borrow();
top_offset = model_ref.ptr.margin.top + model_ref.ptr.border.top +
model_ref.ptr.padding.top;
top_offset = base.margin.top + base.border.top + base.padding.top;
cur_y = cur_y + top_offset;
}
@ -287,15 +283,14 @@ impl FlowContext for FloatFlow {
let mut noncontent_height;
for box in self.box.iter() {
let base = box.base();
let mut model_ref = base.model.mutate();
let mut position_ref = base.position.mutate();
let (model, position) = (&mut model_ref.ptr, &mut position_ref.ptr);
let position = &mut position_ref.ptr;
// The associated box is the border box of this flow.
position.origin.y = model.margin.top;
position.origin.y = base.margin.top;
noncontent_height = model.padding.top + model.padding.bottom + model.border.top +
model.border.bottom;
noncontent_height = base.padding.top + base.padding.bottom + base.border.top +
base.border.bottom;
//TODO(eatkinson): compute heights properly using the 'height' property.
let height_prop = MaybeAuto::from_style(base.style().Box.height,

View file

@ -681,10 +681,10 @@ impl FlowContext for InlineFlow {
let mut top;
let mut bottom;
{
let model = image_box.base.model.get();
top = model.border.top + model.padding.top + model.margin.top;
bottom = model.border.bottom + model.padding.bottom +
model.margin.bottom;
let base = &image_box.base;
top = base.border.top + base.padding.top + base.margin.top;
bottom = base.border.bottom + base.padding.bottom +
base.margin.bottom;
}
let noncontent_height = top + bottom;

View file

@ -4,22 +4,9 @@
//! Borders, padding, and margins.
use std::num::Zero;
use geom::side_offsets::SideOffsets2D;
use servo_util::geometry::Au;
use style::ComputedValues;
use computed = style::computed_values;
/// Encapsulates the borders, padding, and margins, which we collectively call the "box model".
#[deriving(Clone)]
pub struct BoxModel {
border: SideOffsets2D<Au>,
padding: SideOffsets2D<Au>,
margin: SideOffsets2D<Au>,
/// The width of the content box.
content_box_width: Au,
}
/// Useful helper data type when computing values for blocks and positioned elements.
pub enum MaybeAuto {
Auto,
@ -51,63 +38,6 @@ impl MaybeAuto {
}
}
impl Zero for BoxModel {
fn zero() -> BoxModel {
BoxModel {
border: Zero::zero(),
padding: Zero::zero(),
margin: Zero::zero(),
content_box_width: Zero::zero(),
}
}
fn is_zero(&self) -> bool {
self.padding.is_zero() && self.border.is_zero() && self.margin.is_zero()
}
}
impl BoxModel {
/// Populates the box model border parameters from the given computed style.
pub fn compute_borders(&mut self, style: &ComputedValues) {
self.border.top = style.Border.border_top_width;
self.border.right = style.Border.border_right_width;
self.border.bottom = style.Border.border_bottom_width;
self.border.left = style.Border.border_left_width;
}
/// Populates the box model padding parameters from the given computed style.
pub fn compute_padding(&mut self, style: &ComputedValues, containing_width: Au) {
self.padding.top = self.compute_padding_length(style.Padding.padding_top,
containing_width);
self.padding.right = self.compute_padding_length(style.Padding.padding_right,
containing_width);
self.padding.bottom = self.compute_padding_length(style.Padding.padding_bottom,
containing_width);
self.padding.left = self.compute_padding_length(style.Padding.padding_left,
containing_width);
}
pub fn noncontent_width(&self) -> Au {
let left = self.margin.left + self.border.left + self.padding.left;
let right = self.margin.right + self.border.right + self.padding.right;
left + right
}
pub fn noncontent_height(&self) -> Au {
let top = self.margin.top + self.border.top + self.padding.top;
let bottom = self.margin.bottom + self.border.bottom + self.padding.bottom;
top + bottom
}
pub fn offset(&self) -> Au {
self.margin.left + self.border.left + self.padding.left
}
pub fn compute_padding_length(&self, padding: computed::LengthOrPercentage, content_box_width: Au) -> Au {
specified(padding, content_box_width)
}
}
pub fn specified_or_none(length: computed::LengthOrPercentageOrNone, containing_length: Au) -> Option<Au> {
match length {
computed::LPN_None => None,