Added: trunk/LayoutTests/fast/layoutformattingcontext/table-flex-width-colspans-expected.txt (0 => 260342)
--- trunk/LayoutTests/fast/layoutformattingcontext/table-flex-width-colspans-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/layoutformattingcontext/table-flex-width-colspans-expected.txt 2020-04-19 18:34:07 UTC (rev 260342)
@@ -0,0 +1,152 @@
+layer at (0,0) size 800x600
+ RenderView at (0,0) size 800x600
+layer at (0,0) size 800x406
+ RenderBlock {HTML} at (0,0) size 800x406
+ RenderBody {BODY} at (8,8) size 784x390
+ RenderTable {TABLE} at (0,0) size 59x53
+ RenderTableSection {TBODY} at (0,0) size 59x53
+ RenderTableRow {TR} at (0,2) size 59x15
+ RenderTableCell {TD} at (2,2) size 17x15 [r=0 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTableCell {TD} at (21,2) size 17x15 [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (40,2) size 17x15 [r=0 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableRow {TR} at (0,19) size 59x15
+ RenderTableCell {TD} at (2,19) size 17x15 [r=1 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (21,19) size 17x15 [r=1 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (40,19) size 17x15 [r=1 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTableRow {TR} at (0,36) size 59x15
+ RenderTableCell {TD} at (2,36) size 17x15 [r=2 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (21,36) size 17x15 [r=2 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTableCell {TD} at (40,36) size 17x15 [r=2 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTable {TABLE} at (0,53) size 29x53
+ RenderTableSection {TBODY} at (0,0) size 29x53
+ RenderTableRow {TR} at (0,2) size 29x15
+ RenderTableCell {TD} at (2,2) size 7x15 [r=0 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (11,2) size 7x15 [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (20,2) size 7x15 [r=0 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableRow {TR} at (0,19) size 29x15
+ RenderTableCell {TD} at (2,19) size 25x15 [r=1 c=0 rs=1 cs=3]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableRow {TR} at (0,36) size 29x15
+ RenderTableCell {TD} at (2,36) size 16x15 [r=2 c=0 rs=1 cs=2]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (20,36) size 7x15 [r=2 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTable {TABLE} at (0,106) size 44x53
+ RenderTableSection {TBODY} at (0,0) size 44x53
+ RenderTableRow {TR} at (0,2) size 44x15
+ RenderTableCell {TD} at (2,2) size 17x15 [r=0 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTableCell {TD} at (21,2) size 12x15 [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 10x13
+ text run at (1,1) width 10: "##"
+ RenderTableCell {TD} at (35,2) size 7x15 [r=0 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableRow {TR} at (0,19) size 44x15
+ RenderTableCell {TD} at (2,19) size 40x15 [r=1 c=0 rs=1 cs=3]
+ RenderText {#text} at (1,1) size 30x13
+ text run at (1,1) width 30: "######"
+ RenderTableRow {TR} at (0,36) size 44x15
+ RenderTableCell {TD} at (2,36) size 31x15 [r=2 c=0 rs=1 cs=2]
+ RenderText {#text} at (1,1) size 25x13
+ text run at (1,1) width 25: "#####"
+ RenderTableCell {TD} at (35,36) size 7x15 [r=2 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTable {TABLE} at (0,159) size 71x53
+ RenderTableSection {TBODY} at (0,0) size 71x53
+ RenderTableRow {TR} at (0,2) size 71x15
+ RenderTableCell {TD} at (2,2) size 37x15 [r=0 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 25x13
+ text run at (1,1) width 25: "#####"
+ RenderTableCell {TD} at (40,2) size 18x15 [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 10x13
+ text run at (1,1) width 10: "##"
+ RenderTableCell {TD} at (59,2) size 11x15 [r=0 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableRow {TR} at (0,19) size 71x15
+ RenderTableCell {TD} at (2,19) size 68x15 [r=1 c=0 rs=1 cs=3]
+ RenderText {#text} at (1,1) size 65x13
+ text run at (1,1) width 65: "#############"
+ RenderTableRow {TR} at (0,36) size 71x15
+ RenderTableCell {TD} at (2,36) size 56x15 [r=2 c=0 rs=1 cs=2]
+ RenderText {#text} at (1,1) size 35x13
+ text run at (1,1) width 35: "#######"
+ RenderTableCell {TD} at (59,36) size 11x15 [r=2 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTable {TABLE} at (0,212) size 71x53
+ RenderTableSection {TBODY} at (0,0) size 71x53
+ RenderTableRow {TR} at (0,2) size 71x15
+ RenderTableCell {TD} at (2,2) size 37x15 [r=0 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 25x13
+ text run at (1,1) width 25: "#####"
+ RenderTableCell {TD} at (40,2) size 18x15 [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 10x13
+ text run at (1,1) width 10: "##"
+ RenderTableCell {TD} at (59,2) size 11x15 [r=0 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableRow {TR} at (0,19) size 71x15
+ RenderTableCell {TD} at (2,19) size 68x15 [r=1 c=0 rs=1 cs=3]
+ RenderText {#text} at (1,1) size 65x13
+ text run at (1,1) width 65: "#############"
+ RenderTableRow {TR} at (0,36) size 71x15
+ RenderTableCell {TD} at (2,36) size 37x15 [r=2 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (40,36) size 30x15 [r=2 c=1 rs=1 cs=2]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTable {TABLE} at (0,265) size 111x125
+ RenderTableSection {TBODY} at (0,0) size 111x125
+ RenderTableRow {TR} at (0,20) size 111x15
+ RenderTableCell {TD} at (20,20) size 17x15 [r=0 c=0 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTableCell {TD} at (57,20) size 7x15 [r=0 c=1 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableCell {TD} at (84,20) size 7x15 [r=0 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
+ RenderTableRow {TR} at (0,55) size 111x15
+ RenderTableCell {TD} at (20,55) size 71x15 [r=1 c=0 rs=1 cs=3]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTableRow {TR} at (0,90) size 111x15
+ RenderTableCell {TD} at (20,90) size 44x15 [r=2 c=0 rs=1 cs=2]
+ RenderText {#text} at (1,1) size 15x13
+ text run at (1,1) width 15: "###"
+ RenderTableCell {TD} at (84,90) size 7x15 [r=2 c=2 rs=1 cs=1]
+ RenderText {#text} at (1,1) size 5x13
+ text run at (1,1) width 5: "#"
Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp (260341 => 260342)
--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp 2020-04-19 18:12:40 UTC (rev 260341)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp 2020-04-19 18:34:07 UTC (rev 260342)
@@ -339,35 +339,36 @@
auto& rows = grid.rows();
auto tableWidthConstraints = *grid.widthConstraints();
- auto distributeExtraHorizontalSpace = [&] (auto horizontalSpaceToDistribute) {
- auto& columnList = grid.columns().list();
- ASSERT(!columnList.isEmpty());
-
- // 1. Collect minimum widths driven by <td> across columns but ignore spanning cells first.
- struct ColumnMinimumWidth {
+ enum class ColumnWidthBalancingBase { MinimumWidth, MaximumWidth };
+ auto computeColumnWidths = [&] (auto columnWidthBalancingBase, auto extraHorizontalSpace) {
+ auto slotInitialWidth = [&] (auto& slot) {
+ return columnWidthBalancingBase == ColumnWidthBalancingBase::MinimumWidth ? slot.widthConstraints().minimum : slot.widthConstraints().maximum;
+ };
+ // 1. Collect initial widths driven by <td> across columns but ignore spanning cells first.
+ struct ColumnInitialWidth {
float value { 0 };
bool isFixed { false };
};
- Vector<Optional<ColumnMinimumWidth>> columnMinimumWidths(columnList.size());
+ Vector<Optional<ColumnInitialWidth>> columnInitialWidths(columns.size());
Vector<SlotPosition> spanningCellPositionList;
for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
auto& slot = *grid.slot({ columnIndex, rowIndex });
+ if (slot.isColumnSpanned())
+ continue;
if (slot.hasColumnSpan()) {
spanningCellPositionList.append({ columnIndex, rowIndex });
continue;
}
- if (slot.isColumnSpanned())
- continue;
- if (!columnMinimumWidths[columnIndex])
- columnMinimumWidths[columnIndex] = ColumnMinimumWidth { };
- columnMinimumWidths[columnIndex]->value = std::max<float>(columnMinimumWidths[columnIndex]->value, slot.widthConstraints().minimum);
+ if (!columnInitialWidths[columnIndex])
+ columnInitialWidths[columnIndex] = ColumnInitialWidth { };
+ columnInitialWidths[columnIndex]->value = std::max<float>(columnInitialWidths[columnIndex]->value, slotInitialWidth(slot));
}
}
- // 2. Adjust the <td> minimum widths with fixed column widths (<col> vs. <td>) and also manage all-fixed-width-column content.
+ // 2. Adjust the <td> initial widths with fixed column widths (<col> vs. <td>) and also manage all-fixed-width-column content.
auto hasFixedColumnsOnly = columns.hasFixedColumnsOnly();
- for (size_t columnIndex = 0; columnIndex < columnList.size(); ++columnIndex) {
- auto& column = columnList[columnIndex];
+ for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
+ auto& column = columns.list()[columnIndex];
if (!column.isFixedWidth())
continue;
// This is the column width based on <col width=""> and not <td style="width: ">.
@@ -374,11 +375,11 @@
auto columnFixedWidth = column.box() ? column.box()->columnWidth() : WTF::nullopt;
if (!columnFixedWidth)
continue;
- if (!columnMinimumWidths[columnIndex])
- columnMinimumWidths[columnIndex] = ColumnMinimumWidth { };
- columnMinimumWidths[columnIndex]->value = std::max(columnMinimumWidths[columnIndex]->value, columnFixedWidth.valueOr(0).toFloat());
+ if (!columnInitialWidths[columnIndex])
+ columnInitialWidths[columnIndex] = ColumnInitialWidth { };
+ columnInitialWidths[columnIndex]->value = std::max(columnInitialWidths[columnIndex]->value, columnFixedWidth.valueOr(0).toFloat());
// Fixed columns flex when there are no other flexing columns.
- columnMinimumWidths[columnIndex]->isFixed = !hasFixedColumnsOnly;
+ columnInitialWidths[columnIndex]->isFixed = !hasFixedColumnsOnly;
}
// We need these spanning cells in the order of the number of columns they span so that
@@ -388,16 +389,16 @@
std::sort(spanningCellPositionList.begin(), spanningCellPositionList.end(), [&] (auto& a, auto& b) {
return grid.slot(a)->cell().columnSpan() < grid.slot(b)->cell().columnSpan();
});
- // 3. Distribute the spanning cells' mimimum widths across the columns using the non-spanning minimum widths.
+ // 3. Distribute the spanning cells' mimimum widths across the columns using the non-spanning initial widths.
// e.g. [ 1 ][ 5 ][ 1 ]
// [ 9 ][ 1 ]
- // The minimum widths are: [ 2 ][ 7 ][ 1 ]
+ // The initial widths are: [ 2 ][ 7 ][ 1 ]
for (auto spanningCellPosition : spanningCellPositionList) {
auto& slot = *grid.slot(spanningCellPosition);
ASSERT(slot.hasColumnSpan());
auto& cell = slot.cell();
- float spanningMinimumWidth = slot.widthConstraints().minimum;
- if (!columnMinimumWidths[cell.startColumn()] || !columnMinimumWidths[cell.endColumn() - 1]) {
+ float spanningInitialWidth = slotInitialWidth(slot);
+ if (!columnInitialWidths[cell.startColumn()] || !columnInitialWidths[cell.endColumn() - 1]) {
// <td colspan=4>#a</td><td>#b</td>
// <td colspan=2>#c</td><td colspan=3>#d</td>
// Unresolved columns are: 1 2 3 4
@@ -406,85 +407,74 @@
// 3. colspan=4 needs no resolving because all the spanned columns (1 2 3 4) have already been resolved.
auto unresolvedColumnNumber = cell.columnSpan();
for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex) {
- if (!columnMinimumWidths[columnIndex])
+ if (!columnInitialWidths[columnIndex])
continue;
ASSERT(unresolvedColumnNumber);
--unresolvedColumnNumber;
- spanningMinimumWidth = std::max(0.0f, spanningMinimumWidth - columnMinimumWidths[columnIndex]->value);
+ spanningInitialWidth = std::max(0.0f, spanningInitialWidth - columnInitialWidths[columnIndex]->value);
}
ASSERT(unresolvedColumnNumber);
for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex) {
- if (columnMinimumWidths[columnIndex])
+ if (columnInitialWidths[columnIndex])
continue;
- columnMinimumWidths[columnIndex] = ColumnMinimumWidth { spanningMinimumWidth / unresolvedColumnNumber, false };
+ columnInitialWidths[columnIndex] = ColumnInitialWidth { spanningInitialWidth / unresolvedColumnNumber, false };
}
} else {
- // 1. Collect the non-spaning minimum widths.
- float currentSpanningMinimumWidth = 0;
+ // 1. Collect the non-spaning initial widths.
+ float currentSpanningInitialWidth = 0;
for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex)
- currentSpanningMinimumWidth += columnMinimumWidths[columnIndex]->value;
- if (currentSpanningMinimumWidth >= spanningMinimumWidth) {
+ currentSpanningInitialWidth += columnInitialWidths[columnIndex]->value;
+ if (currentSpanningInitialWidth >= spanningInitialWidth) {
// The spanning cell fits the spanned columns just fine. Nothing to distribute.
continue;
}
- // 2. Distribute the extra minimum width among the spanned columns based on the minimum colmn width.
- // e.g. spanning mimimum width: [ 9 ]. Current minimum widths for the spanned columns: [ 1 ] [ 2 ]
- // New minimum widths: [ 3 ] [ 6 ].
- auto spaceToDistribute = std::max(0.0f, spanningMinimumWidth - (cell.columnSpan() - 1) * grid.horizontalSpacing() - currentSpanningMinimumWidth);
+ // 2. Distribute the extra width among the spanned columns based on the initial column width.
+ // e.g. spanning initial width: [ 9 ]. Current initial widths for the spanned columns: [ 1 ] [ 2 ]
+ // New initial widths: [ 3 ] [ 6 ].
+ auto spaceToDistribute = std::max(0.0f, spanningInitialWidth - (cell.columnSpan() - 1) * grid.horizontalSpacing() - currentSpanningInitialWidth);
if (spaceToDistribute) {
for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex)
- columnMinimumWidths[columnIndex]->value += spaceToDistribute / currentSpanningMinimumWidth * columnMinimumWidths[columnIndex]->value;
+ columnInitialWidths[columnIndex]->value += spaceToDistribute / currentSpanningInitialWidth * columnInitialWidths[columnIndex]->value;
}
}
}
- // 3. Distribute the extra space using the final minimum widths.
+ // 4. Distribute the extra space using the final initial widths.
#if ASSERT_ENABLED
- // We have to have all the columns resolved at this point with valid minimum widths.
- for (auto& columnMinimumWidth : columnMinimumWidths)
- ASSERT(columnMinimumWidth);
+ // We have to have all the columns resolved at this point with valid initial widths.
+ for (auto& columnInitialWidth : columnInitialWidths)
+ ASSERT(columnInitialWidth);
#endif
// Fixed width columns don't participate in available space distribution.
// Unless there are no flexing column at all, then they start flexing as if they were not fixed at all.
float adjustabledHorizontalSpace = 0;
- for (auto& columnMinimumWidth : columnMinimumWidths) {
- if (columnMinimumWidth->isFixed)
+ for (auto& columnInitialWidth : columnInitialWidths) {
+ if (columnInitialWidth->isFixed)
continue;
- adjustabledHorizontalSpace += columnMinimumWidth->value;
+ adjustabledHorizontalSpace += columnInitialWidth->value;
}
- if (!adjustabledHorizontalSpace)
- return;
- // FIXME: Implement overconstrained columns when fixed width content is wider than the table.
+
for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
auto& column = columns.list()[columnIndex];
- auto minimumWidth = columnMinimumWidths[columnIndex]->value;
- if (columnMinimumWidths[columnIndex]->isFixed) {
- column.setLogicalWidth(LayoutUnit { minimumWidth });
+ auto initialWidth = columnInitialWidths[columnIndex]->value;
+
+ if (!extraHorizontalSpace || columnInitialWidths[columnIndex]->isFixed) {
+ column.setLogicalWidth(LayoutUnit { initialWidth });
continue;
}
- auto columnExtraSpace = horizontalSpaceToDistribute / adjustabledHorizontalSpace * minimumWidth;
- column.setLogicalWidth(LayoutUnit { minimumWidth + columnExtraSpace });
+ auto columnExtraSpace = extraHorizontalSpace / adjustabledHorizontalSpace * initialWidth;
+ column.setLogicalWidth(LayoutUnit { initialWidth + columnExtraSpace });
}
};
- enum class WidthConstraintsType { Minimum, Maximum };
- auto distributeMinOrMax = [&] (WidthConstraintsType type) {
- for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
- auto logicalWidth = LayoutUnit { };
- for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
- auto widthConstraints = grid.slot({ columnIndex, rowIndex })->widthConstraints();
- logicalWidth = std::max(logicalWidth, type == WidthConstraintsType::Minimum ? widthConstraints.minimum : widthConstraints.maximum);
- }
- columns.list()[columnIndex].setLogicalWidth(logicalWidth);
- }
- };
-
- ASSERT(availableHorizontalSpace >= tableWidthConstraints.minimum);
- if (availableHorizontalSpace == tableWidthConstraints.minimum)
- distributeMinOrMax(WidthConstraintsType::Minimum);
- else if (availableHorizontalSpace == tableWidthConstraints.maximum)
- distributeMinOrMax(WidthConstraintsType::Maximum);
- else
- distributeExtraHorizontalSpace(availableHorizontalSpace - tableWidthConstraints.minimum);
+ auto needsExtraSpaceDistribution = availableHorizontalSpace != tableWidthConstraints.minimum && availableHorizontalSpace != tableWidthConstraints.maximum;
+ if (!needsExtraSpaceDistribution) {
+ auto columnWidthBalancingBase = availableHorizontalSpace == tableWidthConstraints.maximum ? ColumnWidthBalancingBase::MaximumWidth : ColumnWidthBalancingBase::MinimumWidth;
+ computeColumnWidths(columnWidthBalancingBase, LayoutUnit { });
+ return;
+ }
+ auto horizontalSpaceToDistribute = availableHorizontalSpace - tableWidthConstraints.minimum;
+ ASSERT(horizontalSpaceToDistribute > 0);
+ computeColumnWidths(ColumnWidthBalancingBase::MinimumWidth, horizontalSpaceToDistribute);
}
}