Title: [261745] trunk/Source/WebCore
Revision
261745
Author
[email protected]
Date
2020-05-15 07:44:52 -0700 (Fri, 15 May 2020)

Log Message

[LFC][TFC] Move column and row balancing logic to a dedicated class
https://bugs.webkit.org/show_bug.cgi?id=211937

Reviewed by Antti Koivisto.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* layout/tableformatting/TableFormattingContext.cpp:
(WebCore::Layout::TableFormattingContext::layoutInFlowContent):
(WebCore::Layout::TableFormattingContext::setUsedGeometryForRows):
(WebCore::Layout::TableFormattingContext::computeAndDistributeExtraSpace):
(WebCore::Layout::ColumnSpan::hasSpan): Deleted.
(WebCore::Layout::ColumnSpan::isSpanned): Deleted.
(WebCore::Layout::ColumnSpan::spanCount): Deleted.
(WebCore::Layout::ColumnSpan::startSpan): Deleted.
(WebCore::Layout::ColumnSpan::endSpan): Deleted.
(WebCore::Layout::ColumnSpan::index): Deleted.
(WebCore::Layout::ColumnSpan::size): Deleted.
(WebCore::Layout::ColumnSpan::spacing): Deleted.
(WebCore::Layout::RowSpan::hasSpan): Deleted.
(WebCore::Layout::RowSpan::isSpanned): Deleted.
(WebCore::Layout::RowSpan::spanCount): Deleted.
(WebCore::Layout::RowSpan::startSpan): Deleted.
(WebCore::Layout::RowSpan::endSpan): Deleted.
(WebCore::Layout::RowSpan::index): Deleted.
(WebCore::Layout::RowSpan::size): Deleted.
(WebCore::Layout::RowSpan::spacing): Deleted.
(WebCore::Layout::GridSpace::isEmpty const): Deleted.
(): Deleted.
(WebCore::Layout::max): Deleted.
(WebCore::Layout::operator-): Deleted.
(WebCore::Layout::operator+=): Deleted.
(WebCore::Layout::operator-=): Deleted.
(WebCore::Layout::operator/): Deleted.
(WebCore::Layout::distributeAvailableSpace): Deleted.
(WebCore::Layout::TableFormattingContext::computeAndDistributeExtraHorizontalSpace): Deleted.
(WebCore::Layout::TableFormattingContext::computeAndDistributeExtraVerticalSpace): Deleted.
* layout/tableformatting/TableFormattingContext.h:
* layout/tableformatting/TableFormattingState.h:
(WebCore::Layout::TableFormattingState::tableGrid const):
* layout/tableformatting/TableGrid.h:
(WebCore::Layout::TableGrid::widthConstraints const):
(WebCore::Layout::TableGrid::Rows::list const):
(WebCore::Layout::TableGrid::widthConstraints): Deleted.
(WebCore::Layout::TableGrid::Rows::rowList const): Deleted.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (261744 => 261745)


--- trunk/Source/WebCore/ChangeLog	2020-05-15 14:40:51 UTC (rev 261744)
+++ trunk/Source/WebCore/ChangeLog	2020-05-15 14:44:52 UTC (rev 261745)
@@ -1,3 +1,51 @@
+2020-05-15  Zalan Bujtas  <[email protected]>
+
+        [LFC][TFC] Move column and row balancing logic to a dedicated class
+        https://bugs.webkit.org/show_bug.cgi?id=211937
+
+        Reviewed by Antti Koivisto.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * layout/tableformatting/TableFormattingContext.cpp:
+        (WebCore::Layout::TableFormattingContext::layoutInFlowContent):
+        (WebCore::Layout::TableFormattingContext::setUsedGeometryForRows):
+        (WebCore::Layout::TableFormattingContext::computeAndDistributeExtraSpace):
+        (WebCore::Layout::ColumnSpan::hasSpan): Deleted.
+        (WebCore::Layout::ColumnSpan::isSpanned): Deleted.
+        (WebCore::Layout::ColumnSpan::spanCount): Deleted.
+        (WebCore::Layout::ColumnSpan::startSpan): Deleted.
+        (WebCore::Layout::ColumnSpan::endSpan): Deleted.
+        (WebCore::Layout::ColumnSpan::index): Deleted.
+        (WebCore::Layout::ColumnSpan::size): Deleted.
+        (WebCore::Layout::ColumnSpan::spacing): Deleted.
+        (WebCore::Layout::RowSpan::hasSpan): Deleted.
+        (WebCore::Layout::RowSpan::isSpanned): Deleted.
+        (WebCore::Layout::RowSpan::spanCount): Deleted.
+        (WebCore::Layout::RowSpan::startSpan): Deleted.
+        (WebCore::Layout::RowSpan::endSpan): Deleted.
+        (WebCore::Layout::RowSpan::index): Deleted.
+        (WebCore::Layout::RowSpan::size): Deleted.
+        (WebCore::Layout::RowSpan::spacing): Deleted.
+        (WebCore::Layout::GridSpace::isEmpty const): Deleted.
+        (): Deleted.
+        (WebCore::Layout::max): Deleted.
+        (WebCore::Layout::operator-): Deleted.
+        (WebCore::Layout::operator+=): Deleted.
+        (WebCore::Layout::operator-=): Deleted.
+        (WebCore::Layout::operator/): Deleted.
+        (WebCore::Layout::distributeAvailableSpace): Deleted.
+        (WebCore::Layout::TableFormattingContext::computeAndDistributeExtraHorizontalSpace): Deleted.
+        (WebCore::Layout::TableFormattingContext::computeAndDistributeExtraVerticalSpace): Deleted.
+        * layout/tableformatting/TableFormattingContext.h:
+        * layout/tableformatting/TableFormattingState.h:
+        (WebCore::Layout::TableFormattingState::tableGrid const):
+        * layout/tableformatting/TableGrid.h:
+        (WebCore::Layout::TableGrid::widthConstraints const):
+        (WebCore::Layout::TableGrid::Rows::list const):
+        (WebCore::Layout::TableGrid::widthConstraints): Deleted.
+        (WebCore::Layout::TableGrid::Rows::rowList const): Deleted.
+
 2020-05-15  Alicia Boya GarcĂ­a  <[email protected]>
 
         [GStreamer][MediaStream] Fix missing video size

