Handle overlarge rowspans by keeping track of largest leftover incoming sizes

This commit is contained in:
Manish Goregaokar 2018-02-26 23:32:39 -08:00
parent 746acf7e2b
commit 0261762fa4
2 changed files with 35 additions and 12 deletions

View file

@ -815,17 +815,27 @@ impl TableLikeFlow for BlockFlow {
// Second pass: Compute row block sizes // Second pass: Compute row block sizes
// [expensive: iterates over cells] // [expensive: iterates over cells]
let mut i = 0; let mut i = 0;
let mut overflow = Au(0);
for kid in self.base.child_iter_mut() { for kid in self.base.child_iter_mut() {
if kid.is_table_row() { if kid.is_table_row() {
let size = kid.as_mut_table_row() let (size, oflo) = kid.as_mut_table_row()
.compute_block_size_table_row_base(layout_context, .compute_block_size_table_row_base(layout_context,
&mut incoming_rowspan_data, &mut incoming_rowspan_data,
&sizes, &sizes,
i); i);
sizes[i].0 = size; sizes[i].0 = size;
overflow = oflo;
i += 1; i += 1;
// new rowgroups stop rowspans
} else if kid.is_table_rowgroup() {
if i > 0 {
sizes[i - 1].0 = cmp::max(sizes[i - 1].0, overflow);
}
} }
} }
if i > 0 {
sizes[i - 1].0 = cmp::max(sizes[i - 1].0, overflow);
}
// Third pass: Assign block sizes to rows and cells // Third pass: Assign block sizes to rows and cells
// [expensive: iterates over cells] // [expensive: iterates over cells]

View file

@ -106,34 +106,39 @@ impl TableRowFlow {
} }
} }
/// Assign block-size for table-row flow. /// Compute block-size for table-row flow.
/// ///
/// TODO(pcwalton): This doesn't handle floats and positioned elements right. /// TODO(pcwalton): This doesn't handle floats and positioned elements right.
/// ///
/// inline(always) because this is only ever called by in-order or non-in-order top-level /// Returns the block size, as well as the size this should be if this is the last row
/// methods
#[inline(always)]
pub fn compute_block_size_table_row_base<'a>(&'a mut self, layout_context: &LayoutContext, pub fn compute_block_size_table_row_base<'a>(&'a mut self, layout_context: &LayoutContext,
incoming_rowspan_data: &mut Vec<Au>, incoming_rowspan_data: &mut Vec<Au>,
border_info: &[(Au, Au)], // (_, cumulative_border_size) border_info: &[(Au, Au)], // (_, cumulative_border_size)
row_index: usize) -> Au { row_index: usize) -> (Au, Au) {
// XXXManishearth skip this when the REFLOW flag is unset if it is not affected by other // XXXManishearth skip this when the REFLOW flag is unset if it is not affected by other
// rows // rows
fn include_sizes_from_previous_rows(col: &mut usize, fn include_sizes_from_previous_rows(col: &mut usize,
incoming_rowspan: &[u32], incoming_rowspan: &[u32],
incoming_rowspan_data: &mut Vec<Au>, incoming_rowspan_data: &mut Vec<Au>,
max_block_size: &mut Au) { max_block_size: &mut Au,
largest_leftover_incoming_size: &mut Au) {
while let Some(span) = incoming_rowspan.get(*col) { while let Some(span) = incoming_rowspan.get(*col) {
if *span <= 1 { if *span <= 1 {
break; break;
} }
*max_block_size = max(*max_block_size, incoming_rowspan_data[*col]); 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; *col += 1;
} }
} }
// Per CSS 2.1 § 17.5.3, find max_y = max(computed `block-size`, minimum block-size of // Per CSS 2.1 § 17.5.3, find max_y = max(computed `block-size`, minimum block-size of
// all cells). // all cells).
let mut max_block_size = Au(0); 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 thread_id = self.block_flow.base.thread_id;
let content_box = self.block_flow.base.position let content_box = self.block_flow.base.position
- self.block_flow.fragment.border_padding - self.block_flow.fragment.border_padding
@ -142,7 +147,8 @@ impl TableRowFlow {
let mut col = 0; let mut col = 0;
for kid in self.block_flow.base.child_iter_mut() { for kid in self.block_flow.base.child_iter_mut() {
include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan,
incoming_rowspan_data, &mut max_block_size); incoming_rowspan_data, &mut max_block_size,
&mut largest_leftover_incoming_size);
kid.place_float_if_applicable(); kid.place_float_if_applicable();
if !kid.base().flags.is_float() { if !kid.base().flags.is_float() {
kid.assign_block_size_for_inorder_child_if_necessary(layout_context, kid.assign_block_size_for_inorder_child_if_necessary(layout_context,
@ -167,8 +173,9 @@ impl TableRowFlow {
if incoming_rowspan_data.len() <= col { if incoming_rowspan_data.len() <= col {
incoming_rowspan_data.resize(col + 1, Au(0)); incoming_rowspan_data.resize(col + 1, Au(0));
} }
// XXXManishearth rowspan can overflow the table
let border_sizes_spanned = get_spanned_border_size(border_info, row_index, row_span); let border_sizes_spanned = get_spanned_border_size(border_info, row_index, row_span);
let pressure_copy = cell_block_size_pressure;
cell_block_size_pressure -= border_sizes_spanned; cell_block_size_pressure -= border_sizes_spanned;
// XXXManishearth in case this row covers more than cell_block_size_pressure / row_span // XXXManishearth in case this row covers more than cell_block_size_pressure / row_span
@ -176,12 +183,18 @@ impl TableRowFlow {
// require an extra slow-path loop, sadly. // require an extra slow-path loop, sadly.
cell_block_size_pressure /= row_span as i32; cell_block_size_pressure /= row_span as i32;
incoming_rowspan_data[col] = cell_block_size_pressure; 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); max_block_size = max(max_block_size, cell_block_size_pressure);
col += column_span; col += column_span;
} }
include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, incoming_rowspan_data, &mut max_block_size); include_sizes_from_previous_rows(&mut col, &self.incoming_rowspan, incoming_rowspan_data, &mut max_block_size,
&mut largest_leftover_incoming_size);
let mut block_size = max_block_size; let mut block_size = max_block_size;
// TODO: Percentage block-size // TODO: Percentage block-size
@ -193,7 +206,7 @@ impl TableRowFlow {
MaybeAuto::Auto => block_size, MaybeAuto::Auto => block_size,
MaybeAuto::Specified(value) => max(value, block_size), MaybeAuto::Specified(value) => max(value, block_size),
}; };
block_size (block_size, largest_leftover_incoming_size)
} }
pub fn assign_block_size_to_self_and_children(&mut self, sizes: &[(Au, Au)], index: usize, effects_rows: &mut u32) { pub fn assign_block_size_to_self_and_children(&mut self, sizes: &[(Au, Au)], index: usize, effects_rows: &mut u32) {