diff options
Diffstat (limited to 'components/layout/table.rs')
-rw-r--r-- | components/layout/table.rs | 170 |
1 files changed, 107 insertions, 63 deletions
diff --git a/components/layout/table.rs b/components/layout/table.rs index 37f589917a2..0e2af0b2f68 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -11,11 +11,12 @@ use block::{ISizeConstraintInput, ISizeConstraintSolution}; use construct::FlowConstructor; use context::LayoutContext; use floats::FloatKind; -use flow::{Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, ImmutableFlowUtils}; -use flow::{TableFlowClass}; +use flow::{mod, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; +use flow::{ImmutableFlowUtils, TableFlowClass}; use fragment::{Fragment, FragmentBoundsIterator}; use layout_debug; use model::{IntrinsicISizes, IntrinsicISizesContribution}; +use table_row::CellIntrinsicInlineSize; use table_wrapper::{TableLayout, FixedLayout, AutoLayout}; use wrapper::ThreadSafeLayoutNode; @@ -105,24 +106,53 @@ impl TableFlow { /// Update the corresponding value of `self_inline_sizes` if a value of `kid_inline_sizes` has /// a larger value than one of `self_inline_sizes`. Returns the minimum and preferred inline /// sizes. - pub fn update_column_inline_sizes(parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, - child_inline_sizes: &Vec<ColumnIntrinsicInlineSize>) - -> IntrinsicISizes { + fn update_automatic_column_inline_sizes( + parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, + child_cell_inline_sizes: &[CellIntrinsicInlineSize]) + -> IntrinsicISizes { let mut total_inline_sizes = IntrinsicISizes::new(); - for (parent_sizes, child_sizes) in parent_inline_sizes.iter_mut() - .zip(child_inline_sizes.iter()) { - *parent_sizes = ColumnIntrinsicInlineSize { - minimum_length: max(parent_sizes.minimum_length, child_sizes.minimum_length), - percentage: parent_sizes.greatest_percentage(child_sizes), - preferred: max(parent_sizes.preferred, child_sizes.preferred), - constrained: parent_sizes.constrained || child_sizes.constrained - }; - - total_inline_sizes.minimum_inline_size = total_inline_sizes.minimum_inline_size + - parent_sizes.minimum_length; - total_inline_sizes.preferred_inline_size = total_inline_sizes.preferred_inline_size + - parent_sizes.preferred; + let mut column_index = 0; + for child_cell_inline_size in child_cell_inline_sizes.iter() { + for _ in range(0, child_cell_inline_size.column_span) { + if column_index < parent_inline_sizes.len() { + // We already have some intrinsic size information for this column. Merge it in + // according to the rules specified in INTRINSIC § 4. + let parent_sizes = &mut parent_inline_sizes[column_index]; + if child_cell_inline_size.column_span > 1 { + // TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC § + // 4. For now we make this column contribute no width. + } else { + let column_size = &child_cell_inline_size.column_size; + *parent_sizes = ColumnIntrinsicInlineSize { + minimum_length: max(parent_sizes.minimum_length, + column_size.minimum_length), + percentage: parent_sizes.greatest_percentage(column_size), + preferred: max(parent_sizes.preferred, column_size.preferred), + constrained: parent_sizes.constrained || column_size.constrained, + } + } + } else { + // We discovered a new column. Initialize its data. + debug_assert!(column_index == parent_inline_sizes.len()); + if child_cell_inline_size.column_span > 1 { + // TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC § + // 4. For now we make this column contribute no width. + parent_inline_sizes.push(ColumnIntrinsicInlineSize::new()) + } else { + parent_inline_sizes.push(child_cell_inline_size.column_size) + } + } + + total_inline_sizes.minimum_inline_size = total_inline_sizes.minimum_inline_size + + parent_inline_sizes[column_index].minimum_length; + total_inline_sizes.preferred_inline_size = + total_inline_sizes.preferred_inline_size + + parent_inline_sizes[column_index].preferred; + + column_index += 1 + } } + total_inline_sizes } @@ -136,6 +166,39 @@ impl TableFlow { fn assign_block_size_table_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { self.block_flow.assign_block_size_block_base(layout_context, 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, + column_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, + computation: &mut IntrinsicISizesContribution, + did_first_row: &mut bool, + table_layout: TableLayout) { + // Read column inline-sizes from the table-row, and assign inline-size=0 for the columns + // not defined in the column group. + // + // FIXME: Need to read inline-sizes from either table-header-group OR the first table-row. + debug_assert!(child.is_table_row()); + let row = child.as_table_row(); + match table_layout { + FixedLayout => { + // Fixed table layout only looks at the first row. + // + // FIXME(pcwalton): This is really inefficient. We should stop after the first row! + if !*did_first_row { + *did_first_row = true; + for cell_inline_size in row.cell_intrinsic_inline_sizes.iter() { + column_inline_sizes.push(cell_inline_size.column_size); + } + } + } + AutoLayout => { + computation.union_block(&TableFlow::update_automatic_column_inline_sizes( + column_inline_sizes, + row.cell_intrinsic_inline_sizes.as_slice())) + } + } + } } impl Flow for TableFlow { @@ -190,50 +253,22 @@ impl Flow for TableFlow { constrained: false, }) } - } else if kid.is_table_rowgroup() || kid.is_table_row() { - // Read column inline-sizes from the table-row-group/table-row, and assign - // inline-size=0 for the columns not defined in the column group. - // FIXME: Need to read inline-sizes from either table-header-group OR the first - // table-row. - match self.table_layout { - FixedLayout => { - // Fixed table layout only looks at the first row. - if !did_first_row { - did_first_row = true; - for child_column_inline_size in kid.column_intrinsic_inline_sizes() - .iter() { - self.column_intrinsic_inline_sizes.push(*child_column_inline_size); - } - } - } - AutoLayout => { - let child_column_inline_sizes = kid.column_intrinsic_inline_sizes(); - let mut child_intrinsic_sizes = TableFlow::update_column_inline_sizes( - &mut self.column_intrinsic_inline_sizes, - child_column_inline_sizes); - - // Add new columns if processing this row caused us to discover them. - let child_column_count = child_column_inline_sizes.len(); - let parent_column_count = self.column_intrinsic_inline_sizes.len(); - debug!("table until the previous row has {} column(s) and this row has {} \ - column(s)", - parent_column_count, - child_column_count); - self.column_intrinsic_inline_sizes.reserve(child_column_count); - for i in range(parent_column_count, child_column_count) { - let inline_size_for_new_column = (*child_column_inline_sizes)[i]; - child_intrinsic_sizes.minimum_inline_size = - child_intrinsic_sizes.minimum_inline_size + - inline_size_for_new_column.minimum_length; - child_intrinsic_sizes.preferred_inline_size = - child_intrinsic_sizes.preferred_inline_size + - inline_size_for_new_column.preferred; - self.column_intrinsic_inline_sizes.push(inline_size_for_new_column); - } - - computation.union_block(&child_intrinsic_sizes) - } + } else if kid.is_table_rowgroup() { + for grandkid in flow::mut_base(kid).child_iter() { + TableFlow::update_column_inline_sizes_for_row( + grandkid, + &mut self.column_intrinsic_inline_sizes, + &mut computation, + &mut did_first_row, + self.table_layout) } + } else if kid.is_table_row() { + TableFlow::update_column_inline_sizes_for_row( + kid, + &mut self.column_intrinsic_inline_sizes, + &mut computation, + &mut did_first_row, + self.table_layout) } } @@ -277,8 +312,7 @@ impl Flow for TableFlow { // In fixed table layout, we distribute extra space among the unspecified columns // if there are any, or among all the columns if all are specified. self.column_computed_inline_sizes.clear(); - if total_column_inline_size < content_inline_size && - num_unspecified_inline_sizes == 0 { + if num_unspecified_inline_sizes == 0 { let ratio = content_inline_size.to_subpx() / total_column_inline_size.to_subpx(); for column_inline_size in self.column_intrinsic_inline_sizes.iter() { @@ -413,6 +447,16 @@ pub struct ColumnIntrinsicInlineSize { } impl ColumnIntrinsicInlineSize { + /// Returns a newly-initialized `ColumnIntrinsicInlineSize` with all fields blank. + pub fn new() -> ColumnIntrinsicInlineSize { + ColumnIntrinsicInlineSize { + preferred: Au(0), + minimum_length: Au(0), + percentage: 0.0, + constrained: false, + } + } + /// Returns the true minimum size of this column, given the containing block's inline size. /// Beware that this is generally only correct for fixed table layout. (Compare CSS 2.1 § /// 17.5.2.1 with the algorithm in INTRINSIC § 4.) |