diff options
-rw-r--r-- | components/layout/block.rs | 26 | ||||
-rw-r--r-- | components/layout/flow.rs | 16 | ||||
-rw-r--r-- | components/layout/table.rs | 103 | ||||
-rw-r--r-- | components/layout/table_cell.rs | 4 | ||||
-rw-r--r-- | components/layout/table_row.rs | 39 | ||||
-rw-r--r-- | components/layout/table_rowgroup.rs | 85 | ||||
-rw-r--r-- | components/layout/table_wrapper.rs | 155 |
7 files changed, 243 insertions, 185 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs index 6b141b1e749..8e8920e4033 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -47,7 +47,7 @@ use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use layout_debug; use model::{Auto, IntrinsicISizes, MarginCollapseInfo, MarginsCollapse, MarginsCollapseThrough}; use model::{MaybeAuto, NoCollapsibleMargins, Specified, specified, specified_or_none}; -use table::ColumnInlineSize; +use table::ColumnComputedInlineSize; use wrapper::ThreadSafeLayoutNode; use geom::Size2D; @@ -1258,7 +1258,7 @@ impl BlockFlow { &mut self, inline_start_content_edge: Au, content_inline_size: Au, - optional_column_inline_sizes: Option<&[ColumnInlineSize]>) { + optional_column_computed_inline_sizes: Option<&[ColumnComputedInlineSize]>) { // Keep track of whether floats could impact each child. let mut inline_start_floats_impact_child = self.base.flags.contains(IMPACTED_BY_LEFT_FLOATS); @@ -1369,12 +1369,12 @@ impl BlockFlow { } // Handle tables. - match optional_column_inline_sizes { - Some(ref column_inline_sizes) => { + match optional_column_computed_inline_sizes { + Some(ref column_computed_inline_sizes) => { propagate_column_inline_sizes_to_child(kid, i, content_inline_size, - *column_inline_sizes, + *column_computed_inline_sizes, &mut inline_start_margin_edge) } None => {} @@ -2551,22 +2551,24 @@ impl ISizeAndMarginsComputer for FloatReplaced { } } -fn propagate_column_inline_sizes_to_child(kid: &mut Flow, - child_index: uint, - content_inline_size: Au, - column_inline_sizes: &[ColumnInlineSize], - inline_start_margin_edge: &mut Au) { +fn propagate_column_inline_sizes_to_child( + kid: &mut Flow, + child_index: uint, + content_inline_size: Au, + column_computed_inline_sizes: &[ColumnComputedInlineSize], + inline_start_margin_edge: &mut Au) { // If kid is table_rowgroup or table_row, the column inline-sizes info should be copied from // its parent. // // FIXME(pcwalton): This seems inefficient. Reference count it instead? let inline_size = if kid.is_table() || kid.is_table_rowgroup() || kid.is_table_row() { - *kid.column_inline_sizes() = column_inline_sizes.iter().map(|&x| x).collect(); + *kid.column_computed_inline_sizes() = + column_computed_inline_sizes.iter().map(|&x| x).collect(); // ISize of kid flow is our content inline-size. content_inline_size } else if kid.is_table_cell() { - column_inline_sizes[child_index].minimum_length + column_computed_inline_sizes[child_index].size } else { // ISize of kid flow is our content inline-size. content_inline_size diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 598a8717cdb..5435cacbe67 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -38,7 +38,7 @@ use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage}; use inline::InlineFlow; use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo}; use parallel::FlowParallelInfo; -use table::{ColumnInlineSize, TableFlow}; +use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, TableFlow}; use table_caption::TableCaptionFlow; use table_cell::TableCellFlow; use table_colgroup::TableColGroupFlow; @@ -163,10 +163,16 @@ pub trait Flow: fmt::Show + ToString + Sync { panic!("called as_table_cell() on a non-tablecell flow") } - /// If this is a table row or table rowgroup or table flow, returns column inline-sizes. - /// Fails otherwise. - fn column_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnInlineSize> { - panic!("called column_inline_sizes() on non-table flow") + /// If this is a table row, table rowgroup, or table flow, returns column intrinsic + /// inline-sizes. Fails otherwise. + fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> { + panic!("called column_intrinsic_inline_sizes() on non-table flow") + } + + /// If this is a table row, table rowgroup, or table flow, returns column computed + /// inline-sizes. Fails otherwise. + fn column_computed_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnComputedInlineSize> { + panic!("called column_intrinsic_inline_sizes() on non-table flow") } // Main methods diff --git a/components/layout/table.rs b/components/layout/table.rs index 20bc19c91fc..b65fa689919 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -34,8 +34,13 @@ use sync::Arc; pub struct TableFlow { pub block_flow: BlockFlow, - /// Information about the inline-sizes of each column. - pub column_inline_sizes: Vec<ColumnInlineSize>, + /// Information about the intrinsic inline-sizes of each column, computed bottom-up during + /// intrinsic inline-size bubbling. + pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>, + + /// Information about the actual inline-sizes of each column, computed top-down during actual + /// inline-size bubbling. + pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>, /// Table-layout property pub table_layout: TableLayout, @@ -54,7 +59,8 @@ impl TableFlow { }; TableFlow { block_flow: block_flow, - column_inline_sizes: Vec::new(), + column_intrinsic_inline_sizes: Vec::new(), + column_computed_inline_sizes: Vec::new(), table_layout: table_layout } } @@ -71,7 +77,8 @@ impl TableFlow { }; TableFlow { block_flow: block_flow, - column_inline_sizes: Vec::new(), + column_intrinsic_inline_sizes: Vec::new(), + column_computed_inline_sizes: Vec::new(), table_layout: table_layout } } @@ -89,7 +96,8 @@ impl TableFlow { }; TableFlow { block_flow: block_flow, - column_inline_sizes: Vec::new(), + column_intrinsic_inline_sizes: Vec::new(), + column_computed_inline_sizes: Vec::new(), table_layout: table_layout } } @@ -97,13 +105,13 @@ impl TableFlow { /// Update the corresponding value of `self_inline_sizes` if a value of `kid_inline_sizes` has /// a larger value than one of `self_inline_sizes`. Returns the minimum and preferred inline /// sizes. - pub fn update_column_inline_sizes(parent_inline_sizes: &mut Vec<ColumnInlineSize>, - child_inline_sizes: &Vec<ColumnInlineSize>) + pub fn update_column_inline_sizes(parent_inline_sizes: &mut Vec<ColumnIntrinsicInlineSize>, + child_inline_sizes: &Vec<ColumnIntrinsicInlineSize>) -> IntrinsicISizes { let mut total_inline_sizes = IntrinsicISizes::new(); for (parent_sizes, child_sizes) in parent_inline_sizes.iter_mut() .zip(child_inline_sizes.iter()) { - *parent_sizes = ColumnInlineSize { + *parent_sizes = ColumnIntrinsicInlineSize { minimum_length: max(parent_sizes.minimum_length, child_sizes.minimum_length), percentage: parent_sizes.greatest_percentage(child_sizes), preferred: max(parent_sizes.preferred, child_sizes.preferred), @@ -147,8 +155,12 @@ impl Flow for TableFlow { &mut self.block_flow } - fn column_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnInlineSize> { - &mut self.column_inline_sizes + fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> { + &mut self.column_intrinsic_inline_sizes + } + + fn column_computed_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnComputedInlineSize> { + &mut self.column_computed_inline_sizes } /// The specified column inline-sizes are set from column group and the first row for the fixed @@ -165,7 +177,7 @@ impl Flow for TableFlow { debug_assert!(kid.is_proper_table_child()); if kid.is_table_colgroup() { for specified_inline_size in kid.as_table_colgroup().inline_sizes.iter() { - self.column_inline_sizes.push(ColumnInlineSize { + self.column_intrinsic_inline_sizes.push(ColumnIntrinsicInlineSize { minimum_length: match *specified_inline_size { LPA_Auto | LPA_Percentage(_) => Au(0), LPA_Length(length) => length, @@ -188,25 +200,26 @@ impl Flow for TableFlow { // Fixed table layout only looks at the first row. if !did_first_row { did_first_row = true; - for child_column_inline_size in kid.column_inline_sizes().iter() { - self.column_inline_sizes.push(*child_column_inline_size); + for child_column_inline_size in kid.column_intrinsic_inline_sizes() + .iter() { + self.column_intrinsic_inline_sizes.push(*child_column_inline_size); } } } AutoLayout => { - let child_column_inline_sizes = kid.column_inline_sizes(); - let mut child_intrinsic_sizes = - TableFlow::update_column_inline_sizes(&mut self.column_inline_sizes, - child_column_inline_sizes); + let child_column_inline_sizes = kid.column_intrinsic_inline_sizes(); + let mut child_intrinsic_sizes = TableFlow::update_column_inline_sizes( + &mut self.column_intrinsic_inline_sizes, + child_column_inline_sizes); // Add new columns if processing this row caused us to discover them. let child_column_count = child_column_inline_sizes.len(); - let parent_column_count = self.column_inline_sizes.len(); + let parent_column_count = self.column_intrinsic_inline_sizes.len(); debug!("table until the previous row has {} column(s) and this row has {} \ column(s)", parent_column_count, child_column_count); - self.column_inline_sizes.reserve(child_column_count); + self.column_intrinsic_inline_sizes.reserve(child_column_count); for i in range(parent_column_count, child_column_count) { let inline_size_for_new_column = (*child_column_inline_sizes)[i]; child_intrinsic_sizes.minimum_inline_size = @@ -215,7 +228,7 @@ impl Flow for TableFlow { child_intrinsic_sizes.preferred_inline_size = child_intrinsic_sizes.preferred_inline_size + inline_size_for_new_column.preferred; - self.column_inline_sizes.push(inline_size_for_new_column); + self.column_intrinsic_inline_sizes.push(inline_size_for_new_column); } computation.union_block(&child_intrinsic_sizes) @@ -239,7 +252,7 @@ impl Flow for TableFlow { let mut num_unspecified_inline_sizes = 0; let mut total_column_inline_size = Au(0); - for column_inline_size in self.column_inline_sizes.iter() { + for column_inline_size in self.column_intrinsic_inline_sizes.iter() { let this_column_inline_size = column_inline_size.minimum_length; if this_column_inline_size == Au(0) { num_unspecified_inline_sizes += 1 @@ -263,28 +276,38 @@ impl Flow for TableFlow { FixedLayout => { // In fixed table layout, we distribute extra space among the unspecified columns // if there are any, or among all the columns if all are specified. + self.column_computed_inline_sizes.clear(); if total_column_inline_size < content_inline_size && num_unspecified_inline_sizes == 0 { - let ratio = content_inline_size.to_subpx() / total_column_inline_size.to_subpx(); - for column_inline_size in self.column_inline_sizes.iter_mut() { - column_inline_size.minimum_length = column_inline_size.minimum_length.scale_by(ratio); - column_inline_size.percentage = 0.0; + let ratio = content_inline_size.to_subpx() / + total_column_inline_size.to_subpx(); + for column_inline_size in self.column_intrinsic_inline_sizes.iter() { + self.column_computed_inline_sizes.push(ColumnComputedInlineSize { + size: column_inline_size.minimum_length.scale_by(ratio), + }); } } else if num_unspecified_inline_sizes != 0 { let extra_column_inline_size = (content_inline_size - total_column_inline_size) / num_unspecified_inline_sizes; - for column_inline_size in self.column_inline_sizes.iter_mut() { + for column_inline_size in self.column_intrinsic_inline_sizes.iter() { if column_inline_size.minimum_length == Au(0) && column_inline_size.percentage == 0.0 { - column_inline_size.minimum_length = extra_column_inline_size / - num_unspecified_inline_sizes + self.column_computed_inline_sizes.push(ColumnComputedInlineSize { + size: extra_column_inline_size / num_unspecified_inline_sizes, + }); + } else { + self.column_computed_inline_sizes.push(ColumnComputedInlineSize { + size: column_inline_size.minimum_length, + }); } - column_inline_size.percentage = 0.0; } } } - _ => {} + _ => { + // The table wrapper already computed the inline-sizes and propagated them down + // to us. + } } // As tables are always wrapped inside a table wrapper, they are never impacted by floats. @@ -294,7 +317,7 @@ impl Flow for TableFlow { self.block_flow.propagate_assigned_inline_size_to_children( inline_start_content_edge, content_inline_size, - Some(self.column_inline_sizes.as_slice())); + Some(self.column_computed_inline_sizes.as_slice())); } fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) { @@ -365,7 +388,7 @@ impl ISizeAndMarginsComputer for InternalTable { } } -/// Information about the inline sizes of columns within a table. +/// Information about the intrinsic inline sizes of columns within a table. /// /// During table inline-size bubbling, we might need to store both a percentage constraint and a /// specific width constraint. For instance, one cell might say that it wants to be 100 pixels wide @@ -377,7 +400,7 @@ impl ISizeAndMarginsComputer for InternalTable { /// potentially store both a specified width *and* a specified percentage, so that the inline-size /// assignment phase of layout will know which one to pick. #[deriving(Clone, Encodable, Show)] -pub struct ColumnInlineSize { +pub struct ColumnIntrinsicInlineSize { /// The preferred intrinsic inline size. pub preferred: Au, /// The largest specified size of this column as a length. @@ -388,7 +411,7 @@ pub struct ColumnInlineSize { pub constrained: bool, } -impl ColumnInlineSize { +impl ColumnIntrinsicInlineSize { /// Returns the true minimum size of this column, given the containing block's inline size. /// Beware that this is generally only correct for fixed table layout. (Compare CSS 2.1 § /// 17.5.2.1 with the algorithm in INTRINSIC § 4.) @@ -397,7 +420,7 @@ impl ColumnInlineSize { } /// Returns the higher of the two percentages specified in `self` and `other`. - pub fn greatest_percentage(&self, other: &ColumnInlineSize) -> CSSFloat { + pub fn greatest_percentage(&self, other: &ColumnIntrinsicInlineSize) -> CSSFloat { if self.percentage > other.percentage { self.percentage } else { @@ -405,3 +428,13 @@ impl ColumnInlineSize { } } } + +/// The actual inline size for each column. +/// +/// TODO(pcwalton): There will probably be some `border-collapse`-related info in here too +/// eventually. +#[deriving(Encodable)] +pub struct ColumnComputedInlineSize { + /// The computed size of this inline column. + pub size: Au, +} diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 9fc6c17b52b..7dbfa3d678c 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -45,10 +45,8 @@ impl TableCellFlow { /// Assign block-size for table-cell flow. /// - /// TODO(#2015, pcwalton): This doesn't handle floats right. - /// /// inline(always) because this is only ever called by in-order or non-in-order top-level - /// methods + /// methods. #[inline(always)] fn assign_block_size_table_cell_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse) diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index 4c12ef1ef87..5ecdac0b5b4 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -14,7 +14,7 @@ use flow::{TableRowFlowClass, FlowClass, Flow, ImmutableFlowUtils}; use flow; use fragment::{Fragment, FragmentBoundsIterator}; use layout_debug; -use table::{ColumnInlineSize, InternalTable}; +use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; use model::{MaybeAuto, Specified, Auto}; use wrapper::ThreadSafeLayoutNode; @@ -30,8 +30,11 @@ use sync::Arc; pub struct TableRowFlow { pub block_flow: BlockFlow, - /// Information about the inline-sizes of each column. - pub column_inline_sizes: Vec<ColumnInlineSize>, + /// Information about the intrinsic inline-sizes of each column. + pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>, + + /// Information about the computed inline-sizes of each column. + pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>, } impl TableRowFlow { @@ -40,7 +43,8 @@ impl TableRowFlow { -> TableRowFlow { TableRowFlow { block_flow: BlockFlow::from_node_and_fragment(node, fragment), - column_inline_sizes: Vec::new() + column_intrinsic_inline_sizes: Vec::new(), + column_computed_inline_sizes: Vec::new(), } } @@ -49,7 +53,8 @@ impl TableRowFlow { -> TableRowFlow { TableRowFlow { block_flow: BlockFlow::from_node(constructor, node), - column_inline_sizes: Vec::new() + column_intrinsic_inline_sizes: Vec::new(), + column_computed_inline_sizes: Vec::new(), } } @@ -150,8 +155,12 @@ impl Flow for TableRowFlow { &mut self.block_flow } - fn column_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnInlineSize> { - &mut self.column_inline_sizes + fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> { + &mut self.column_intrinsic_inline_sizes + } + + fn column_computed_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnComputedInlineSize> { + &mut self.column_computed_inline_sizes } /// Recursively (bottom-up) determines the context's preferred and minimum inline-sizes. When @@ -180,7 +189,7 @@ impl Flow for TableRowFlow { // Collect minimum and preferred inline-sizes of the cell for automatic table layout // calculation. let child_base = flow::mut_base(kid); - let child_column_inline_size = ColumnInlineSize { + let child_column_inline_size = ColumnIntrinsicInlineSize { minimum_length: match child_specified_inline_size { LPA_Auto | LPA_Percentage(_) => { child_base.intrinsic_inline_sizes.minimum_inline_size @@ -199,7 +208,7 @@ impl Flow for TableRowFlow { }; min_inline_size = min_inline_size + child_column_inline_size.minimum_length; pref_inline_size = pref_inline_size + child_column_inline_size.preferred; - self.column_inline_sizes.push(child_column_inline_size); + self.column_intrinsic_inline_sizes.push(child_column_inline_size); } self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size; self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size, @@ -208,7 +217,7 @@ impl Flow for TableRowFlow { /// Recursively (top-down) determines the actual inline-size of child contexts and fragments. /// When called on this context, the context has had its inline-size set by the parent context. - fn assign_inline_sizes(&mut self, ctx: &LayoutContext) { + fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { let _scope = layout_debug_scope!("table_row::assign_inline_sizes {:x}", self.block_flow.base.debug_id()); debug!("assign_inline_sizes({}): assigning inline_size for flow", "table_row"); @@ -221,13 +230,13 @@ impl Flow for TableRowFlow { let inline_size_computer = InternalTable; inline_size_computer.compute_used_inline_size(&mut self.block_flow, - ctx, + layout_context, containing_block_inline_size); - self.block_flow - .propagate_assigned_inline_size_to_children(inline_start_content_edge, - containing_block_inline_size, - Some(self.column_inline_sizes.as_slice())); + self.block_flow.propagate_assigned_inline_size_to_children( + inline_start_content_edge, + containing_block_inline_size, + Some(self.column_computed_inline_sizes.as_slice())); } fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) { diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index 865c0a3c081..0b9d37d1182 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -6,16 +6,14 @@ #![deny(unsafe_blocks)] -use block::BlockFlow; -use block::ISizeAndMarginsComputer; +use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayNotCollapse}; use construct::FlowConstructor; use context::LayoutContext; use flow::{TableRowGroupFlowClass, FlowClass, Flow, ImmutableFlowUtils}; -use flow; use fragment::{Fragment, FragmentBoundsIterator}; use layout_debug; use model::IntrinsicISizesContribution; -use table::{ColumnInlineSize, InternalTable, TableFlow}; +use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable, TableFlow}; use wrapper::ThreadSafeLayoutNode; use servo_util::geometry::Au; @@ -28,26 +26,29 @@ use sync::Arc; pub struct TableRowGroupFlow { pub block_flow: BlockFlow, - /// Information about the inline-sizes of each column. - pub column_inline_sizes: Vec<ColumnInlineSize>, + /// Information about the intrinsic inline-sizes of each column. + pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>, + + /// Information about the actual inline sizes of each column. + pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>, } impl TableRowGroupFlow { - pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, - fragment: Fragment) + pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) -> TableRowGroupFlow { TableRowGroupFlow { block_flow: BlockFlow::from_node_and_fragment(node, fragment), - column_inline_sizes: Vec::new(), + column_intrinsic_inline_sizes: Vec::new(), + column_computed_inline_sizes: Vec::new(), } } - pub fn from_node(constructor: &mut FlowConstructor, - node: &ThreadSafeLayoutNode) + pub fn from_node(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> TableRowGroupFlow { TableRowGroupFlow { block_flow: BlockFlow::from_node(constructor, node), - column_inline_sizes: Vec::new(), + column_intrinsic_inline_sizes: Vec::new(), + column_computed_inline_sizes: Vec::new(), } } @@ -55,41 +56,13 @@ impl TableRowGroupFlow { &self.block_flow.fragment } - fn initialize_offsets(&mut self) -> (Au, Au, Au) { - // TODO: If border-collapse: collapse, block-start_offset, block-end_offset, and - // inline-start_offset should be updated. Currently, they are set as Au(0). - (Au(0), Au(0), Au(0)) - } - /// Assign block-size for table-rowgroup flow. /// - /// FIXME(pcwalton): This doesn't handle floats right. - /// /// inline(always) because this is only ever called by in-order or non-in-order top-level - /// methods + /// methods. #[inline(always)] fn assign_block_size_table_rowgroup_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { - let (block_start_offset, _, _) = self.initialize_offsets(); - - let mut cur_y = block_start_offset; - - for kid in self.block_flow.base.child_iter() { - kid.place_float_if_applicable(layout_context); - if !flow::base(kid).flags.is_float() { - kid.assign_block_size_for_inorder_child_if_necessary(layout_context); - } - - let child_node = flow::mut_base(kid); - child_node.position.start.b = cur_y; - cur_y = cur_y + child_node.position.size.block; - } - - let block_size = cur_y - block_start_offset; - - let mut position = self.block_flow.fragment.border_box; - position.size.block = block_size; - self.block_flow.fragment.border_box = position; - self.block_flow.base.position.size.block = block_size; + self.block_flow.assign_block_size_block_base(layout_context, MarginsMayNotCollapse) } } @@ -110,10 +83,15 @@ impl Flow for TableRowGroupFlow { &mut self.block_flow } - fn column_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnInlineSize> { - &mut self.column_inline_sizes + fn column_intrinsic_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnIntrinsicInlineSize> { + &mut self.column_intrinsic_inline_sizes } + fn column_computed_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<ColumnComputedInlineSize> { + &mut self.column_computed_inline_sizes + } + + /// Recursively (bottom-up) determines the context's preferred and minimum inline-sizes. When /// called on this context, all child contexts have had their min/pref inline-sizes set. This /// function must decide min/pref inline-sizes based on child context inline-sizes and @@ -132,20 +110,19 @@ impl Flow for TableRowGroupFlow { assert!(kid.is_table_row()); // Calculate minimum and preferred inline sizes for automatic table layout. - if self.column_inline_sizes.is_empty() { + if self.column_intrinsic_inline_sizes.is_empty() { // We're the first row. - debug_assert!(self.column_inline_sizes.is_empty()); - self.column_inline_sizes = kid.column_inline_sizes().clone(); + self.column_intrinsic_inline_sizes = kid.column_intrinsic_inline_sizes().clone(); } else { let mut child_intrinsic_sizes = - TableFlow::update_column_inline_sizes(&mut self.column_inline_sizes, - kid.column_inline_sizes()); + TableFlow::update_column_inline_sizes(&mut self.column_intrinsic_inline_sizes, + kid.column_intrinsic_inline_sizes()); // update the number of column inline-sizes from table-rows. - let column_count = self.column_inline_sizes.len(); - let child_column_count = kid.column_inline_sizes().len(); + let column_count = self.column_intrinsic_inline_sizes.len(); + let child_column_count = kid.column_intrinsic_inline_sizes().len(); for i in range(column_count, child_column_count) { - let this_column_inline_size = (*kid.column_inline_sizes())[i]; + let this_column_inline_size = (*kid.column_intrinsic_inline_sizes())[i]; // FIXME(pcwalton): Ignoring the percentage here seems dubious. child_intrinsic_sizes.minimum_inline_size = @@ -154,7 +131,7 @@ impl Flow for TableRowGroupFlow { child_intrinsic_sizes.preferred_inline_size = child_intrinsic_sizes.preferred_inline_size + this_column_inline_size.preferred; - self.column_inline_sizes.push(this_column_inline_size); + self.column_intrinsic_inline_sizes.push(this_column_inline_size); } computation.union_block(&child_intrinsic_sizes) @@ -186,7 +163,7 @@ impl Flow for TableRowGroupFlow { self.block_flow.propagate_assigned_inline_size_to_children( inline_start_content_edge, content_inline_size, - Some(self.column_inline_sizes.as_slice())); + Some(self.column_computed_inline_sizes.as_slice())); } fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) { diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index 7ec0ed874a4..5003dca66c1 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -21,7 +21,7 @@ use floats::FloatKind; use flow::{TableWrapperFlowClass, FlowClass, Flow, ImmutableFlowUtils}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use fragment::{Fragment, FragmentBoundsIterator}; -use table::ColumnInlineSize; +use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; use wrapper::ThreadSafeLayoutNode; use servo_util::geometry::Au; @@ -43,13 +43,7 @@ pub struct TableWrapperFlow { pub block_flow: BlockFlow, /// Intrinsic column inline sizes according to INTRINSIC § 4.1 - pub intrinsic_column_inline_sizes: Vec<ColumnInlineSize>, - - /// Computed inline-size for each column. - /// - /// FIXME: This should be a separate type that only contains computed inline - /// sizes. - pub column_inline_sizes: Vec<ColumnInlineSize>, + pub column_intrinsic_inline_sizes: Vec<ColumnIntrinsicInlineSize>, /// Table-layout property pub table_layout: TableLayout, @@ -68,8 +62,7 @@ impl TableWrapperFlow { }; TableWrapperFlow { block_flow: block_flow, - intrinsic_column_inline_sizes: vec!(), - column_inline_sizes: vec!(), + column_intrinsic_inline_sizes: vec!(), table_layout: table_layout } } @@ -86,8 +79,7 @@ impl TableWrapperFlow { }; TableWrapperFlow { block_flow: block_flow, - intrinsic_column_inline_sizes: vec!(), - column_inline_sizes: vec!(), + column_intrinsic_inline_sizes: vec!(), table_layout: table_layout } } @@ -105,14 +97,15 @@ impl TableWrapperFlow { }; TableWrapperFlow { block_flow: block_flow, - intrinsic_column_inline_sizes: vec!(), - column_inline_sizes: vec!(), + column_intrinsic_inline_sizes: vec!(), table_layout: table_layout } } /// Calculates table column sizes for automatic layout per INTRINSIC § 4.3. - fn calculate_table_column_sizes_for_automatic_layout(&mut self) { + 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, @@ -141,9 +134,9 @@ impl TableWrapperFlow { // Compute all the guesses for the column sizes, and sum them. let mut total_guess = AutoLayoutCandidateGuess::new(); let guesses: Vec<AutoLayoutCandidateGuess> = - self.column_inline_sizes.iter().map(|column_inline_size| { - let guess = AutoLayoutCandidateGuess::from_column_inline_size( - column_inline_size, + self.column_intrinsic_inline_sizes.iter().map(|column_intrinsic_inline_size| { + let guess = AutoLayoutCandidateGuess::from_column_intrinsic_inline_size( + column_intrinsic_inline_size, available_inline_size); total_guess = total_guess + guess; guess @@ -153,12 +146,11 @@ impl TableWrapperFlow { let selection = SelectedAutoLayoutCandidateGuess::select(&total_guess, available_inline_size); let mut total_used_inline_size = Au(0); - for (column_inline_size, guess) in self.column_inline_sizes - .iter_mut() - .zip(guesses.iter()) { - column_inline_size.minimum_length = guess.calculate(selection); - column_inline_size.percentage = 0.0; - total_used_inline_size = total_used_inline_size + column_inline_size.minimum_length + for (intermediate_column_inline_size, guess) in + intermediate_column_inline_sizes.iter_mut().zip(guesses.iter()) { + intermediate_column_inline_size.size = guess.calculate(selection); + intermediate_column_inline_size.percentage = 0.0; + total_used_inline_size = total_used_inline_size + intermediate_column_inline_size.size } // Distribute excess inline-size if necessary per INTRINSIC § 4.4. @@ -168,13 +160,17 @@ impl TableWrapperFlow { if excess_inline_size > Au(0) && selection == UsePreferredGuessAndDistributeExcessInlineSize { let mut info = ExcessInlineSizeDistributionInfo::new(); - for column_inline_size in self.column_inline_sizes.iter() { - info.update(column_inline_size) + for column_intrinsic_inline_size in self.column_intrinsic_inline_sizes.iter() { + info.update(column_intrinsic_inline_size) } let mut total_distributed_excess_size = Au(0); - for column_inline_size in self.column_inline_sizes.iter_mut() { - info.distribute_excess_inline_size_to_column(column_inline_size, + for (intermediate_column_inline_size, column_intrinsic_inline_size) in + intermediate_column_inline_sizes.iter_mut() + .zip(self.column_intrinsic_inline_sizes + .iter()) { + info.distribute_excess_inline_size_to_column(intermediate_column_inline_size, + column_intrinsic_inline_size, excess_inline_size, &mut total_distributed_excess_size) } @@ -234,11 +230,11 @@ impl Flow for TableWrapperFlow { } fn bubble_inline_sizes(&mut self) { - // Get the column inline-sizes info from the table flow. + // Get the intrinsic column inline-sizes info from the table flow. for kid in self.block_flow.base.child_iter() { debug_assert!(kid.is_table_caption() || kid.is_table()); if kid.is_table() { - self.intrinsic_column_inline_sizes = kid.column_inline_sizes().clone() + self.column_intrinsic_inline_sizes = kid.column_intrinsic_inline_sizes().clone() } } @@ -253,7 +249,14 @@ impl Flow for TableWrapperFlow { "table_wrapper" }); - self.column_inline_sizes = self.intrinsic_column_inline_sizes.clone(); + let mut intermediate_column_inline_sizes = self.column_intrinsic_inline_sizes + .iter() + .map(|column_intrinsic_inline_size| { + IntermediateColumnInlineSize { + size: column_intrinsic_inline_size.minimum_length, + percentage: column_intrinsic_inline_size.percentage, + } + }).collect::<Vec<_>>(); // Table wrappers are essentially block formatting contexts and are therefore never // impacted by floats. @@ -273,7 +276,8 @@ impl Flow for TableWrapperFlow { match self.table_layout { FixedLayout => {} AutoLayout => { - self.calculate_table_column_sizes_for_automatic_layout() + self.calculate_table_column_sizes_for_automatic_layout( + intermediate_column_inline_sizes.as_mut_slice()) } } @@ -283,12 +287,29 @@ impl Flow for TableWrapperFlow { // In case of fixed layout, column inline-sizes are calculated in table flow. let assigned_column_inline_sizes = match self.table_layout { FixedLayout => None, - AutoLayout => Some(self.column_inline_sizes.as_slice()) + AutoLayout => { + Some(intermediate_column_inline_sizes.iter().map(|sizes| { + ColumnComputedInlineSize { + size: sizes.size, + } + }).collect::<Vec<_>>()) + } }; - self.block_flow.propagate_assigned_inline_size_to_children(inline_start_content_edge, - content_inline_size, - assigned_column_inline_sizes); + match assigned_column_inline_sizes { + None => { + self.block_flow.propagate_assigned_inline_size_to_children( + inline_start_content_edge, + content_inline_size, + None) + } + Some(ref assigned_column_inline_sizes) => { + self.block_flow.propagate_assigned_inline_size_to_children( + inline_start_content_edge, + content_inline_size, + Some(assigned_column_inline_sizes.as_slice())); + } + } } @@ -395,27 +416,28 @@ impl AutoLayoutCandidateGuess { } /// Fills in the inline-size guesses for this column per INTRINSIC § 4.3. - fn from_column_inline_size(column_inline_size: &ColumnInlineSize, assignable_inline_size: Au) - -> AutoLayoutCandidateGuess { + fn from_column_intrinsic_inline_size(column_intrinsic_inline_size: &ColumnIntrinsicInlineSize, + assignable_inline_size: Au) + -> AutoLayoutCandidateGuess { let minimum_percentage_guess = - max(assignable_inline_size.scale_by(column_inline_size.percentage), - column_inline_size.minimum_length); + max(assignable_inline_size.scale_by(column_intrinsic_inline_size.percentage), + column_intrinsic_inline_size.minimum_length); AutoLayoutCandidateGuess { - minimum_guess: column_inline_size.minimum_length, + minimum_guess: column_intrinsic_inline_size.minimum_length, minimum_percentage_guess: minimum_percentage_guess, // FIXME(pcwalton): We need the notion of *constrainedness* per INTRINSIC § 4 to // implement this one correctly. - minimum_specified_guess: if column_inline_size.percentage > 0.0 { + minimum_specified_guess: if column_intrinsic_inline_size.percentage > 0.0 { minimum_percentage_guess - } else if column_inline_size.constrained { - column_inline_size.preferred + } else if column_intrinsic_inline_size.constrained { + column_intrinsic_inline_size.preferred } else { - column_inline_size.minimum_length + column_intrinsic_inline_size.minimum_length }, - preferred_guess: if column_inline_size.percentage > 0.0 { + preferred_guess: if column_intrinsic_inline_size.percentage > 0.0 { minimum_percentage_guess } else { - column_inline_size.preferred + column_intrinsic_inline_size.preferred }, } } @@ -526,19 +548,21 @@ impl ExcessInlineSizeDistributionInfo { } } - fn update(&mut self, column_inline_size: &ColumnInlineSize) { - if !column_inline_size.constrained && column_inline_size.percentage == 0.0 { + fn update(&mut self, column_intrinsic_inline_size: &ColumnIntrinsicInlineSize) { + if !column_intrinsic_inline_size.constrained && + column_intrinsic_inline_size.percentage == 0.0 { self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage = self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage + - column_inline_size.preferred; + column_intrinsic_inline_size.preferred; self.count_of_nonconstrained_columns_with_no_percentage += 1 } - if column_inline_size.constrained && column_inline_size.percentage == 0.0 { + if column_intrinsic_inline_size.constrained && + column_intrinsic_inline_size.percentage == 0.0 { self.preferred_inline_size_of_constrained_columns_with_no_percentage = self.preferred_inline_size_of_constrained_columns_with_no_percentage + - column_inline_size.preferred + column_intrinsic_inline_size.preferred } - self.total_percentage += column_inline_size.percentage; + self.total_percentage += column_intrinsic_inline_size.percentage; self.column_count += 1 } @@ -547,23 +571,25 @@ impl ExcessInlineSizeDistributionInfo { /// /// `#[inline]` so the compiler will hoist out the branch, which is loop-invariant. #[inline] - fn distribute_excess_inline_size_to_column(&self, - column_inline_size: &mut ColumnInlineSize, - excess_inline_size: Au, - total_distributed_excess_size: &mut Au) { + fn distribute_excess_inline_size_to_column( + &self, + intermediate_column_inline_size: &mut IntermediateColumnInlineSize, + column_intrinsic_inline_size: &ColumnIntrinsicInlineSize, + excess_inline_size: Au, + total_distributed_excess_size: &mut Au) { let proportion = if self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage > Au(0) { - column_inline_size.preferred.to_subpx() / + column_intrinsic_inline_size.preferred.to_subpx() / self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage .to_subpx() } else if self.count_of_nonconstrained_columns_with_no_percentage > 0 { 1.0 / (self.count_of_nonconstrained_columns_with_no_percentage as CSSFloat) } else if self.preferred_inline_size_of_constrained_columns_with_no_percentage > Au(0) { - column_inline_size.preferred.to_subpx() / + column_intrinsic_inline_size.preferred.to_subpx() / self.preferred_inline_size_of_constrained_columns_with_no_percentage.to_subpx() } else if self.total_percentage > 0.0 { - column_inline_size.percentage / self.total_percentage + column_intrinsic_inline_size.percentage / self.total_percentage } else { 1.0 / (self.column_count as CSSFloat) }; @@ -573,7 +599,14 @@ impl ExcessInlineSizeDistributionInfo { let amount_to_distribute = min(excess_inline_size.scale_by(proportion), excess_inline_size - *total_distributed_excess_size); *total_distributed_excess_size = *total_distributed_excess_size + amount_to_distribute; - column_inline_size.minimum_length = column_inline_size.minimum_length + + intermediate_column_inline_size.size = intermediate_column_inline_size.size + amount_to_distribute } } + +/// An intermediate column size assignment. +struct IntermediateColumnInlineSize { + size: Au, + percentage: f64, +} + |