diff options
Diffstat (limited to 'components/layout/table_wrapper.rs')
-rw-r--r-- | components/layout/table_wrapper.rs | 203 |
1 files changed, 156 insertions, 47 deletions
diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index 8e85604bb2c..5e321382e97 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -13,13 +13,14 @@ #![deny(unsafe_code)] -use block::{BlockFlow, BlockNonReplaced, FloatNonReplaced, ISizeAndMarginsComputer}; -use block::{MarginsMayCollapseFlag}; +use block::{BlockFlow, FloatNonReplaced, ISizeAndMarginsComputer, ISizeConstraintInput}; +use block::{ISizeConstraintSolution, MarginsMayCollapseFlag}; use context::LayoutContext; use floats::FloatKind; use flow::{FlowClass, Flow, ImmutableFlowUtils}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use fragment::{Fragment, FragmentBorderBoxIterator}; +use model::MaybeAuto; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; use table_row; use wrapper::ThreadSafeLayoutNode; @@ -31,7 +32,7 @@ use std::cmp::{max, min}; use std::fmt; use std::ops::Add; use std::sync::Arc; -use style::computed_values::table_layout; +use style::computed_values::{border_collapse, table_layout}; use style::properties::ComputedValues; use style::values::CSSFloat; use style::values::computed::LengthOrPercentageOrAuto; @@ -55,8 +56,7 @@ pub struct TableWrapperFlow { } impl TableWrapperFlow { - pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, - fragment: Fragment) + pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) -> TableWrapperFlow { let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment); let table_layout = if block_flow.fragment().style().get_table().table_layout == @@ -90,6 +90,21 @@ impl TableWrapperFlow { } } + fn border_padding_and_spacing(&mut self) -> (Au, Au) { + let (mut table_border_padding, mut spacing) = (Au(0), Au(0)); + for kid in self.block_flow.base.child_iter() { + if kid.is_table() { + let kid_table = kid.as_table(); + let spacing_per_cell = kid_table.spacing().horizontal; + spacing = spacing_per_cell * (self.column_intrinsic_inline_sizes.len() as i32 + 1); + table_border_padding = + kid_table.block_flow.fragment.border_padding.inline_start_end(); + break + } + } + (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, @@ -100,20 +115,13 @@ impl TableWrapperFlow { // 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. - // - // FIXME(pcwalton): Handle `border-collapse` correctly. - let mut available_inline_size = self.block_flow.fragment.border_box.size.inline; - let (mut table_border_padding, mut spacing) = (Au(0), Au(0)); + let available_inline_size = self.block_flow.fragment.border_box.size.inline; for kid in self.block_flow.base.child_iter() { if !kid.is_table() { continue } let kid_table = kid.as_table(); - let spacing_per_cell = kid_table.spacing().horizontal; - spacing = spacing_per_cell * (self.column_intrinsic_inline_sizes.len() as i32 + 1); - available_inline_size = self.block_flow.fragment.border_box.size.inline; - let kid_block_flow = &mut kid_table.block_flow; kid_block_flow.fragment .compute_border_and_padding(available_inline_size, @@ -124,10 +132,11 @@ impl TableWrapperFlow { .border_collapse); kid_block_flow.fragment.compute_block_direction_margins(available_inline_size); kid_block_flow.fragment.compute_inline_direction_margins(available_inline_size); - table_border_padding = kid_block_flow.fragment.border_padding.inline_start_end(); break } + 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. @@ -201,37 +210,55 @@ impl TableWrapperFlow { table_border_padding + spacing + self.block_flow.fragment.margin.inline_start_end(); } - fn compute_used_inline_size(&mut self, - layout_context: &LayoutContext, - parent_flow_inline_size: Au) { - // Delegate to the appropriate inline size computer to find the constraint inputs. + fn compute_used_inline_size( + &mut self, + layout_context: &LayoutContext, + parent_flow_inline_size: Au, + intermediate_column_inline_sizes: &[IntermediateColumnInlineSize]) { + let (border_padding, spacing) = self.border_padding_and_spacing(); + let minimum_width_of_all_columns = + intermediate_column_inline_sizes.iter() + .fold(border_padding + spacing, + |accumulator, intermediate_column_inline_sizes| { + accumulator + intermediate_column_inline_sizes.size + }); + + // Delegate to the appropriate inline size computer to find the constraint inputs and write + // the constraint solutions in. let border_collapse = self.block_flow.fragment.style.get_inheritedtable().border_collapse; - let input = if self.block_flow.base.flags.is_float() { - FloatNonReplaced.compute_inline_size_constraint_inputs(&mut self.block_flow, - parent_flow_inline_size, - layout_context, - border_collapse) - } else { - BlockNonReplaced.compute_inline_size_constraint_inputs(&mut self.block_flow, - parent_flow_inline_size, - layout_context, - border_collapse) - }; - - // Delegate to the appropriate inline size computer to write the constraint solutions in. if self.block_flow.base.flags.is_float() { - let solution = FloatNonReplaced.solve_inline_size_constraints(&mut self.block_flow, - &input); - FloatNonReplaced.set_inline_size_constraint_solutions(&mut self.block_flow, solution); - FloatNonReplaced.set_inline_position_of_flow_if_necessary(&mut self.block_flow, + let inline_size_computer = FloatedTable { + minimum_width_of_all_columns: minimum_width_of_all_columns, + border_collapse: border_collapse, + }; + let input = + inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow, + parent_flow_inline_size, + layout_context); + + let solution = inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, + &input); + inline_size_computer.set_inline_size_constraint_solutions(&mut self.block_flow, solution); - } else { - let solution = BlockNonReplaced.solve_inline_size_constraints(&mut self.block_flow, + inline_size_computer.set_inline_position_of_flow_if_necessary(&mut self.block_flow, + solution); + return + } + + let inline_size_computer = Table { + minimum_width_of_all_columns: minimum_width_of_all_columns, + border_collapse: border_collapse, + }; + let input = + inline_size_computer.compute_inline_size_constraint_inputs(&mut self.block_flow, + parent_flow_inline_size, + layout_context); + + let solution = inline_size_computer.solve_inline_size_constraints(&mut self.block_flow, &input); - BlockNonReplaced.set_inline_size_constraint_solutions(&mut self.block_flow, solution); - BlockNonReplaced.set_inline_position_of_flow_if_necessary(&mut self.block_flow, + inline_size_computer.set_inline_size_constraint_solutions(&mut self.block_flow, solution); + inline_size_computer.set_inline_position_of_flow_if_necessary(&mut self.block_flow, solution); - } } } @@ -294,14 +321,13 @@ impl Flow for TableWrapperFlow { containing_block_inline_size; } - self.compute_used_inline_size(layout_context, containing_block_inline_size); + self.compute_used_inline_size(layout_context, + containing_block_inline_size, + intermediate_column_inline_sizes.as_slice()); - match self.table_layout { - TableLayout::Fixed => {} - TableLayout::Auto => { - self.calculate_table_column_sizes_for_automatic_layout( - &mut intermediate_column_inline_sizes) - } + if let TableLayout::Auto = self.table_layout { + self.calculate_table_column_sizes_for_automatic_layout( + &mut intermediate_column_inline_sizes) } let inline_start_content_edge = self.block_flow.fragment.border_box.start.i; @@ -679,3 +705,86 @@ struct IntermediateColumnInlineSize { percentage: f64, } +fn initial_computed_inline_size(block: &mut BlockFlow, + containing_block_inline_size: Au, + minimum_width_of_all_columns: Au) + -> MaybeAuto { + let inline_size_from_style = MaybeAuto::from_style(block.fragment.style.content_inline_size(), + containing_block_inline_size); + match inline_size_from_style { + MaybeAuto::Auto => { + MaybeAuto::Specified(Au::max(containing_block_inline_size, + minimum_width_of_all_columns)) + } + MaybeAuto::Specified(inline_size_from_style) => { + MaybeAuto::Specified(Au::max(inline_size_from_style, minimum_width_of_all_columns)) + } + } +} + +struct Table { + minimum_width_of_all_columns: Au, + border_collapse: border_collapse::T, +} + +impl ISizeAndMarginsComputer for Table { + fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) { + block.fragment.compute_border_and_padding(containing_block_inline_size, + self.border_collapse) + } + + fn initial_computed_inline_size(&self, + block: &mut BlockFlow, + parent_flow_inline_size: Au, + layout_context: &LayoutContext) + -> MaybeAuto { + let containing_block_inline_size = + self.containing_block_inline_size(block, + parent_flow_inline_size, + layout_context); + initial_computed_inline_size(block, + containing_block_inline_size, + self.minimum_width_of_all_columns) + } + + fn solve_inline_size_constraints(&self, + block: &mut BlockFlow, + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + self.solve_block_inline_size_constraints(block, input) + } +} + +struct FloatedTable { + minimum_width_of_all_columns: Au, + border_collapse: border_collapse::T, +} + +impl ISizeAndMarginsComputer for FloatedTable { + fn compute_border_and_padding(&self, block: &mut BlockFlow, containing_block_inline_size: Au) { + block.fragment.compute_border_and_padding(containing_block_inline_size, + self.border_collapse) + } + + fn initial_computed_inline_size(&self, + block: &mut BlockFlow, + parent_flow_inline_size: Au, + layout_context: &LayoutContext) + -> MaybeAuto { + let containing_block_inline_size = + self.containing_block_inline_size(block, + parent_flow_inline_size, + layout_context); + initial_computed_inline_size(block, + containing_block_inline_size, + self.minimum_width_of_all_columns) + } + + fn solve_inline_size_constraints(&self, + block: &mut BlockFlow, + input: &ISizeConstraintInput) + -> ISizeConstraintSolution { + FloatNonReplaced.solve_inline_size_constraints(block, input) + } +} + |