Title: [259982] trunk/Source/WebCore
Revision
259982
Author
[email protected]
Date
2020-04-12 10:21:44 -0700 (Sun, 12 Apr 2020)

Log Message

[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.

Modified Paths

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>>;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to