diff options
Diffstat (limited to 'components/layout/table_row.rs')
-rw-r--r-- | components/layout/table_row.rs | 94 |
1 files changed, 57 insertions, 37 deletions
diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index dbe0bf7b665..a332bc668ac 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -19,7 +19,7 @@ use gfx_traits::print_tree::PrintTree; use layout_debug; use model::MaybeAuto; use serde::{Serialize, Serializer}; -use std::cmp::{max, min}; +use std::cmp::max; use std::fmt; use std::iter::{Enumerate, IntoIterator, Peekable}; use style::computed_values::border_collapse::T as BorderCollapse; @@ -110,33 +110,27 @@ impl TableRowFlow { /// /// TODO(pcwalton): This doesn't handle floats and positioned elements right. /// - /// Returns the block size, as well as the size this should be if this is the last row + /// Returns the block size pub fn compute_block_size_table_row_base<'a>(&'a mut self, layout_context: &LayoutContext, incoming_rowspan_data: &mut Vec<Au>, - border_info: &[(Au, Au)], // (_, cumulative_border_size) - row_index: usize) -> (Au, Au) { + border_info: &[TableRowSizeData], + row_index: usize) -> Au { fn include_sizes_from_previous_rows(col: &mut usize, incoming_rowspan: &[u32], incoming_rowspan_data: &mut Vec<Au>, - max_block_size: &mut Au, - largest_leftover_incoming_size: &mut Au) { + max_block_size: &mut Au) { while let Some(span) = incoming_rowspan.get(*col) { - if *span <= 1 { + if *span == 1 { break; } let incoming = incoming_rowspan_data[*col]; *max_block_size = max(*max_block_size, incoming); - if *span > 2 { - *largest_leftover_incoming_size = max(*largest_leftover_incoming_size, - incoming * (*span - 1) as i32) - } *col += 1; } } // Per CSS 2.1 § 17.5.3, find max_y = max(computed `block-size`, minimum block-size of // all cells). let mut max_block_size = Au(0); - let mut largest_leftover_incoming_size = Au(0); let thread_id = self.block_flow.base.thread_id; let content_box = self.block_flow.base.position - self.block_flow.fragment.border_padding @@ -145,15 +139,14 @@ impl TableRowFlow { let mut col = 0; for kid in self.block_flow.base.child_iter_mut() { include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, - incoming_rowspan_data, &mut max_block_size, - &mut largest_leftover_incoming_size); + incoming_rowspan_data, &mut max_block_size); kid.place_float_if_applicable(); debug_assert!(!kid.base().flags.is_float(), "table cells should never float"); kid.assign_block_size_for_inorder_child_if_necessary(layout_context, thread_id, content_box); - let row_span; + let mut row_span; let column_span; let cell_total; { @@ -166,12 +159,11 @@ impl TableRowFlow { child_node.position.start.b = Au(0); let mut cell_block_size_pressure = max(cell_total, child_node.position.size.block); - if row_span > 1 { + if row_span != 1 { if incoming_rowspan_data.len() <= col { incoming_rowspan_data.resize(col + 1, Au(0)); } - let border_sizes_spanned = get_spanned_border_size(border_info, row_index, row_span); - let pressure_copy = cell_block_size_pressure; + let border_sizes_spanned = get_spanned_border_size(border_info, row_index, &mut row_span); cell_block_size_pressure -= border_sizes_spanned; @@ -180,18 +172,12 @@ impl TableRowFlow { // require an extra slow-path loop, sadly. cell_block_size_pressure /= row_span as i32; incoming_rowspan_data[col] = cell_block_size_pressure; - - // If this ends up being the last row, it needs to cover - // *all* this space - largest_leftover_incoming_size = max(largest_leftover_incoming_size, - pressure_copy); } max_block_size = max(max_block_size, cell_block_size_pressure); col += column_span; } - include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, incoming_rowspan_data, &mut max_block_size, - &mut largest_leftover_incoming_size); + include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, incoming_rowspan_data, &mut max_block_size); let mut block_size = max_block_size; // TODO: Percentage block-size @@ -203,20 +189,21 @@ impl TableRowFlow { MaybeAuto::Auto => block_size, MaybeAuto::Specified(value) => max(value, block_size), }; - (block_size, largest_leftover_incoming_size) + block_size } - pub fn assign_block_size_to_self_and_children(&mut self, sizes: &[(Au, Au)], index: usize) { + pub fn assign_block_size_to_self_and_children(&mut self, sizes: &[TableRowSizeData], index: usize) { // Assign the block-size of kid fragments, which is the same value as own block-size. - let block_size = sizes[index].0; + let block_size = sizes[index].size; for kid in self.block_flow.base.child_iter_mut() { let child_table_cell = kid.as_mut_table_cell(); - let block_size = if child_table_cell.row_span > 1 { - let row_sizes = sizes[index..].iter() - .take(child_table_cell.row_span as usize) - .fold(Au(0), |accum, size| accum + size.0); + let block_size = if child_table_cell.row_span != 1 { + let mut row_span = child_table_cell.row_span; let border_sizes_spanned = - get_spanned_border_size(sizes, index, child_table_cell.row_span); + get_spanned_border_size(sizes, index, &mut row_span); + let row_sizes = sizes[index..].iter() + .take(row_span as usize) + .fold(Au(0), |accum, r| accum + r.size); row_sizes + border_sizes_spanned } else { block_size @@ -279,12 +266,45 @@ impl TableRowFlow { } } +#[derive(Debug, Default)] +pub struct TableRowSizeData { + /// The block-size of the row. + pub size: Au, + /// Border spacing up to this row (not including spacing below the row) + pub cumulative_border_spacing: Au, + /// The "segment" of the table it is in. Tables containing + /// both row groups and rows have the bare rows grouped in + /// segments separated by row groups. It's helpful to look + /// at these as if they are rowgroups themselves. + /// + /// This is enough information for us to be able to check whether we + /// are in a case where we are overflowing a rowgroup with rowspan, + /// however calculating the amount of overflow requires lookahead. + pub rowgroup_id: u32, +} + /// Given an array of (_, cumulative_border_size), the index of the /// current row, and the >1 row_span of the cell, calculate the amount of -/// border-spacing spanned by the row -fn get_spanned_border_size(sizes: &[(Au, Au)], row_index: usize, row_span: u32) -> Au { - let last_row_idx = min(row_index + row_span as usize - 1, sizes.len() - 1); - sizes[last_row_idx].1 - sizes[row_index].1 +/// border-spacing spanned by the row. In case the rowspan was larger +/// than required, this will fix it up. +fn get_spanned_border_size(sizes: &[TableRowSizeData], row_index: usize, row_span: &mut u32) -> Au { + // A zero rowspan is functionally equivalent to rowspan=infinity + if *row_span == 0 || row_index + *row_span as usize > sizes.len() { + *row_span = (sizes.len() - row_index) as u32; + } + let mut last_row_idx = row_index + *row_span as usize - 1; + // This is a slow path and should be rare -- this should only get triggered + // when you use `rowspan=0` or an overlarge rowspan in a table with + // mixed rows + rowgroups + if sizes[last_row_idx].rowgroup_id != sizes[row_index].rowgroup_id { + // XXXManishearth this loop can be avoided by also storing + // a "last_rowgroup_at" index so we can leapfrog back quickly + *row_span = sizes[row_index..last_row_idx + 1].iter() + .position(|s| s.rowgroup_id != sizes[row_index].rowgroup_id) + .unwrap() as u32; + last_row_idx = row_index + *row_span as usize - 1; + } + sizes[last_row_idx].cumulative_border_spacing - sizes[row_index].cumulative_border_spacing } impl Flow for TableRowFlow { |