Modified: trunk/Source/WebCore/Sources.txt (261744 => 261745)


--- trunk/Source/WebCore/Sources.txt	2020-05-15 14:40:51 UTC (rev 261744)
+++ trunk/Source/WebCore/Sources.txt	2020-05-15 14:44:52 UTC (rev 261745)
@@ -1494,6 +1494,7 @@
 layout/tableformatting/TableFormattingContextGeometry.cpp
 layout/tableformatting/TableFormattingState.cpp
 layout/tableformatting/TableGrid.cpp
+layout/tableformatting/TableLayout.cpp
 
 loader/AdClickAttribution.cpp
 loader/CanvasActivityRecord.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (261744 => 261745)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-05-15 14:40:51 UTC (rev 261744)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-05-15 14:44:52 UTC (rev 261745)
@@ -9491,6 +9491,7 @@
 		6FE8E6F8237BA6B200758D26 /* InvalidationState.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InvalidationState.cpp; sourceTree = "<group>"; };
 		6FE9F09222211035004C5082 /* ContentChangeObserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentChangeObserver.cpp; sourceTree = "<group>"; };
 		6FEFE81D22F9D22A00114927 /* LayoutPhase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LayoutPhase.h; sourceTree = "<group>"; };
+		6FF9F1BE246D966C00435083 /* TableLayout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TableLayout.cpp; sourceTree = "<group>"; };
 		6FFA4BFE23F2FECD007E4EBC /* LayoutLineBreakBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutLineBreakBox.cpp; sourceTree = "<group>"; };
 		6FFA4C0023F2FED9007E4EBC /* LayoutLineBreakBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutLineBreakBox.h; sourceTree = "<group>"; };
 		6FFDC43E212EFF1600A9CA91 /* FloatAvoider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FloatAvoider.cpp; sourceTree = "<group>"; };
@@ -21265,6 +21266,7 @@
 			children = (
 				6FC5CA9422E3599400B13E11 /* TableFormattingContext.cpp */,
 				6FC5CA9522E3599400B13E11 /* TableFormattingContext.h */,
+				6FF9F1BE246D966C00435083 /* TableLayout.cpp */,
 				11D19C2E23159BAE008F24D3 /* TableFormattingContextGeometry.cpp */,
 				6FC5CA9222E3599300B13E11 /* TableFormattingState.cpp */,
 				6FC5CA9622E3599500B13E11 /* TableFormattingState.h */,

Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp (261744 => 261745)


--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp	2020-05-15 14:40:51 UTC (rev 261744)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp	2020-05-15 14:44:52 UTC (rev 261745)
@@ -53,8 +53,7 @@
     auto availableHorizontalSpace = constraints.horizontal.logicalWidth;
     auto availableVerticalSpace = constraints.vertical.logicalHeight;
     // 1. Compute width and height for the grid.
-    computeAndDistributeExtraHorizontalSpace(availableHorizontalSpace);
-    computeAndDistributeExtraVerticalSpace(availableHorizontalSpace, availableVerticalSpace);
+    computeAndDistributeExtraSpace(availableHorizontalSpace, availableVerticalSpace);
     // 2. Finalize cells.
     setUsedGeometryForCells(availableHorizontalSpace);
     // 3. Finalize rows.
@@ -111,9 +110,11 @@
 void TableFormattingContext::setUsedGeometryForRows(LayoutUnit availableHorizontalSpace)
 {
     auto& grid = formattingState().tableGrid();
+    auto& rows = grid.rows().list();
+
     auto rowWidth = grid.columns().logicalWidth() + 2 * grid.horizontalSpacing();
     auto rowLogicalTop = grid.verticalSpacing();
-    for (auto& row : grid.rows().list()) {
+    for (auto& row : rows) {
         auto& rowBox = row.box();
         auto& rowDisplayBox = formattingState().displayBox(rowBox);
         computeBorderAndPadding(rowBox, HorizontalConstraints { { }, availableHorizontalSpace });
@@ -130,6 +131,23 @@
         row.setLogicalTop(rowLogicalTop);
         rowLogicalTop += row.logicalHeight() + grid.verticalSpacing();
     }
+
+    auto& columns = grid.columns();
+    Vector<InlineLayoutUnit> rowBaselines(rows.size());
+    // Now that cells are laid out, let's compute the row baselines.
+    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.isRowSpanned())
+                continue;
+            if (slot.hasRowSpan())
+                continue;
+            auto& cell = slot.cell();
+            rowBaselines[rowIndex] = std::max(rowBaselines[rowIndex], cell.baselineOffset());
+        }
+    }
+    for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex)
+        rows[rowIndex].setBaselineOffset(rowBaselines[rowIndex]);
 }
 
 void TableFormattingContext::setUsedGeometryForSections(const ConstraintsForInFlowContent& constraints)
@@ -350,259 +368,29 @@
     return tableWidthConstraints;
 }
 
-struct ColumnSpan {
-    static size_t hasSpan(const TableGrid::Slot& slot) { return slot.hasColumnSpan(); }
-    static size_t isSpanned(const TableGrid::Slot& slot) { return slot.isColumnSpanned(); }
-
-    static size_t spanCount(const TableGrid::Cell& cell) { return cell.columnSpan(); }
-    static size_t startSpan(const TableGrid::Cell& cell) { return cell.startColumn(); }
-    static size_t endSpan(const TableGrid::Cell& cell) { return cell.endColumn(); }
-
-    static size_t index(size_t columnIndex, size_t /*rowIndex*/) { return columnIndex; }
-    static size_t size(const TableGrid& grid) { return grid.columns().size(); }
-
-    static LayoutUnit spacing(const TableGrid& grid) { return grid.horizontalSpacing(); }
-};
-
-struct RowSpan {
-    static size_t hasSpan(const TableGrid::Slot& slot) { return slot.hasRowSpan(); }
-    static size_t isSpanned(const TableGrid::Slot& slot) { return slot.isRowSpanned(); }
-
-    static size_t spanCount(const TableGrid::Cell& cell) { return cell.rowSpan(); }
-    static size_t startSpan(const TableGrid::Cell& cell) { return cell.startRow(); }
-    static size_t endSpan(const TableGrid::Cell& cell) { return cell.endRow(); }
-
-    static size_t index(size_t /*columnIndex*/, size_t rowIndex) { return rowIndex; }
-    static size_t size(const TableGrid& grid) { return grid.rows().size(); }
-
-    static LayoutUnit spacing(const TableGrid& grid) { return grid.verticalSpacing(); }
-};
-
-struct GridSpace {
-    bool isEmpty() const { return !value; }
-
-    // Initial width/height for column/row we start the distribution width (usually a minumum width).
-    float value { 0 };
-    // The base to compute the distribution ratio. It normally matches the [value] but in some cases we use the maximum value to distribute the extra space. 
-    float distributionBase { 0 };
-};
-
-inline static GridSpace max(const GridSpace& a, const GridSpace& b)
+void TableFormattingContext::computeAndDistributeExtraSpace(LayoutUnit availableHorizontalSpace, Optional<LayoutUnit> availableVerticalSpace)
 {
-    return { std::max(a.value, b.value), std::max(a.distributionBase, b.distributionBase) };
-}
+    // Compute and balance the column and row spaces.
+    auto& grid = formattingState().tableGrid();
+    auto& columns = grid.columns().list();
+    auto tableLayout = this->tableLayout();
 
-inline static GridSpace& operator-(GridSpace& a, const GridSpace& b)
-{
-    a.value = std::max(0.0f, a.value - b.value);
-    a.distributionBase = std::max(0.0f, a.distributionBase - b.distributionBase);
-    return a;
-}
-
-inline static GridSpace& operator+=(GridSpace& a, const GridSpace& b)
-{
-    a.value += b.value;
-    a.distributionBase += b.distributionBase;
-    return a;
-}
-
-inline static GridSpace& operator-=(GridSpace& a, const GridSpace& b)
-{
-    return a - b;
-}
-
-inline static GridSpace& operator/(GridSpace& a, unsigned value)
-{
-    a.value /= value;
-    a.distributionBase /= value;
-    return a;
-}
-
-using DistributedSpaces = Vector<float>;
-template <typename SpanType>
-static DistributedSpaces distributeAvailableSpace(const TableGrid& grid, LayoutUnit availableSpace, const WTF::Function<GridSpace(const TableGrid::Slot&, size_t)>& slotSpace)
-{
-    struct ResolvedItem {
-        GridSpace slotSpace;
-        bool isFixed { false };
-    };
-
-    auto& columns = grid.columns();
-    auto& rows = grid.rows();
-    // 1. Collect the non-spanning spaces first. They are used for the final distribution as well as for distributing the spanning space.
-    Vector<Optional<ResolvedItem>> resolvedItems(SpanType::size(grid));
+    // Columns first.
+    auto distributedHorizontalSpaces = tableLayout.distributedHorizontalSpace(availableHorizontalSpace);
+    ASSERT(distributedHorizontalSpaces.size() == columns.size());
+    auto columnLogicalLeft = grid.horizontalSpacing();
     for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
-        for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
-            auto& slot = *grid.slot({ columnIndex, rowIndex });
-            if (SpanType::hasSpan(slot) || SpanType::isSpanned(slot))
-                continue;
-            auto index = SpanType::index(columnIndex, rowIndex);
-            if (!resolvedItems[index])
-                resolvedItems[index] = ResolvedItem { };
-            resolvedItems[index]->slotSpace = max(resolvedItems[index]->slotSpace, slotSpace(slot, index));
-        }
+        auto& column = columns[columnIndex];
+        column.setLogicalLeft(columnLogicalLeft);
+        column.setLogicalWidth(distributedHorizontalSpaces[columnIndex]);
+        columnLogicalLeft += distributedHorizontalSpaces[columnIndex] + grid.horizontalSpacing();
     }
 
-    // 2. Collect the spanning cells.
-    struct SpanningCell {
-        SlotPosition position;
-        GridSpace unresolvedSpace;
-    };
-    Vector<SpanningCell> spanningCells;
+    // Rows second.
+    auto& rows = grid.rows().list();
     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 (SpanType::hasSpan(slot))
