mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Account for rowspan in inline layout of table columns/cells
This commit is contained in:
parent
e982d6003f
commit
9700b0e8b3
6 changed files with 180 additions and 11 deletions
|
@ -94,7 +94,16 @@ impl TableFlow {
|
||||||
preferred_inline_size: surrounding_size,
|
preferred_inline_size: surrounding_size,
|
||||||
};
|
};
|
||||||
let mut column_index = 0;
|
let mut column_index = 0;
|
||||||
|
let mut incoming_rowspan = vec![];
|
||||||
|
|
||||||
for child_cell_inline_size in child_cell_inline_sizes {
|
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 {
|
for _ in 0..child_cell_inline_size.column_span {
|
||||||
if column_index < parent_inline_sizes.len() {
|
if column_index < parent_inline_sizes.len() {
|
||||||
// We already have some intrinsic size information for this column. Merge it in
|
// We already have some intrinsic size information for this column. Merge it in
|
||||||
|
@ -130,6 +139,14 @@ impl TableFlow {
|
||||||
total_inline_sizes.preferred_inline_size +=
|
total_inline_sizes.preferred_inline_size +=
|
||||||
parent_inline_sizes[column_index].preferred;
|
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
|
column_index += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,6 +435,7 @@ impl Flow for TableFlow {
|
||||||
&self.collapsed_inline_direction_border_widths_for_table;
|
&self.collapsed_inline_direction_border_widths_for_table;
|
||||||
let mut collapsed_block_direction_border_widths_for_table =
|
let mut collapsed_block_direction_border_widths_for_table =
|
||||||
self.collapsed_block_direction_border_widths_for_table.iter().peekable();
|
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,
|
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
|
||||||
inline_start_content_edge,
|
inline_start_content_edge,
|
||||||
inline_end_content_edge,
|
inline_end_content_edge,
|
||||||
|
@ -432,7 +450,8 @@ impl Flow for TableFlow {
|
||||||
child_flow,
|
child_flow,
|
||||||
writing_mode,
|
writing_mode,
|
||||||
column_computed_inline_sizes,
|
column_computed_inline_sizes,
|
||||||
&spacing_per_cell);
|
&spacing_per_cell,
|
||||||
|
&mut incoming_rowspan);
|
||||||
if child_flow.is_table_row() {
|
if child_flow.is_table_row() {
|
||||||
let child_table_row = child_flow.as_mut_table_row();
|
let child_table_row = child_flow.as_mut_table_row();
|
||||||
child_table_row.populate_collapsed_border_spacing(
|
child_table_row.populate_collapsed_border_spacing(
|
||||||
|
@ -647,6 +666,7 @@ fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow,
|
||||||
next_block_borders: NextBlockCollapsedBorders,
|
next_block_borders: NextBlockCollapsedBorders,
|
||||||
inline_spacing: &mut Vec<Au>,
|
inline_spacing: &mut Vec<Au>,
|
||||||
block_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();
|
let number_of_borders_inline_direction = child_table_row.preliminary_collapsed_borders.inline.len();
|
||||||
// Compute interior inline borders.
|
// Compute interior inline borders.
|
||||||
for (i, this_inline_border) in child_table_row.preliminary_collapsed_borders
|
for (i, this_inline_border) in child_table_row.preliminary_collapsed_borders
|
||||||
|
|
|
@ -45,6 +45,12 @@ pub struct TableRowFlow {
|
||||||
/// Information about the computed inline-sizes of each column.
|
/// Information about the computed inline-sizes of each column.
|
||||||
pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
|
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
|
/// The spacing for this row, propagated down from the table during the inline-size assignment
|
||||||
/// phase.
|
/// phase.
|
||||||
pub spacing: border_spacing::T,
|
pub spacing: border_spacing::T,
|
||||||
|
@ -90,6 +96,7 @@ impl TableRowFlow {
|
||||||
block_flow: BlockFlow::from_fragment(fragment),
|
block_flow: BlockFlow::from_fragment(fragment),
|
||||||
cell_intrinsic_inline_sizes: Vec::new(),
|
cell_intrinsic_inline_sizes: Vec::new(),
|
||||||
column_computed_inline_sizes: Vec::new(),
|
column_computed_inline_sizes: Vec::new(),
|
||||||
|
incoming_rowspan: Vec::new(),
|
||||||
spacing: border_spacing::T {
|
spacing: border_spacing::T {
|
||||||
horizontal: Au(0),
|
horizontal: Au(0),
|
||||||
vertical: Au(0),
|
vertical: Au(0),
|
||||||
|
@ -353,12 +360,23 @@ impl Flow for TableRowFlow {
|
||||||
containing_block_inline_size);
|
containing_block_inline_size);
|
||||||
|
|
||||||
// Spread out the completed inline sizes among columns with spans > 1.
|
// Spread out the completed inline sizes among columns with spans > 1.
|
||||||
let mut computed_inline_size_for_cells = Vec::new();
|
let num_columns = self.column_computed_inline_sizes.len();
|
||||||
let mut column_computed_inline_size_iterator = self.column_computed_inline_sizes.iter();
|
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 {
|
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.
|
// Start with the computed inline size for the first column in the span.
|
||||||
let mut column_computed_inline_size =
|
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,
|
Some(column_computed_inline_size) => *column_computed_inline_size,
|
||||||
None => {
|
None => {
|
||||||
// We're in fixed layout mode and there are more cells in this row than
|
// We're in fixed layout mode and there are more cells in this row than
|
||||||
|
@ -371,16 +389,18 @@ impl Flow for TableRowFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
col += 1;
|
||||||
|
|
||||||
// Add in computed inline sizes for any extra columns in the span.
|
// Add in computed inline sizes for any extra columns in the span.
|
||||||
for _ in 1..cell_intrinsic_inline_size.column_span {
|
for _ in 1..cell_intrinsic_inline_size.column_span {
|
||||||
let extra_column_computed_inline_size =
|
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,
|
Some(column_computed_inline_size) => column_computed_inline_size,
|
||||||
None => break,
|
None => break,
|
||||||
};
|
};
|
||||||
column_computed_inline_size.size = column_computed_inline_size.size +
|
column_computed_inline_size.size = column_computed_inline_size.size +
|
||||||
extra_column_computed_inline_size.size + self.spacing.horizontal;
|
extra_column_computed_inline_size.size + self.spacing.horizontal;
|
||||||
|
col += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
computed_inline_size_for_cells.push(column_computed_inline_size)
|
computed_inline_size_for_cells.push(column_computed_inline_size)
|
||||||
|
@ -402,6 +422,9 @@ impl Flow for TableRowFlow {
|
||||||
let spacing = self.spacing;
|
let spacing = self.spacing;
|
||||||
let row_writing_mode = self.block_flow.base.writing_mode;
|
let row_writing_mode = self.block_flow.base.writing_mode;
|
||||||
let table_writing_mode = self.table_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,
|
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
|
||||||
inline_start_content_edge,
|
inline_start_content_edge,
|
||||||
inline_end_content_edge,
|
inline_end_content_edge,
|
||||||
|
@ -415,6 +438,8 @@ impl Flow for TableRowFlow {
|
||||||
set_inline_position_of_child_flow(
|
set_inline_position_of_child_flow(
|
||||||
child_flow,
|
child_flow,
|
||||||
child_index,
|
child_index,
|
||||||
|
&mut column_index,
|
||||||
|
incoming_rowspan,
|
||||||
row_writing_mode,
|
row_writing_mode,
|
||||||
table_writing_mode,
|
table_writing_mode,
|
||||||
&computed_inline_size_for_cells,
|
&computed_inline_size_for_cells,
|
||||||
|
@ -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(
|
pub fn propagate_column_inline_sizes_to_child(
|
||||||
child_flow: &mut Flow,
|
child_flow: &mut Flow,
|
||||||
table_writing_mode: WritingMode,
|
table_writing_mode: WritingMode,
|
||||||
column_computed_inline_sizes: &[ColumnComputedInlineSize],
|
column_computed_inline_sizes: &[ColumnComputedInlineSize],
|
||||||
border_spacing: &border_spacing::T) {
|
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
|
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.
|
// parent.
|
||||||
//
|
//
|
||||||
// FIXME(pcwalton): This seems inefficient. Reference count it instead?
|
// FIXME(pcwalton): This seems inefficient. Reference count it instead?
|
||||||
|
@ -736,7 +762,8 @@ pub fn propagate_column_inline_sizes_to_child(
|
||||||
propagate_column_inline_sizes_to_child(kid,
|
propagate_column_inline_sizes_to_child(kid,
|
||||||
table_writing_mode,
|
table_writing_mode,
|
||||||
column_computed_inline_sizes,
|
column_computed_inline_sizes,
|
||||||
border_spacing);
|
border_spacing,
|
||||||
|
incoming_rowspan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FlowClass::TableRow => {
|
FlowClass::TableRow => {
|
||||||
|
@ -745,6 +772,32 @@ pub fn propagate_column_inline_sizes_to_child(
|
||||||
column_computed_inline_sizes.to_vec();
|
column_computed_inline_sizes.to_vec();
|
||||||
child_table_row_flow.spacing = *border_spacing;
|
child_table_row_flow.spacing = *border_spacing;
|
||||||
child_table_row_flow.table_writing_mode = table_writing_mode;
|
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)
|
c => warn!("unexpected flow in table {:?}", c)
|
||||||
}
|
}
|
||||||
|
@ -754,6 +807,8 @@ pub fn propagate_column_inline_sizes_to_child(
|
||||||
fn set_inline_position_of_child_flow(
|
fn set_inline_position_of_child_flow(
|
||||||
child_flow: &mut Flow,
|
child_flow: &mut Flow,
|
||||||
child_index: usize,
|
child_index: usize,
|
||||||
|
column_index: &mut usize,
|
||||||
|
incoming_rowspan: &[u32],
|
||||||
row_writing_mode: WritingMode,
|
row_writing_mode: WritingMode,
|
||||||
table_writing_mode: WritingMode,
|
table_writing_mode: WritingMode,
|
||||||
column_computed_inline_sizes: &[ColumnComputedInlineSize],
|
column_computed_inline_sizes: &[ColumnComputedInlineSize],
|
||||||
|
@ -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();
|
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.
|
// Handle border collapsing, if necessary.
|
||||||
let child_table_cell = child_flow.as_mut_table_cell();
|
let child_table_cell = child_flow.as_mut_table_cell();
|
||||||
match *border_collapse_info {
|
match *border_collapse_info {
|
||||||
|
@ -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;
|
let kid_base = &mut child_table_cell.block_flow.base;
|
||||||
kid_base.block_container_inline_size = column_inline_size;
|
kid_base.block_container_inline_size = column_inline_size;
|
||||||
|
|
||||||
|
|
|
@ -420,7 +420,8 @@ impl Flow for TableWrapperFlow {
|
||||||
child_flow,
|
child_flow,
|
||||||
writing_mode,
|
writing_mode,
|
||||||
assigned_column_inline_sizes,
|
assigned_column_inline_sizes,
|
||||||
&border_spacing);
|
&border_spacing,
|
||||||
|
&mut vec![]);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5292,6 +5292,18 @@
|
||||||
"url": "/_mozilla/css/table_row_direction_a.html"
|
"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": [
|
"css/table_specified_width_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/table_specified_width_a.html",
|
"path": "css/table_specified_width_a.html",
|
||||||
|
@ -20328,6 +20340,30 @@
|
||||||
"url": "/_mozilla/css/table_row_direction_a.html"
|
"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": [
|
"css/table_specified_width_a.html": [
|
||||||
{
|
{
|
||||||
"path": "css/table_specified_width_a.html",
|
"path": "css/table_specified_width_a.html",
|
||||||
|
|
20
tests/wpt/mozilla/tests/css/table_rowspan_simple_a.html
Normal file
20
tests/wpt/mozilla/tests/css/table_rowspan_simple_a.html
Normal file
|
@ -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"> </td><td> </td></tr>
|
||||||
|
<tr><td id="test"> </td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
20
tests/wpt/mozilla/tests/css/table_rowspan_simple_ref.html
Normal file
20
tests/wpt/mozilla/tests/css/table_rowspan_simple_ref.html
Normal file
|
@ -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> </td><td> </td></tr>
|
||||||
|
<tr><td> </td><td id="test"> </td></tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue