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, 2013 Apple Inc. All rights reserved.
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.
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.
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.
25 #ifndef LayoutTableSection_h
26 #define LayoutTableSection_h
28 #include "core/CoreExport.h"
29 #include "core/layout/LayoutTable.h"
30 #include "wtf/Vector.h"
34 // This variable is used to balance the memory consumption vs the paint invalidation time on big tables.
35 const float gMaxAllowedOverflowingCellRatioForFastPaintPath
= 0.1f
;
37 enum CollapsedBorderSide
{
44 // Helper class for paintObject.
48 CellSpan(unsigned start
, unsigned end
)
54 unsigned start() const { return m_start
; }
55 unsigned end() const { return m_end
; }
57 void decreaseStart() { --m_start
; }
58 void increaseEnd() { ++m_end
; }
60 void ensureConsistency(const unsigned);
67 class LayoutTableCell
;
70 // LayoutTableSection is used to represent table row group (display:
71 // table-row-group), header group (display: table-header-group) and footer group
72 // (display: table-footer-group).
74 // The object holds the internal representation of the rows (m_grid). See
75 // recalcCells() below for some extra explanation.
77 // A lot of the complexity in this class is related to handling rowspan, colspan
78 // or just non-regular tables.
80 // Example of rowspan / colspan leading to overlapping cells (rowspan and
81 // colspan are overlapping):
85 // <td rowspan="2">rowspan</td>
88 // <td colspan="2">colspan</td>
92 // Example of non-regular table (missing one cell in the first row):
95 // <tr><td>First row only child.</td></tr>
97 // <td>Second row first child</td>
98 // <td>Second row second child</td>
102 // LayoutTableSection is responsible for laying out LayoutTableRows and
103 // LayoutTableCells (see layoutRows()). However it is not their containing
104 // block, the enclosing LayoutTable (this object's parent()) is. This is why
105 // this class inherits from LayoutBox and not LayoutBlock.
106 class CORE_EXPORT LayoutTableSection final
: public LayoutBox
{
108 LayoutTableSection(Element
*);
109 ~LayoutTableSection() override
;
111 LayoutTableRow
* firstRow() const;
112 LayoutTableRow
* lastRow() const;
114 const LayoutObjectChildList
* children() const { return &m_children
; }
115 LayoutObjectChildList
* children() { return &m_children
; }
117 void addChild(LayoutObject
* child
, LayoutObject
* beforeChild
= nullptr) override
;
119 int firstLineBoxBaseline() const override
;
121 void addCell(LayoutTableCell
*, LayoutTableRow
*);
123 int calcRowLogicalHeight();
125 void computeOverflowFromCells();
127 LayoutTable
* table() const { return toLayoutTable(parent()); }
129 typedef Vector
<LayoutTableCell
*, 2> SpanningLayoutTableCells
;
132 ALLOW_ONLY_INLINE_ALLOCATION();
134 Vector
<LayoutTableCell
*, 1> cells
;
135 bool inColSpan
; // true for columns after the first in a colspan
142 LayoutTableCell
* primaryCell()
144 return hasCells() ? cells
[cells
.size() - 1] : 0;
147 const LayoutTableCell
* primaryCell() const
149 return hasCells() ? cells
[cells
.size() - 1] : 0;
152 bool hasCells() const { return cells
.size() > 0; }
155 typedef Vector
<CellStruct
> Row
;
158 ALLOW_ONLY_INLINE_ALLOCATION();
161 : rowLayoutObject(nullptr)
167 LayoutTableRow
* rowLayoutObject
;
169 Length logicalHeight
;
172 struct SpanningRowsHeight
{
174 WTF_MAKE_NONCOPYABLE(SpanningRowsHeight
);
179 , spanningCellHeightIgnoringBorderSpacing(0)
180 , isAnyRowWithOnlySpanningCells(false)
184 Vector
<int> rowHeight
;
186 int spanningCellHeightIgnoringBorderSpacing
;
187 bool isAnyRowWithOnlySpanningCells
;
190 const BorderValue
& borderAdjoiningTableStart() const
192 if (hasSameDirectionAs(table()))
193 return style()->borderStart();
195 return style()->borderEnd();
198 const BorderValue
& borderAdjoiningTableEnd() const
200 if (hasSameDirectionAs(table()))
201 return style()->borderEnd();
203 return style()->borderStart();
206 const BorderValue
& borderAdjoiningStartCell(const LayoutTableCell
*) const;
207 const BorderValue
& borderAdjoiningEndCell(const LayoutTableCell
*) const;
209 const LayoutTableCell
* firstRowCellAdjoiningTableStart() const;
210 const LayoutTableCell
* firstRowCellAdjoiningTableEnd() const;
212 CellStruct
& cellAt(unsigned row
, unsigned col
) { return m_grid
[row
].row
[col
]; }
213 const CellStruct
& cellAt(unsigned row
, unsigned col
) const { return m_grid
[row
].row
[col
]; }
214 LayoutTableCell
* primaryCellAt(unsigned row
, unsigned col
)
216 CellStruct
& c
= m_grid
[row
].row
[col
];
217 return c
.primaryCell();
220 LayoutTableRow
* rowLayoutObjectAt(unsigned row
) const { return m_grid
[row
].rowLayoutObject
; }
222 void appendColumn(unsigned pos
);
223 void splitColumn(unsigned pos
, unsigned first
);
225 enum BlockBorderSide
{ BorderBefore
, BorderAfter
};
226 int calcBlockDirectionOuterBorder(BlockBorderSide
) const;
227 enum InlineBorderSide
{ BorderStart
, BorderEnd
};
228 int calcInlineDirectionOuterBorder(InlineBorderSide
) const;
229 void recalcOuterBorder();
231 int outerBorderBefore() const { return m_outerBorderBefore
; }
232 int outerBorderAfter() const { return m_outerBorderAfter
; }
233 int outerBorderStart() const { return m_outerBorderStart
; }
234 int outerBorderEnd() const { return m_outerBorderEnd
; }
236 unsigned numRows() const { return m_grid
.size(); }
237 unsigned numColumns() const;
239 // recalcCells() is used when we are not sure about the section's structure
240 // and want to do an expensive (but safe) reconstruction of m_grid from
242 // An example of this is inserting a new cell in the middle of an existing
243 // row or removing a row.
245 // Accessing m_grid when m_needsCellRecalc is set is UNSAFE as pointers can
246 // be left dangling. Thus care should be taken in the code to check
247 // m_needsCellRecalc before accessing m_grid.
249 void recalcCellsIfNeeded()
251 if (m_needsCellRecalc
)
255 bool needsCellRecalc() const { return m_needsCellRecalc
; }
256 void setNeedsCellRecalc();
258 LayoutUnit
rowBaseline(unsigned row
) { return m_grid
[row
].baseline
; }
260 void rowLogicalHeightChanged(LayoutTableRow
*);
262 void removeCachedCollapsedBorders(const LayoutTableCell
*);
263 // Returns true if any collapsed borders of the cell changed.
264 bool setCachedCollapsedBorder(const LayoutTableCell
*, CollapsedBorderSide
, const CollapsedBorderValue
&);
265 const CollapsedBorderValue
& cachedCollapsedBorder(const LayoutTableCell
*, CollapsedBorderSide
) const;
267 // distributeExtraLogicalHeightToRows methods return the *consumed* extra logical height.
268 // FIXME: We may want to introduce a structure holding the in-flux layout information.
269 int distributeExtraLogicalHeightToRows(int extraLogicalHeight
);
271 static LayoutTableSection
* createAnonymousWithParent(const LayoutObject
*);
272 LayoutBox
* createAnonymousBoxWithSameTypeAs(const LayoutObject
* parent
) const override
274 return createAnonymousWithParent(parent
);
277 void paint(const PaintInfo
&, const LayoutPoint
&) override
;
279 // Flip the rect so it aligns with the coordinates used by the rowPos and columnPos vectors.
280 LayoutRect
logicalRectForWritingModeAndDirection(const LayoutRect
&) const;
282 CellSpan
dirtiedRows(const LayoutRect
& paintInvalidationRect
) const;
283 CellSpan
dirtiedColumns(const LayoutRect
& paintInvalidationRect
) const;
284 HashSet
<LayoutTableCell
*>& overflowingCells() { return m_overflowingCells
; }
285 bool hasMultipleCellLevels() { return m_hasMultipleCellLevels
; }
287 const char* name() const override
{ return "LayoutTableSection"; }
290 void styleDidChange(StyleDifference
, const ComputedStyle
* oldStyle
) override
;
291 bool nodeAtPoint(HitTestResult
&, const HitTestLocation
& locationInContainer
, const LayoutPoint
& accumulatedOffset
, HitTestAction
) override
;
294 LayoutObjectChildList
* virtualChildren() override
{ return children(); }
295 const LayoutObjectChildList
* virtualChildren() const override
{ return children(); }
297 bool isOfType(LayoutObjectType type
) const override
{ return type
== LayoutObjectTableSection
|| LayoutBox::isOfType(type
); }
299 void willBeRemovedFromTree() override
;
301 void layout() override
;
303 void imageChanged(WrappedImagePtr
, const IntRect
* = nullptr) override
;
305 int borderSpacingForRow(unsigned row
) const { return m_grid
[row
].rowLayoutObject
? table()->vBorderSpacing() : 0; }
307 void ensureRows(unsigned);
309 bool rowHasOnlySpanningCells(unsigned);
310 unsigned calcRowHeightHavingOnlySpanningCells(unsigned, int&, unsigned, unsigned&, Vector
<int>&);
311 void updateRowsHeightHavingOnlySpanningCells(LayoutTableCell
*, struct SpanningRowsHeight
&, unsigned&, Vector
<int>&);
313 void populateSpanningRowsHeightFromCell(LayoutTableCell
*, struct SpanningRowsHeight
&);
314 void distributeExtraRowSpanHeightToPercentRows(LayoutTableCell
*, int, int&, Vector
<int>&);
315 void distributeWholeExtraRowSpanHeightToPercentRows(LayoutTableCell
*, float, int&, Vector
<int>&);
316 void distributeExtraRowSpanHeightToAutoRows(LayoutTableCell
*, int, int&, Vector
<int>&);
317 void distributeExtraRowSpanHeightToRemainingRows(LayoutTableCell
*, int, int&, Vector
<int>&);
318 void distributeRowSpanHeightToRows(SpanningLayoutTableCells
& rowSpanCells
);
320 void distributeExtraLogicalHeightToPercentRows(int& extraLogicalHeight
, int totalPercent
);
321 void distributeExtraLogicalHeightToAutoRows(int& extraLogicalHeight
, unsigned autoRowsCount
);
322 void distributeRemainingExtraLogicalHeight(int& extraLogicalHeight
);
324 void updateBaselineForCell(LayoutTableCell
*, unsigned row
, LayoutUnit
& baselineDescent
);
326 bool hasOverflowingCell() const { return m_overflowingCells
.size() || m_forceSlowPaintPathWithOverflowingCell
; }
328 void computeOverflowFromCells(unsigned totalRows
, unsigned nEffCols
);
330 CellSpan
fullTableRowSpan() const { return CellSpan(0, m_grid
.size()); }
331 CellSpan
fullTableColumnSpan() const { return CellSpan(0, table()->columns().size()); }
333 // These two functions take a rectangle as input that has been flipped by logicalRectForWritingModeAndDirection.
334 // The returned span of rows or columns is end-exclusive, and empty if start==end.
335 CellSpan
spannedRows(const LayoutRect
& flippedRect
) const;
336 CellSpan
spannedColumns(const LayoutRect
& flippedRect
) const;
338 void setLogicalPositionForCell(LayoutTableCell
*, unsigned effectiveColumn
) const;
340 LayoutObjectChildList m_children
;
342 // The representation of the rows and their cells (CellStruct).
343 Vector
<RowStruct
> m_grid
;
345 // The logical offset of each row from the top of the section.
347 // Note that this Vector has one more entry than the number of rows so that
348 // we can keep track of the final size of the section
349 // (m_rowPos[m_grid.size() + 1]).
351 // To know a row's height at |rowIndex|, use the formula:
352 // m_rowPos[rowIndex + 1] - m_rowPos[rowIndex]
353 Vector
<int> m_rowPos
;
355 // The current insertion position in the grid.
356 // The position is used when inserting a new cell into the section to
357 // know where it should be inserted and expand our internal structure.
359 // The reason for them is that we process cells as we discover them
360 // during parsing or during recalcCells (ie in DOM order). This means
361 // that we can discover changes in the structure later (e.g. due to
362 // colspans, extra cells, ...).
364 // Do not use outside of recalcCells and addChild.
368 int m_outerBorderStart
;
369 int m_outerBorderEnd
;
370 int m_outerBorderBefore
;
371 int m_outerBorderAfter
;
373 bool m_needsCellRecalc
;
375 // This HashSet holds the overflowing cells for faster painting.
376 // If we have more than gMaxAllowedOverflowingCellRatio * total cells, it will be empty
377 // and m_forceSlowPaintPathWithOverflowingCell will be set to save memory.
378 HashSet
<LayoutTableCell
*> m_overflowingCells
;
379 bool m_forceSlowPaintPathWithOverflowingCell
;
381 bool m_hasMultipleCellLevels
;
383 // This map holds the collapsed border values for cells with collapsed borders.
384 // It is held at LayoutTableSection level to spare memory consumption by table cells.
385 using CellsCollapsedBordersMap
= HashMap
<pair
<const LayoutTableCell
*, int>, CollapsedBorderValue
>;
386 CellsCollapsedBordersMap m_cellsCollapsedBorders
;
389 DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTableSection
, isTableSection());
393 #endif // LayoutTableSection_h