--- a/servo/components/layout/table.rs
+++ b/servo/components/layout/table.rs
@@ -89,17 +89,26 @@ impl TableFlow {
child_cell_inline_sizes: &[CellIntrinsicInlineSize],
surrounding_size: Au)
-> IntrinsicISizes {
let mut total_inline_sizes = IntrinsicISizes {
minimum_inline_size: surrounding_size,
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
// according to the rules specified in INTRINSIC § 4.
let parent_sizes = &mut parent_inline_sizes[column_index];
if child_cell_inline_size.column_span > 1 {
// TODO(pcwalton): Perform the recursive algorithm specified in INTRINSIC §
// 4. For now we make this column contribute no width.
@@ -125,16 +134,24 @@ impl TableFlow {
}
}
total_inline_sizes.minimum_inline_size +=
parent_inline_sizes[column_index].minimum_length;
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
}
}
total_inline_sizes
}
/// Updates the minimum and preferred inline-size calculation for a single row. This is
@@ -413,31 +430,33 @@ impl Flow for TableFlow {
}
}
let column_computed_inline_sizes = &self.column_computed_inline_sizes;
let collapsed_inline_direction_border_widths_for_table =
&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,
content_inline_size,
|child_flow,
_child_index,
_content_inline_size,
writing_mode,
_inline_start_margin_edge,
_inline_end_margin_edge| {
table_row::propagate_column_inline_sizes_to_child(
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(
collapsed_inline_direction_border_widths_for_table,
&mut collapsed_block_direction_border_widths_for_table);
} else if child_flow.is_table_rowgroup() {
let child_table_rowgroup = child_flow.as_mut_table_rowgroup();
child_table_rowgroup.populate_collapsed_border_spacing(
@@ -642,16 +661,17 @@ impl<T> VecExt<T> for Vec<T> {
/// only be called if border collapsing is on. It is factored out into a separate function
/// because we process children of rowgroups too.
fn perform_border_collapse_for_row(child_table_row: &mut TableRowFlow,
table_inline_borders: &TableInlineCollapsedBorders,
previous_block_borders: PreviousBlockCollapsedBorders,
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
.inline
.iter_mut()
.enumerate() {
child_table_row.final_collapsed_borders.inline.push_or_set(i, *this_inline_border);
if i == 0 {
--- a/servo/components/layout/table_cell.rs
+++ b/servo/components/layout/table_cell.rs
@@ -36,37 +36,42 @@ pub struct TableCellFlow {
pub block_flow: BlockFlow,
/// Border collapse information for the cell.
pub collapsed_borders: CollapsedBordersForCell,
/// The column span of this cell.
pub column_span: u32,
+ /// The rows spanned by this cell.
+ pub row_span: u32,
+
/// Whether this cell is visible. If false, the value of `empty-cells` means that we must not
/// display this cell.
pub visible: bool,
}
impl TableCellFlow {
pub fn from_fragment(fragment: Fragment) -> TableCellFlow {
TableCellFlow {
block_flow: BlockFlow::from_fragment(fragment),
collapsed_borders: CollapsedBordersForCell::new(),
column_span: 1,
+ row_span: 1,
visible: true,
}
}
pub fn from_node_fragment_and_visibility_flag<N: ThreadSafeLayoutNode>(
node: &N, fragment: Fragment, visible: bool) -> TableCellFlow {
TableCellFlow {
block_flow: BlockFlow::from_fragment(fragment),
collapsed_borders: CollapsedBordersForCell::new(),
column_span: node.get_colspan(),
+ row_span: node.get_rowspan(),
visible: visible,
}
}
pub fn fragment(&mut self) -> &Fragment {
&self.block_flow.fragment
}
--- a/servo/components/layout/table_row.rs
+++ b/servo/components/layout/table_row.rs
@@ -40,16 +40,22 @@ pub struct TableRowFlow {
pub block_flow: BlockFlow,
/// Information about the intrinsic inline-sizes of each cell.
pub cell_intrinsic_inline_sizes: Vec<CellIntrinsicInlineSize>,
/// 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,
/// The direction of the columns, propagated down from the table during the inline-size
/// assignment phase.
pub table_writing_mode: WritingMode,
@@ -73,26 +79,29 @@ impl Serialize for TableRowFlow {
/// Information about the column inline size and span for each cell.
#[derive(Serialize, Copy, Clone)]
pub struct CellIntrinsicInlineSize {
/// Inline sizes that this cell contributes to the column.
pub column_size: ColumnIntrinsicInlineSize,
/// The column span of this cell.
pub column_span: u32,
+ /// The row span of this cell.
+ pub row_span: u32,
}
impl TableRowFlow {
pub fn from_fragment(fragment: Fragment) -> TableRowFlow {
let writing_mode = fragment.style().writing_mode;
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),
},
table_writing_mode: writing_mode,
preliminary_collapsed_borders: CollapsedBordersForRow::new(),
final_collapsed_borders: CollapsedBordersForRow::new(),
collapsed_border_spacing: CollapsedBorderSpacingForRow::new(),
@@ -263,23 +272,25 @@ impl Flow for TableRowFlow {
let mut iterator = self.block_flow.base.child_iter_mut().enumerate().peekable();
while let Some((i, kid)) = iterator.next() {
assert!(kid.is_table_cell());
// Collect the specified column inline-size of the cell. This is used in both
// fixed and automatic table layout calculation.
let child_specified_inline_size;
let child_column_span;
+ let child_row_span;
{
let child_table_cell = kid.as_mut_table_cell();
child_specified_inline_size = child_table_cell.block_flow
.fragment
.style
.content_inline_size();
child_column_span = child_table_cell.column_span;
+ child_row_span = child_table_cell.row_span;
// Perform border collapse if necessary.
if collapsing_borders {
perform_inline_direction_border_collapse_for_row(
row_style,
children_count,
i,
child_table_cell,
@@ -314,16 +325,17 @@ impl Flow for TableRowFlow {
LengthOrPercentageOrAuto::Percentage(_) => false,
},
};
min_inline_size = min_inline_size + child_column_inline_size.minimum_length;
pref_inline_size = pref_inline_size + child_column_inline_size.preferred;
self.cell_intrinsic_inline_sizes.push(CellIntrinsicInlineSize {
column_size: child_column_inline_size,
column_span: child_column_span,
+ row_span: child_row_span,
});
}
}
self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size;
self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size,
pref_inline_size);
}
@@ -343,44 +355,57 @@ impl Flow for TableRowFlow {
let inline_size_computer = InternalTable {
border_collapse: self.block_flow.fragment.style.get_inheritedtable().border_collapse,
};
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
shared_context,
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
// columns we know about. According to CSS 2.1 § 17.5.2.1, the behavior is
// now undefined. So just use zero.
//
// FIXME(pcwalton): $10 says this isn't Web compatible.
ColumnComputedInlineSize {
size: Au(0),
}
}
};
+ 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)
}
// Set up border collapse info.
let border_collapse_info =
match self.block_flow.fragment.style().get_inheritedtable().border_collapse {
@@ -392,29 +417,34 @@ impl Flow for TableRowFlow {
}
border_collapse::T::separate => None,
};
// Push those inline sizes down to the cells.
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,
containing_block_inline_size,
|child_flow,
child_index,
content_inline_size,
_writing_mode,
inline_start_margin_edge,
inline_end_margin_edge| {
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,
&spacing,
&border_collapse_info,
content_inline_size,
inline_start_margin_edge,
inline_end_margin_edge);
@@ -704,67 +734,111 @@ impl CollapsedBorder {
(this_style, other_style) if this_style < other_style => *self = *other,
// Step 4.
_ if (self.provenance as i8) >= other.provenance as i8 => {}
_ => *self = *other,
}
}
}
-/// 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?
match child_flow.class() {
- FlowClass::Table => {
- let child_table_flow = child_flow.as_mut_table();
- child_table_flow.column_computed_inline_sizes = column_computed_inline_sizes.to_vec();
- }
FlowClass::TableRowGroup => {
let child_table_rowgroup_flow = child_flow.as_mut_table_rowgroup();
- child_table_rowgroup_flow.column_computed_inline_sizes =
- column_computed_inline_sizes.to_vec();
child_table_rowgroup_flow.spacing = *border_spacing;
- child_table_rowgroup_flow.table_writing_mode = table_writing_mode;
+ for kid in child_table_rowgroup_flow.block_flow.base.child_iter_mut() {
+ propagate_column_inline_sizes_to_child(kid,
+ table_writing_mode,
+ column_computed_inline_sizes,
+ border_spacing,
+ incoming_rowspan);
+ }
}
FlowClass::TableRow => {
let child_table_row_flow = child_flow.as_mut_table_row();
child_table_row_flow.column_computed_inline_sizes =
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)
}
}
/// Lay out table cells inline according to the computer column sizes.
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],
border_spacing: &border_spacing::T,
border_collapse_info: &Option<BorderCollapseInfoForChildTableCell>,
parent_content_inline_size: Au,
inline_start_margin_edge: &mut Au,
inline_end_margin_edge: &mut Au) {
if !child_flow.is_table_cell() {
return
}
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 {
Some(ref border_collapse_info) => {
// Write in the child's border collapse state.
child_table_cell.collapsed_borders = CollapsedBordersForCell {
inline_start_border: border_collapse_info.collapsed_borders_for_row
.inline
@@ -792,46 +866,46 @@ fn set_inline_position_of_child_flow(
.map_or(Au(0), |x| *x),
block_start_width: border_collapse_info.collapsed_border_spacing_for_row
.block_start,
block_end_width: border_collapse_info.collapsed_border_spacing_for_row.block_end,
};
// Move over past the collapsed border.
if reverse_column_order {
- *inline_end_margin_edge = *inline_end_margin_edge +
- child_table_cell.collapsed_borders.inline_start_width
+ *inline_end_margin_edge += child_table_cell.collapsed_borders.inline_start_width;
} else {
- *inline_start_margin_edge = *inline_start_margin_edge +
- child_table_cell.collapsed_borders.inline_start_width
+ *inline_start_margin_edge += child_table_cell.collapsed_borders.inline_start_width;
}
}
None => {
// Take spacing into account.
if reverse_column_order {
- *inline_end_margin_edge = *inline_end_margin_edge + border_spacing.horizontal
+ *inline_end_margin_edge += border_spacing.horizontal;
} else {
- *inline_start_margin_edge = *inline_start_margin_edge + border_spacing.horizontal
+ *inline_start_margin_edge += border_spacing.horizontal;
}
}
}
- 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;
if reverse_column_order {
// Columns begin from the inline-end edge.
kid_base.position.start.i =
parent_content_inline_size - *inline_end_margin_edge - column_inline_size;
- *inline_end_margin_edge = *inline_end_margin_edge + column_inline_size;
+ *inline_end_margin_edge += column_inline_size;
} else {
// Columns begin from the inline-start edge.
kid_base.position.start.i = *inline_start_margin_edge;
- *inline_start_margin_edge = *inline_start_margin_edge + column_inline_size;
+ *inline_start_margin_edge += column_inline_size;
}
}
#[derive(Copy, Clone)]
pub struct BorderCollapseInfoForChildTableCell<'a> {
collapsed_borders_for_row: &'a CollapsedBordersForRow,
collapsed_border_spacing_for_row: &'a CollapsedBorderSpacingForRow,
}
--- a/servo/components/layout/table_rowgroup.rs
+++ b/servo/components/layout/table_rowgroup.rs
@@ -18,39 +18,31 @@ use gfx_traits::ScrollRootId;
use gfx_traits::print_tree::PrintTree;
use layout_debug;
use serde::{Serialize, Serializer};
use std::fmt;
use std::iter::{IntoIterator, Iterator, Peekable};
use std::sync::Arc;
use style::computed_values::{border_collapse, border_spacing};
use style::context::SharedStyleContext;
-use style::logical_geometry::{LogicalSize, WritingMode};
+use style::logical_geometry::LogicalSize;
use style::properties::ServoComputedValues;
-use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, TableLikeFlow};
-use table_row;
+use table::{ColumnIntrinsicInlineSize, InternalTable, TableLikeFlow};
/// A table formatting context.
pub struct TableRowGroupFlow {
/// Fields common to all block flows.
pub block_flow: BlockFlow,
/// Information about the intrinsic inline-sizes of each column.
pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>,
- /// Information about the actual inline sizes of each column.
- pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>,
-
/// The spacing for this rowgroup.
pub spacing: border_spacing::T,
- /// The direction of the columns, propagated down from the table during the inline-size
- /// assignment phase.
- pub table_writing_mode: WritingMode,
-
/// The final width of the borders in the inline direction for each cell, computed by the
/// entire table and pushed down into each row during inline size computation.
pub collapsed_inline_direction_border_widths_for_table: Vec<Au>,
/// The final width of the borders in the block direction for each cell, computed by the
/// entire table and pushed down into each row during inline size computation.
pub collapsed_block_direction_border_widths_for_table: Vec<Au>,
}
@@ -58,26 +50,23 @@ pub struct TableRowGroupFlow {
impl Serialize for TableRowGroupFlow {
fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
self.block_flow.serialize(serializer)
}
}
impl TableRowGroupFlow {
pub fn from_fragment(fragment: Fragment) -> TableRowGroupFlow {
- let writing_mode = fragment.style().writing_mode;
TableRowGroupFlow {
block_flow: BlockFlow::from_fragment(fragment),
column_intrinsic_inline_sizes: Vec::new(),
- column_computed_inline_sizes: Vec::new(),
spacing: border_spacing::T {
horizontal: Au(0),
vertical: Au(0),
},
- table_writing_mode: writing_mode,
collapsed_inline_direction_border_widths_for_table: Vec::new(),
collapsed_block_direction_border_widths_for_table: Vec::new(),
}
}
pub fn populate_collapsed_border_spacing<'a, I>(
&mut self,
collapsed_inline_direction_border_widths_for_table: &[Au],
@@ -145,39 +134,30 @@ impl Flow for TableRowGroupFlow {
let border_collapse = self.block_flow.fragment.style.get_inheritedtable().border_collapse;
let inline_size_computer = InternalTable {
border_collapse: border_collapse,
};
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
shared_context,
containing_block_inline_size);
- let column_computed_inline_sizes = &self.column_computed_inline_sizes;
- let border_spacing = self.spacing;
- let table_writing_mode = self.table_writing_mode;
let collapsed_inline_direction_border_widths_for_table =
&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();
self.block_flow.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|child_flow,
_child_index,
_content_inline_size,
_writing_mode,
_inline_start_margin_edge,
_inline_end_margin_edge| {
- table_row::propagate_column_inline_sizes_to_child(
- child_flow,
- table_writing_mode,
- column_computed_inline_sizes,
- &border_spacing);
-
if border_collapse == border_collapse::T::collapse {
let child_table_row = child_flow.as_mut_table_row();
child_table_row.populate_collapsed_border_spacing(
collapsed_inline_direction_border_widths_for_table,
&mut collapsed_block_direction_border_widths_for_table);
}
});
}
--- a/servo/components/layout/table_wrapper.rs
+++ b/servo/components/layout/table_wrapper.rs
@@ -32,17 +32,16 @@ use std::ops::Add;
use std::sync::Arc;
use style::computed_values::{border_collapse, position, table_layout};
use style::context::SharedStyleContext;
use style::logical_geometry::{LogicalRect, LogicalSize};
use style::properties::ServoComputedValues;
use style::values::CSSFloat;
use style::values::computed::LengthOrPercentageOrAuto;
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
-use table_row;
#[derive(Copy, Clone, Serialize, Debug)]
pub enum TableLayout {
Fixed,
Auto
}
/// A table wrapper flow based on a block formatting context.
@@ -389,43 +388,36 @@ impl Flow for TableWrapperFlow {
Some(intermediate_column_inline_sizes.iter().map(|sizes| {
ColumnComputedInlineSize {
size: sizes.size,
}
}).collect::<Vec<_>>())
}
};
- let border_spacing = self.block_flow.fragment.style().get_inheritedtable().border_spacing;
match assigned_column_inline_sizes {
None => {
self.block_flow
.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
|_, _, _, _, _, _| {})
}
Some(ref assigned_column_inline_sizes) => {
self.block_flow
.propagate_assigned_inline_size_to_children(shared_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
- |child_flow,
- _child_index,
- _content_inline_size,
- writing_mode,
- _inline_start_margin_edge,
- _inline_end_margin_edge| {
- table_row::propagate_column_inline_sizes_to_child(
- child_flow,
- writing_mode,
- assigned_column_inline_sizes,
- &border_spacing);
+ |child_flow, _, _, _, _, _| {
+ if child_flow.class() == FlowClass::Table {
+ child_flow.as_mut_table().column_computed_inline_sizes =
+ assigned_column_inline_sizes.to_vec();
+ }
})
}
}
}
fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
debug!("assign_block_size: assigning block_size for table_wrapper");
--- a/servo/components/script/dom/element.rs
+++ b/servo/components/script/dom/element.rs
@@ -320,16 +320,18 @@ pub trait LayoutElementHelpers {
unsafe fn get_classes_for_layout(&self) -> Option<&'static [Atom]>;
#[allow(unsafe_code)]
unsafe fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V)
where V: Push<ApplicableDeclarationBlock>;
#[allow(unsafe_code)]
unsafe fn get_colspan(self) -> u32;
#[allow(unsafe_code)]
+ unsafe fn get_rowspan(self) -> u32;
+ #[allow(unsafe_code)]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
fn id_attribute(&self) -> *const Option<Atom>;
fn style_attribute(&self) -> *const Option<Arc<RwLock<PropertyDeclarationBlock>>>;
fn local_name(&self) -> &LocalName;
fn namespace(&self) -> &Namespace;
fn get_checked_state_for_layout(&self) -> bool;
fn get_indeterminate_state_for_layout(&self) -> bool;
fn get_state_for_layout(&self) -> ElementState;
@@ -623,16 +625,27 @@ impl LayoutElementHelpers for LayoutJS<E
this.get_colspan().unwrap_or(1)
} else {
// Don't panic since `display` can cause this to be called on arbitrary
// elements.
1
}
}
+ #[allow(unsafe_code)]
+ unsafe fn get_rowspan(self) -> u32 {
+ if let Some(this) = self.downcast::<HTMLTableCellElement>() {
+ this.get_rowspan().unwrap_or(1)
+ } else {
+ // Don't panic since `display` can cause this to be called on arbitrary
+ // elements.
+ 1
+ }
+ }
+
#[inline]
#[allow(unsafe_code)]
unsafe fn html_element_in_html_document_for_layout(&self) -> bool {
if (*self.unsafe_get()).namespace != ns!(html) {
return false;
}
self.upcast::<Node>().owner_doc_for_layout().is_html_document_for_layout()
}
--- a/servo/components/script/dom/htmltablecellelement.rs
+++ b/servo/components/script/dom/htmltablecellelement.rs
@@ -13,16 +13,17 @@ use dom::element::{Element, RawLayoutEle
use dom::htmlelement::HTMLElement;
use dom::htmltablerowelement::HTMLTableRowElement;
use dom::node::Node;
use dom::virtualmethods::VirtualMethods;
use html5ever_atoms::LocalName;
use style::attr::{AttrValue, LengthOrPercentageOrAuto};
const DEFAULT_COLSPAN: u32 = 1;
+const DEFAULT_ROWSPAN: u32 = 1;
#[dom_struct]
pub struct HTMLTableCellElement {
htmlelement: HTMLElement,
}
impl HTMLTableCellElement {
pub fn new_inherited(tag_name: LocalName,
@@ -37,16 +38,22 @@ impl HTMLTableCellElement {
impl HTMLTableCellElementMethods for HTMLTableCellElement {
// https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN);
// https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
make_uint_setter!(SetColSpan, "colspan", DEFAULT_COLSPAN);
+ // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
+ make_uint_getter!(RowSpan, "rowspan", DEFAULT_ROWSPAN);
+
+ // https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
+ make_uint_setter!(SetRowSpan, "rowspan", DEFAULT_ROWSPAN);
+
// https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
make_getter!(BgColor, "bgcolor");
// https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
make_legacy_color_setter!(SetBgColor, "bgcolor");
// https://html.spec.whatwg.org/multipage/#dom-tdth-width
make_getter!(Width, "width");
@@ -70,16 +77,17 @@ impl HTMLTableCellElementMethods for HTM
.map_or(-1, |p| p as i32)
}
}
pub trait HTMLTableCellElementLayoutHelpers {
fn get_background_color(&self) -> Option<RGBA>;
fn get_colspan(&self) -> Option<u32>;
+ fn get_rowspan(&self) -> Option<u32>;
fn get_width(&self) -> LengthOrPercentageOrAuto;
}
#[allow(unsafe_code)]
impl HTMLTableCellElementLayoutHelpers for LayoutJS<HTMLTableCellElement> {
fn get_background_color(&self) -> Option<RGBA> {
unsafe {
(&*self.upcast::<Element>().unsafe_get())
@@ -92,16 +100,24 @@ impl HTMLTableCellElementLayoutHelpers f
fn get_colspan(&self) -> Option<u32> {
unsafe {
(&*self.upcast::<Element>().unsafe_get())
.get_attr_for_layout(&ns!(), &local_name!("colspan"))
.map(AttrValue::as_uint)
}
}
+ fn get_rowspan(&self) -> Option<u32> {
+ unsafe {
+ (&*self.upcast::<Element>().unsafe_get())
+ .get_attr_for_layout(&ns!(), &local_name!("rowspan"))
+ .map(AttrValue::as_uint)
+ }
+ }
+
fn get_width(&self) -> LengthOrPercentageOrAuto {
unsafe {
(&*self.upcast::<Element>().unsafe_get())
.get_attr_for_layout(&ns!(), &local_name!("width"))
.map(AttrValue::as_dimension)
.cloned()
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
@@ -111,14 +127,15 @@ impl HTMLTableCellElementLayoutHelpers f
impl VirtualMethods for HTMLTableCellElement {
fn super_type(&self) -> Option<&VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &VirtualMethods)
}
fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
match *local_name {
local_name!("colspan") => AttrValue::from_u32(value.into(), DEFAULT_COLSPAN),
+ local_name!("rowspan") => AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN),
local_name!("bgcolor") => AttrValue::from_legacy_color(value.into()),
local_name!("width") => AttrValue::from_nonzero_dimension(value.into()),
_ => self.super_type().unwrap().parse_plain_attribute(local_name, value),
}
}
}
--- a/servo/components/script/dom/webidls/HTMLTableCellElement.webidl
+++ b/servo/components/script/dom/webidls/HTMLTableCellElement.webidl
@@ -1,17 +1,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://html.spec.whatwg.org/multipage/#htmltablecellelement
[Abstract]
interface HTMLTableCellElement : HTMLElement {
- attribute unsigned long colSpan;
- // attribute unsigned long rowSpan;
+ attribute unsigned long colSpan;
+ attribute unsigned long rowSpan;
// attribute DOMString headers;
readonly attribute long cellIndex;
// also has obsolete members
};
// https://html.spec.whatwg.org/multipage/#HTMLTableCellElement-partial
partial interface HTMLTableCellElement {
--- a/servo/components/script/layout_wrapper.rs
+++ b/servo/components/script/layout_wrapper.rs
@@ -859,16 +859,22 @@ impl<'ln> ThreadSafeLayoutNode for Servo
this.iframe_pipeline_id()
}
fn get_colspan(&self) -> u32 {
unsafe {
self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan()
}
}
+
+ fn get_rowspan(&self) -> u32 {
+ unsafe {
+ self.get_jsmanaged().downcast::<Element>().unwrap().get_rowspan()
+ }
+ }
}
pub struct ThreadSafeLayoutNodeChildrenIterator<ConcreteNode: ThreadSafeLayoutNode> {
current_node: Option<ConcreteNode>,
parent_node: ConcreteNode,
}
impl<ConcreteNode> ThreadSafeLayoutNodeChildrenIterator<ConcreteNode>
--- a/servo/components/script_layout_interface/wrapper_traits.rs
+++ b/servo/components/script_layout_interface/wrapper_traits.rs
@@ -260,16 +260,18 @@ pub trait ThreadSafeLayoutNode: Clone +
fn svg_data(&self) -> Option<SVGSVGData>;
/// If this node is an iframe element, returns its pipeline ID. If this node is
/// not an iframe element, fails.
fn iframe_pipeline_id(&self) -> PipelineId;
fn get_colspan(&self) -> u32;
+ fn get_rowspan(&self) -> u32;
+
fn fragment_type(&self) -> FragmentType {
match self.get_pseudo_element_type() {
PseudoElementType::Normal => FragmentType::FragmentBody,
PseudoElementType::Before(_) => FragmentType::BeforePseudoContent,
PseudoElementType::After(_) => FragmentType::AfterPseudoContent,
PseudoElementType::DetailsSummary(_) => FragmentType::FragmentBody,
PseudoElementType::DetailsContent(_) => FragmentType::FragmentBody,
}
--- a/servo/components/style/matching.rs
+++ b/servo/components/style/matching.rs
@@ -258,18 +258,18 @@ pub fn common_style_affecting_attributes
mode: CommonStyleAffectingAttributeMode::IsEqual(atom!("right"), ALIGN_RIGHT_ATTRIBUTE),
}
]
}
/// Attributes that, if present, disable style sharing. All legacy HTML attributes must be in
/// either this list or `common_style_affecting_attributes`. See the comment in
/// `synthesize_presentational_hints_for_legacy_attributes`.
-pub fn rare_style_affecting_attributes() -> [LocalName; 3] {
- [ local_name!("bgcolor"), local_name!("border"), local_name!("colspan") ]
+pub fn rare_style_affecting_attributes() -> [LocalName; 4] {
+ [local_name!("bgcolor"), local_name!("border"), local_name!("colspan"), local_name!("rowspan")]
}
fn have_same_class<E: TElement>(element: &E,
candidate: &mut StyleSharingCandidate<E>,
candidate_element: &E) -> bool {
// XXX Efficiency here, I'm only validating ideas.
let mut element_class_attributes = vec![];
element.each_class(|c| element_class_attributes.push(c.clone()));