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