diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index af53bc606ec..61abc7fc7d5 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -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 == diff --git a/components/layout/table.rs b/components/layout/table.rs index 2d31f92dda7..a1ec2553f99 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -85,9 +85,13 @@ impl TableFlow { /// sizes. fn update_automatic_column_inline_sizes( parent_inline_sizes: &mut Vec, - 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 { @@ -139,7 +143,8 @@ impl TableFlow { column_inline_sizes: &mut Vec, 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. // @@ -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)) } } } @@ -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 { @@ -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 = @@ -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() } @@ -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 => { diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index fd01546774d..7d8deff2ac9 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -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,