layout: Implement most of border-collapse per CSS 2.1 § 17.6.2.

Known issues:

* Collapsed borders do not correctly affect the border-box of the table
  itself.

* The content widths of all cells in a column and the content height of
  all cells in a row is the same in this patch, but not in Gecko and
  WebKit.

* Corners are not painted well. The spec does not say what to do here.

* Column spans are not handled well. The spec does not say what to do
  here either.
This commit is contained in:
Patrick Walton 2015-03-09 12:33:04 -07:00 committed by Simon Sapin
parent 92359c7b9a
commit 48299a53cb
22 changed files with 1975 additions and 520 deletions

View file

@ -11,20 +11,21 @@ use context::LayoutContext;
use flow::{FlowClass, Flow};
use fragment::{Fragment, FragmentBorderBoxIterator};
use layout_debug;
use style::computed_values::border_spacing;
use table::{ChildInlineSizeInfo, ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
use table::{InternalTable, TableLikeFlow};
use style::computed_values::{border_collapse, border_spacing};
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, TableLikeFlow};
use table_row::{self, CollapsedBordersForRow};
use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
use rustc_serialize::{Encoder, Encodable};
use std::fmt;
use std::iter::{IntoIterator, Iterator, Peekable};
use std::sync::Arc;
use style::properties::ComputedValues;
use util::geometry::Au;
use util::logical_geometry::LogicalRect;
use std::fmt;
use style::properties::ComputedValues;
use std::sync::Arc;
/// A table formatting context.
#[derive(RustcEncodable)]
pub struct TableRowGroupFlow {
/// Fields common to all block flows.
pub block_flow: BlockFlow,
@ -37,6 +38,24 @@ pub struct TableRowGroupFlow {
/// The spacing for this rowgroup.
pub spacing: border_spacing::T,
/// Information about the borders for each cell that we bubble up to our parent. This is only
/// computed if `border-collapse` is `collapse`.
pub preliminary_collapsed_borders: CollapsedBordersForRow,
/// 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>,
}
impl Encodable for TableRowGroupFlow {
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
self.block_flow.encode(e)
}
}
impl TableRowGroupFlow {
@ -50,12 +69,38 @@ impl TableRowGroupFlow {
horizontal: Au(0),
vertical: Au(0),
},
preliminary_collapsed_borders: CollapsedBordersForRow::new(),
collapsed_inline_direction_border_widths_for_table: Vec::new(),
collapsed_block_direction_border_widths_for_table: Vec::new(),
}
}
pub fn fragment<'a>(&'a mut self) -> &'a Fragment {
&self.block_flow.fragment
}
pub fn populate_collapsed_border_spacing<'a,I>(
&mut self,
collapsed_inline_direction_border_widths_for_table: &[Au],
collapsed_block_direction_border_widths_for_table: &mut Peekable<I>)
where I: Iterator<Item=&'a Au> {
self.collapsed_inline_direction_border_widths_for_table.clear();
self.collapsed_inline_direction_border_widths_for_table
.extend(collapsed_inline_direction_border_widths_for_table.into_iter().map(|x| *x));
for _ in range(0, self.block_flow.base.children.len()) {
if let Some(collapsed_block_direction_border_width_for_table) =
collapsed_block_direction_border_widths_for_table.next() {
self.collapsed_block_direction_border_widths_for_table
.push(*collapsed_block_direction_border_width_for_table)
}
}
if let Some(collapsed_block_direction_border_width_for_table) =
collapsed_block_direction_border_widths_for_table.peek() {
self.collapsed_block_direction_border_widths_for_table
.push(**collapsed_block_direction_border_width_for_table)
}
}
}
impl Flow for TableRowGroupFlow {
@ -75,6 +120,10 @@ impl Flow for TableRowGroupFlow {
&mut self.block_flow
}
fn as_immutable_block(&self) -> &BlockFlow {
&self.block_flow
}
fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> {
&mut self.column_intrinsic_inline_sizes
}
@ -99,26 +148,48 @@ impl Flow for TableRowGroupFlow {
// The position was set to the containing block by the flow's parent.
let containing_block_inline_size = self.block_flow.base.block_container_inline_size;
// FIXME: In case of border-collapse: collapse, inline-start_content_edge should be
// the border width on the inline-start side.
let inline_start_content_edge = Au::new(0);
let inline_end_content_edge = Au::new(0);
let (inline_start_content_edge, inline_end_content_edge) = (Au(0), Au(0));
let content_inline_size = containing_block_inline_size;
let inline_size_computer = InternalTable;
let border_collapse = self.block_flow.fragment.style.get_inheritedtable().border_collapse;
inline_size_computer.compute_used_inline_size(&mut self.block_flow,
layout_context,
containing_block_inline_size);
containing_block_inline_size,
border_collapse);
let info = ChildInlineSizeInfo {
column_computed_inline_sizes: &self.column_computed_inline_sizes,
spacing: self.spacing,
};
let column_computed_inline_sizes = self.column_computed_inline_sizes.as_slice();
let border_spacing = self.spacing;
let collapsed_inline_direction_border_widths_for_table =
self.collapsed_inline_direction_border_widths_for_table.as_slice();
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(layout_context,
inline_start_content_edge,
inline_end_content_edge,
content_inline_size,
Some(info));
|child_flow,
child_index,
content_inline_size,
writing_mode,
inline_start_margin_edge| {
table_row::propagate_column_inline_sizes_to_child(
child_flow,
child_index,
content_inline_size,
writing_mode,
column_computed_inline_sizes,
&border_spacing,
&None,
inline_start_margin_edge);
if border_collapse == border_collapse::T::collapse {
let child_table_row = child_flow.as_table_row();
child_table_row.populate_collapsed_border_spacing(
collapsed_inline_direction_border_widths_for_table.as_slice(),
&mut collapsed_block_direction_border_widths_for_table);
}
});
}
fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {