layout: Assign border and padding to tables instead of table wrappers.

This is more straightforward when anonymous table object generation is
involved.
This commit is contained in:
Patrick Walton 2016-10-24 18:15:42 -07:00
parent a1bbc5d5fd
commit d222e3e8a3
3 changed files with 105 additions and 64 deletions

View file

@ -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;
@ -90,17 +90,15 @@ 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
@ -108,38 +106,19 @@ impl TableWrapperFlow {
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();
@ -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 +
@ -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,
@ -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,
@ -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,
@ -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);
@ -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);
@ -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))
}
}
}
@ -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 {
@ -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,
@ -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 {
@ -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,
@ -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 {
@ -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,