-                spanningCells.append({ { columnIndex, rowIndex }, slotSpace(slot, SpanType::index(columnIndex, rowIndex)) });
-        }
-    }
-    // We need these spanning cells in the order of the number of columns/rows they span so that
-    // we can resolve overlapping spans starting with the shorter ones e.g.
-    // <td colspan=4>#a</td><td>#b</td>
-    // <td colspan=2>#c</td><td colspan=3>#d</td>
-    std::sort(spanningCells.begin(), spanningCells.end(), [&] (auto& a, auto& b) {
-        return SpanType::spanCount(grid.slot(a.position)->cell()) < SpanType::spanCount(grid.slot(b.position)->cell());
-    });
-
-    // 3. Distribute the spanning cells' mimimum space across the columns/rows using the non-spanning spaces.
-    // e.g. [ 1 ][ 5 ][ 1 ]
-    //      [    9   ][ 1 ]
-    // The initial widths are: [ 2 ][ 7 ][ 1 ]
-    for (auto spanningCell : spanningCells) {
-        auto& cell = grid.slot(spanningCell.position)->cell();
-        auto unresolvedSpanningSpace = spanningCell.unresolvedSpace;
-        if (!resolvedItems[SpanType::startSpan(cell)] || !resolvedItems[SpanType::endSpan(cell) - 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
-            // 1. Take colspan=2 (shortest span) and resolve column 1 and 2
-            // 2. Take colspan=3 and resolve column 3 and 4 (5 is resolved because it already has a non-spanning cell).
-            // 3. colspan=4 needs no resolving because all the spanned columns (1 2 3 4) have already been resolved.
-            auto unresolvedColumnCount = cell.columnSpan();
-            for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex) {
-                if (!resolvedItems[spanIndex])
-                    continue;
-                ASSERT(unresolvedColumnCount);
-                --unresolvedColumnCount;
-                unresolvedSpanningSpace -= resolvedItems[spanIndex]->slotSpace;
-            }
-            ASSERT(unresolvedColumnCount);
-            auto equalSpaceForSpannedColumns = unresolvedSpanningSpace / unresolvedColumnCount;
-            for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex) {
-                if (resolvedItems[spanIndex])
-                    continue;
-                resolvedItems[spanIndex] = ResolvedItem { equalSpaceForSpannedColumns, false };
-            }
-        } else {
-            // 1. Collect the non-spaning resolved spaces.
-            // 2. Distribute the extra space among the spanned columns/rows based on the resolved space values.
-            // e.g. spanning width: [   9   ]. Resolved widths for the spanned columns: [ 1 ] [ 2 ]
-            // New resolved widths: [ 3 ] [ 6 ].
-            auto resolvedSpanningSpace = GridSpace { };
-            for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex)
-                resolvedSpanningSpace += resolvedItems[spanIndex]->slotSpace;
-            if (resolvedSpanningSpace.value >= unresolvedSpanningSpace.value) {
-                // The spanning cell fits the spanned columns/rows just fine. Nothing to distribute.
-                continue;
-            }
-            auto spacing = SpanType::spacing(grid) * (SpanType::spanCount(cell) - 1);
-            auto spaceToDistribute = unresolvedSpanningSpace - GridSpace { spacing, spacing } - resolvedSpanningSpace; 
-            if (!spaceToDistribute.isEmpty()) {
-                auto distributionRatio = spaceToDistribute.distributionBase / resolvedSpanningSpace.distributionBase;
-                for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex)
-                    resolvedItems[spanIndex]->slotSpace += GridSpace { resolvedItems[spanIndex]->slotSpace.value * distributionRatio, resolvedItems[spanIndex]->slotSpace.distributionBase * distributionRatio};
-            }
-        }
-    }
-    // 4. Distribute the extra space using the final resolved widths.
-#if ASSERT_ENABLED
-    // We have to have all the spaces resolved at this point.
-    for (auto& resolvedItem : resolvedItems)
-        ASSERT(resolvedItem);
-#endif
-    // Fixed size cells don't participate in available space distribution.
-    auto adjustabledSpace = GridSpace { };
-    for (auto& resolvedItem : resolvedItems) {
-        if (resolvedItem->isFixed)
-            continue;
-        adjustabledSpace += resolvedItem->slotSpace;
-    }
-
-    DistributedSpaces distributedSpaces(resolvedItems.size());
-    float spaceToDistribute = availableSpace - adjustabledSpace.value - ((resolvedItems.size() + 1) * SpanType::spacing(grid));
-    // Essentially the remaining space to distribute should never be negative. LayoutUnit::epsilon() is required to compensate for LayoutUnit's low precision.
-    ASSERT(spaceToDistribute >= -LayoutUnit::epsilon() * resolvedItems.size());
-    // Distribute the extra space based on the resolved spaces.
-    auto distributionRatio = spaceToDistribute / adjustabledSpace.distributionBase;
-    for (size_t index = 0; index < resolvedItems.size(); ++index) {
-        auto slotSpace = resolvedItems[index]->slotSpace.value;
-        auto needsSpaceDistribution = spaceToDistribute && !resolvedItems[index]->isFixed;
-        distributedSpaces[index] = slotSpace;
-        if (!needsSpaceDistribution)
-            continue;
-        distributedSpaces[index] += resolvedItems[index]->slotSpace.distributionBase * distributionRatio;
-    }
-    return distributedSpaces;
-}
-
-void TableFormattingContext::computeAndDistributeExtraHorizontalSpace(LayoutUnit availableHorizontalSpace)
-{
-    auto& grid = formattingState().tableGrid();
-    auto& columns = grid.columns();
-    auto tableWidthConstraints = *grid.widthConstraints();
-
-    enum class ColumnWidthBalancingBase { MinimumWidth, MaximumWidth };
-    auto computeColumnWidths = [&] (auto columnWidthBalancingBase, auto extraHorizontalSpace) {
-        auto distributedSpaces = distributeAvailableSpace<ColumnSpan>(grid, extraHorizontalSpace, [&] (const TableGrid::Slot& slot, size_t columnIndex) {
-            auto& column = columns.list()[columnIndex];
-            auto columnBoxFixedWidth = column.box() ? column.box()->columnWidth().valueOr(0_lu) : 0_lu;
-            if (columnWidthBalancingBase == ColumnWidthBalancingBase::MinimumWidth) {
-                auto minimumWidth = std::max<float>(slot.widthConstraints().minimum, columnBoxFixedWidth);
-                return GridSpace { minimumWidth, minimumWidth };
-            }
-            // When the column has a fixed width cell, the maximum width balancing is based on the minimum width.
-            auto minimumWidth = std::max<float>(slot.widthConstraints().minimum, columnBoxFixedWidth);
-            auto maximumWidth = std::max<float>(slot.widthConstraints().maximum, columnBoxFixedWidth);
-            if (column.isFixedWidth())
-                return GridSpace { minimumWidth, maximumWidth };
-            return GridSpace { maximumWidth, maximumWidth };
-        });
-        // Set final horizontal position and width.
-        auto columnLogicalLeft = grid.horizontalSpacing();
-        for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
-            auto& column = columns.list()[columnIndex];
-            auto columnWidth = LayoutUnit { distributedSpaces[columnIndex] };
-
-            column.setLogicalLeft(columnLogicalLeft);
-            column.setLogicalWidth(columnWidth);
-            columnLogicalLeft += columnWidth + grid.horizontalSpacing();
-        }
-    };
-    auto columnWidthBalancingBase = availableHorizontalSpace == tableWidthConstraints.maximum ? ColumnWidthBalancingBase::MaximumWidth : ColumnWidthBalancingBase::MinimumWidth;
-    computeColumnWidths(columnWidthBalancingBase, availableHorizontalSpace);
-}
-
-void TableFormattingContext::computeAndDistributeExtraVerticalSpace(LayoutUnit availableHorizontalSpace, Optional<LayoutUnit> availableVerticalSpace)
-{
-    auto& grid = formattingState().tableGrid();
-    auto& columns = grid.columns().list();
-    auto& rows = grid.rows();
-
-    struct RowHeight {
-        InlineLayoutUnit height() const { return ascent + descent; }
-
-        InlineLayoutUnit ascent { 0 };
-        InlineLayoutUnit descent { 0 };
-    };
-    Vector<RowHeight> rowHeight(rows.size());
-    Vector<SlotPosition> spanningRowPositionList;
-    LayoutUnit tableUsedHeight;
-    // 1. Collect initial, basline aligned row heights.
-    for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
-        auto maximumColumnAscent = InlineLayoutUnit { };
-        auto maximumColumnDescent = InlineLayoutUnit { };
-        for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
-            auto& slot = *grid.slot({ columnIndex, rowIndex });
             if (slot.isRowSpanned())
                 continue;
             layoutCell(slot.cell(), availableHorizontalSpace);
@@ -611,37 +399,18 @@
             // The minimum height of a row (without spanning-related height distribution) is defined as the height of an hypothetical
             // linebox containing the cells originating in the row.
             auto& cell = slot.cell();
-            auto& cellBox = cell.box();
-            cell.setBaselineOffset(geometry().usedBaselineForCell(cellBox));
-            maximumColumnAscent = std::max(maximumColumnAscent, cell.baselineOffset());
-            maximumColumnDescent = std::max(maximumColumnDescent, geometryForBox(cellBox).height() - cell.baselineOffset());
+            cell.setBaselineOffset(geometry().usedBaselineForCell(cell.box()));
         }
