mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00: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,
|
||||
};
|
||||
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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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?
|
||||
|
@ -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 => {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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],
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -420,7 +420,8 @@ impl Flow for TableWrapperFlow {
|
|||
child_flow,
|
||||
writing_mode,
|
||||
assigned_column_inline_sizes,
|
||||
&border_spacing);
|
||||
&border_spacing,
|
||||
&mut vec![]);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
@ -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",
|
||||
|
|
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