Skip to content

Commit

Permalink
layout: Assign border and padding to tables instead of table wrappers.
Browse files Browse the repository at this point in the history
This is more straightforward when anonymous table object generation is
involved.
  • Loading branch information
pcwalton committed Oct 26, 2016
1 parent a1bbc5d commit d222e3e
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 64 deletions.
7 changes: 6 additions & 1 deletion components/layout/fragment.rs
Expand Up @@ -1075,7 +1075,12 @@ impl Fragment {
SpecificFragmentInfo::Svg(_) => {
QuantitiesIncludedInIntrinsicInlineSizes::all()
}
SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => {
SpecificFragmentInfo::Table => {
INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED |
INTRINSIC_INLINE_SIZE_INCLUDES_PADDING |
INTRINSIC_INLINE_SIZE_INCLUDES_BORDER
}
SpecificFragmentInfo::TableCell => {
let base_quantities = INTRINSIC_INLINE_SIZE_INCLUDES_PADDING |
INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED;
if self.style.get_inheritedtable().border_collapse ==
Expand Down
43 changes: 28 additions & 15 deletions components/layout/table.rs
Expand Up @@ -85,9 +85,13 @@ impl TableFlow {
/// sizes.
fn update_automatic_column_inline_sizes(
parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
child_cell_inline_sizes: &[CellIntrinsicInlineSize])
child_cell_inline_sizes: &[CellIntrinsicInlineSize],
surrounding_size: Au)
-> IntrinsicISizes {
let mut total_inline_sizes = IntrinsicISizes::new();
let mut total_inline_sizes = IntrinsicISizes {
minimum_inline_size: surrounding_size,
preferred_inline_size: surrounding_size,
};
let mut column_index = 0;
for child_cell_inline_size in child_cell_inline_sizes {
for _ in 0..child_cell_inline_size.column_span {
Expand Down Expand Up @@ -139,7 +143,8 @@ impl TableFlow {
column_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>,
computation: &mut IntrinsicISizesContribution,
first_row: bool,
table_layout: TableLayout) {
table_layout: TableLayout,
surrounding_inline_size: Au) {
// Read column inline-sizes from the table-row, and assign inline-size=0 for the columns
// not defined in the column group.
//
Expand All @@ -158,7 +163,8 @@ impl TableFlow {
TableLayout::Auto => {
computation.union_block(&TableFlow::update_automatic_column_inline_sizes(
column_inline_sizes,
&row.cell_intrinsic_inline_sizes))
&row.cell_intrinsic_inline_sizes,
surrounding_inline_size))
}
}
}
Expand Down Expand Up @@ -227,9 +233,6 @@ impl Flow for TableFlow {
let _scope = layout_debug_scope!("table::bubble_inline_sizes {:x}",
self.block_flow.base.debug_id());

// Don't use `compute_intrinsic_inline_sizes` here because that will count padding as
// part of the table, which we don't want to do—it belongs to the table wrapper instead.

// Get column inline sizes from colgroups
for kid in self.block_flow.base.child_iter_mut().filter(|kid| kid.is_table_colgroup()) {
for specified_inline_size in &kid.as_mut_table_colgroup().inline_sizes {
Expand Down Expand Up @@ -277,15 +280,18 @@ impl Flow for TableFlow {
&*self.block_flow.fragment.style,
CollapsedBorderProvenance::FromTable));
let mut first_row = true;
let (border_padding, _) = self.block_flow.fragment.surrounding_intrinsic_inline_size();

{
let mut iterator = TableRowIterator::new(&mut self.block_flow.base).peekable();
while let Some(row) = iterator.next() {
TableFlow::update_column_inline_sizes_for_row(row,
TableFlow::update_column_inline_sizes_for_row(
row,
&mut self.column_intrinsic_inline_sizes,
&mut computation,
first_row,
self.table_layout);
self.table_layout,
border_padding);
if collapsing_borders {
let next_index_and_sibling = iterator.peek();
let next_collapsed_borders_in_block_direction =
Expand Down Expand Up @@ -316,9 +322,16 @@ impl Flow for TableFlow {
};
}


computation.surrounding_size = computation.surrounding_size +
self.total_horizontal_spacing();
let total_horizontal_spacing = self.total_horizontal_spacing();
let mut style_specified_intrinsic_inline_size =
self.block_flow
.fragment
.style_specified_intrinsic_inline_size()
.finish();
style_specified_intrinsic_inline_size.minimum_inline_size -= total_horizontal_spacing;
style_specified_intrinsic_inline_size.preferred_inline_size -= total_horizontal_spacing;
computation.union_block(&style_specified_intrinsic_inline_size);
computation.surrounding_size += total_horizontal_spacing;

self.block_flow.base.intrinsic_inline_sizes = computation.finish()
}
Expand Down Expand Up @@ -359,9 +372,9 @@ impl Flow for TableFlow {
let inline_end_content_edge = self.block_flow.fragment.border_padding.inline_end;
let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end();
let spacing_per_cell = self.spacing();
let spacing = self.total_horizontal_spacing();
let content_inline_size =
self.block_flow.fragment.border_box.size.inline - padding_and_borders - spacing;
let total_horizontal_spacing = self.total_horizontal_spacing();
let content_inline_size = self.block_flow.fragment.border_box.size.inline -
padding_and_borders - total_horizontal_spacing;

match self.table_layout {
TableLayout::Fixed => {
Expand Down
119 changes: 71 additions & 48 deletions components/layout/table_wrapper.rs
Expand Up @@ -29,7 +29,7 @@ use std::cmp::{max, min};
use std::fmt;
use std::ops::Add;
use std::sync::Arc;
use style::computed_values::{border_collapse, table_layout};
use style::computed_values::{border_collapse, position, table_layout};
use style::context::SharedStyleContext;
use style::logical_geometry::{LogicalRect, LogicalSize};
use style::properties::ServoComputedValues;
Expand Down Expand Up @@ -90,56 +90,35 @@ impl TableWrapperFlow {
(table_border_padding, spacing)
}

/// Calculates table column sizes for automatic layout per INTRINSIC § 4.3.
fn calculate_table_column_sizes_for_automatic_layout(
&mut self,
intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize]) {
// Find the padding and border of our first child, which is the table itself.
//
// This is a little weird because we're computing border/padding/margins for our child,
// when normally the child computes it itself. But it has to be this way because the
// padding will affect where we place the child. This is an odd artifact of the way that
// tables are separated into table flows and table wrapper flows.
let available_inline_size = self.block_flow.fragment.border_box.size.inline;
// Instructs our first child, which is the table itself, to compute its border and padding.
//
// This is a little weird because we're computing border/padding/margins for our child,
// when normally the child computes it itself. But it has to be this way because the
// padding will affect where we place the child. This is an odd artifact of the way that
// tables are separated into table flows and table wrapper flows.
fn compute_border_and_padding_of_table(&mut self) {
let available_inline_size = self.block_flow.base.block_container_inline_size;
let border_collapse = self.block_flow.fragment.style.get_inheritedtable().border_collapse;
for kid in self.block_flow.base.child_iter_mut() {
if !kid.is_table() {
continue
}

let kid_table = kid.as_mut_table();
let kid_block_flow = &mut kid_table.block_flow;
kid_block_flow.fragment
.compute_border_and_padding(available_inline_size,
self.block_flow
.fragment
.style
.get_inheritedtable()
.border_collapse);
kid_block_flow.fragment.compute_border_and_padding(available_inline_size,
border_collapse);
kid_block_flow.fragment.compute_block_direction_margins(available_inline_size);
kid_block_flow.fragment.compute_inline_direction_margins(available_inline_size);
break
return
}
}

let (table_border_padding, spacing) = self.border_padding_and_spacing();

// FIXME(pcwalton, spec): INTRINSIC § 8 does not properly define how to compute this, but
// says "the basic idea is the same as the shrink-to-fit width that CSS2.1 defines". So we
// just use the shrink-to-fit inline size.
let mut available_inline_size =
match self.block_flow.fragment.style().content_inline_size() {
LengthOrPercentageOrAuto::Auto => {
self.block_flow.get_shrink_to_fit_inline_size(available_inline_size)
}
// FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm
// not completely sure this is "correct".
//
// That said, `available_inline_size` is, as far as I can tell, equal to the
// table's computed width property (W) and is used from this point forward in a way
// that seems to correspond with CSS 2.1 § 17.5.2.2 under "Column and caption
// widths influence the final table width as follows: …"
_ => available_inline_size,
};
available_inline_size = available_inline_size - spacing;
/// Calculates table column sizes for automatic layout per INTRINSIC § 4.3.
fn calculate_table_column_sizes_for_automatic_layout(
&mut self,
intermediate_column_inline_sizes: &mut [IntermediateColumnInlineSize]) {
let available_inline_size = self.available_inline_size();

// Compute all the guesses for the column sizes, and sum them.
let mut total_guess = AutoLayoutCandidateGuess::new();
Expand Down Expand Up @@ -187,8 +166,35 @@ impl TableWrapperFlow {
total_used_inline_size = available_inline_size
}

self.set_inline_size(total_used_inline_size)
}

fn available_inline_size(&mut self) -> Au {
let available_inline_size = self.block_flow.fragment.border_box.size.inline;
let (table_border_padding, spacing) = self.border_padding_and_spacing();

// FIXME(pcwalton, spec): INTRINSIC § 8 does not properly define how to compute this, but
// says "the basic idea is the same as the shrink-to-fit width that CSS2.1 defines". So we
// just use the shrink-to-fit inline size.
let available_inline_size = match self.block_flow.fragment.style().content_inline_size() {
LengthOrPercentageOrAuto::Auto => {
self.block_flow.get_shrink_to_fit_inline_size(available_inline_size) -
table_border_padding
}
// FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm not
// completely sure this is "correct".
//
// That said, `available_inline_size` is, as far as I can tell, equal to the table's
// computed width property (W) and is used from this point forward in a way that seems
// to correspond with CSS 2.1 § 17.5.2.2 under "Column and caption widths influence the
// final table width as follows: …"
_ => available_inline_size,
};
available_inline_size - spacing
}

fn set_inline_size(&mut self, total_used_inline_size: Au) {
let (table_border_padding, spacing) = self.border_padding_and_spacing();
self.block_flow.fragment.border_box.size.inline = total_used_inline_size +
table_border_padding + spacing;
self.block_flow.base.position.size.inline = total_used_inline_size +
Expand Down Expand Up @@ -234,6 +240,7 @@ impl TableWrapperFlow {
minimum_width_of_all_columns: minimum_width_of_all_columns,
preferred_width_of_all_columns: preferred_width_of_all_columns,
border_collapse: border_collapse,
table_border_padding: border_padding,
};
let input =
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow,
Expand All @@ -254,6 +261,7 @@ impl TableWrapperFlow {
minimum_width_of_all_columns: minimum_width_of_all_columns,
preferred_width_of_all_columns: preferred_width_of_all_columns,
border_collapse: border_collapse,
table_border_padding: border_padding,
};
let input =
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow,
Expand All @@ -273,6 +281,7 @@ impl TableWrapperFlow {
minimum_width_of_all_columns: minimum_width_of_all_columns,
preferred_width_of_all_columns: preferred_width_of_all_columns,
border_collapse: border_collapse,
table_border_padding: border_padding,
};
let input =
inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow,
Expand Down Expand Up @@ -349,6 +358,10 @@ impl Flow for TableWrapperFlow {
containing_block_inline_size;
}

// This has to be done before computing our inline size because `compute_used_inline_size`
// internally consults the border and padding of the table.
self.compute_border_and_padding_of_table();

self.compute_used_inline_size(shared_context,
containing_block_inline_size,
&intermediate_column_inline_sizes);
Expand Down Expand Up @@ -743,10 +756,15 @@ struct IntermediateColumnInlineSize {
percentage: f32,
}

/// Returns the computed inline size of the table wrapper represented by `block`.
///
/// `table_border_padding` is the sum of the sizes of all border and padding in the inline
/// direction of the table contained within this table wrapper.
fn initial_computed_inline_size(block: &mut BlockFlow,
containing_block_inline_size: Au,
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au)
preferred_width_of_all_columns: Au,
table_border_padding: Au)
-> MaybeAuto {
let inline_size_from_style = MaybeAuto::from_style(block.fragment.style.content_inline_size(),
containing_block_inline_size);
Expand All @@ -755,7 +773,8 @@ fn initial_computed_inline_size(block: &mut BlockFlow,
MaybeAuto::Specified(min(containing_block_inline_size, preferred_width_of_all_columns))
}
MaybeAuto::Specified(inline_size_from_style) => {
MaybeAuto::Specified(max(inline_size_from_style, minimum_width_of_all_columns))
MaybeAuto::Specified(max(inline_size_from_style - table_border_padding,
minimum_width_of_all_columns))
}
}
}
Expand All @@ -764,6 +783,7 @@ struct Table {
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
border_collapse: border_collapse::T,
table_border_padding: Au,
}

impl ISizeAndMarginsComputer for Table {
Expand All @@ -778,13 +798,12 @@ impl ISizeAndMarginsComputer for Table {
shared_context: &SharedStyleContext)
-> MaybeAuto {
let containing_block_inline_size =
self.containing_block_inline_size(block,
parent_flow_inline_size,
shared_context);
self.containing_block_inline_size(block, parent_flow_inline_size, shared_context);
initial_computed_inline_size(block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns)
self.preferred_width_of_all_columns,
self.table_border_padding)
}

fn solve_inline_size_constraints(&self,
Expand All @@ -799,6 +818,7 @@ struct FloatedTable {
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
border_collapse: border_collapse::T,
table_border_padding: Au,
}

impl ISizeAndMarginsComputer for FloatedTable {
Expand All @@ -819,7 +839,8 @@ impl ISizeAndMarginsComputer for FloatedTable {
initial_computed_inline_size(block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns)
self.preferred_width_of_all_columns,
self.table_border_padding)
}

fn solve_inline_size_constraints(&self,
Expand All @@ -834,6 +855,7 @@ struct AbsoluteTable {
minimum_width_of_all_columns: Au,
preferred_width_of_all_columns: Au,
border_collapse: border_collapse::T,
table_border_padding: Au,
}

impl ISizeAndMarginsComputer for AbsoluteTable {
Expand All @@ -854,7 +876,8 @@ impl ISizeAndMarginsComputer for AbsoluteTable {
initial_computed_inline_size(block,
containing_block_inline_size,
self.minimum_width_of_all_columns,
self.preferred_width_of_all_columns)
self.preferred_width_of_all_columns,
self.table_border_padding)
}

fn containing_block_inline_size(&self,
Expand Down

0 comments on commit d222e3e

Please sign in to comment.