-        // <tr style="height: 10px"> is considered as min height.
-        rowHeight[rowIndex] = { maximumColumnAscent, maximumColumnDescent };
-        tableUsedHeight += maximumColumnAscent + maximumColumnDescent;
     }
-    // FIXME: Collect spanning row maximum heights.
 
-    // Distribute extra space if the table is supposed to be taller than the sum of the row heights.
-    tableUsedHeight += (rows.size() + 1) * grid.verticalSpacing();
-    auto availableSpace = std::max(availableVerticalSpace.valueOr(0_lu), tableUsedHeight);
-    auto distributedSpaces = distributeAvailableSpace<RowSpan>(grid, availableSpace, [&] (const TableGrid::Slot& slot, size_t rowIndex) {
-        if (slot.hasRowSpan())
-            return GridSpace { geometryForBox(slot.cell().box()).height(), geometryForBox(slot.cell().box()).height() };
-        auto computedRowHeight = geometry().computedHeight(rows.list()[rowIndex].box(), { });
-        auto height = std::max<float>(rowHeight[rowIndex].height(), computedRowHeight.valueOr(0_lu));
-        return GridSpace { height, height };
-    });
-
+    auto distributedVerticalSpaces = tableLayout.distributedVerticalSpace(availableVerticalSpace);
+    ASSERT(distributedVerticalSpaces.size() == rows.size());
     auto rowLogicalTop = grid.verticalSpacing();
     for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
-        auto& row = grid.rows().list()[rowIndex];
-        auto rowUsedHeight = LayoutUnit { distributedSpaces[rowIndex] };
-
-        row.setLogicalHeight(rowUsedHeight);
-        row.setBaselineOffset(rowHeight[rowIndex].ascent);
+        auto& row = rows[rowIndex];
+        row.setLogicalHeight(distributedVerticalSpaces[rowIndex]);
         row.setLogicalTop(rowLogicalTop);
-        rowLogicalTop += rowUsedHeight + grid.verticalSpacing();
+        rowLogicalTop += distributedVerticalSpaces[rowIndex] + grid.verticalSpacing();
     }
 }
 

Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h (261744 => 261745)


--- trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h	2020-05-15 14:40:51 UTC (rev 261744)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h	2020-05-15 14:44:52 UTC (rev 261745)
@@ -28,6 +28,7 @@
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "FormattingContext.h"
+#include "TableFormattingState.h"
 #include "TableGrid.h"
 #include <wtf/IsoMalloc.h>
 
