Commit a43ec143 authored by Aleks Totic's avatar Aleks Totic Committed by Commit Bot

[TablesNG] Widths of cells with content-box, %width inside fixed table

Cells with percentage widths have either content or border box sizing.
Handling of these is very inconsistent across browsers.
This implements my current beliefs, and passes most test:

- table-layout: auto ignores content vs border box.
- table-layout: fixed distinguishes between content and border box

These widths are resolved multiple times inside table layout algorithm:
- computing grid_minmax
- during table width redistribution

Bug: 958381
Change-Id: I93eb167aa4ab9e144d4c44734c04ddbf775ecc2d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2416843
Commit-Queue: Aleks Totic <atotic@chromium.org>
Reviewed-by: default avatarMorten Stenshorne <mstensho@chromium.org>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#808965}
parent 64031df2
...@@ -334,7 +334,7 @@ void SynchronizeAssignableTableInlineSizeAndColumnsFixed( ...@@ -334,7 +334,7 @@ void SynchronizeAssignableTableInlineSizeAndColumnsFixed(
percent_columns_count++; percent_columns_count++;
total_percent += *column->percent; total_percent += *column->percent;
total_percent_inline_size += total_percent_inline_size +=
LayoutUnit(*column->percent / 100 * target_inline_size); column->ResolvePercentInlineSize(target_inline_size);
} else if (column->is_constrained) { // Fixed column } else if (column->is_constrained) { // Fixed column
fixed_columns_count++; fixed_columns_count++;
total_fixed_inline_size += *column->max_inline_size; total_fixed_inline_size += *column->max_inline_size;
...@@ -407,8 +407,8 @@ void SynchronizeAssignableTableInlineSizeAndColumnsFixed( ...@@ -407,8 +407,8 @@ void SynchronizeAssignableTableInlineSizeAndColumnsFixed(
continue; continue;
last_distributed_column = column; last_distributed_column = column;
if (scale_available) { if (scale_available) {
column->computed_inline_size = column->computed_inline_size = LayoutUnit(
LayoutUnit(scale * *column->percent / 100 * target_inline_size); scale * column->ResolvePercentInlineSize(target_inline_size));
} else { } else {
column->computed_inline_size = column->computed_inline_size =
LayoutUnit((target_inline_size - assigned_inline_size).ToFloat() / LayoutUnit((target_inline_size - assigned_inline_size).ToFloat() /
...@@ -447,19 +447,19 @@ void DistributeColspanCellToColumnsFixed( ...@@ -447,19 +447,19 @@ void DistributeColspanCellToColumnsFixed(
LayoutUnit colspan_cell_min_inline_size; LayoutUnit colspan_cell_min_inline_size;
LayoutUnit colspan_cell_max_inline_size; LayoutUnit colspan_cell_max_inline_size;
// Colspanned cells only distribute min inline size if constrained.
if (colspan_cell.cell_inline_constraint.is_constrained) { if (colspan_cell.cell_inline_constraint.is_constrained) {
colspan_cell_min_inline_size = colspan_cell_min_inline_size =
(colspan_cell.cell_inline_constraint.min_inline_size - (colspan_cell.cell_inline_constraint.min_inline_size -
(colspan_cell.span - 1) * inline_border_spacing) (colspan_cell.span - 1) * inline_border_spacing)
.ClampNegativeToZero(); .ClampNegativeToZero();
colspan_cell_max_inline_size =
(colspan_cell.cell_inline_constraint.max_inline_size -
(colspan_cell.span - 1) * inline_border_spacing)
.ClampNegativeToZero();
} }
colspan_cell_max_inline_size =
(colspan_cell.cell_inline_constraint.max_inline_size -
(colspan_cell.span - 1) * inline_border_spacing)
.ClampNegativeToZero();
// Distribute min/max/percentage evenly between all cells. // Distribute min/max/percentage evenly between all cells.
// Colspanned cells only distribute min inline size if constrained.
LayoutUnit rounding_error_min_inline_size = colspan_cell_min_inline_size; LayoutUnit rounding_error_min_inline_size = colspan_cell_min_inline_size;
LayoutUnit rounding_error_max_inline_size = colspan_cell_max_inline_size; LayoutUnit rounding_error_max_inline_size = colspan_cell_max_inline_size;
float rounding_error_percent = float rounding_error_percent =
...@@ -843,8 +843,9 @@ void NGTableAlgorithmHelpers::ComputeGridInlineMinmax( ...@@ -843,8 +843,9 @@ void NGTableAlgorithmHelpers::ComputeGridInlineMinmax(
} }
if (column.percent) { if (column.percent) {
if (*column.max_inline_size > LayoutUnit() && *column.percent > 0) { if (*column.max_inline_size > LayoutUnit() && *column.percent > 0) {
LayoutUnit estimate = LayoutUnit estimate = LayoutUnit(
LayoutUnit(100 / *column.percent * *column.max_inline_size); 100 / *column.percent *
(*column.max_inline_size - column.percent_border_padding));
percent_maxsize_estimate = percent_maxsize_estimate =
std::max(percent_maxsize_estimate, estimate); std::max(percent_maxsize_estimate, estimate);
} }
......
...@@ -89,6 +89,7 @@ NGTableTypes::Column NGTableTypes::CreateColumn( ...@@ -89,6 +89,7 @@ NGTableTypes::Column NGTableTypes::CreateColumn(
return Column{min_inline_size.value_or(LayoutUnit()), return Column{min_inline_size.value_or(LayoutUnit()),
inline_size, inline_size,
percentage_inline_size, percentage_inline_size,
LayoutUnit() /* percent_border_padding */,
is_constrained, is_constrained,
is_collapsed, is_collapsed,
kIndefiniteSize}; kIndefiniteSize};
...@@ -144,7 +145,6 @@ NGTableTypes::CellInlineConstraint NGTableTypes::CreateCellInlineConstraint( ...@@ -144,7 +145,6 @@ NGTableTypes::CellInlineConstraint NGTableTypes::CreateCellInlineConstraint(
} else { } else {
min_max_size = node.ComputeMinMaxSizes(table_writing_mode, input); min_max_size = node.ComputeMinMaxSizes(table_writing_mode, input);
} }
// Compute min inline size. // Compute min inline size.
LayoutUnit resolved_min_inline_size; LayoutUnit resolved_min_inline_size;
if (!is_fixed_layout) { if (!is_fixed_layout) {
...@@ -152,6 +152,7 @@ NGTableTypes::CellInlineConstraint NGTableTypes::CreateCellInlineConstraint( ...@@ -152,6 +152,7 @@ NGTableTypes::CellInlineConstraint NGTableTypes::CreateCellInlineConstraint(
std::max(min_max_size.sizes.min_size, std::max(min_max_size.sizes.min_size,
css_min_inline_size.value_or(LayoutUnit())); css_min_inline_size.value_or(LayoutUnit()));
// https://quirks.spec.whatwg.org/#the-table-cell-nowrap-minimum-width-calculation-quirk // https://quirks.spec.whatwg.org/#the-table-cell-nowrap-minimum-width-calculation-quirk
// Has not worked in Legacy, might be pulled out.
if (css_inline_size && node.GetDocument().InQuirksMode()) { if (css_inline_size && node.GetDocument().InQuirksMode()) {
bool has_nowrap_attribute = bool has_nowrap_attribute =
!To<Element>(node.GetLayoutBox()->GetNode()) !To<Element>(node.GetLayoutBox()->GetNode())
...@@ -182,9 +183,18 @@ NGTableTypes::CellInlineConstraint NGTableTypes::CreateCellInlineConstraint( ...@@ -182,9 +183,18 @@ NGTableTypes::CellInlineConstraint NGTableTypes::CreateCellInlineConstraint(
bool is_constrained = css_inline_size.has_value(); bool is_constrained = css_inline_size.has_value();
DCHECK_LE(resolved_min_inline_size, resolved_max_inline_size); DCHECK_LE(resolved_min_inline_size, resolved_max_inline_size);
// Only fixed tables use border padding in percentage size computations.
LayoutUnit percent_border_padding;
if (is_fixed_layout && css_percentage_inline_size &&
node.Style().BoxSizing() == EBoxSizing::kContentBox) {
percent_border_padding = (cell_border + cell_padding).InlineSum();
}
DCHECK_GE(resolved_max_inline_size, percent_border_padding);
return NGTableTypes::CellInlineConstraint{ return NGTableTypes::CellInlineConstraint{
resolved_min_inline_size, resolved_max_inline_size, resolved_min_inline_size, resolved_max_inline_size,
css_percentage_inline_size, is_constrained}; css_percentage_inline_size, percent_border_padding, is_constrained};
} }
NGTableTypes::Section NGTableTypes::CreateSection( NGTableTypes::Section NGTableTypes::CreateSection(
...@@ -261,6 +271,10 @@ void NGTableTypes::CellInlineConstraint::Encompass( ...@@ -261,6 +271,10 @@ void NGTableTypes::CellInlineConstraint::Encompass(
is_constrained = is_constrained || other.is_constrained; is_constrained = is_constrained || other.is_constrained;
max_inline_size = std::max(max_inline_size, other.max_inline_size); max_inline_size = std::max(max_inline_size, other.max_inline_size);
percent = std::max(percent, other.percent); percent = std::max(percent, other.percent);
if (other.percent > percent) {
percent = other.percent;
percent_border_padding = other.percent_border_padding;
}
} }
void NGTableTypes::Column::Encompass( void NGTableTypes::Column::Encompass(
...@@ -288,11 +302,10 @@ void NGTableTypes::Column::Encompass( ...@@ -288,11 +302,10 @@ void NGTableTypes::Column::Encompass(
if (min_inline_size && max_inline_size) { if (min_inline_size && max_inline_size) {
max_inline_size = std::max(*min_inline_size, *max_inline_size); max_inline_size = std::max(*min_inline_size, *max_inline_size);
} }
if (percent) {
if (cell->percent) if (cell->percent > percent) {
percent = std::max(*cell->percent, *percent);
} else {
percent = cell->percent; percent = cell->percent;
percent_border_padding = cell->percent_border_padding;
} }
is_constrained |= cell->is_constrained; is_constrained |= cell->is_constrained;
} }
......
...@@ -30,6 +30,8 @@ class CORE_EXPORT NGTableTypes { ...@@ -30,6 +30,8 @@ class CORE_EXPORT NGTableTypes {
LayoutUnit min_inline_size; LayoutUnit min_inline_size;
LayoutUnit max_inline_size; LayoutUnit max_inline_size;
base::Optional<float> percent; // 100% is stored as 100.0f base::Optional<float> percent; // 100% is stored as 100.0f
LayoutUnit percent_border_padding; // Border/padding used for percentage
// size resolution.
bool is_constrained; // True if this cell has a specified inline-size. bool is_constrained; // True if this cell has a specified inline-size.
void Encompass(const CellInlineConstraint&); void Encompass(const CellInlineConstraint&);
...@@ -65,6 +67,8 @@ class CORE_EXPORT NGTableTypes { ...@@ -65,6 +67,8 @@ class CORE_EXPORT NGTableTypes {
base::Optional<LayoutUnit> min_inline_size; base::Optional<LayoutUnit> min_inline_size;
base::Optional<LayoutUnit> max_inline_size; base::Optional<LayoutUnit> max_inline_size;
base::Optional<float> percent; // 100% is stored as 100.0f base::Optional<float> percent; // 100% is stored as 100.0f
LayoutUnit percent_border_padding; // Border/padding used for percentage
// size resolution.
// True if any cell for this column is constrained. // True if any cell for this column is constrained.
bool is_constrained = false; bool is_constrained = false;
bool is_collapsed = false; bool is_collapsed = false;
...@@ -76,7 +80,8 @@ class CORE_EXPORT NGTableTypes { ...@@ -76,7 +80,8 @@ class CORE_EXPORT NGTableTypes {
LayoutUnit percentage_resolution_inline_size) { LayoutUnit percentage_resolution_inline_size) {
return std::max( return std::max(
min_inline_size.value_or(LayoutUnit()), min_inline_size.value_or(LayoutUnit()),
LayoutUnit(*percent * percentage_resolution_inline_size / 100)); LayoutUnit(*percent * percentage_resolution_inline_size / 100) +
percent_border_padding);
} }
bool IsFixed() const { bool IsFixed() const {
return is_constrained && !percent && max_inline_size; return is_constrained && !percent && max_inline_size;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment