aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout')
-rw-r--r--components/layout/block.rs78
-rw-r--r--components/layout/fragment.rs3
-rw-r--r--components/layout/table.rs237
-rw-r--r--components/layout/table_row.rs49
-rw-r--r--components/layout/table_rowgroup.rs40
-rw-r--r--components/layout/table_wrapper.rs92
-rw-r--r--components/layout/wrapper.rs4
7 files changed, 337 insertions, 166 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 77c60b25b3d..7fb63c0045d 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -44,7 +44,7 @@ use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug;
use model::{IntrinsicISizes, MarginCollapseInfo};
use model::{MaybeAuto, CollapsibleMargins, specified, specified_or_none};
-use table::ColumnComputedInlineSize;
+use table;
use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect, Size2D};
@@ -53,13 +53,13 @@ use msg::compositor_msg::LayerId;
use rustc_serialize::{Encoder, Encodable};
use std::cmp::{max, min};
use std::fmt;
+use std::sync::Arc;
use style::computed_values::{overflow_x, overflow_y, position, box_sizing, display, float};
use style::properties::ComputedValues;
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::computed::{LengthOrPercentageOrNone};
-use std::sync::Arc;
use util::geometry::{Au, MAX_AU};
-use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
+use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use util::opts;
/// Information specific to floated blocks.
@@ -302,11 +302,11 @@ impl BSizeConstraintSolution {
/// current calculated value of `height`.
///
/// See CSS 2.1 § 10.7.
-struct CandidateBSizeIterator {
+pub struct CandidateBSizeIterator {
block_size: MaybeAuto,
max_block_size: Option<Au>,
min_block_size: Au,
- candidate_value: Au,
+ pub candidate_value: Au,
status: CandidateBSizeIteratorStatus,
}
@@ -510,7 +510,7 @@ enum FormattingContextType {
//
// TODO(#1244, #2007, pcwalton): Do this for CSS transforms and opacity too, at least if they're
// animating.
-fn propagate_layer_flag_from_child(layers_needed_for_descendants: &mut bool, kid: &mut Flow) {
+pub fn propagate_layer_flag_from_child(layers_needed_for_descendants: &mut bool, kid: &mut Flow) {
if kid.is_absolute_containing_block() {
let kid_base = flow::mut_base(kid);
if kid_base.flags.contains(NEEDS_LAYER) {
@@ -1234,7 +1234,7 @@ impl BlockFlow {
layout_context: &LayoutContext,
inline_start_content_edge: Au,
content_inline_size: Au,
- optional_column_computed_inline_sizes: Option<&[ColumnComputedInlineSize]>) {
+ table_info: Option<table::ChildInlineSizeInfo>) {
// Keep track of whether floats could impact each child.
let mut inline_start_floats_impact_child =
self.base.flags.contains(IMPACTED_BY_LEFT_FLOATS);
@@ -1256,9 +1256,6 @@ impl BlockFlow {
let fixed_static_i_offset = self.base.fixed_static_i_offset + inline_start_content_edge;
let flags = self.base.flags.clone();
- // This value is used only for table cells.
- let mut inline_start_margin_edge = inline_start_content_edge;
-
// Remember the inline-sizes of the last left and right floats, if there were any. These
// are used for estimating the inline-sizes of block formatting contexts. (We estimate that
// the inline-size of any block formatting context that we see will be based on the
@@ -1286,7 +1283,8 @@ impl BlockFlow {
(LengthOrPercentageOrAuto::Percentage(percent), Some(container_size)) => {
Some(container_size.scale_by(percent))
}
- (LengthOrPercentageOrAuto::Percentage(_), None) | (LengthOrPercentageOrAuto::Auto, _) => None,
+ (LengthOrPercentageOrAuto::Percentage(_), None) |
+ (LengthOrPercentageOrAuto::Auto, _) => None,
(LengthOrPercentageOrAuto::Length(length), _) => Some(length),
};
@@ -1299,6 +1297,13 @@ impl BlockFlow {
// FIXME (mbrubeck): Get correct mode for absolute containing block
let containing_block_mode = self.base.writing_mode;
+ // This value is used only for table cells.
+ let mut inline_start_margin_edge = if table_info.is_some() {
+ inline_start_content_edge
+ } else {
+ Au(0)
+ };
+
for (i, kid) in self.base.child_iter().enumerate() {
{
let kid_base = flow::mut_base(kid);
@@ -1376,16 +1381,12 @@ impl BlockFlow {
}
// Handle tables.
- match optional_column_computed_inline_sizes {
- Some(ref column_computed_inline_sizes) => {
- propagate_column_inline_sizes_to_child(kid,
- i,
- content_inline_size,
- containing_block_mode,
- *column_computed_inline_sizes,
- &mut inline_start_margin_edge)
- }
- None => {}
+ if let Some(ref table_info) = table_info {
+ table_info.propagate_to_child(kid,
+ i,
+ content_inline_size,
+ containing_block_mode,
+ &mut inline_start_margin_edge);
}
// Per CSS 2.1 § 16.3.1, text alignment propagates to all children in flow.
@@ -2661,38 +2662,3 @@ impl ISizeAndMarginsComputer for FloatReplaced {
}
}
-fn propagate_column_inline_sizes_to_child(
- kid: &mut Flow,
- child_index: uint,
- content_inline_size: Au,
- writing_mode: WritingMode,
- column_computed_inline_sizes: &[ColumnComputedInlineSize],
- inline_start_margin_edge: &mut Au) {
- // If kid is table_rowgroup or table_row, the column inline-sizes info should be copied from
- // its parent.
- //
- // FIXME(pcwalton): This seems inefficient. Reference count it instead?
- let inline_size = if kid.is_table() || kid.is_table_rowgroup() || kid.is_table_row() {
- *kid.column_computed_inline_sizes() =
- column_computed_inline_sizes.iter().map(|&x| x).collect();
-
- // ISize of kid flow is our content inline-size.
- content_inline_size
- } else if kid.is_table_cell() {
- column_computed_inline_sizes[child_index].size
- } else {
- // ISize of kid flow is our content inline-size.
- content_inline_size
- };
-
- {
- let kid_base = flow::mut_base(kid);
- kid_base.position.start.i = *inline_start_margin_edge;
- kid_base.block_container_inline_size = inline_size;
- kid_base.block_container_writing_mode = writing_mode;
- }
-
- if kid.is_table_cell() {
- *inline_start_margin_edge = *inline_start_margin_edge + inline_size
- }
-}
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 3b8dff61e63..329d7849508 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -886,7 +886,8 @@ impl Fragment {
SpecificFragmentInfo::InlineBlock(_) => {
QuantitiesIncludedInIntrinsicInlineSizes::all()
}
- SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => {
+ SpecificFragmentInfo::Table |
+ SpecificFragmentInfo::TableCell => {
INTRINSIC_INLINE_SIZE_INCLUDES_PADDING |
INTRINSIC_INLINE_SIZE_INCLUDES_BORDER |
INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED
diff --git a/components/layout/table.rs b/components/layout/table.rs
index a1fa55889ea..7917af12904 100644
--- a/components/layout/table.rs
+++ b/components/layout/table.rs
@@ -6,29 +6,30 @@
#![deny(unsafe_blocks)]
-use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
+use block::{self, BlockFlow, CandidateBSizeIterator, ISizeAndMarginsComputer};
use block::{ISizeConstraintInput, ISizeConstraintSolution};
use context::LayoutContext;
use floats::FloatKind;
use flow::{self, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
-use flow::ImmutableFlowUtils;
+use flow::{ImmutableFlowUtils, MutableFlowUtils};
use fragment::{Fragment, FragmentBorderBoxIterator};
+use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug;
-use model::{IntrinsicISizes, IntrinsicISizesContribution};
+use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto};
use table_row::CellIntrinsicInlineSize;
use table_wrapper::TableLayout;
use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
-use util::geometry::Au;
-use util::logical_geometry::LogicalRect;
use std::cmp::max;
use std::fmt;
+use std::sync::Arc;
+use style::computed_values::{border_collapse, border_spacing, table_layout};
use style::properties::ComputedValues;
use style::values::CSSFloat;
-use style::values::computed::{LengthOrPercentageOrAuto};
-use style::computed_values::table_layout;
-use std::sync::Arc;
+use style::values::computed::LengthOrPercentageOrAuto;
+use util::geometry::Au;
+use util::logical_geometry::{LogicalRect, WritingMode};
/// A table flow corresponded to the table's internal table fragment under a table wrapper flow.
/// The properties `position`, `float`, and `margin-*` are used on the table wrapper fragment,
@@ -140,17 +141,6 @@ impl TableFlow {
total_inline_sizes
}
- /// Assign block-size for table flow.
- ///
- /// TODO(#2014, pcwalton): This probably doesn't handle margin collapse right.
- ///
- /// inline(always) because this is only ever called by in-order or non-in-order top-level
- /// methods
- #[inline(always)]
- fn assign_block_size_table_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
- self.block_flow.assign_block_size_block_base(layout_context, MarginsMayCollapseFlag::MarginsMayNotCollapse);
- }
-
/// Updates the minimum and preferred inline-size calculation for a single row. This is
/// factored out into a separate function because we process children of rowgroups too.
fn update_column_inline_sizes_for_row(child: &mut Flow,
@@ -183,6 +173,20 @@ impl TableFlow {
}
}
}
+
+ /// Returns the effective spacing per cell, taking the value of `border-collapse` into account.
+ fn spacing(&self) -> border_spacing::T {
+ let style = self.block_flow.fragment.style();
+ match style.get_inheritedtable().border_collapse {
+ border_collapse::T::separate => style.get_inheritedtable().border_spacing,
+ border_collapse::T::collapse => {
+ border_spacing::T {
+ horizontal: Au(0),
+ vertical: Au(0),
+ }
+ }
+ }
+ }
}
impl Flow for TableFlow {
@@ -218,6 +222,8 @@ impl Flow for TableFlow {
let _scope = layout_debug_scope!("table::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id());
+ // Don't use `compute_intrinsic_inline_sizes` here because that will count padding as
+ // part of the table, which we don't want to do—it belongs to the table wrapper instead.
let mut computation = IntrinsicISizesContribution::new();
let mut did_first_row = false;
for kid in self.block_flow.base.child_iter() {
@@ -256,6 +262,14 @@ impl Flow for TableFlow {
}
}
+ let spacing = self.block_flow
+ .fragment
+ .style()
+ .get_inheritedtable()
+ .border_spacing
+ .horizontal * (self.column_intrinsic_inline_sizes.len() as i32 + 1);
+ computation.surrounding_size = computation.surrounding_size + spacing;
+
self.block_flow.base.intrinsic_inline_sizes = computation.finish()
}
@@ -272,24 +286,26 @@ impl Flow for TableFlow {
let mut num_unspecified_inline_sizes = 0;
let mut total_column_inline_size = Au(0);
for column_inline_size in self.column_intrinsic_inline_sizes.iter() {
- let this_column_inline_size = column_inline_size.minimum_length;
- if this_column_inline_size == Au(0) {
- num_unspecified_inline_sizes += 1
+ if column_inline_size.constrained {
+ total_column_inline_size = total_column_inline_size +
+ column_inline_size.minimum_length
} else {
- total_column_inline_size = total_column_inline_size + this_column_inline_size
+ num_unspecified_inline_sizes += 1
}
}
let inline_size_computer = InternalTable;
-
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
layout_context,
containing_block_inline_size);
let inline_start_content_edge = self.block_flow.fragment.border_padding.inline_start;
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
+ let spacing_per_cell = self.spacing();
+ let spacing = spacing_per_cell.horizontal *
+ (self.column_intrinsic_inline_sizes.len() as i32 + 1);
let content_inline_size =
- self.block_flow.fragment.border_box.size.inline - padding_and_borders;
+ self.block_flow.fragment.border_box.size.inline - padding_and_borders - spacing;
match self.table_layout {
TableLayout::Fixed => {
@@ -305,11 +321,9 @@ impl Flow for TableFlow {
});
}
} else if num_unspecified_inline_sizes != 0 {
- let extra_column_inline_size =
- (content_inline_size - total_column_inline_size) /
- num_unspecified_inline_sizes;
+ let extra_column_inline_size = content_inline_size - total_column_inline_size;
for column_inline_size in self.column_intrinsic_inline_sizes.iter() {
- if column_inline_size.minimum_length == Au(0) &&
+ if !column_inline_size.constrained &&
column_inline_size.percentage == 0.0 {
self.column_computed_inline_sizes.push(ColumnComputedInlineSize {
size: extra_column_inline_size / num_unspecified_inline_sizes,
@@ -332,16 +346,20 @@ impl Flow for TableFlow {
self.block_flow.base.flags.remove(IMPACTED_BY_LEFT_FLOATS);
self.block_flow.base.flags.remove(IMPACTED_BY_RIGHT_FLOATS);
- self.block_flow.propagate_assigned_inline_size_to_children(
- layout_context,
- inline_start_content_edge,
- content_inline_size,
- Some(self.column_computed_inline_sizes.as_slice()));
+ let info = ChildInlineSizeInfo {
+ column_computed_inline_sizes: self.column_computed_inline_sizes.as_slice(),
+ spacing: spacing_per_cell,
+ };
+ self.block_flow.propagate_assigned_inline_size_to_children(layout_context,
+ inline_start_content_edge,
+ content_inline_size,
+ Some(info));
}
- fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
+ fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
debug!("assign_block_size: assigning block_size for table");
- self.assign_block_size_table_base(ctx);
+ let vertical_spacing = self.spacing().vertical;
+ self.block_flow.assign_block_size_for_table_like_flow(layout_context, vertical_spacing)
}
fn compute_absolute_position(&mut self) {
@@ -417,6 +435,90 @@ impl ISizeAndMarginsComputer for InternalTable {
}
}
+/// Encapsulates functionality shared among all table-like flows: for now, tables and table
+/// rowgroups.
+pub trait TableLikeFlow {
+ /// Lays out the rows of a table.
+ fn assign_block_size_for_table_like_flow<'a>(&mut self,
+ layout_context: &'a LayoutContext<'a>,
+ block_direction_spacing: Au);
+}
+
+impl TableLikeFlow for BlockFlow {
+ fn assign_block_size_for_table_like_flow<'a>(&mut self,
+ _: &'a LayoutContext<'a>,
+ block_direction_spacing: Au) {
+ if self.base.restyle_damage.contains(REFLOW) {
+ // Our current border-box position.
+ let block_start_border_padding = self.fragment.border_padding.block_start;
+ let mut current_block_offset = block_start_border_padding;
+
+ // At this point, `current_block_offset` is at the content edge of our box. Now iterate
+ // over children.
+ let mut layers_needed_for_descendants = false;
+ for kid in self.base.child_iter() {
+ // Mark flows for layerization if necessary to handle painting order correctly.
+ block::propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid);
+
+ // Account for spacing.
+ if kid.is_table_row() {
+ current_block_offset = current_block_offset + block_direction_spacing;
+ }
+
+ // At this point, `current_block_offset` is at the border edge of the child.
+ flow::mut_base(kid).position.start.b = current_block_offset;
+
+ // Move past the child's border box. Do not use the `translate_including_floats`
+ // function here because the child has already translated floats past its border
+ // box.
+ let kid_base = flow::mut_base(kid);
+ current_block_offset = current_block_offset + kid_base.position.size.block;
+ }
+
+ // Collect various offsets needed by absolutely positioned descendants.
+ (&mut *self as &mut Flow).collect_static_block_offsets_from_children();
+
+ // Compute any explicitly-specified block size.
+ // Can't use `for` because we assign to `candidate_block_size_iterator.candidate_value`.
+ let mut block_size = current_block_offset - block_start_border_padding;
+ let mut candidate_block_size_iterator = CandidateBSizeIterator::new(
+ &self.fragment,
+ self.base.block_container_explicit_block_size);
+ loop {
+ match candidate_block_size_iterator.next() {
+ Some(candidate_block_size) => {
+ candidate_block_size_iterator.candidate_value =
+ match candidate_block_size {
+ MaybeAuto::Auto => block_size,
+ MaybeAuto::Specified(value) => value
+ }
+ }
+ None => break,
+ }
+ }
+
+ // Adjust `current_block_offset` as necessary to account for the explicitly-specified
+ // block-size.
+ block_size = candidate_block_size_iterator.candidate_value;
+ let delta = block_size - (current_block_offset - block_start_border_padding);
+ current_block_offset = current_block_offset + delta;
+
+ // Take border, padding, and spacing into account.
+ let block_end_offset = self.fragment.border_padding.block_end +
+ block_direction_spacing;
+ current_block_offset = current_block_offset + block_end_offset;
+
+ // Now that `current_block_offset` is at the block-end of the border box, compute the
+ // final border box position.
+ self.fragment.border_box.size.block = current_block_offset;
+ self.fragment.border_box.start.b = Au(0);
+ self.base.position.size.block = current_block_offset;
+ }
+
+ self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW);
+ }
+}
+
/// Information about the intrinsic inline sizes of columns within a table.
///
/// During table inline-size bubbling, we might need to store both a percentage constraint and a
@@ -472,8 +574,69 @@ impl ColumnIntrinsicInlineSize {
///
/// TODO(pcwalton): There will probably be some `border-collapse`-related info in here too
/// eventually.
-#[derive(RustcEncodable, Copy)]
+#[derive(RustcEncodable, Clone, Copy)]
pub struct ColumnComputedInlineSize {
/// The computed size of this inline column.
pub size: Au,
}
+
+/// Inline-size information that we need to push down to table children.
+pub struct ChildInlineSizeInfo<'a> {
+ /// The spacing of the table.
+ pub spacing: border_spacing::T,
+ /// The computed inline sizes for each column.
+ pub column_computed_inline_sizes: &'a [ColumnComputedInlineSize],
+}
+
+impl<'a> ChildInlineSizeInfo<'a> {
+ /// Propagates information computed during inline size assignment to a child of a table, and
+ /// lays out that child in the inline direction.
+ pub fn propagate_to_child(&self,
+ kid: &mut Flow,
+ child_index: uint,
+ content_inline_size: Au,
+ writing_mode: WritingMode,
+ inline_start_margin_edge: &mut Au) {
+ // If the child is a table or a row, copy computed inline size information from its parent.
+ //
+ // FIXME(pcwalton): This seems inefficient. Reference count it instead?
+ let inline_size;
+ if kid.is_table() {
+ let table_kid = kid.as_table();
+ table_kid.column_computed_inline_sizes = self.column_computed_inline_sizes.to_vec();
+ inline_size = content_inline_size
+ } else if kid.is_table_rowgroup() {
+ let table_rowgroup_kid = kid.as_table_rowgroup();
+ table_rowgroup_kid.column_computed_inline_sizes =
+ self.column_computed_inline_sizes.to_vec();
+ table_rowgroup_kid.spacing = self.spacing;
+ inline_size = content_inline_size
+ } else if kid.is_table_row() {
+ let table_row_kid = kid.as_table_row();
+ table_row_kid.column_computed_inline_sizes =
+ self.column_computed_inline_sizes.to_vec();
+ table_row_kid.spacing = self.spacing;
+ inline_size = content_inline_size
+ } else if kid.is_table_cell() {
+ // Take spacing into account.
+ *inline_start_margin_edge = *inline_start_margin_edge + self.spacing.horizontal;
+ inline_size = self.column_computed_inline_sizes[child_index].size;
+ } else {
+ // ISize of kid flow is our content inline-size.
+ inline_size = content_inline_size
+ }
+
+ {
+ let kid_base = flow::mut_base(kid);
+ kid_base.position.start.i = *inline_start_margin_edge;
+ kid_base.block_container_inline_size = inline_size;
+ kid_base.block_container_writing_mode = writing_mode
+ }
+
+ // Move over for the next table cell.
+ if kid.is_table_cell() {
+ *inline_start_margin_edge = *inline_start_margin_edge + inline_size
+ }
+ }
+}
+
diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs
index 1e45ba48fc1..78b5a68e80a 100644
--- a/components/layout/table_row.rs
+++ b/components/layout/table_row.rs
@@ -12,7 +12,8 @@ use context::LayoutContext;
use flow::{self, FlowClass, Flow, ImmutableFlowUtils};
use fragment::{Fragment, FragmentBorderBoxIterator};
use layout_debug;
-use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
+use table::{ChildInlineSizeInfo, ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
+use table::{InternalTable};
use model::MaybeAuto;
use wrapper::ThreadSafeLayoutNode;
@@ -21,9 +22,10 @@ use util::geometry::Au;
use util::logical_geometry::LogicalRect;
use std::cmp::max;
use std::fmt;
+use std::sync::Arc;
+use style::computed_values::border_spacing;
use style::properties::ComputedValues;
use style::values::computed::LengthOrPercentageOrAuto;
-use std::sync::Arc;
/// A single row of a table.
#[derive(RustcEncodable)]
@@ -35,6 +37,10 @@ pub struct TableRowFlow {
/// Information about the computed inline-sizes of each column.
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
+
+ /// The spacing for this row, propagated down from the table during the inline-size assignment
+ /// phase.
+ pub spacing: border_spacing::T,
}
/// Information about the column inline size and span for each cell.
@@ -53,6 +59,10 @@ impl TableRowFlow {
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
cell_intrinsic_inline_sizes: Vec::new(),
column_computed_inline_sizes: Vec::new(),
+ spacing: border_spacing::T {
+ horizontal: Au(0),
+ vertical: Au(0),
+ },
}
}
@@ -76,11 +86,9 @@ impl TableRowFlow {
fn assign_block_size_table_row_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
let (block_start_offset, _, _) = self.initialize_offsets();
- let /* mut */ cur_y = block_start_offset;
-
// Per CSS 2.1 § 17.5.3, find max_y = max(computed `block-size`, minimum block-size of all
// cells).
- let mut max_y = Au(0);
+ let mut max_block_size = Au(0);
let thread_id = self.block_flow.base.thread_id;
for kid in self.block_flow.base.child_iter() {
kid.place_float_if_applicable(layout_context);
@@ -93,17 +101,18 @@ impl TableRowFlow {
// TODO: Percentage block-size
let child_specified_block_size =
MaybeAuto::from_style(child_fragment.style().content_block_size(),
- Au::new(0)).specified_or_zero();
- max_y = max(max_y,
- child_specified_block_size +
- child_fragment.border_padding.block_start_end());
+ Au(0)).specified_or_zero();
+ max_block_size =
+ max(max_block_size,
+ child_specified_block_size +
+ child_fragment.border_padding.block_start_end());
}
let child_node = flow::mut_base(kid);
- child_node.position.start.b = cur_y;
- max_y = max(max_y, child_node.position.size.block);
+ child_node.position.start.b = block_start_offset;
+ max_block_size = max(max_block_size, child_node.position.size.block);
}
- let mut block_size = max_y;
+ let mut block_size = max_block_size;
// TODO: Percentage block-size
block_size = match MaybeAuto::from_style(self.block_flow
.fragment
@@ -113,11 +122,8 @@ impl TableRowFlow {
MaybeAuto::Auto => block_size,
MaybeAuto::Specified(value) => max(value, block_size)
};
- // cur_y = cur_y + block-size;
// Assign the block-size of own fragment
- //
- // FIXME(pcwalton): Take `cur_y` into account.
let mut position = self.block_flow.fragment.border_box;
position.size.block = block_size;
self.block_flow.fragment.border_box = position;
@@ -273,11 +279,14 @@ impl Flow for TableRowFlow {
}
// Push those inline sizes down to the cells.
- self.block_flow.propagate_assigned_inline_size_to_children(
- layout_context,
- inline_start_content_edge,
- containing_block_inline_size,
- Some(computed_inline_size_for_cells.as_slice()));
+ let info = ChildInlineSizeInfo {
+ column_computed_inline_sizes: computed_inline_size_for_cells.as_slice(),
+ spacing: self.spacing,
+ };
+ self.block_flow.propagate_assigned_inline_size_to_children(layout_context,
+ inline_start_content_edge,
+ containing_block_inline_size,
+ Some(info));
}
fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs
index 6ea1c4aaa18..a1d1bdc133d 100644
--- a/components/layout/table_rowgroup.rs
+++ b/components/layout/table_rowgroup.rs
@@ -6,12 +6,14 @@
#![deny(unsafe_blocks)]
-use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
+use block::{BlockFlow, ISizeAndMarginsComputer};
use context::LayoutContext;
use flow::{FlowClass, Flow};
use fragment::{Fragment, FragmentBorderBoxIterator};
use layout_debug;
-use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
+use style::computed_values::border_spacing;
+use table::{ChildInlineSizeInfo, ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
+use table::{InternalTable, TableLikeFlow};
use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
@@ -32,6 +34,9 @@ pub struct TableRowGroupFlow {
/// Information about the actual inline sizes of each column.
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
+
+ /// The spacing for this rowgroup.
+ pub spacing: border_spacing::T,
}
impl TableRowGroupFlow {
@@ -41,21 +46,16 @@ impl TableRowGroupFlow {
block_flow: BlockFlow::from_node_and_fragment(node, fragment),
column_intrinsic_inline_sizes: Vec::new(),
column_computed_inline_sizes: Vec::new(),
+ spacing: border_spacing::T {
+ horizontal: Au(0),
+ vertical: Au(0),
+ },
}
}
pub fn fragment<'a>(&'a mut self) -> &'a Fragment {
&self.block_flow.fragment
}
-
- /// Assign block-size for table-rowgroup flow.
- ///
- /// inline(always) because this is only ever called by in-order or non-in-order top-level
- /// methods.
- #[inline(always)]
- fn assign_block_size_table_rowgroup_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
- self.block_flow.assign_block_size_block_base(layout_context, MarginsMayCollapseFlag::MarginsMayNotCollapse)
- }
}
impl Flow for TableRowGroupFlow {
@@ -109,16 +109,20 @@ impl Flow for TableRowGroupFlow {
layout_context,
containing_block_inline_size);
- self.block_flow.propagate_assigned_inline_size_to_children(
- layout_context,
- inline_start_content_edge,
- content_inline_size,
- Some(self.column_computed_inline_sizes.as_slice()));
+ let info = ChildInlineSizeInfo {
+ column_computed_inline_sizes: self.column_computed_inline_sizes.as_slice(),
+ spacing: self.spacing,
+ };
+ self.block_flow.propagate_assigned_inline_size_to_children(layout_context,
+ inline_start_content_edge,
+ content_inline_size,
+ Some(info));
}
- fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
+ fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
debug!("assign_block_size: assigning block_size for table_rowgroup");
- self.assign_block_size_table_rowgroup_base(ctx);
+ self.block_flow.assign_block_size_for_table_like_flow(layout_context,
+ self.spacing.vertical)
}
fn compute_absolute_position(&mut self) {
diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs
index 042c08b5ed3..d37e377f92d 100644
--- a/components/layout/table_wrapper.rs
+++ b/components/layout/table_wrapper.rs
@@ -20,7 +20,7 @@ use floats::FloatKind;
use flow::{FlowClass, Flow, ImmutableFlowUtils};
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
use fragment::{Fragment, FragmentBorderBoxIterator};
-use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
+use table::{ChildInlineSizeInfo, ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
@@ -28,11 +28,11 @@ use util::geometry::Au;
use std::cmp::{max, min};
use std::fmt;
use std::ops::Add;
-use style::properties::ComputedValues;
+use std::sync::Arc;
use style::computed_values::table_layout;
+use style::properties::ComputedValues;
use style::values::CSSFloat;
use style::values::computed::LengthOrPercentageOrAuto;
-use std::sync::Arc;
#[derive(Copy, RustcEncodable, Debug)]
pub enum TableLayout {
@@ -98,11 +98,19 @@ impl TableWrapperFlow {
// when normally the child computes it itself. But it has to be this way because the
// padding will affect where we place the child. This is an odd artifact of the way that
// tables are separated into table flows and table wrapper flows.
- let available_inline_size = self.block_flow.fragment.border_box.size.inline;
- let mut table_border_padding = Au(0);
+ let mut available_inline_size = self.block_flow.fragment.border_box.size.inline;
+ let (mut table_border_padding, mut spacing) = (Au(0), Au(0));
for kid in self.block_flow.base.child_iter() {
if kid.is_table() {
let kid_block = kid.as_block();
+ let spacing_per_cell = kid_block.fragment
+ .style()
+ .get_inheritedtable()
+ .border_spacing
+ .horizontal;
+ spacing = spacing_per_cell * (self.column_intrinsic_inline_sizes.len() as i32 + 1);
+ available_inline_size = self.block_flow.fragment.border_box.size.inline;
+
kid_block.fragment.compute_border_and_padding(available_inline_size);
kid_block.fragment.compute_block_direction_margins(available_inline_size);
kid_block.fragment.compute_inline_direction_margins(available_inline_size);
@@ -114,18 +122,21 @@ impl TableWrapperFlow {
// FIXME(pcwalton, spec): INTRINSIC § 8 does not properly define how to compute this, but
// says "the basic idea is the same as the shrink-to-fit width that CSS2.1 defines". So we
// just use the shrink-to-fit inline size.
- let available_inline_size = match self.block_flow.fragment.style().content_inline_size() {
- LengthOrPercentageOrAuto::Auto => self.block_flow
- .get_shrink_to_fit_inline_size(available_inline_size),
- // FIXME(mttr) This fixes #4421 without breaking our current reftests, but I'm
- // not completely sure this is "correct".
- //
- // That said, `available_inline_size` is, as far as I can tell, equal to the table's
- // computed width property (W) and is used from this point forward in a way that seems
- // to correspond with CSS 2.1 § 17.5.2.2 under "Column and caption widths
- // influence the final table width as follows: ..."
- _ => available_inline_size,
- };
+ let mut available_inline_size =
+ match self.block_flow.fragment.style().content_inline_size() {
+ LengthOrPercentageOrAuto::Auto => {
+ self.block_flow.get_shrink_to_fit_inline_size(available_inline_size)
+ }
+ // FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm
+ // not completely sure this is "correct".
+ //
+ // That said, `available_inline_size` is, as far as I can tell, equal to the
+ // table's computed width property (W) and is used from this point forward in a way
+ // that seems to correspond with CSS 2.1 § 17.5.2.2 under "Column and caption
+ // widths influence the final table width as follows: …"
+ _ => available_inline_size,
+ };
+ available_inline_size = available_inline_size - spacing;
// Compute all the guesses for the column sizes, and sum them.
let mut total_guess = AutoLayoutCandidateGuess::new();
@@ -153,8 +164,8 @@ impl TableWrapperFlow {
//
// FIXME(pcwalton, spec): How do I deal with fractional excess?
let excess_inline_size = available_inline_size - total_used_inline_size;
- if excess_inline_size > Au(0) &&
- selection == SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize {
+ if excess_inline_size > Au(0) && selection ==
+ SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize {
let mut info = ExcessInlineSizeDistributionInfo::new();
for column_intrinsic_inline_size in self.column_intrinsic_inline_sizes.iter() {
info.update(column_intrinsic_inline_size)
@@ -173,10 +184,12 @@ impl TableWrapperFlow {
total_used_inline_size = available_inline_size
}
+
+
self.block_flow.fragment.border_box.size.inline = total_used_inline_size +
- table_border_padding;
+ table_border_padding + spacing;
self.block_flow.base.position.size.inline = total_used_inline_size +
- table_border_padding + self.block_flow.fragment.margin.inline_start_end();
+ table_border_padding + spacing + self.block_flow.fragment.margin.inline_start_end();
}
fn compute_used_inline_size(&mut self,
@@ -301,11 +314,15 @@ impl Flow for TableWrapperFlow {
None)
}
Some(ref assigned_column_inline_sizes) => {
- self.block_flow.propagate_assigned_inline_size_to_children(
- layout_context,
- inline_start_content_edge,
- content_inline_size,
- Some(assigned_column_inline_sizes.as_slice()));
+ let info = ChildInlineSizeInfo {
+ column_computed_inline_sizes: assigned_column_inline_sizes.as_slice(),
+ spacing: self.block_flow.fragment.style().get_inheritedtable().border_spacing,
+ };
+ self.block_flow
+ .propagate_assigned_inline_size_to_children(layout_context,
+ inline_start_content_edge,
+ content_inline_size,
+ Some(info));
}
}
@@ -458,13 +475,16 @@ impl AutoLayoutCandidateGuess {
fn calculate(&self, selection: SelectedAutoLayoutCandidateGuess) -> Au {
match selection {
SelectedAutoLayoutCandidateGuess::UseMinimumGuess => self.minimum_guess,
- SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight) => {
+ SelectedAutoLayoutCandidateGuess::
+ InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight) => {
interp(self.minimum_guess, self.minimum_percentage_guess, weight)
}
- SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight) => {
+ SelectedAutoLayoutCandidateGuess::
+ InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight) => {
interp(self.minimum_percentage_guess, self.minimum_specified_guess, weight)
}
- SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight) => {
+ SelectedAutoLayoutCandidateGuess::
+ InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight) => {
interp(self.minimum_specified_guess, self.preferred_guess, weight)
}
SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize => {
@@ -590,9 +610,17 @@ impl ExcessInlineSizeDistributionInfo {
total_distributed_excess_size: &mut Au) {
let proportion =
if self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage > Au(0) {
- column_intrinsic_inline_size.preferred.to_subpx() /
- self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage
- .to_subpx()
+ // FIXME(spec, pcwalton): Gecko and WebKit do *something* here when there are
+ // nonconstrained columns with no percentage *and* no preferred width. What do they
+ // do?
+ if !column_intrinsic_inline_size.constrained &&
+ column_intrinsic_inline_size.percentage == 0.0 {
+ column_intrinsic_inline_size.preferred.to_subpx() /
+ self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage
+ .to_subpx()
+ } else {
+ 0.0
+ }
} else if self.count_of_nonconstrained_columns_with_no_percentage > 0 {
1.0 / (self.count_of_nonconstrained_columns_with_no_percentage as CSSFloat)
} else if self.preferred_inline_size_of_constrained_columns_with_no_percentage >
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs
index bc89f74ea1b..52623f75ad9 100644
--- a/components/layout/wrapper.rs
+++ b/components/layout/wrapper.rs
@@ -635,8 +635,8 @@ impl<'le> TElement<'le> for LayoutElement<'le> {
#[inline]
fn has_nonzero_border(self) -> bool {
unsafe {
- match self.element
- .get_unsigned_integer_attribute_for_layout(UnsignedIntegerAttribute::Border) {
+ match self.element.get_unsigned_integer_attribute_for_layout(
+ UnsignedIntegerAttribute::Border) {
None | Some(0) => false,
_ => true,
}