@@ -35,7 +36,6 @@
 namespace Layout {
 
 class InvalidationState;
-class TableFormattingState;
 // This class implements the layout logic for table formatting contexts.
 // https://www.w3.org/TR/CSS22/tables.html
 class TableFormattingContext final : public FormattingContext {
@@ -45,6 +45,21 @@
     void layoutInFlowContent(InvalidationState&, const ConstraintsForInFlowContent&) override;
 
 private:
+    class TableLayout {
+    public:
+        TableLayout(const TableFormattingContext&, const TableGrid&);
+
+        using DistributedSpaces = Vector<LayoutUnit>;
+        DistributedSpaces distributedHorizontalSpace(LayoutUnit availableHorizontalSpace);
+        DistributedSpaces distributedVerticalSpace(Optional<LayoutUnit> availableVerticalSpace);
+
+    private:
+        const TableFormattingContext& formattingContext() const { return m_formattingContext; }
+
+        const TableFormattingContext& m_formattingContext;
+        const TableGrid& m_grid;
+    };
+
     class Geometry : public FormattingContext::Geometry {
     public:
         LayoutUnit cellHeigh(const ContainerBox&) const;
@@ -59,6 +74,7 @@
         const TableFormattingContext& formattingContext() const { return downcast<TableFormattingContext>(FormattingContext::Geometry::formattingContext()); }
     };
     TableFormattingContext::Geometry geometry() const { return Geometry(*this); }
+    TableFormattingContext::TableLayout tableLayout() const { return TableLayout(*this, formattingState().tableGrid()); }
 
     IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
     void layoutCell(const TableGrid::Cell&, LayoutUnit availableHorizontalSpace, Optional<LayoutUnit> usedCellHeight = WTF::nullopt);
@@ -68,8 +84,7 @@
 
     void ensureTableGrid();
     IntrinsicWidthConstraints computedPreferredWidthForColumns();
-    void computeAndDistributeExtraHorizontalSpace(LayoutUnit availableHorizontalSpace);
-    void computeAndDistributeExtraVerticalSpace(LayoutUnit availableHorizontalSpace, Optional<LayoutUnit> availableVerticalSpace);
+    void computeAndDistributeExtraSpace(LayoutUnit availableHorizontalSpace, Optional<LayoutUnit> availableVerticalSpace);
 
     const TableFormattingState& formattingState() const { return downcast<TableFormattingState>(FormattingContext::formattingState()); }
     TableFormattingState& formattingState() { return downcast<TableFormattingState>(FormattingContext::formattingState()); }

Modified: trunk/Source/WebCore/layout/tableformatting/TableFormattingState.h (261744 => 261745)


--- trunk/Source/WebCore/layout/tableformatting/TableFormattingState.h	2020-05-15 14:40:51 UTC (rev 261744)
+++ trunk/Source/WebCore/layout/tableformatting/TableFormattingState.h	2020-05-15 14:44:52 UTC (rev 261745)
@@ -42,6 +42,7 @@
     ~TableFormattingState();
 
     TableGrid& tableGrid() { return m_tableGrid; }
+    const TableGrid& tableGrid() const { return m_tableGrid; }
 
 private:
     TableGrid m_tableGrid;

Modified: trunk/Source/WebCore/layout/tableformatting/TableGrid.h (261744 => 261745)


--- trunk/Source/WebCore/layout/tableformatting/TableGrid.h	2020-05-15 14:40:51 UTC (rev 261744)
+++ trunk/Source/WebCore/layout/tableformatting/TableGrid.h	2020-05-15 14:44:52 UTC (rev 261745)
@@ -56,7 +56,7 @@
     LayoutUnit verticalSpacing() const { return m_verticalSpacing; }
 
     void setWidthConstraints(FormattingContext::IntrinsicWidthConstraints intrinsicWidthConstraints) { m_intrinsicWidthConstraints = intrinsicWidthConstraints; }
-    Optional<FormattingContext::IntrinsicWidthConstraints> widthConstraints() { return m_intrinsicWidthConstraints; }
+    Optional<FormattingContext::IntrinsicWidthConstraints> widthConstraints() const { return m_intrinsicWidthConstraints; }
 
     // Column represents a vertical set of slots in the grid. A column has horizontal position and width.
     class Column {
@@ -132,7 +132,7 @@
     public:
         using RowList = Vector<Row>;
         RowList& list() { return m_rowList; }
-        const RowList& rowList() const { return m_rowList; }
+        const RowList& list() const { return m_rowList; }
 
         void addRow(const ContainerBox&);
 

Added: trunk/Source/WebCore/layout/tableformatting/TableLayout.cpp (0 => 261745)


--- trunk/Source/WebCore/layout/tableformatting/TableLayout.cpp	                        (rev 0)
+++ trunk/Source/WebCore/layout/tableformatting/TableLayout.cpp	2020-05-15 14:44:52 UTC (rev 261745)
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TableFormattingContext.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "DisplayBox.h"
+#include "LayoutBox.h"
+
+namespace WebCore {
+namespace Layout {
+
+// https://www.w3.org/TR/css-tables-3/#table-layout-algorithm
+TableFormattingContext::TableLayout::TableLayout(const TableFormattingContext& formattingContext, const TableGrid& grid)
+    : m_formattingContext(formattingContext)
+    , m_grid(grid)
+{
+}
+
+struct ColumnSpan {
+    static size_t hasSpan(const TableGrid::Slot& slot) { return slot.hasColumnSpan(); }
+    static size_t isSpanned(const TableGrid::Slot& slot) { return slot.isColumnSpanned(); }
+
+    static size_t spanCount(const TableGrid::Cell& cell) { return cell.columnSpan(); }
+    static size_t startSpan(const TableGrid::Cell& cell) { return cell.startColumn(); }
+    static size_t endSpan(const TableGrid::Cell& cell) { return cell.endColumn(); }
+
+    static size_t index(size_t columnIndex, size_t /*rowIndex*/) { return columnIndex; }
+    static size_t size(const TableGrid& grid) { return grid.columns().size(); }
+
+    static LayoutUnit spacing(const TableGrid& grid) { return grid.horizontalSpacing(); }
+};
+
+struct RowSpan {
+    static size_t hasSpan(const TableGrid::Slot& slot) { return slot.hasRowSpan(); }
+    static size_t isSpanned(const TableGrid::Slot& slot) { return slot.isRowSpanned(); }
+
+    static size_t spanCount(const TableGrid::Cell& cell) { return cell.rowSpan(); }
+    static size_t startSpan(const TableGrid::Cell& cell) { return cell.startRow(); }
+    static size_t endSpan(const TableGrid::Cell& cell) { return cell.endRow(); }
+
+    static size_t index(size_t /*columnIndex*/, size_t rowIndex) { return rowIndex; }
+    static size_t size(const TableGrid& grid) { return grid.rows().size(); }
+
+    static LayoutUnit spacing(const TableGrid& grid) { return grid.verticalSpacing(); }
+};
+
+struct GridSpace {
+    bool isEmpty() const { return !value; }
+
+    // Initial width/height for column/row we start the distribution width (usually a minumum width).
+    float value { 0 };
+    // The base to compute the distribution ratio. It normally matches the [value] but in some cases we use the maximum value to distribute the extra space. 
+    float distributionBase { 0 };
+};
+
+inline static GridSpace max(const GridSpace& a, const GridSpace& b)
+{
+    return { std::max(a.value, b.value), std::max(a.distributionBase, b.distributionBase) };
+}
+
+inline static GridSpace& operator-(GridSpace& a, const GridSpace& b)
+{
+    a.value = std::max(0.0f, a.value - b.value);
+    a.distributionBase = std::max(0.0f, a.distributionBase - b.distributionBase);
+    return a;
+}
+
+inline static GridSpace& operator+=(GridSpace& a, const GridSpace& b)
+{
+    a.value += b.value;
+    a.distributionBase += b.distributionBase;
+    return a;
+}
+
+inline static GridSpace& operator-=(GridSpace& a, const GridSpace& b)
+{
+    return a - b;
+}
+
+inline static GridSpace& operator/(GridSpace& a, unsigned value)
+{
+    a.value /= value;
+    a.distributionBase /= value;
+    return a;
+}
+
+template <typename SpanType>
+static Vector<LayoutUnit> distributeAvailableSpace(const TableGrid& grid, LayoutUnit availableSpace, const WTF::Function<GridSpace(const TableGrid::Slot&, size_t)>& slotSpace)
+{
+    struct ResolvedItem {
+        GridSpace slotSpace;
+        bool isFixed { false };
+    };
+
+    auto& columns = grid.columns();
+    auto& rows = grid.rows();
+    // 1. Collect the non-spanning spaces first. They are used for the final distribution as well as for distributing the spanning space.
+    Vector<Optional<ResolvedItem>> resolvedItems(SpanType::size(grid));
+    for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
+        for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
+            auto& slot = *grid.slot({ columnIndex, rowIndex });
+            if (SpanType::hasSpan(slot) || SpanType::isSpanned(slot))
+                continue;
+            auto index = SpanType::index(columnIndex, rowIndex);
+            if (!resolvedItems[index])
+                resolvedItems[index] = ResolvedItem { };
+            resolvedItems[index]->slotSpace = max(resolvedItems[index]->slotSpace, slotSpace(slot, index));
+        }
+    }
+
+    // 2. Collect the spanning cells.
+    struct SpanningCell {
+        SlotPosition position;
+        GridSpace unresolvedSpace;
+    };
+    Vector<SpanningCell> spanningCells;
+    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 (SpanType::hasSpan(slot))
+                spanningCells.append({ { columnIndex, rowIndex }, slotSpace(slot, SpanType::index(columnIndex, rowIndex)) });
+        }
+    }
+    // We need these spanning cells in the order of the number of columns/rows they span so that
+    // we can resolve overlapping spans starting with the shorter ones e.g.
+    // <td colspan=4>#a</td><td>#b</td>
+    // <td colspan=2>#c</td><td colspan=3>#d</td>
+    std::sort(spanningCells.begin(), spanningCells.end(), [&] (auto& a, auto& b) {
+        return SpanType::spanCount(grid.slot(a.position)->cell()) < SpanType::spanCount(grid.slot(b.position)->cell());
+    });
+
+    // 3. Distribute the spanning cells' mimimum space across the columns/rows using the non-spanning spaces.
+    // e.g. [ 1 ][ 5 ][ 1 ]
+    //      [    9   ][ 1 ]
+    // The initial widths are: [ 2 ][ 7 ][ 1 ]
+    for (auto spanningCell : spanningCells) {
+        auto& cell = grid.slot(spanningCell.position)->cell();
+        auto unresolvedSpanningSpace = spanningCell.unresolvedSpace;
+        if (!resolvedItems[SpanType::startSpan(cell)] || !resolvedItems[SpanType::endSpan(cell) - 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
+            // 1. Take colspan=2 (shortest span) and resolve column 1 and 2
+            // 2. Take colspan=3 and resolve column 3 and 4 (5 is resolved because it already has a non-spanning cell).
+            // 3. colspan=4 needs no resolving because all the spanned columns (1 2 3 4) have already been resolved.
+            auto unresolvedColumnCount = cell.columnSpan();
+            for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex) {
+                if (!resolvedItems[spanIndex])
+                    continue;
+                ASSERT(unresolvedColumnCount);
+                --unresolvedColumnCount;
+                unresolvedSpanningSpace -= resolvedItems[spanIndex]->slotSpace;
+            }
+            ASSERT(unresolvedColumnCount);
+            auto equalSpaceForSpannedColumns = unresolvedSpanningSpace / unresolvedColumnCount;
+            for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex) {
+                if (resolvedItems[spanIndex])
+                    continue;
+                resolvedItems[spanIndex] = ResolvedItem { equalSpaceForSpannedColumns, false };
+            }
+        } else {
+            // 1. Collect the non-spaning resolved spaces.
+            // 2. Distribute the extra space among the spanned columns/rows based on the resolved space values.
+            // e.g. spanning width: [   9   ]. Resolved widths for the spanned columns: [ 1 ] [ 2 ]
+            // New resolved widths: [ 3 ] [ 6 ].
+            auto resolvedSpanningSpace = GridSpace { };
+            for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex)
+                resolvedSpanningSpace += resolvedItems[spanIndex]->slotSpace;
+            if (resolvedSpanningSpace.value >= unresolvedSpanningSpace.value) {
+                // The spanning cell fits the spanned columns/rows just fine. Nothing to distribute.
+                continue;
+            }
+            auto spacing = SpanType::spacing(grid) * (SpanType::spanCount(cell) - 1);
+            auto spaceToDistribute = unresolvedSpanningSpace - GridSpace { spacing, spacing } - resolvedSpanningSpace; 
+            if (!spaceToDistribute.isEmpty()) {
+                auto distributionRatio = spaceToDistribute.distributionBase / resolvedSpanningSpace.distributionBase;
+                for (auto spanIndex = SpanType::startSpan(cell); spanIndex < SpanType::endSpan(cell); ++spanIndex)
+                    resolvedItems[spanIndex]->slotSpace += GridSpace { resolvedItems[spanIndex]->slotSpace.value * distributionRatio, resolvedItems[spanIndex]->slotSpace.distributionBase * distributionRatio};
+            }
+        }
+    }
+    // 4. Distribute the extra space using the final resolved widths.
+#if ASSERT_ENABLED
+    // We have to have all the spaces resolved at this point.
+    for (auto& resolvedItem : resolvedItems)
+        ASSERT(resolvedItem);
+#endif
+    // Fixed size cells don't participate in available space distribution.
+    auto adjustabledSpace = GridSpace { };
+    for (auto& resolvedItem : resolvedItems) {
+        if (resolvedItem->isFixed)
+            continue;
+        adjustabledSpace += resolvedItem->slotSpace;
+    }
+
+    Vector<LayoutUnit> distributedSpaces(resolvedItems.size());
+    float spaceToDistribute = availableSpace - adjustabledSpace.value - ((resolvedItems.size() + 1) * SpanType::spacing(grid));
+    // Essentially the remaining space to distribute should never be negative. LayoutUnit::epsilon() is required to compensate for LayoutUnit's low precision.
+    ASSERT(spaceToDistribute >= -LayoutUnit::epsilon() * resolvedItems.size());
+    // Distribute the extra space based on the resolved spaces.
+    auto distributionRatio = spaceToDistribute / adjustabledSpace.distributionBase;
+    for (size_t index = 0; index < resolvedItems.size(); ++index) {
+        auto slotSpace = resolvedItems[index]->slotSpace.value;
+        auto needsSpaceDistribution = spaceToDistribute && !resolvedItems[index]->isFixed;
+        distributedSpaces[index] = LayoutUnit { slotSpace };
+        if (!needsSpaceDistribution)
+            continue;
+        distributedSpaces[index] += LayoutUnit { resolvedItems[index]->slotSpace.distributionBase * distributionRatio };
+    }
+    return distributedSpaces;
+}
+
+TableFormattingContext::TableLayout::DistributedSpaces TableFormattingContext::TableLayout::distributedHorizontalSpace(LayoutUnit availableHorizontalSpace)
+{
+    enum class ColumnWidthBalancingBase { MinimumWidth, MaximumWidth };
+    auto columnWidthBalancingBase = availableHorizontalSpace == m_grid.widthConstraints()->maximum ? ColumnWidthBalancingBase::MaximumWidth : ColumnWidthBalancingBase::MinimumWidth;
+    return distributeAvailableSpace<ColumnSpan>(m_grid, availableHorizontalSpace, [&] (const TableGrid::Slot& slot, size_t columnIndex) {
+        auto& column = m_grid.columns().list()[columnIndex];
+        auto columnBoxFixedWidth = column.box() ? column.box()->columnWidth().valueOr(0_lu) : 0_lu;
+        if (columnWidthBalancingBase == ColumnWidthBalancingBase::MinimumWidth) {
+            auto minimumWidth = std::max<float>(slot.widthConstraints().minimum, columnBoxFixedWidth);
+            return GridSpace { minimumWidth, minimumWidth };
+        }
+        // When the column has a fixed width cell, the maximum width balancing is based on the minimum width.
+        auto minimumWidth = std::max<float>(slot.widthConstraints().minimum, columnBoxFixedWidth);
+        auto maximumWidth = std::max<float>(slot.widthConstraints().maximum, columnBoxFixedWidth);
+        if (column.isFixedWidth())
+            return GridSpace { minimumWidth, maximumWidth };
+        return GridSpace { maximumWidth, maximumWidth };
+    });
+}
+
+TableFormattingContext::TableLayout::DistributedSpaces TableFormattingContext::TableLayout::distributedVerticalSpace(Optional<LayoutUnit> availableVerticalSpace)
+{
+    auto& rows = m_grid.rows();
+    auto& columns = m_grid.columns();
+
+    Vector<LayoutUnit> rowHeight(rows.size());
+    auto tableUsedHeight = LayoutUnit { };
+    // 2. Collect initial, baseline aligned row heights.
+    for (size_t rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
+        auto maximumColumnAscent = InlineLayoutUnit { };
+        auto maximumColumnDescent = InlineLayoutUnit { };
+        for (size_t columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
+            auto& slot = *m_grid.slot({ columnIndex, rowIndex });
+            if (slot.isRowSpanned())
+                continue;
+            if (slot.hasRowSpan())
+                continue;
+            // The minimum height of a row (without spanning-related height distribution) is defined as the height of an hypothetical
+            // linebox containing the cells originating in the row.
+            auto& cell = slot.cell();
+            maximumColumnAscent = std::max(maximumColumnAscent, cell.baselineOffset());
+            maximumColumnDescent = std::max(maximumColumnDescent, formattingContext().geometryForBox(cell.box()).height() - cell.baselineOffset());
+        }
+        // <tr style="height: 10px"> is considered as min height.
+        rowHeight[rowIndex] = maximumColumnAscent + maximumColumnDescent;
+        tableUsedHeight += rowHeight[rowIndex];
+    }
+    // FIXME: Collect spanning row maximum heights.
+
+    tableUsedHeight += (rows.size() + 1) * m_grid.verticalSpacing();
+    auto availableSpace = std::max(availableVerticalSpace.valueOr(0_lu), tableUsedHeight);
+    // Distribute extra space if the table is supposed to be taller than the sum of the row heights.
+    return distributeAvailableSpace<RowSpan>(m_grid, availableSpace, [&] (const TableGrid::Slot& slot, size_t rowIndex) {
+        if (slot.hasRowSpan())
+            return GridSpace { formattingContext().geometryForBox(slot.cell().box()).height(), formattingContext().geometryForBox(slot.cell().box()).height() };
+        auto& rows = m_grid.rows();
+        auto computedRowHeight = formattingContext().geometry().computedHeight(rows.list()[rowIndex].box(), { });
+        auto height = std::max<float>(rowHeight[rowIndex], computedRowHeight.valueOr(0_lu));
+        return GridSpace { height, height };
+    });
+}
+
+}
+}
+
+#endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to