Changeset 248834 in webkit


Ignore:
Timestamp:
Aug 18, 2019 3:16:52 PM (5 years ago)
Author:
Alan Bujtas
Message:

[LFC][TFC] Compute column min/max widths and table width.
https://bugs.webkit.org/show_bug.cgi?id=200757
<rdar://problem/54333148>

Reviewed by Antti Koivisto.

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

  • layout/tableformatting/TableFormattingContext.cpp:

(WebCore::Layout::TableFormattingContext::computePreferredWidthForColumns const):

  • layout/tableformatting/TableGrid.cpp:

(WebCore::Layout::TableGrid::appendCell):

  • layout/tableformatting/TableGrid.h:

(WebCore::Layout::TableGrid::columns):
(WebCore::Layout::TableGrid::rows):

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r248831 r248834  
     12019-08-18  Zalan Bujtas  <zalan@apple.com>
     2
     3        [LFC][TFC] Compute column min/max widths and table width.
     4        https://bugs.webkit.org/show_bug.cgi?id=200757
     5        <rdar://problem/54333148>
     6
     7        Reviewed by Antti Koivisto.
     8
     9        For each column, determine a maximum and minimum column width from the cells that span only that column.
     10        The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger).
     11        The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
     12
     13        * layout/tableformatting/TableFormattingContext.cpp:
     14        (WebCore::Layout::TableFormattingContext::computePreferredWidthForColumns const):
     15        * layout/tableformatting/TableGrid.cpp:
     16        (WebCore::Layout::TableGrid::appendCell):
     17        * layout/tableformatting/TableGrid.h:
     18        (WebCore::Layout::TableGrid::columns):
     19        (WebCore::Layout::TableGrid::rows):
     20
    1212019-08-17  Darin Adler  <darin@apple.com>
    222
  • trunk/Source/WebCore/layout/FormattingContext.h

    r248365 r248834  
    5555    struct IntrinsicWidthConstraints {
    5656        void expand(LayoutUnit horizontalValue);
     57        IntrinsicWidthConstraints& operator+=(const IntrinsicWidthConstraints&);
    5758
    5859        LayoutUnit minimum;
     
    148149}
    149150
     151inline FormattingContext::IntrinsicWidthConstraints& FormattingContext::IntrinsicWidthConstraints::operator+=(const IntrinsicWidthConstraints& other)
     152{
     153    minimum += other.minimum;
     154    maximum += other.maximum;
     155    return *this;
     156}
     157
    150158}
    151159}
  • trunk/Source/WebCore/layout/displaytree/DisplayBox.h

    r248262 r248834  
    4545class InlineFormattingContext;
    4646class LayoutState;
     47class TableFormattingContext;
    4748}
    4849
     
    5960    friend class Layout::InlineFormattingContext;
    6061    friend class Layout::LayoutState;
     62    friend class Layout::TableFormattingContext;
    6163
    6264    Box(const RenderStyle&);
  • trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.cpp

    r248671 r248834  
    5454    // 3. Compute the width of the table.
    5555    computeTableWidth();
    56     // 4. Distribute the width of the table among columns.
    57     distributeAvailabeWidth();
    58     // 5. Compute the height of the table.
     56    // 4. Compute the height of the table.
    5957    computeTableHeight();
    60     // 6. Distribute the height of the table among rows.
     58    // 5. Distribute the height of the table among rows.
    6159    distributeAvailableHeight();
    6260}
     
    105103            grid.slot({ initialPosition.x() + i, initialPosition.y() })->widthConstraints = slotIntrinsicWidth;
    106104    }
     105    // 2. For each column, determine a maximum and minimum column width from the cells that span only that column.
     106    //    The minimum is that required by the cell with the largest minimum cell width (or the column 'width', whichever is larger).
     107    //    The maximum is that required by the cell with the largest maximum cell width (or the column 'width', whichever is larger).
     108    auto& columns = grid.columnsContext().columns();
     109    int numberOfRows = grid.rows().size();
     110    int numberOfColumns = columns.size();
     111    for (int columnIndex = 0; columnIndex < numberOfColumns; ++columnIndex) {
     112        auto columnIntrinsicWidths = FormattingContext::IntrinsicWidthConstraints { };
     113        for (int rowIndex = 0; rowIndex < numberOfRows; ++rowIndex) {
     114            auto* slot = grid.slot({ columnIndex, rowIndex });
     115            columnIntrinsicWidths.minimum = std::max(slot->widthConstraints.minimum, columnIntrinsicWidths.minimum);
     116            columnIntrinsicWidths.maximum = std::max(slot->widthConstraints.maximum, columnIntrinsicWidths.maximum);
     117        }
     118        columns[columnIndex].setWidthConstraints(columnIntrinsicWidths);
     119    }
     120    // FIXME: Take column group elements into account.
    107121}
    108122
    109123void TableFormattingContext::computeTableWidth() const
    110124{
     125    // Column and caption widths influence the final table width as follows:
     126    // 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
     127    // W, CAPMIN, and the minimum width required by all the columns plus cell spacing or borders (MIN).
     128    // If the used width is greater than MIN, the extra width should be distributed over the columns.
     129    // If the 'table' or 'inline-table' element has 'width: auto', the used width is the greater of the table's containing block width,
     130    // CAPMIN, and MIN. However, if either CAPMIN or the maximum width required by the columns plus cell spacing or borders (MAX) is
     131    // less than that of the containing block, use max(MAX, CAPMIN).
     132
     133    // FIXME: This kind of code usually lives in *FormattingContextGeometry class.
     134    auto& tableWrapperBox = root();
     135    auto& style = tableWrapperBox.style();
     136    auto& containingBlock = *tableWrapperBox.containingBlock();
     137    auto& containingBlockDisplayBox = layoutState().displayBoxForLayoutBox(containingBlock);
     138    auto containingBlockWidth = containingBlockDisplayBox.contentBoxWidth();
     139
     140    auto& grid = formattingState().tableGrid();
     141    auto& columnsContext = grid.columnsContext();
     142    auto tableWidthConstraints = grid.widthConstraints();
     143
     144    auto width = Geometry::computedValueIfNotAuto(style.width(), containingBlockWidth);
     145    LayoutUnit usedWidth;
     146    if (width) {
     147        if (*width > tableWidthConstraints.minimum) {
     148            distributeAvailableWidth(*width - tableWidthConstraints.minimum);
     149            usedWidth = *width;
     150        } else {
     151            usedWidth = tableWidthConstraints.minimum;
     152            columnsContext.useAsLogicalWidth(TableGrid::ColumnsContext::WidthConstraintsType::Minimum);
     153        }
     154    } else {
     155        if (tableWidthConstraints.minimum > containingBlockWidth) {
     156            usedWidth = tableWidthConstraints.minimum;
     157            columnsContext.useAsLogicalWidth(TableGrid::ColumnsContext::WidthConstraintsType::Minimum);
     158        } else if (tableWidthConstraints.maximum < containingBlockWidth) {
     159            usedWidth = tableWidthConstraints.maximum;
     160            columnsContext.useAsLogicalWidth(TableGrid::ColumnsContext::WidthConstraintsType::Maximum);
     161        } else {
     162            usedWidth = containingBlockWidth;
     163            distributeAvailableWidth(*width - tableWidthConstraints.minimum);
     164        }
     165    }
     166
     167    auto& tableDisplayBox = layoutState().displayBoxForLayoutBox(tableWrapperBox);
     168    tableDisplayBox.setContentBoxWidth(usedWidth);
    111169}
    112170
    113 void TableFormattingContext::distributeAvailabeWidth() const
     171void TableFormattingContext::distributeAvailableWidth(LayoutUnit extraHorizontalSpace) const
    114172{
     173    // FIXME: Right now just distribute the extra space equaly among the columns.
     174    auto& columns = formattingState().tableGrid().columnsContext().columns();
     175    ASSERT(!columns.isEmpty());
     176
     177    auto columnExtraSpace = extraHorizontalSpace / columns.size();
     178    for (auto& column : columns)
     179        column.setLogicalWidth(column.widthConstraints().minimum + columnExtraSpace);
    115180}
    116181
  • trunk/Source/WebCore/layout/tableformatting/TableFormattingContext.h

    r248596 r248834  
    4949    void computePreferredWidthForColumns() const;
    5050    void computeTableWidth() const;
    51     void distributeAvailabeWidth() const;
     51    void distributeAvailableWidth(LayoutUnit extraHorizontalSpace) const;
    5252    void computeTableHeight() const;
    5353    void distributeAvailableHeight() const;
  • trunk/Source/WebCore/layout/tableformatting/TableGrid.cpp

    r248671 r248834  
    3636WTF_MAKE_ISO_ALLOCATED_IMPL(TableGrid);
    3737
     38void TableGrid::Column::setWidthConstraints(FormattingContext::IntrinsicWidthConstraints widthConstraints)
     39{
     40#ifndef NDEBUG
     41    m_hasWidthConstraints = true;
     42#endif
     43    m_widthConstraints = widthConstraints;
     44}
     45
     46FormattingContext::IntrinsicWidthConstraints TableGrid::Column::widthConstraints() const
     47{
     48    ASSERT(m_hasWidthConstraints);
     49    return m_widthConstraints;
     50}
     51
     52void TableGrid::Column::setLogicalWidth(LayoutUnit computedLogicalWidth)
     53{
     54#ifndef NDEBUG
     55    m_hasComputedWidth = true;
     56#endif
     57    m_computedLogicalWidth = computedLogicalWidth;
     58}
     59
     60LayoutUnit TableGrid::Column::logicalWidth() const
     61{
     62    ASSERT(m_hasComputedWidth);
     63    return m_computedLogicalWidth;
     64}
     65
     66void TableGrid::ColumnsContext::addColumn()
     67{
     68    m_columns.append({ });
     69}
     70
     71void TableGrid::ColumnsContext::useAsLogicalWidth(WidthConstraintsType type)
     72{
     73    for (auto& column : m_columns)
     74        column.setLogicalWidth(type == WidthConstraintsType::Minimum ? column.widthConstraints().minimum : column.widthConstraints().maximum);
     75}
     76
    3877TableGrid::CellInfo::CellInfo(const Box& tableCellBox, SlotPosition position, CellSize size)
    3978    : tableCellBox(tableCellBox)
     
    61100    int rowSpan = tableCellBox.rowSpan();
    62101    int columnSpan = tableCellBox.columnSpan();
     102    auto isInNewRow = !tableCellBox.previousSibling();
    63103    auto initialSlotPosition = SlotPosition { };
    64104
     
    67107        auto lastSlotPosition = lastCell->position;
    68108        // First table cell in this row?
    69         if (!tableCellBox.previousSibling())
     109        if (isInNewRow)
    70110            initialSlotPosition = SlotPosition { 0, lastSlotPosition.y() + 1 };
    71111        else
     
    88128        }
    89129    }
     130    // Initialize columns/rows if needed.
     131    auto missingNumberOfColumns = std::max<unsigned>(0, (initialSlotPosition.x() + columnSpan) - m_columnsContext.columns().size());
     132    for (unsigned column = 0; column < missingNumberOfColumns; ++column)
     133        m_columnsContext.addColumn();
     134
     135    if (isInNewRow)
     136        m_rows.append({ });
     137
    90138    m_cellList.add(WTFMove(cellInfo));
    91139}
     
    102150}
    103151
     152FormattingContext::IntrinsicWidthConstraints TableGrid::widthConstraints() const
     153{
     154    // FIXME: We should probably cache this value.
     155    auto widthConstraints = FormattingContext::IntrinsicWidthConstraints { };
     156    for (auto& column : m_columnsContext.columns())
     157        widthConstraints += column.widthConstraints();
     158    return widthConstraints;
     159}
     160
    104161}
    105162}
  • trunk/Source/WebCore/layout/tableformatting/TableGrid.h

    r248762 r248834  
    4848
    4949    using SlotPosition = IntPoint;
     50
     51    // Cell represents a <td> or <th>. It can span multiple slots in the grid.
    5052    using CellSize = IntSize;
    5153    struct CellInfo : public CanMakeWeakPtr<CellInfo> {
     
    6062    CellList& cells() { return m_cellList; }
    6163
    62     using SlotLogicalSize = LayoutSize;
     64    // Column represents a vertical set of slots in the grid. A column has min/max and final width.
     65    class ColumnsContext;
     66    class Column {
     67    public:
     68        void setWidthConstraints(FormattingContext::IntrinsicWidthConstraints);
     69        FormattingContext::IntrinsicWidthConstraints widthConstraints() const;
     70
     71        void setLogicalWidth(LayoutUnit);
     72        LayoutUnit logicalWidth() const;
     73
     74    private:
     75        friend class ColumnsContext;
     76        Column() = default;
     77
     78        FormattingContext::IntrinsicWidthConstraints m_widthConstraints;
     79        LayoutUnit m_computedLogicalWidth;
     80#ifndef NDEBUG
     81        bool m_hasWidthConstraints { false };
     82        bool m_hasComputedWidth { false };
     83#endif
     84    };
     85
     86    class ColumnsContext {
     87    public:
     88        using ColumnList = Vector<Column>;
     89        ColumnList& columns() { return m_columns; }
     90        const ColumnList& columns() const { return m_columns; }
     91
     92        enum class WidthConstraintsType { Minimum, Maximum };
     93        void useAsLogicalWidth(WidthConstraintsType);
     94
     95    private:
     96        friend class TableGrid;
     97        void addColumn();
     98
     99        ColumnList m_columns;
     100    };
     101    ColumnsContext& columnsContext() { return m_columnsContext; }
     102
     103    struct Row {
     104        LayoutUnit height;
     105    };
     106    using RowList = WTF::Vector<Row>;
     107    RowList& rows() { return m_rows; }
     108
    63109    struct SlotInfo {
    64110        WTF_MAKE_STRUCT_FAST_ALLOCATED;
     
    68114        WeakPtr<CellInfo> cell;
    69115        FormattingContext::IntrinsicWidthConstraints widthConstraints;
    70         SlotLogicalSize size;
    71116    };
    72117    SlotInfo* slot(SlotPosition);
    73118
     119    FormattingContext::IntrinsicWidthConstraints widthConstraints() const;
     120
    74121private:
    75122    using SlotMap = WTF::HashMap<SlotPosition, std::unique_ptr<SlotInfo>>;
     123
    76124    SlotMap m_slotMap;
    77125    CellList m_cellList;
     126    ColumnsContext m_columnsContext;
     127    RowList m_rows;
    78128};
    79129
Note: See TracChangeset for help on using the changeset viewer.