1/*
2 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3 *           (C) 1997 Torben Weis (weis@kde.org)
4 *           (C) 1998 Waldo Bastian (bastian@kde.org)
5 *           (C) 1999 Lars Knoll (knoll@kde.org)
6 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
7 * Copyright (C) 2003, 2004, 2005, 2006, 2009 Apple Inc. All rights reserved.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB.  If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#ifndef RenderTableSection_h
26#define RenderTableSection_h
27
28#include "RenderTable.h"
29#include <wtf/Vector.h>
30
31namespace WebCore {
32
33class RenderTableRow;
34
35enum CollapsedBorderSide {
36    CBSBefore,
37    CBSAfter,
38    CBSStart,
39    CBSEnd
40};
41
42// Helper class for paintObject.
43class CellSpan {
44public:
45    CellSpan(unsigned start, unsigned end)
46        : m_start(start)
47        , m_end(end)
48    {
49    }
50
51    unsigned start() const { return m_start; }
52    unsigned end() const { return m_end; }
53
54    unsigned& start() { return m_start; }
55    unsigned& end() { return m_end; }
56
57private:
58    unsigned m_start;
59    unsigned m_end;
60};
61
62class RenderTableCell;
63class RenderTableRow;
64
65class RenderTableSection final : public RenderBox {
66public:
67    RenderTableSection(Element&, PassRef<RenderStyle>);
68    RenderTableSection(Document&, PassRef<RenderStyle>);
69    virtual ~RenderTableSection();
70
71    RenderTableRow* firstRow() const;
72    RenderTableRow* lastRow() const;
73
74    virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) override;
75
76    virtual int firstLineBaseline() const override;
77
78    void addCell(RenderTableCell*, RenderTableRow* row);
79
80    int calcRowLogicalHeight();
81    void layoutRows();
82    void computeOverflowFromCells();
83
84    RenderTable* table() const { return toRenderTable(parent()); }
85
86    struct CellStruct {
87        Vector<RenderTableCell*, 1> cells;
88        bool inColSpan; // true for columns after the first in a colspan
89
90        CellStruct()
91            : inColSpan(false)
92        {
93        }
94
95        RenderTableCell* primaryCell()
96        {
97            return hasCells() ? cells[cells.size() - 1] : 0;
98        }
99
100        const RenderTableCell* primaryCell() const
101        {
102            return hasCells() ? cells[cells.size() - 1] : 0;
103        }
104
105        bool hasCells() const { return cells.size() > 0; }
106    };
107
108    typedef Vector<CellStruct> Row;
109
110    struct RowStruct {
111        RowStruct()
112            : rowRenderer(0)
113            , baseline()
114        {
115        }
116
117        Row row;
118        RenderTableRow* rowRenderer;
119        LayoutUnit baseline;
120        Length logicalHeight;
121    };
122
123    const BorderValue& borderAdjoiningTableStart() const
124    {
125        if (hasSameDirectionAs(table()))
126            return style().borderStart();
127
128        return style().borderEnd();
129    }
130
131    const BorderValue& borderAdjoiningTableEnd() const
132    {
133        if (hasSameDirectionAs(table()))
134            return style().borderEnd();
135
136        return style().borderStart();
137    }
138
139    const BorderValue& borderAdjoiningStartCell(const RenderTableCell*) const;
140    const BorderValue& borderAdjoiningEndCell(const RenderTableCell*) const;
141
142    const RenderTableCell* firstRowCellAdjoiningTableStart() const;
143    const RenderTableCell* firstRowCellAdjoiningTableEnd() const;
144
145    CellStruct& cellAt(unsigned row,  unsigned col)
146    {
147        recalcCellsIfNeeded();
148        return m_grid[row].row[col];
149    }
150
151    const CellStruct& cellAt(unsigned row, unsigned col) const
152    {
153        ASSERT(!m_needsCellRecalc);
154        return m_grid[row].row[col];
155    }
156
157    RenderTableCell* primaryCellAt(unsigned row, unsigned col)
158    {
159        recalcCellsIfNeeded();
160        CellStruct& c = m_grid[row].row[col];
161        return c.primaryCell();
162    }
163
164    RenderTableRow* rowRendererAt(unsigned row) const
165    {
166        ASSERT(!m_needsCellRecalc);
167        return m_grid[row].rowRenderer;
168    }
169
170    void appendColumn(unsigned pos);
171    void splitColumn(unsigned pos, unsigned first);
172
173    int calcOuterBorderBefore() const;
174    int calcOuterBorderAfter() const;
175    int calcOuterBorderStart() const;
176    int calcOuterBorderEnd() const;
177    void recalcOuterBorder();
178
179    int outerBorderBefore() const { return m_outerBorderBefore; }
180    int outerBorderAfter() const { return m_outerBorderAfter; }
181    int outerBorderStart() const { return m_outerBorderStart; }
182    int outerBorderEnd() const { return m_outerBorderEnd; }
183
184    int outerBorderLeft(const RenderStyle* styleForCellFlow) const
185    {
186    if (styleForCellFlow->isHorizontalWritingMode())
187        return styleForCellFlow->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd();
188    return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore();
189    }
190
191    int outerBorderRight(const RenderStyle* styleForCellFlow) const
192    {
193    if (styleForCellFlow->isHorizontalWritingMode())
194        return styleForCellFlow->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart();
195    return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter();
196    }
197
198    int outerBorderTop(const RenderStyle* styleForCellFlow) const
199    {
200    if (styleForCellFlow->isHorizontalWritingMode())
201        return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore();
202    return styleForCellFlow->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd();
203    }
204
205    int outerBorderBottom(const RenderStyle* styleForCellFlow) const
206    {
207    if (styleForCellFlow->isHorizontalWritingMode())
208        return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter();
209    return styleForCellFlow->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart();
210    }
211
212    unsigned numRows() const
213    {
214        ASSERT(!m_needsCellRecalc);
215        return m_grid.size();
216    }
217
218    unsigned numColumns() const;
219    void recalcCells();
220    void recalcCellsIfNeeded()
221    {
222        if (m_needsCellRecalc)
223            recalcCells();
224    }
225
226    bool needsCellRecalc() const { return m_needsCellRecalc; }
227    void setNeedsCellRecalc();
228
229    LayoutUnit rowBaseline(unsigned row)
230    {
231        recalcCellsIfNeeded();
232        return m_grid[row].baseline;
233    }
234
235    void rowLogicalHeightChanged(unsigned rowIndex);
236
237    void removeCachedCollapsedBorders(const RenderTableCell*);
238    void setCachedCollapsedBorder(const RenderTableCell*, CollapsedBorderSide, CollapsedBorderValue);
239    CollapsedBorderValue& cachedCollapsedBorder(const RenderTableCell*, CollapsedBorderSide);
240
241    // distributeExtraLogicalHeightToRows methods return the *consumed* extra logical height.
242    // FIXME: We may want to introduce a structure holding the in-flux layout information.
243    int distributeExtraLogicalHeightToRows(int extraLogicalHeight);
244
245    static RenderTableSection* createAnonymousWithParentRenderer(const RenderObject*);
246    virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const override
247    {
248        return createAnonymousWithParentRenderer(parent);
249    }
250
251    virtual void paint(PaintInfo&, const LayoutPoint&) override;
252
253protected:
254    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override;
255
256private:
257    enum ShouldIncludeAllIntersectingCells {
258        IncludeAllIntersectingCells,
259        DoNotIncludeAllIntersectingCells
260    };
261
262    virtual const char* renderName() const override { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
263
264    virtual bool canHaveChildren() const override { return true; }
265
266    virtual bool isTableSection() const override { return true; }
267
268    virtual void willBeRemovedFromTree() override;
269
270    virtual void layout() override;
271
272    void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&);
273    virtual void paintObject(PaintInfo&, const LayoutPoint&) override;
274    void paintRowGroupBorder(const PaintInfo&, bool antialias, LayoutRect, BoxSide, CSSPropertyID borderColor, EBorderStyle, EBorderStyle tableBorderStyle);
275    void paintRowGroupBorderIfRequired(const PaintInfo&, const LayoutPoint& paintOffset, unsigned row, unsigned col, BoxSide, RenderTableCell* = 0);
276    int offsetLeftForRowGroupBorder(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row);
277
278    int offsetTopForRowGroupBorder(RenderTableCell*, BoxSide borderSide, unsigned row);
279    int verticalRowGroupBorderHeight(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row);
280    int horizontalRowGroupBorderWidth(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row, unsigned column);
281
282    virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) override;
283
284    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
285
286    void ensureRows(unsigned);
287
288    void distributeExtraLogicalHeightToPercentRows(int& extraLogicalHeight, int totalPercent);
289    void distributeExtraLogicalHeightToAutoRows(int& extraLogicalHeight, unsigned autoRowsCount);
290    void distributeRemainingExtraLogicalHeight(int& extraLogicalHeight);
291
292    bool hasOverflowingCell() const { return m_overflowingCells.size() || m_forceSlowPaintPathWithOverflowingCell; }
293    void computeOverflowFromCells(unsigned totalRows, unsigned nEffCols);
294
295    CellSpan fullTableRowSpan() const
296    {
297        ASSERT(!m_needsCellRecalc);
298        return CellSpan(0, m_grid.size());
299    }
300
301    CellSpan fullTableColumnSpan() const { return CellSpan(0, table()->columns().size()); }
302
303    // Flip the rect so it aligns with the coordinates used by the rowPos and columnPos vectors.
304    LayoutRect logicalRectForWritingModeAndDirection(const LayoutRect&) const;
305
306    CellSpan dirtiedRows(const LayoutRect& repaintRect) const;
307    CellSpan dirtiedColumns(const LayoutRect& repaintRect) const;
308
309    // These two functions take a rectangle as input that has been flipped by logicalRectForWritingModeAndDirection.
310    // The returned span of rows or columns is end-exclusive, and empty if start==end.
311    // The IncludeAllIntersectingCells argument is used to determine which cells to include when
312    // an edge of the flippedRect lies exactly on a cell boundary. Using IncludeAllIntersectingCells
313    // will return both cells, and using DoNotIncludeAllIntersectingCells will return only the cell
314    // that hittesting should return.
315    CellSpan spannedRows(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells) const;
316    CellSpan spannedColumns(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells) const;
317
318    void setLogicalPositionForCell(RenderTableCell*, unsigned effectiveColumn) const;
319
320    void firstChild() const = delete;
321    void lastChild() const = delete;
322
323    Vector<RowStruct> m_grid;
324    Vector<int> m_rowPos;
325
326    // the current insertion position
327    unsigned m_cCol;
328    unsigned m_cRow;
329
330    int m_outerBorderStart;
331    int m_outerBorderEnd;
332    int m_outerBorderBefore;
333    int m_outerBorderAfter;
334
335    bool m_needsCellRecalc;
336
337    // This HashSet holds the overflowing cells for faster painting.
338    // If we have more than gMaxAllowedOverflowingCellRatio * total cells, it will be empty
339    // and m_forceSlowPaintPathWithOverflowingCell will be set to save memory.
340    HashSet<RenderTableCell*> m_overflowingCells;
341    bool m_forceSlowPaintPathWithOverflowingCell;
342
343    bool m_hasMultipleCellLevels;
344
345    // This map holds the collapsed border values for cells with collapsed borders.
346    // It is held at RenderTableSection level to spare memory consumption by table cells.
347    HashMap<std::pair<const RenderTableCell*, int>, CollapsedBorderValue > m_cellsCollapsedBorders;
348};
349
350RENDER_OBJECT_TYPE_CASTS(RenderTableSection, isTableSection())
351
352} // namespace WebCore
353
354#endif // RenderTableSection_h
355