Skip to content

Commit

Permalink
Account for rowspan in inline layout of table columns/cells
Browse files Browse the repository at this point in the history
  • Loading branch information
mbrubeck committed Dec 14, 2016
1 parent e982d60 commit 9700b0e
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 11 deletions.
22 changes: 21 additions & 1 deletion components/layout/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,16 @@ impl TableFlow {
preferred_inline_size: surrounding_size,
};
let mut column_index = 0;
let mut incoming_rowspan = vec![];

for child_cell_inline_size in child_cell_inline_sizes {
// Skip any column occupied by a cell from a previous row.
while column_index < incoming_rowspan.len() && incoming_rowspan[column_index] != 1 {
if incoming_rowspan[column_index] > 1 {
incoming_rowspan[column_index] -= 1;
}
column_index += 1;
}
for _ in 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
Expand Down Expand Up @@ -130,6 +139,14 @@ impl TableFlow {
total_inline_sizes.preferred_inline_size +=
parent_inline_sizes[column_index].preferred;

// If this cell spans later rows, record its rowspan.
if child_cell_inline_size.row_span > 1 {
if incoming_rowspan.len() < column_index + 1 {
incoming_rowspan.resize(column_index + 1, 0);
}
incoming_rowspan[column_index] = child_cell_inline_size.row_span;
}

column_index += 1
}
}
Expand Down Expand Up @@ -418,6 +435,7 @@ impl Flow for TableFlow {
&self.collapsed_inline_direction_border_widths_for_table;
let mut collapsed_block_direction_border_widths_for_table =
self.collapsed_block_direction_border_widths_for_table.iter().peekable();
let mut incoming_rowspan = vec![];
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
Expand All @@ -432,7 +450,8 @@ impl Flow for TableFlow {
child_flow,
writing_mode,
column_computed_inline_sizes,
&spacing_per_cell);
&spacing_per_cell,
&mut incoming_rowspan);
if child_flow.is_table_row() {
let child_table_row = child_flow.as_mut_table_row();
child_table_row.populate_collapsed_border_spacing(
Expand Down Expand Up @@ -647,6 +666,7 @@ fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow,
next_block_borders: NextBlockCollapsedBorders,
inline_spacing: &mut Vec<Au>,
block_spacing: &mut Vec<Au>) {
// TODO mbrubeck: Take rowspan and colspan into account.
let number_of_borders_inline_direction = child_table_row.preliminary_collapsed_borders.inline.len();
// Compute interior inline borders.
for (i, this_inline_border) in child_table_row.preliminary_collapsed_borders
Expand Down
90 changes: 81 additions & 9 deletions components/layout/table_row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ pub struct TableRowFlow {
/// Information about the computed inline-sizes of each column.
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,

/// The number of remaining rows spanned by cells in previous rows, indexed by column.
///
/// Columns that are not included in this vector have the default rowspan of "1". If there are
/// no cells with rowspan != 1 in previous rows, this vector may be empty.
pub incoming_rowspan: Vec<u32>,

/// The spacing for this row, propagated down from the table during the inline-size assignment
/// phase.
pub spacing: border_spacing::T,
Expand Down Expand Up @@ -90,6 +96,7 @@ impl TableRowFlow {
block_flow: BlockFlow::from_fragment(fragment),
cell_intrinsic_inline_sizes: Vec::new(),
column_computed_inline_sizes: Vec::new(),
incoming_rowspan: Vec::new(),
spacing: border_spacing::T {
horizontal: Au(0),
vertical: Au(0),
Expand Down Expand Up @@ -353,12 +360,23 @@ impl Flow for TableRowFlow {
containing_block_inline_size);

// Spread out the completed inline sizes among columns with spans > 1.
let mut computed_inline_size_for_cells = Vec::new();
let mut column_computed_inline_size_iterator = self.column_computed_inline_sizes.iter();
let num_columns = self.column_computed_inline_sizes.len();
let mut computed_inline_size_for_cells = Vec::with_capacity(num_columns);
let mut col = 0;

for cell_intrinsic_inline_size in &self.cell_intrinsic_inline_sizes {
// Skip any column occupied by a cell from a previous row.
while col < self.incoming_rowspan.len() && self.incoming_rowspan[col] != 1 {
let size = match self.column_computed_inline_sizes.get(col) {
Some(column_computed_inline_size) => *column_computed_inline_size,
None => ColumnComputedInlineSize { size: Au(0) } // See FIXME below.
};
computed_inline_size_for_cells.push(size);
col += 1;
}
// Start with the computed inline size for the first column in the span.
let mut column_computed_inline_size =
match column_computed_inline_size_iterator.next() {
match self.column_computed_inline_sizes.get(col) {
Some(column_computed_inline_size) => *column_computed_inline_size,
None => {
// We're in fixed layout mode and there are more cells in this row than
Expand All @@ -371,16 +389,18 @@ impl Flow for TableRowFlow {
}
}
};
col += 1;

// Add in computed inline sizes for any extra columns in the span.
for _ in 1..cell_intrinsic_inline_size.column_span {
let extra_column_computed_inline_size =
match column_computed_inline_size_iterator.next() {
match self.column_computed_inline_sizes.get(col) {
Some(column_computed_inline_size) => column_computed_inline_size,
None => break,
};
column_computed_inline_size.size = column_computed_inline_size.size +
extra_column_computed_inline_size.size + self.spacing.horizontal;
col += 1;
}

computed_inline_size_for_cells.push(column_computed_inline_size)
Expand All @@ -402,6 +422,9 @@ impl Flow for TableRowFlow {
let spacing = self.spacing;
let row_writing_mode = self.block_flow.base.writing_mode;
let table_writing_mode = self.table_writing_mode;
let incoming_rowspan = &self.incoming_rowspan;
let mut column_index = 0;

self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
Expand All @@ -415,6 +438,8 @@ impl Flow for TableRowFlow {
set_inline_position_of_child_flow(
child_flow,
child_index,
&mut column_index,
incoming_rowspan,
row_writing_mode,
table_writing_mode,
&computed_inline_size_for_cells,
Expand Down Expand Up @@ -714,13 +739,14 @@ impl CollapsedBorder {
}
}

/// Pushes column inline size and border collapse info down to a child.
/// Pushes column inline size, incoming rowspan, and border collapse info down to a child.
pub fn propagate_column_inline_sizes_to_child(
child_flow: &mut Flow,
table_writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize],
border_spacing: &border_spacing::T) {
// If the child is a row group or a row, the column inline-size info should be copied from its
border_spacing: &border_spacing::T,
incoming_rowspan: &mut Vec<u32>) {
// If the child is a row group or a row, the column inline-size and rowspan info should be copied from its
// parent.
//
// FIXME(pcwalton): This seems inefficient. Reference count it instead?
Expand All @@ -736,7 +762,8 @@ pub fn propagate_column_inline_sizes_to_child(
propagate_column_inline_sizes_to_child(kid,
table_writing_mode,
column_computed_inline_sizes,
border_spacing);
border_spacing,
incoming_rowspan);
}
}
FlowClass::TableRow => {
Expand All @@ -745,6 +772,32 @@ pub fn propagate_column_inline_sizes_to_child(
column_computed_inline_sizes.to_vec();
child_table_row_flow.spacing = *border_spacing;
child_table_row_flow.table_writing_mode = table_writing_mode;
child_table_row_flow.incoming_rowspan = incoming_rowspan.clone();

// Update the incoming rowspan for the next row.
let mut col = 0;
for cell in &child_table_row_flow.cell_intrinsic_inline_sizes {
// Skip any column occupied by a cell from a previous row.
while col < incoming_rowspan.len() && incoming_rowspan[col] != 1 {
if incoming_rowspan[col] > 1 {
incoming_rowspan[col] -= 1;
}
col += 1;
}
for _ in 0..cell.column_span {
if col < incoming_rowspan.len() && incoming_rowspan[col] > 1 {
incoming_rowspan[col] -= 1;
}
// If this cell spans later rows, record its rowspan.
if cell.row_span != 1 {
if incoming_rowspan.len() < col + 1 {
incoming_rowspan.resize(col + 1, 1);
}
incoming_rowspan[col] = max(cell.row_span, incoming_rowspan[col]);
}
col += 1;
}
}
}
c => warn!("unexpected flow in table {:?}", c)
}
Expand All @@ -754,6 +807,8 @@ pub fn propagate_column_inline_sizes_to_child(
fn set_inline_position_of_child_flow(
child_flow: &mut Flow,
child_index: usize,
column_index: &mut usize,
incoming_rowspan: &[u32],
row_writing_mode: WritingMode,
table_writing_mode: WritingMode,
column_computed_inline_sizes: &[ColumnComputedInlineSize],
Expand All @@ -768,6 +823,21 @@ fn set_inline_position_of_child_flow(

let reverse_column_order = table_writing_mode.is_bidi_ltr() != row_writing_mode.is_bidi_ltr();

// Advance past any column occupied by a cell from a previous row.
while *column_index < incoming_rowspan.len() && incoming_rowspan[*column_index] != 1 {
let column_inline_size = column_computed_inline_sizes[*column_index].size;
let border_inline_size = match *border_collapse_info {
Some(_) => Au(0), // FIXME: Make collapsed borders account for colspan/rowspan.
None => border_spacing.horizontal,
};
if reverse_column_order {
*inline_end_margin_edge += column_inline_size + border_inline_size;
} else {
*inline_start_margin_edge += column_inline_size + border_inline_size;
}
*column_index += 1;
}

// Handle border collapsing, if necessary.
let child_table_cell = child_flow.as_mut_table_cell();
match *border_collapse_info {
Expand Down Expand Up @@ -822,7 +892,9 @@ fn set_inline_position_of_child_flow(
}
}

let column_inline_size = column_computed_inline_sizes[child_index].size;
let column_inline_size = column_computed_inline_sizes[*column_index].size;
*column_index += 1;

let kid_base = &mut child_table_cell.block_flow.base;
kid_base.block_container_inline_size = column_inline_size;

Expand Down
3 changes: 2 additions & 1 deletion components/layout/table_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,8 @@ impl Flow for TableWrapperFlow {
child_flow,
writing_mode,
assigned_column_inline_sizes,
&border_spacing);
&border_spacing,
&mut vec![]);
})
}
}
Expand Down
36 changes: 36 additions & 0 deletions tests/wpt/mozilla/meta/MANIFEST.json
Original file line number Diff line number Diff line change
Expand Up @@ -5292,6 +5292,18 @@
"url": "/_mozilla/css/table_row_direction_a.html"
}
],
"css/table_rowspan_simple_a.html": [
{
"path": "css/table_rowspan_simple_a.html",
"references": [
[
"/_mozilla/css/table_rowspan_simple_ref.html",
"=="
]
],
"url": "/_mozilla/css/table_rowspan_simple_a.html"
}
],
"css/table_specified_width_a.html": [
{
"path": "css/table_specified_width_a.html",
Expand Down Expand Up @@ -20328,6 +20340,30 @@
"url": "/_mozilla/css/table_row_direction_a.html"
}
],
"css/table_rowspan_simple_a.html": [
{
"path": "css/table_rowspan_simple_a.html",
"references": [
[
"/_mozilla/css/table_rowspan_simple_ref.html",
"=="
]
],
"url": "/_mozilla/css/table_rowspan_simple_a.html"
}
],
"css/table_rowspan_simple_ref.html": [
{
"path": "css/table_rowspan_simple_ref.html",
"references": [
[
"/_mozilla/css/table_rowspan_simple_ref.html",
"=="
]
],
"url": "/_mozilla/css/table_rowspan_simple_ref.html"
}
],
"css/table_specified_width_a.html": [
{
"path": "css/table_specified_width_a.html",
Expand Down
20 changes: 20 additions & 0 deletions tests/wpt/mozilla/tests/css/table_rowspan_simple_a.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<link rel="match" href="table_rowspan_simple_ref.html">
<style>
td {
width: 100px;
}
#test {
background-color: green;
}
</style>
<body>
<table border="0" cellspacing="0" cellpadding="0">
<tr><td rowspan="2">&nbsp;</td><td>&nbsp;</td></tr>
<tr><td id="test">&nbsp;</td></tr>
</table>
</body>
</html>

20 changes: 20 additions & 0 deletions tests/wpt/mozilla/tests/css/table_rowspan_simple_ref.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<link rel="match" href="table_rowspan_simple_ref.html">
<style>
td {
width: 100px;
}
#test {
background-color: green;
}
</style>
<body>
<table border="0" cellspacing="0" cellpadding="0">
<tr><td>&nbsp;</td><td>&nbsp;</td></tr>
<tr><td>&nbsp;</td><td id="test">&nbsp;</td></tr>
</table>
</body>
</html>

0 comments on commit 9700b0e

Please sign in to comment.