Diff
Modified: trunk/Source/WebCore/ChangeLog (259981 => 259982)
--- trunk/Source/WebCore/ChangeLog 2020-04-12 16:34:57 UTC (rev 259981)
+++ trunk/Source/WebCore/ChangeLog 2020-04-12 17:21:44 UTC (rev 259982)
@@ -1,5 +1,53 @@
2020-04-12 Zalan Bujtas <[email protected]>
+ [LFC][TFC] Add support for fixed width columns
+ https://bugs.webkit.org/show_bug.cgi?id=210401
+
+ Reviewed by Antti Koivisto.
+
+ This is in preparation for adding support for spanner cells.
+ Fixed width columns (<col> and <td>) don't participate in the spanner width distribution.
+
+ * layout/FormattingContext.h:
+ (WebCore::Layout::FormattingContext::IntrinsicWidthConstraints::operator-=):
+ * layout/Verification.cpp:
+ (WebCore::Layout::areEssentiallyEqual):
+ (WebCore::Layout::LayoutContext::verifyAndOutputMismatchingLayoutTree):
+ * layout/tableformatting/TableFormattingContext.cpp:
+ (WebCore::Layout::TableFormattingContext::computedIntrinsicWidthConstraints):
+ (WebCore::Layout::TableFormattingContext::computedPreferredWidthForColumns):
+ (WebCore::Layout::TableFormattingContext::computeAndDistributeExtraHorizontalSpace):
+ (WebCore::Layout::TableFormattingContext::computePreferredWidthForColumns): Deleted.
+ (WebCore::Layout::TableFormattingContext::useAsContentLogicalWidth): Deleted.
+ * layout/tableformatting/TableFormattingContext.h:
+ * layout/tableformatting/TableFormattingContextGeometry.cpp:
+ (WebCore::Layout::TableFormattingContext::Geometry::intrinsicWidthConstraintsForCell):
+ * layout/tableformatting/TableGrid.cpp:
+ (WebCore::Layout::TableGrid::Column::isFixedWidth const):
+ (WebCore::Layout::TableGrid::Cell::isFixedWidth const):
+ (WebCore::Layout::TableGrid::Slot::Slot):
+ (WebCore::Layout::TableGrid::appendCell):
+ (WebCore::Layout::TableGrid::Column::setWidthConstraints): Deleted.
+ (WebCore::Layout::TableGrid::Column::widthConstraints const): Deleted.
+ (WebCore::Layout::TableGrid::Column::hasFixedWidth const): Deleted.
+ (WebCore::Layout::TableGrid::widthConstraints): Deleted.
+ * layout/tableformatting/TableGrid.h:
+ (WebCore::Layout::TableGrid::setWidthConstraints):
+ (WebCore::Layout::TableGrid::widthConstraints):
+ (WebCore::Layout::TableGrid::Column::setHasFixedWidthCell):
+ (WebCore::Layout::TableGrid::Column::hasFixedWidthCell const):
+ (WebCore::Layout::TableGrid::Slot::cell const):
+ (WebCore::Layout::TableGrid::Slot::cell):
+ (WebCore::Layout::TableGrid::Slot::widthConstraints const):
+ (WebCore::Layout::TableGrid::Slot::setWidthConstraints):
+ (WebCore::Layout::TableGrid::Slot::hasColumnSpan const):
+ (WebCore::Layout::TableGrid::Slot::hasRowSpan const):
+ (WebCore::Layout::TableGrid::Slot::isColumnSpanned const):
+ (WebCore::Layout::TableGrid::Slot::isRowSpanned const):
+ (WebCore::Layout::TableGrid::hasComputedWidthConstraints const): Deleted.
+
+2020-04-12 Zalan Bujtas <[email protected]>
+
[LFC][TFC] Introduce dedicated SlotPosition/CellSpan structs
https://bugs.webkit.org/show_bug.cgi?id=210399
Modified: trunk/Source/WebCore/layout/FormattingContext.h (259981 => 259982)
--- trunk/Source/WebCore/layout/FormattingContext.h 2020-04-12 16:34:57 UTC (rev 259981)
+++ trunk/Source/WebCore/layout/FormattingContext.h 2020-04-12 17:21:44 UTC (rev 259982)
@@ -71,6 +71,7 @@
struct IntrinsicWidthConstraints {
void expand(LayoutUnit horizontalValue);
IntrinsicWidthConstraints& operator+=(const IntrinsicWidthConstraints&);
+ IntrinsicWidthConstraints& operator-=(LayoutUnit);
LayoutUnit minimum;
LayoutUnit maximum;
@@ -228,8 +229,15 @@
return *this;
}
+inline FormattingContext::IntrinsicWidthConstraints& FormattingContext::IntrinsicWidthConstraints::operator-=(LayoutUnit value)
+{
+ minimum -= value;
+ maximum -= value;
+ return *this;
}
+
}
+}
#define SPECIALIZE_TYPE_TRAITS_LAYOUT_FORMATTING_CONTEXT(ToValueTypeName, predicate) \
SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::Layout::ToValueTypeName) \
Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp (259981 => 259982)
--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp 2020-04-12 16:34:57 UTC (rev 259981)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp 2020-04-12 17:21:44 UTC (rev 259982)
@@ -180,13 +180,16 @@
// a generic shrink-to fit block level box like a float box would be just sized to the computed value of "width", tables
// can actually be streched way over.
auto& grid = formattingState().tableGrid();
- if (!grid.hasComputedWidthConstraints()) {
- // 1. Ensure each cell slot is occupied by at least one cell.
- ensureTableGrid();
- // 2. Compute the minimum/maximum width of each column.
- computePreferredWidthForColumns();
- }
- return grid.widthConstraints();
+ if (auto computedWidthConstraints = grid.widthConstraints())
+ return *computedWidthConstraints;
+
+ // 1. Ensure each cell slot is occupied by at least one cell.
+ ensureTableGrid();
+ // 2. Compute the minimum/maximum width of each column.
+ auto computedWidthConstraints = computedPreferredWidthForColumns();
+ computedWidthConstraints.expand(grid.totalHorizontalSpacing());
+ grid.setWidthConstraints(computedWidthConstraints);
+ return computedWidthConstraints;
}
void TableFormattingContext::ensureTableGrid()
@@ -233,11 +236,11 @@
}
}
-void TableFormattingContext::computePreferredWidthForColumns()
+FormattingContext::IntrinsicWidthConstraints TableFormattingContext::computedPreferredWidthForColumns()
{
auto& formattingState = this->formattingState();
auto& grid = formattingState.tableGrid();
- ASSERT(!grid.hasComputedWidthConstraints());
+ ASSERT(!grid.widthConstraints());
// 1. Calculate the minimum content width (MCW) of each cell: the formatted content may span any number of lines but may not overflow the cell box.
// If the specified 'width' (W) of the cell is greater than MCW, W is the minimum cell width. A value of 'auto' means that MCW is the minimum cell width.
@@ -244,56 +247,73 @@
// Also, calculate the "maximum" cell width of each cell: formatting the content without breaking lines other than where explicit line breaks occur.
for (auto& cell : grid.cells()) {
auto& cellBox = cell->box();
- ASSERT(cellBox.establishesFormattingContext());
+ ASSERT(cellBox.establishesBlockFormattingContext());
auto intrinsicWidth = formattingState.intrinsicWidthConstraintsForBox(cellBox);
if (!intrinsicWidth) {
- intrinsicWidth = IntrinsicWidthConstraints { };
- if (is<ContainerBox>(cellBox) && downcast<ContainerBox>(cellBox).hasInFlowOrFloatingChild())
- intrinsicWidth = LayoutContext::createFormattingContext(downcast<ContainerBox>(cellBox), layoutState())->computedIntrinsicWidthConstraints();
- intrinsicWidth = geometry().constrainByMinMaxWidth(cellBox, *intrinsicWidth);
- auto border = geometry().computedBorder(cellBox);
- auto padding = *geometry().computedPadding(cellBox, { });
-
- intrinsicWidth->expand(border.horizontal.width() + padding.horizontal.width());
+ intrinsicWidth = geometry().intrinsicWidthConstraintsForCell(downcast<ContainerBox>(cellBox));
formattingState.setIntrinsicWidthConstraintsForBox(cellBox, *intrinsicWidth);
}
+ // Spanner cells put their intrinsic widths on the initial slots.
+ grid.slot(cell->position())->setWidthConstraints(*intrinsicWidth);
+ }
- auto columnSpan = cell->span().column;
- auto slotIntrinsicWidth = FormattingContext::IntrinsicWidthConstraints { intrinsicWidth->minimum / columnSpan, intrinsicWidth->maximum / columnSpan };
- auto initialPosition = cell->position();
- for (size_t i = 0; i < columnSpan; ++i)
- grid.slot({ initialPosition.column + i, initialPosition.row })->widthConstraints = slotIntrinsicWidth;
- }
- // 2. For each column, determine a maximum and minimum column width from the cells that span only that column.
- // The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger).
- // The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
auto& columnList = grid.columns().list();
- auto numberOfRows = grid.rows().size();
- auto numberOfColumns = columnList.size();
- for (size_t columnIndex = 0; columnIndex < numberOfColumns; ++columnIndex) {
- auto columnIntrinsicWidths = FormattingContext::IntrinsicWidthConstraints { };
- for (size_t rowIndex = 0; rowIndex < numberOfRows; ++rowIndex) {
- auto* slot = grid.slot({ columnIndex, rowIndex });
- columnIntrinsicWidths.minimum = std::max(slot->widthConstraints.minimum, columnIntrinsicWidths.minimum);
- columnIntrinsicWidths.maximum = std::max(slot->widthConstraints.maximum, columnIntrinsicWidths.maximum);
- }
- // Now that we have the content driven min/max widths, check if <col> sets a preferred width on this column.
- if (auto* columnBox = columnList[columnIndex].box()) {
- if (auto columnPreferredWidth = geometry().computedColumnWidth(*columnBox)) {
- // Let's stay at least as wide as the preferred width.
- columnIntrinsicWidths.minimum = std::max(columnIntrinsicWidths.minimum, *columnPreferredWidth);
+ Vector<Optional<LayoutUnit>> fixedWidthColumns;
+ for (size_t columnIndex = 0; columnIndex < columnList.size(); ++columnIndex) {
+ auto fixedWidth = [&] () -> Optional<LayoutUnit> {
+ auto* columnBox = columnList[columnIndex].box();
+ if (!columnBox) {
+ // Anoynmous columns don't have associated layout boxes.
+ return { };
}
+ if (auto width = columnBox->columnWidth())
+ return width;
+ return geometry().computedColumnWidth(*columnBox);
+ };
+ fixedWidthColumns.append(fixedWidth());
+ }
+
+ Vector<FormattingContext::IntrinsicWidthConstraints> columnIntrinsicWidths;
+ // Collect he min/max width for each column and finalize the preferred width for the table.
+ for (size_t columnIndex = 0; columnIndex < columnList.size(); ++columnIndex) {
+ columnIntrinsicWidths.append(FormattingContext::IntrinsicWidthConstraints { });
+ for (size_t rowIndex = 0; rowIndex < grid.rows().size(); ++rowIndex) {
+ auto& slot = *grid.slot({ columnIndex, rowIndex });
+ if (slot.hasColumnSpan()) {
+ auto& cell = slot.cell();
+ auto widthConstraintsToDistribute = slot.widthConstraints();
+ auto numberOfNonFixedSpannedColumns = cell.columnSpan();
+ for (size_t columnSpanIndex = cell.startColumn(); columnSpanIndex < cell.endColumn(); ++columnSpanIndex) {
+ if (auto fixedWidth = fixedWidthColumns[columnSpanIndex]) {
+ widthConstraintsToDistribute -= *fixedWidth;
+ --numberOfNonFixedSpannedColumns;
+ }
+ }
+ for (size_t columnSpanIndex = cell.startColumn(); columnSpanIndex < cell.endColumn(); ++columnSpanIndex) {
+ columnIntrinsicWidths[columnIndex].minimum = std::max(widthConstraintsToDistribute.minimum / numberOfNonFixedSpannedColumns, columnIntrinsicWidths[columnIndex].minimum);
+ columnIntrinsicWidths[columnIndex].maximum = std::max(widthConstraintsToDistribute.maximum / numberOfNonFixedSpannedColumns, columnIntrinsicWidths[columnIndex].maximum);
+ }
+ } else {
+ auto columnFixedWidth = fixedWidthColumns[columnIndex];
+ auto widthConstraints = !columnFixedWidth ? slot.widthConstraints() : FormattingContext::IntrinsicWidthConstraints { *columnFixedWidth, *columnFixedWidth };
+ columnIntrinsicWidths[columnIndex].minimum = std::max(widthConstraints.minimum, columnIntrinsicWidths[columnIndex].minimum);
+ columnIntrinsicWidths[columnIndex].maximum = std::max(widthConstraints.maximum, columnIntrinsicWidths[columnIndex].maximum);
+ }
}
- columnList[columnIndex].setWidthConstraints(columnIntrinsicWidths);
}
+ auto tableWidthConstraints = IntrinsicWidthConstraints { };
+ for (auto& columnIntrinsicWidth : columnIntrinsicWidths)
+ tableWidthConstraints += columnIntrinsicWidth;
+ return tableWidthConstraints;
}
-void TableFormattingContext::computeAndDistributeExtraHorizontalSpace(LayoutUnit containingBlockWidth)
+void TableFormattingContext::computeAndDistributeExtraHorizontalSpace(LayoutUnit availableHorizontalSpace)
{
auto& grid = formattingState().tableGrid();
- ASSERT(grid.hasComputedWidthConstraints());
- auto tableWidthConstraints = grid.widthConstraints();
+ auto& columns = grid.columns();
+ auto& rows = grid.rows();
+ auto tableWidthConstraints = *grid.widthConstraints();
// Column and caption widths influence the final table width as follows:
// If the 'table' or 'inline-table' element's 'width' property has a computed value (W) other than 'auto', the used width is the greater of
@@ -302,16 +322,58 @@
// If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width,
// CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is
// less than that of the containing block, use max(MAX, CAPMIN).
- auto distributeExtraHorizontalSpace = [&](auto extraHorizontalSpace) {
+ auto distributeExtraHorizontalSpace = [&] (auto horizontalSpaceToDistribute) {
auto& columnList = grid.columns().list();
ASSERT(!columnList.isEmpty());
- auto tableMinimumContentWidth = tableWidthConstraints.minimum - grid.totalHorizontalSpacing();
- auto adjustabledHorizontalSpace = tableMinimumContentWidth;
+ // 1. Collect minimum widths across columns but ignore spanning cells first.
+ Vector<float> columnMinimumWidths;
+ 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.hasColumnSpan()) {
+ spanningCellPositionList.append({ columnIndex, rowIndex });
+ continue;
+ }
+ if (slot.isColumnSpanned())
+ continue;
+ if (!rowIndex)
+ columnMinimumWidths.append(slot.widthConstraints().minimum);
+ else
+ columnMinimumWidths[columnIndex] = std::max<float>(columnMinimumWidths[columnIndex], slot.widthConstraints().minimum);
+ }
+ }
+ // 2. Distribute the spanning cells' mimimum widths across the columns using the non-spanning minium widths.
+ // e.g. [ 1 ][ 5 ][ 1 ]
+ // [ 9 ][ 1 ]
+ // The minimum widths are: [ 2 ][ 7 ][ 1 ]
+ for (auto spanningCellPosition : spanningCellPositionList) {
+ auto& slot = *grid.slot(spanningCellPosition);
+ auto& cell = slot.cell();
+ ASSERT(slot.hasColumnSpan());
+ float currentSpanningMinimumWidth = 0;
+ // 1. Collect the non-spaning minimum widths.
+ for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex)
+ currentSpanningMinimumWidth += columnMinimumWidths[columnIndex];
+ float spanningMinimumWidth = slot.widthConstraints().minimum;
+ if (currentSpanningMinimumWidth >= spanningMinimumWidth) {
+ // 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 = spanningMinimumWidth - currentSpanningMinimumWidth;
+ for (auto columnIndex = cell.startColumn(); columnIndex < cell.endColumn(); ++columnIndex)
+ columnMinimumWidths[columnIndex] += spaceToDistribute / currentSpanningMinimumWidth * columnMinimumWidths[columnIndex];
+ }
+ // 3. Distribute the extra space using the final minimum widths.
+ float adjustabledHorizontalSpace = tableWidthConstraints.minimum - grid.totalHorizontalSpacing();
auto numberOfColumns = columnList.size();
// Fixed width columns don't participate in available space distribution.
for (auto& column : columnList) {
- if (!column.hasFixedWidth())
+ if (!column.isFixedWidth())
continue;
auto columnFixedWidth = *column.box()->columnWidth();
column.setLogicalWidth(columnFixedWidth);
@@ -321,38 +383,35 @@
}
if (!numberOfColumns || !adjustabledHorizontalSpace)
return;
- // FIXME: Right now just distribute the extra space equaly among the columns using the minimum width.
ASSERT(adjustabledHorizontalSpace > 0);
- for (auto& column : columnList) {
- if (column.hasFixedWidth())
+ for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
+ auto& column = columns.list()[columnIndex];
+ if (column.isFixedWidth())
continue;
- auto columnExtraSpace = extraHorizontalSpace / adjustabledHorizontalSpace * column.widthConstraints().minimum;
- column.setLogicalWidth(column.widthConstraints().minimum + columnExtraSpace);
+ auto columnExtraSpace = horizontalSpaceToDistribute / adjustabledHorizontalSpace * columnMinimumWidths[columnIndex];
+ column.setLogicalWidth(LayoutUnit { columnMinimumWidths[columnIndex] + columnExtraSpace });
}
};
- if (auto contentWidth = geometry().computedContentWidth(root(), containingBlockWidth)) {
- if (*contentWidth > tableWidthConstraints.minimum)
- distributeExtraHorizontalSpace(*contentWidth - tableWidthConstraints.minimum);
- else
- useAsContentLogicalWidth(WidthConstraintsType::Minimum);
- } else {
- if (tableWidthConstraints.minimum > containingBlockWidth)
- useAsContentLogicalWidth(WidthConstraintsType::Minimum);
- else if (tableWidthConstraints.maximum <= containingBlockWidth)
- useAsContentLogicalWidth(WidthConstraintsType::Maximum);
- else
- distributeExtraHorizontalSpace(containingBlockWidth - tableWidthConstraints.minimum);
- }
-}
+ 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);
+ }
+ };
-void TableFormattingContext::useAsContentLogicalWidth(WidthConstraintsType type)
-{
- auto& columnList = formattingState().tableGrid().columns().list();
- ASSERT(!columnList.isEmpty());
-
- for (auto& column : columnList)
- column.setLogicalWidth(type == WidthConstraintsType::Minimum ? column.widthConstraints().minimum : column.widthConstraints().maximum);
+ ASSERT(availableHorizontalSpace >= tableWidthConstraints.minimum);
+ if (availableHorizontalSpace == tableWidthConstraints.minimum)
+ distributeMinOrMax(WidthConstraintsType::Minimum);
+ else if (availableHorizontalSpace == tableWidthConstraints.maximum)
+ distributeMinOrMax(WidthConstraintsType::Maximum);
+ else
+ distributeExtraHorizontalSpace(availableHorizontalSpace - tableWidthConstraints.minimum);
}
}
Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h (259981 => 259982)
--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h 2020-04-12 16:34:57 UTC (rev 259981)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h 2020-04-12 17:21:44 UTC (rev 259982)
@@ -49,6 +49,7 @@
public:
ContentHeightAndMargin tableCellHeightAndMargin(const Box&) const;
Optional<LayoutUnit> computedColumnWidth(const Box& columnBox) const;
+ FormattingContext::IntrinsicWidthConstraints intrinsicWidthConstraintsForCell(const ContainerBox& cellBox);
private:
friend class TableFormattingContext;
@@ -65,10 +66,8 @@
void setComputedGeometryForSections();
void ensureTableGrid();
- void computePreferredWidthForColumns();
+ IntrinsicWidthConstraints computedPreferredWidthForColumns();
void computeAndDistributeExtraHorizontalSpace(LayoutUnit containingBlockWidth);
- enum class WidthConstraintsType { Minimum, Maximum };
- void useAsContentLogicalWidth(WidthConstraintsType);
void initializeDisplayBoxToBlank(Display::Box&) const;
Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContextGeometry.cpp (259981 => 259982)
--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContextGeometry.cpp 2020-04-12 16:34:57 UTC (rev 259981)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContextGeometry.cpp 2020-04-12 17:21:44 UTC (rev 259982)
@@ -55,7 +55,35 @@
return columnBox.columnWidth();
}
+FormattingContext::IntrinsicWidthConstraints TableFormattingContext::Geometry::intrinsicWidthConstraintsForCell(const ContainerBox& cellBox)
+{
+ auto fixedMarginBorderAndPadding = [&] {
+ auto& style = cellBox.style();
+ return fixedValue(style.marginStart()).valueOr(0)
+ + LayoutUnit { style.borderLeftWidth() }
+ + fixedValue(style.paddingLeft()).valueOr(0)
+ + fixedValue(style.paddingRight()).valueOr(0)
+ + LayoutUnit { style.borderRightWidth() }
+ + fixedValue(style.marginEnd()).valueOr(0);
+ };
+
+ auto computedIntrinsicWidthConstraints = [&] {
+ // Even fixed width cells expand to their minimum content width
+ // <td style="width: 10px">test_content</td> will size to max(minimum content width, computed width).
+ auto intrinsicWidthConstraints = FormattingContext::IntrinsicWidthConstraints { };
+ if (cellBox.hasChild())
+ intrinsicWidthConstraints = LayoutContext::createFormattingContext(cellBox, layoutState())->computedIntrinsicWidthConstraints();
+ if (auto width = fixedValue(cellBox.style().logicalWidth()))
+ return FormattingContext::IntrinsicWidthConstraints { std::max(intrinsicWidthConstraints.minimum, *width), std::max(intrinsicWidthConstraints.maximum, *width) };
+ return intrinsicWidthConstraints;
+ };
+ // FIXME Check for box-sizing: border-box;
+ auto intrinsicWidthConstraints = constrainByMinMaxWidth(cellBox, computedIntrinsicWidthConstraints());
+ intrinsicWidthConstraints.expand(fixedMarginBorderAndPadding());
+ return intrinsicWidthConstraints;
}
+
}
+}
#endif
Modified: trunk/Source/WebCore/layout/tableformatting/TableGrid.cpp (259981 => 259982)
--- trunk/Source/WebCore/layout/tableformatting/TableGrid.cpp 2020-04-12 16:34:57 UTC (rev 259981)
+++ trunk/Source/WebCore/layout/tableformatting/TableGrid.cpp 2020-04-12 17:21:44 UTC (rev 259982)
@@ -40,20 +40,6 @@
{
}
-void TableGrid::Column::setWidthConstraints(FormattingContext::IntrinsicWidthConstraints widthConstraints)
-{
-#if ASSERT_ENABLED
- m_hasWidthConstraints = true;
-#endif
- m_widthConstraints = widthConstraints;
-}
-
-FormattingContext::IntrinsicWidthConstraints TableGrid::Column::widthConstraints() const
-{
- ASSERT(m_hasWidthConstraints);
- return m_widthConstraints;
-}
-
void TableGrid::Column::setLogicalWidth(LayoutUnit computedLogicalWidth)
{
#if ASSERT_ENABLED
@@ -82,10 +68,9 @@
return m_computedLogicalLeft;
}
-bool TableGrid::Column::hasFixedWidth() const
+bool TableGrid::Column::isFixedWidth() const
{
- // FIXME: This only covers the <col> attribute case.
- return box() && box()->columnWidth();
+ return hasFixedWidthCell() || (box() && box()->columnWidth());
}
void TableGrid::Columns::addColumn(const Box& columnBox)
@@ -115,11 +100,18 @@
{
}
-TableGrid::Slot::Slot(Cell& cell)
- : cell(makeWeakPtr(cell))
+bool TableGrid::Cell::isFixedWidth() const
{
+ return box().style().logicalWidth().isFixed();
}
+TableGrid::Slot::Slot(Cell& cell, bool isColumnSpanned, bool isRowSpanned)
+ : m_cell(makeWeakPtr(cell))
+ , m_isColumnSpanned(isColumnSpanned)
+ , m_isRowSpanned(isRowSpanned)
+{
+}
+
TableGrid::TableGrid()
{
}
@@ -154,11 +146,14 @@
}
auto cell = makeUnique<Cell>(cellBox, initialSlotPosition, CellSpan { columnSpan, rowSpan });
// Row and column spanners create additional slots.
- for (size_t row = 1; row <= rowSpan; ++row) {
- for (size_t column = 1; column <= columnSpan; ++column) {
- auto position = SlotPosition { initialSlotPosition.column + column - 1, initialSlotPosition.row + row - 1 };
+ for (size_t row = 0; row < rowSpan; ++row) {
+ for (auto column = cell->startColumn(); column < cell->endColumn(); ++column) {
+ auto position = SlotPosition { column, cell->startRow() + row };
ASSERT(!m_slotMap.contains(position));
- m_slotMap.add(position, makeUnique<Slot>(*cell));
+ // This slot is spanned by a cell at the initial slow position.
+ auto isColumnSpanned = column != cell->startColumn();
+ auto isRowSpanned = !!row;
+ m_slotMap.add(position, makeUnique<Slot>(*cell, isColumnSpanned, isRowSpanned));
}
}
// Initialize columns/rows if needed.
@@ -166,6 +161,11 @@
for (auto column = 0; column < missingNumberOfColumns; ++column)
m_columns.addAnonymousColumn();
+ if (cell->isFixedWidth()) {
+ for (auto column = cell->startColumn(); column < cell->endColumn(); ++column)
+ m_columns.list()[column].setHasFixedWidthCell();
+ }
+
if (isInNewRow)
m_rows.addRow(cellBox.parent());
@@ -183,19 +183,6 @@
UNUSED_PARAM(cellBox);
}
-FormattingContext::IntrinsicWidthConstraints TableGrid::widthConstraints()
-{
- // FIXME: Add constraint invalidation for incremental layouts.
- if (m_intrinsicWidthConstraints)
- return *m_intrinsicWidthConstraints;
-
- m_intrinsicWidthConstraints = FormattingContext::IntrinsicWidthConstraints { };
- for (auto& column : m_columns.list())
- *m_intrinsicWidthConstraints += column.widthConstraints();
- m_intrinsicWidthConstraints->expand(totalHorizontalSpacing());
- return *m_intrinsicWidthConstraints;
}
-
}
-}
#endif
Modified: trunk/Source/WebCore/layout/tableformatting/TableGrid.h (259981 => 259982)
--- trunk/Source/WebCore/layout/tableformatting/TableGrid.h 2020-04-12 16:34:57 UTC (rev 259981)
+++ trunk/Source/WebCore/layout/tableformatting/TableGrid.h 2020-04-12 17:21:44 UTC (rev 259982)
@@ -55,17 +55,14 @@
void setVerticalSpacing(LayoutUnit verticalSpacing) { m_verticalSpacing = verticalSpacing; }
LayoutUnit verticalSpacing() const { return m_verticalSpacing; }
- bool hasComputedWidthConstraints() const { return m_intrinsicWidthConstraints.hasValue(); }
- FormattingContext::IntrinsicWidthConstraints widthConstraints();
+ void setWidthConstraints(FormattingContext::IntrinsicWidthConstraints intrinsicWidthConstraints) { m_intrinsicWidthConstraints = intrinsicWidthConstraints; }
+ Optional<FormattingContext::IntrinsicWidthConstraints> widthConstraints() { return m_intrinsicWidthConstraints; }
- // Column represents a vertical set of slots in the grid. A column has min/max and final width.
+ // Column represents a vertical set of slots in the grid. A column has horizontal position and width.
class Column {
public:
Column(const Box*);
- void setWidthConstraints(FormattingContext::IntrinsicWidthConstraints);
- FormattingContext::IntrinsicWidthConstraints widthConstraints() const;
-
void setLogicalLeft(LayoutUnit);
LayoutUnit logicalLeft() const;
LayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); }
@@ -72,18 +69,20 @@
void setLogicalWidth(LayoutUnit);
LayoutUnit logicalWidth() const;
- bool hasFixedWidth() const;
+ bool isFixedWidth() const;
+ void setHasFixedWidthCell() { m_hasFixedWidthCell = true; }
const Box* box() const { return m_layoutBox.get(); }
private:
- FormattingContext::IntrinsicWidthConstraints m_widthConstraints;
+ bool hasFixedWidthCell() const { return m_hasFixedWidthCell; }
+
LayoutUnit m_computedLogicalWidth;
LayoutUnit m_computedLogicalLeft;
WeakPtr<const Box> m_layoutBox;
+ bool m_hasFixedWidthCell { false };
#if ASSERT_ENABLED
- bool m_hasWidthConstraints { false };
bool m_hasComputedWidth { false };
bool m_hasComputedLeft { false };
#endif
@@ -156,6 +155,8 @@
SlotPosition position() const { return m_position; }
CellSpan span() const { return m_span; }
+ bool isFixedWidth() const;
+
const Box& box() const { return *m_layoutBox.get(); }
private:
@@ -164,13 +165,34 @@
CellSpan m_span;
};
- struct Slot {
+ class Slot {
+ public:
WTF_MAKE_STRUCT_FAST_ALLOCATED;
Slot() = default;
- Slot(Cell&);
+ Slot(Cell&, bool isColumnSpanned, bool isRowSpanned);
- WeakPtr<Cell> cell;
- FormattingContext::IntrinsicWidthConstraints widthConstraints;
+ const Cell& cell() const { return *m_cell; }
+ Cell& cell() { return *m_cell; }
+
+ const FormattingContext::IntrinsicWidthConstraints& widthConstraints() const { return m_widthConstraints; }
+ void setWidthConstraints(const FormattingContext::IntrinsicWidthConstraints& widthConstraints) { m_widthConstraints = widthConstraints; }
+
+ // Initial slot position for a spanning cell.
+ // <td></td><td colspan=2></td> [1, 0] slot has column span of 2.
+ bool hasColumnSpan() const { return m_cell->columnSpan() > 1 && !isColumnSpanned(); }
+ bool hasRowSpan() const { return m_cell->rowSpan() > 1 && !isRowSpanned(); }
+
+ // Non-initial spanned slot.
+ // <td></td><td colspan=2></td> [2, 0] slot is column spanned by [1, 0].
+ // <td></td><td></td><td></td>
+ bool isColumnSpanned() const { return m_isColumnSpanned; }
+ bool isRowSpanned() const { return m_isRowSpanned; }
+
+ private:
+ WeakPtr<Cell> m_cell;
+ bool m_isColumnSpanned { false };
+ bool m_isRowSpanned { false };
+ FormattingContext::IntrinsicWidthConstraints m_widthConstraints;
};
const Columns& columns() const { return m_columns; }
@@ -183,6 +205,7 @@
Cells& cells() { return m_cells; }
Slot* slot(SlotPosition);
+ bool isSpanned(SlotPosition);
private:
using SlotMap = WTF::HashMap<SlotPosition, std::unique_ptr<Slot>>;