aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/table.rs
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-12-11 14:22:20 -0800
committerPatrick Walton <pcwalton@mimiga.net>2014-12-11 14:24:55 -0800
commit3cddaf8da69b147f4808019ccdfca12b5f293a40 (patch)
tree0bddd5028e5c4b4933ba1566f1b483fd7dcc45c8 /components/layout/table.rs
parent512d55ecefac4c5f7f6fc52ad5cedb7f2664b0c9 (diff)
downloadservo-3cddaf8da69b147f4808019ccdfca12b5f293a40.tar.gz
servo-3cddaf8da69b147f4808019ccdfca12b5f293a40.zip
layout: Make table layout idempotent.
By "idempotent" I mean that later passes do not stomp on data from earlier passes, so that we can run the passes individually for incremental reflow. The main change here was to stop overwriting the "minimum inline-size" field of each column with the column's computed inline-size.
Diffstat (limited to 'components/layout/table.rs')
-rw-r--r--components/layout/table.rs103
1 files changed, 68 insertions, 35 deletions
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,
+}