Diff
Modified: trunk/Source/WebCore/ChangeLog (249653 => 249654)
--- trunk/Source/WebCore/ChangeLog 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/ChangeLog 2019-09-09 19:01:28 UTC (rev 249654)
@@ -1,3 +1,45 @@
+2019-09-09 Zalan Bujtas <[email protected]>
+
+ [LFC][TFC] Introduce cell spacing.
+ https://bugs.webkit.org/show_bug.cgi?id=201605
+ <rdar://problem/55184009>
+
+ Reviewed by Antti Koivisto.
+
+ This patch adds support for horizontal and vertical cell spacing (border-spacing). Now LFC matches table geometry for simple table content with multiple columns and rows.
+
+ * layout/FormattingContextGeometry.cpp:
+ (WebCore::Layout::FormattingContext::Geometry::contentHeightForFormattingContextRoot const): Now we can use the generic, check the inflow content logic for table height.
+ * layout/LayoutUnits.h:
+ (WebCore::Layout::HorizontalEdges::width const):
+ (WebCore::Layout::VerticalEdges::height const):
+ * layout/Verification.cpp:
+ (WebCore::Layout::verifyAndOutputSubtree):
+ * layout/tableformatting/TableFormattingContext.cpp:
+ (WebCore::Layout::TableFormattingContext::layout):
+ (WebCore::Layout::TableFormattingContext::layoutTableCellBox):
+ (WebCore::Layout::TableFormattingContext::positionTableCells):
+ (WebCore::Layout::TableFormattingContext::setComputedGeometryForRows):
+ (WebCore::Layout::TableFormattingContext::setComputedGeometryForSections):
+ (WebCore::Layout::TableFormattingContext::computedIntrinsicWidthConstraints):
+ (WebCore::Layout::TableFormattingContext::ensureTableGrid):
+ (WebCore::Layout::TableFormattingContext::computePreferredWidthForColumns):
+ (WebCore::Layout::TableFormattingContext::computedTableWidth):
+ (WebCore::Layout::TableFormattingContext::useAsContentLogicalWidth):
+ * layout/tableformatting/TableFormattingContext.h:
+ * layout/tableformatting/TableFormattingContextGeometry.cpp:
+ (WebCore::Layout::TableFormattingContext::Geometry::tableCellHeightAndMargin const):
+ * layout/tableformatting/TableGrid.cpp:
+ (WebCore::Layout::TableGrid::appendCell):
+ (WebCore::Layout::TableGrid::widthConstraints const):
+ (WebCore::Layout::TableGrid::ColumnsContext::useAsLogicalWidth): Deleted.
+ * layout/tableformatting/TableGrid.h:
+ (WebCore::Layout::TableGrid::setHorizontalSpacing):
+ (WebCore::Layout::TableGrid::horizontalSpacing const):
+ (WebCore::Layout::TableGrid::setVerticalSpacing):
+ (WebCore::Layout::TableGrid::verticalSpacing const):
+ (WebCore::Layout::TableGrid::ColumnsContext::logicalWidth const):
+
2019-09-09 Ryan Haddad <[email protected]>
Unreviewed, rolling out r249574.
Modified: trunk/Source/WebCore/layout/FormattingContextGeometry.cpp (249653 => 249654)
--- trunk/Source/WebCore/layout/FormattingContextGeometry.cpp 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/FormattingContextGeometry.cpp 2019-09-09 19:01:28 UTC (rev 249654)
@@ -118,7 +118,7 @@
ASSERT(!lineBoxes.isEmpty());
top = lineBoxes.first().logicalTop();
bottom = lineBoxes.last().logicalBottom();
- } else if (formattingRootContainer.establishesBlockFormattingContext() || layoutBox.isDocumentBox()) {
+ } else if (formattingRootContainer.establishesBlockFormattingContext() || formattingRootContainer.establishesTableFormattingContext() || layoutBox.isDocumentBox()) {
if (formattingRootContainer.hasInFlowChild()) {
auto& firstDisplayBox = formattingContext.displayBoxForLayoutBox(*formattingRootContainer.firstInFlowChild(), EscapeType::AccessChildFormattingContext);
auto& lastDisplayBox = formattingContext.displayBoxForLayoutBox(*formattingRootContainer.lastInFlowChild(), EscapeType::AccessChildFormattingContext);
@@ -125,12 +125,6 @@
top = firstDisplayBox.rectWithMargin().top();
bottom = lastDisplayBox.rectWithMargin().bottom();
}
- } else if (formattingRootContainer.establishesTableFormattingContext()) {
- auto& rowList = downcast<TableFormattingState>(layoutState.establishedFormattingState(formattingRootContainer)).tableGrid().rows();
- ASSERT(!rowList.isEmpty());
- top += rowList.first().logicalTop();
- auto& lastRow = rowList.last();
- bottom += lastRow.logicalBottom();
} else
ASSERT_NOT_REACHED();
Modified: trunk/Source/WebCore/layout/LayoutUnits.h (249653 => 249654)
--- trunk/Source/WebCore/layout/LayoutUnits.h 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/LayoutUnits.h 2019-09-09 19:01:28 UTC (rev 249654)
@@ -98,11 +98,15 @@
struct HorizontalEdges {
LayoutUnit left;
LayoutUnit right;
+
+ LayoutUnit width() const { return left + right; }
};
struct VerticalEdges {
LayoutUnit top;
LayoutUnit bottom;
+
+ LayoutUnit height() const { return top + bottom; }
};
struct Edges {
Modified: trunk/Source/WebCore/layout/Verification.cpp (249653 => 249654)
--- trunk/Source/WebCore/layout/Verification.cpp 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/Verification.cpp 2019-09-09 19:01:28 UTC (rev 249654)
@@ -272,6 +272,10 @@
static bool verifyAndOutputSubtree(TextStream& stream, const LayoutState& context, const RenderBox& renderer, const Box& layoutBox)
{
+ // Rendering code does not have the concept of table wrapper box. Skip it by verifying the first child(table box) instead.
+ if (layoutBox.isTableWrapperBox())
+ return verifyAndOutputSubtree(stream, context, renderer, *downcast<Container>(layoutBox).firstChild());
+
auto mismtachingGeometry = outputMismatchingBlockBoxInformationIfNeeded(stream, context, renderer, layoutBox);
if (!is<Container>(layoutBox))
Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp (249653 => 249654)
--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp 2019-09-09 19:01:28 UTC (rev 249654)
@@ -61,65 +61,85 @@
{
auto& grid = formattingState().tableGrid();
auto& cellList = grid.cells();
+ auto& columnList = grid.columnsContext().columns();
ASSERT(!cellList.isEmpty());
// Layout and position each table cell (and compute row height as well).
- auto& layoutState = this->layoutState();
- auto& rowList = grid.rows();
- auto& columnList = grid.columnsContext().columns();
-
for (auto& cell : cellList) {
auto& cellLayoutBox = cell->tableCellBox;
- auto cellPosition = cell->position;
+ layoutTableCellBox(cellLayoutBox, columnList.at(cell->position.x()));
+ // FIXME: Add support for column and row spanning and this requires a 2 pass layout.
+ auto& row = grid.rows().at(cell->position.y());
+ row.setLogicalHeight(std::max(row.logicalHeight(), displayBoxForLayoutBox(cellLayoutBox).marginBoxHeight()));
+ }
+ // This is after the second pass when cell heights are fully computed.
+ auto rowLogicalTop = grid.verticalSpacing();
+ for (auto& row : grid.rows()) {
+ row.setLogicalTop(rowLogicalTop);
+ rowLogicalTop += (row.logicalHeight() + grid.verticalSpacing());
+ }
- auto& column = columnList.at(cellPosition.x());
- auto& row = rowList.at(cellPosition.y());
+ // Finalize size and position.
+ positionTableCells();
+ setComputedGeometryForSections();
+ setComputedGeometryForRows();
+}
- auto& cellDisplayBox = displayBoxForLayoutBox(cell->tableCellBox);
- initializeDisplayBoxToBlank(cellDisplayBox);
- cellDisplayBox.setContentBoxWidth(column.logicalWidth());
- cellDisplayBox.setTopLeft({ column.logicalLeft(), row.logicalTop() });
- ASSERT(cellLayoutBox.establishesBlockFormattingContext());
- layoutState.createFormattingContext(cellLayoutBox)->layout();
- auto heightAndMargin = geometry().tableCellHeightAndMargin(cellLayoutBox);
+void TableFormattingContext::layoutTableCellBox(const Box& cellLayoutBox, const TableGrid::Column& column)
+{
+ auto& cellDisplayBox = displayBoxForLayoutBox(cellLayoutBox);
+ computeBorderAndPadding(cellLayoutBox);
+ // Margins do not apply to internal table elements.
+ cellDisplayBox.setHorizontalMargin({ });
+ cellDisplayBox.setHorizontalComputedMargin({ });
+ // Don't know the actual position yet.
+ cellDisplayBox.setTopLeft({ });
+ cellDisplayBox.setContentBoxWidth(column.logicalWidth() - cellDisplayBox.horizontalMarginBorderAndPadding());
- // FIXME: Add support for column and row spanning and this requires a 2 pass layout.
- row.setLogicalHeight(std::max(row.logicalHeight(), heightAndMargin.height));
- if (!cellPosition.x() && cellPosition.y()) {
- auto& previousRow = rowList.at(cellPosition.y() - 1);
- row.setLogicalTop(previousRow.logicalBottom());
- }
- }
+ ASSERT(cellLayoutBox.establishesBlockFormattingContext());
+ layoutState().createFormattingContext(cellLayoutBox)->layout();
+ cellDisplayBox.setVerticalMargin({ { }, { } });
+ cellDisplayBox.setContentBoxHeight(geometry().tableCellHeightAndMargin(cellLayoutBox).height);
+}
- // Finalize size and position.
- for (auto& cell : cellList) {
+void TableFormattingContext::positionTableCells()
+{
+ auto& grid = formattingState().tableGrid();
+ auto& rowList = grid.rows();
+ auto& columnList = grid.columnsContext().columns();
+ for (auto& cell : grid.cells()) {
auto& cellDisplayBox = displayBoxForLayoutBox(cell->tableCellBox);
- auto cellPosition = cell->position;
- auto& column = columnList.at(cellPosition.x());
- auto& row = rowList.at(cellPosition.y());
-
- cellDisplayBox.setTop(row.logicalTop());
- cellDisplayBox.setLeft(column.logicalLeft());
- cellDisplayBox.setContentBoxWidth(column.logicalWidth());
- cellDisplayBox.setContentBoxHeight(row.logicalHeight());
- cellDisplayBox.setVerticalMargin({ });
- cellDisplayBox.setHorizontalMargin({ });
+ cellDisplayBox.setTop(rowList.at(cell->position.y()).logicalTop());
+ cellDisplayBox.setLeft(columnList.at(cell->position.x()).logicalLeft());
}
+}
- LayoutUnit rowWidth;
- for (auto& column : columnList)
- rowWidth += column.logicalWidth();
+void TableFormattingContext::setComputedGeometryForRows()
+{
+ auto& grid = formattingState().tableGrid();
+ auto rowWidth = grid.columnsContext().logicalWidth() + 2 * grid.horizontalSpacing();
+ auto& rowList = grid.rows();
for (auto& row : rowList) {
- auto& rowDisplayBox = layoutState.displayBoxForLayoutBox(row.box());
+ auto& rowDisplayBox = displayBoxForLayoutBox(row.box());
initializeDisplayBoxToBlank(rowDisplayBox);
rowDisplayBox.setContentBoxHeight(row.logicalHeight());
rowDisplayBox.setContentBoxWidth(rowWidth);
rowDisplayBox.setTop(row.logicalTop());
}
+}
- // FIXME: This is temporary only. Size table sections properly.
- for (auto& section : childrenOfType<Box>(downcast<Container>(root())))
- initializeDisplayBoxToBlank(layoutState.displayBoxForLayoutBox(section));
+void TableFormattingContext::setComputedGeometryForSections()
+{
+ auto& grid = formattingState().tableGrid();
+ auto sectionWidth = grid.columnsContext().logicalWidth() + 2 * grid.horizontalSpacing();
+
+ for (auto& section : childrenOfType<Box>(downcast<Container>(root()))) {
+ auto& sectionDisplayBox = displayBoxForLayoutBox(section);
+ initializeDisplayBoxToBlank(sectionDisplayBox);
+ // FIXME: Size table sections properly.
+ sectionDisplayBox.setContentBoxWidth(sectionWidth);
+ sectionDisplayBox.setContentBoxHeight(grid.rows().last().logicalBottom() + grid.verticalSpacing());
+ }
}
FormattingContext::IntrinsicWidthConstraints TableFormattingContext::computedIntrinsicWidthConstraints()
@@ -135,6 +155,7 @@
// 3. Compute the width of the table.
auto width = computedTableWidth();
// This is the actual computed table width that we want to present as min/max width.
+ formattingState().setIntrinsicWidthConstraints({ width, width });
return { width, width };
}
@@ -142,6 +163,8 @@
{
auto& tableWrapperBox = downcast<Container>(root());
auto& tableGrid = formattingState().tableGrid();
+ tableGrid.setHorizontalSpacing(LayoutUnit { tableWrapperBox.style().horizontalBorderSpacing() });
+ tableGrid.setVerticalSpacing(LayoutUnit { tableWrapperBox.style().verticalBorderSpacing() });
for (auto* section = tableWrapperBox.firstChild(); section; section = section->nextSibling()) {
ASSERT(section->isTableHeader() || section->isTableBody() || section->isTableFooter());
@@ -164,14 +187,22 @@
// 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.
// 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()) {
- ASSERT(cell->tableCellBox.establishesFormattingContext());
+ auto& tableCellBox = cell->tableCellBox;
+ ASSERT(tableCellBox.establishesFormattingContext());
- auto intrinsicWidth = layoutState().createFormattingContext(cell->tableCellBox)->computedIntrinsicWidthConstraints();
- intrinsicWidth = geometry().constrainByMinMaxWidth(cell->tableCellBox, intrinsicWidth);
- formattingState.setIntrinsicWidthConstraints(intrinsicWidth);
+ auto intrinsicWidth = formattingState.intrinsicWidthConstraintsForBox(tableCellBox);
+ if (!intrinsicWidth) {
+ intrinsicWidth = layoutState().createFormattingContext(tableCellBox)->computedIntrinsicWidthConstraints();
+ intrinsicWidth = geometry().constrainByMinMaxWidth(tableCellBox, *intrinsicWidth);
+ auto border = geometry().computedBorder(tableCellBox);
+ auto padding = *geometry().computedPadding(tableCellBox, UsedHorizontalValues({ }));
+ intrinsicWidth->expand(border.horizontal.width() + padding.horizontal.width());
+ formattingState.setIntrinsicWidthConstraintsForBox(tableCellBox, *intrinsicWidth);
+ }
+
auto columnSpan = cell->size.width();
- auto slotIntrinsicWidth = FormattingContext::IntrinsicWidthConstraints { intrinsicWidth.minimum / columnSpan, intrinsicWidth.maximum / columnSpan };
+ auto slotIntrinsicWidth = FormattingContext::IntrinsicWidthConstraints { intrinsicWidth->minimum / columnSpan, intrinsicWidth->maximum / columnSpan };
auto initialPosition = cell->position;
for (auto i = 0; i < columnSpan; ++i)
grid.slot({ initialPosition.x() + i, initialPosition.y() })->widthConstraints = slotIntrinsicWidth;
@@ -223,15 +254,15 @@
usedWidth = *width;
} else {
usedWidth = tableWidthConstraints.minimum;
- columnsContext.useAsLogicalWidth(TableGrid::ColumnsContext::WidthConstraintsType::Minimum);
+ useAsContentLogicalWidth(WidthConstraintsType::Minimum);
}
} else {
if (tableWidthConstraints.minimum > containingBlockWidth) {
usedWidth = tableWidthConstraints.minimum;
- columnsContext.useAsLogicalWidth(TableGrid::ColumnsContext::WidthConstraintsType::Minimum);
+ useAsContentLogicalWidth(WidthConstraintsType::Minimum);
} else if (tableWidthConstraints.maximum < containingBlockWidth) {
usedWidth = tableWidthConstraints.maximum;
- columnsContext.useAsLogicalWidth(TableGrid::ColumnsContext::WidthConstraintsType::Maximum);
+ useAsContentLogicalWidth(WidthConstraintsType::Maximum);
} else {
usedWidth = containingBlockWidth;
distributeAvailableWidth(*width - tableWidthConstraints.minimum);
@@ -238,11 +269,11 @@
}
}
// FIXME: This should also deal with collapsing borders etc.
- LayoutUnit columnLogicalLeft;
- auto& columns = columnsContext.columns();
- for (auto& column : columns) {
+ auto horizontalSpacing = grid.horizontalSpacing();
+ auto columnLogicalLeft = horizontalSpacing;
+ for (auto& column : columnsContext.columns()) {
column.setLogicalLeft(columnLogicalLeft);
- columnLogicalLeft += column.logicalWidth();
+ columnLogicalLeft += (column.logicalWidth() + horizontalSpacing);
}
return usedWidth;
}
@@ -258,7 +289,16 @@
column.setLogicalWidth(column.widthConstraints().minimum + columnExtraSpace);
}
+void TableFormattingContext::useAsContentLogicalWidth(WidthConstraintsType type)
+{
+ auto& columns = formattingState().tableGrid().columnsContext().columns();
+ ASSERT(!columns.isEmpty());
+
+ for (auto& column : columns)
+ column.setLogicalWidth(type == WidthConstraintsType::Minimum ? column.widthConstraints().minimum : column.widthConstraints().maximum);
}
+
}
+}
#endif
Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h (249653 => 249654)
--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h 2019-09-09 19:01:28 UTC (rev 249654)
@@ -56,10 +56,16 @@
IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
LayoutUnit computedTableWidth();
+ void layoutTableCellBox(const Box& cellLayoutBox, const TableGrid::Column&);
+ void positionTableCells();
+ void setComputedGeometryForRows();
+ void setComputedGeometryForSections();
void ensureTableGrid();
void computePreferredWidthForColumns();
void distributeAvailableWidth(LayoutUnit extraHorizontalSpace);
+ enum class WidthConstraintsType { Minimum, Maximum };
+ void useAsContentLogicalWidth(WidthConstraintsType);
void initializeDisplayBoxToBlank(Display::Box&) const;
Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContextGeometry.cpp (249653 => 249654)
--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContextGeometry.cpp 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContextGeometry.cpp 2019-09-09 19:01:28 UTC (rev 249654)
@@ -43,7 +43,7 @@
if (!height)
height = contentHeightForFormattingContextRoot(layoutBox);
- // FIXME: Compute vertical margin values.
+ // Margins don't apply to internal table elements.
return HeightAndMargin { *height, { } };
}
Modified: trunk/Source/WebCore/layout/tableformatting/TableGrid.cpp (249653 => 249654)
--- trunk/Source/WebCore/layout/tableformatting/TableGrid.cpp 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/tableformatting/TableGrid.cpp 2019-09-09 19:01:28 UTC (rev 249654)
@@ -82,12 +82,6 @@
m_columns.append({ });
}
-void TableGrid::ColumnsContext::useAsLogicalWidth(WidthConstraintsType type)
-{
- for (auto& column : m_columns)
- column.setLogicalWidth(type == WidthConstraintsType::Minimum ? column.widthConstraints().minimum : column.widthConstraints().maximum);
-}
-
TableGrid::Row::Row(const Box& rowBox)
: m_layoutBox(rowBox)
{
@@ -147,8 +141,8 @@
}
}
// Initialize columns/rows if needed.
- auto missingNumberOfColumns = std::max<unsigned>(0, (initialSlotPosition.x() + columnSpan) - m_columnsContext.columns().size());
- for (unsigned column = 0; column < missingNumberOfColumns; ++column)
+ auto missingNumberOfColumns = std::max<int>(0, initialSlotPosition.x() + columnSpan - m_columnsContext.columns().size());
+ for (auto column = 0; column < missingNumberOfColumns; ++column)
m_columnsContext.addColumn();
if (isInNewRow)
@@ -174,6 +168,7 @@
auto widthConstraints = FormattingContext::IntrinsicWidthConstraints { };
for (auto& column : m_columnsContext.columns())
widthConstraints += column.widthConstraints();
+ widthConstraints.expand((m_columnsContext.columns().size() + 1) * m_horizontalSpacing);
return widthConstraints;
}
Modified: trunk/Source/WebCore/layout/tableformatting/TableGrid.h (249653 => 249654)
--- trunk/Source/WebCore/layout/tableformatting/TableGrid.h 2019-09-09 18:56:47 UTC (rev 249653)
+++ trunk/Source/WebCore/layout/tableformatting/TableGrid.h 2019-09-09 19:01:28 UTC (rev 249654)
@@ -46,6 +46,12 @@
void insertCell(const Box&, const Box& before);
void removeCell(const Box&);
+ void setHorizontalSpacing(LayoutUnit horizontalSpacing) { m_horizontalSpacing = horizontalSpacing; }
+ LayoutUnit horizontalSpacing() const { return m_horizontalSpacing; }
+
+ void setVerticalSpacing(LayoutUnit verticalSpacing) { m_verticalSpacing = verticalSpacing; }
+ LayoutUnit verticalSpacing() const { return m_verticalSpacing; }
+
using SlotPosition = IntPoint;
// Cell represents a <td> or <th>. It can span multiple slots in the grid.
@@ -68,13 +74,11 @@
void setWidthConstraints(FormattingContext::IntrinsicWidthConstraints);
FormattingContext::IntrinsicWidthConstraints widthConstraints() const;
- void setLogicalWidth(LayoutUnit);
- LayoutUnit logicalWidth() const;
-
void setLogicalLeft(LayoutUnit);
LayoutUnit logicalLeft() const;
-
LayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); }
+ void setLogicalWidth(LayoutUnit);
+ LayoutUnit logicalWidth() const;
private:
friend class ColumnsContext;
@@ -95,10 +99,8 @@
using ColumnList = Vector<Column>;
ColumnList& columns() { return m_columns; }
const ColumnList& columns() const { return m_columns; }
+ LayoutUnit logicalWidth() const { return columns().last().logicalRight() - columns().first().logicalLeft(); }
- enum class WidthConstraintsType { Minimum, Maximum };
- void useAsLogicalWidth(WidthConstraintsType);
-
private:
friend class TableGrid;
void addColumn();
@@ -148,6 +150,8 @@
CellList m_cellList;
ColumnsContext m_columnsContext;
RowList m_rows;
+ LayoutUnit m_horizontalSpacing;
+ LayoutUnit m_verticalSpacing;
};
}