1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "core/paint/TableSectionPainter.h"
8 #include "core/layout/LayoutTable.h"
9 #include "core/layout/LayoutTableCell.h"
10 #include "core/layout/LayoutTableCol.h"
11 #include "core/layout/LayoutTableRow.h"
12 #include "core/paint/BlockPainter.h"
13 #include "core/paint/BoxClipper.h"
14 #include "core/paint/LayoutObjectDrawingRecorder.h"
15 #include "core/paint/ObjectPainter.h"
16 #include "core/paint/PaintInfo.h"
17 #include "core/paint/TableCellPainter.h"
18 #include "core/paint/TableRowPainter.h"
22 void TableSectionPainter::paint(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
24 ASSERT(!m_layoutTableSection
.needsLayout());
25 // avoid crashing on bugs that cause us to paint with dirty layout
26 if (m_layoutTableSection
.needsLayout())
29 unsigned totalRows
= m_layoutTableSection
.numRows();
30 unsigned totalCols
= m_layoutTableSection
.table()->columns().size();
32 if (!totalRows
|| !totalCols
)
35 LayoutPoint adjustedPaintOffset
= paintOffset
+ m_layoutTableSection
.location();
37 BoxClipper
boxClipper(m_layoutTableSection
, paintInfo
, adjustedPaintOffset
, ForceContentsClip
);
38 paintObject(paintInfo
, adjustedPaintOffset
);
41 if ((paintInfo
.phase
== PaintPhaseOutline
|| paintInfo
.phase
== PaintPhaseSelfOutline
) && m_layoutTableSection
.style()->visibility() == VISIBLE
)
42 ObjectPainter(m_layoutTableSection
).paintOutline(paintInfo
, adjustedPaintOffset
);
45 static inline bool compareCellPositions(LayoutTableCell
* elem1
, LayoutTableCell
* elem2
)
47 return elem1
->rowIndex() < elem2
->rowIndex();
50 // This comparison is used only when we have overflowing cells as we have an unsorted array to sort. We thus need
51 // to sort both on rows and columns to properly issue paint invalidations.
52 static inline bool compareCellPositionsWithOverflowingCells(LayoutTableCell
* elem1
, LayoutTableCell
* elem2
)
54 if (elem1
->rowIndex() != elem2
->rowIndex())
55 return elem1
->rowIndex() < elem2
->rowIndex();
57 return elem1
->col() < elem2
->col();
60 void TableSectionPainter::paintObject(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
62 LayoutRect localPaintInvalidationRect
= LayoutRect(paintInfo
.rect
);
63 localPaintInvalidationRect
.moveBy(-paintOffset
);
65 LayoutRect tableAlignedRect
= m_layoutTableSection
.logicalRectForWritingModeAndDirection(localPaintInvalidationRect
);
67 CellSpan dirtiedRows
= m_layoutTableSection
.dirtiedRows(tableAlignedRect
);
68 CellSpan dirtiedColumns
= m_layoutTableSection
.dirtiedColumns(tableAlignedRect
);
70 HashSet
<LayoutTableCell
*> overflowingCells
= m_layoutTableSection
.overflowingCells();
71 if (dirtiedColumns
.start() < dirtiedColumns
.end()) {
72 if (!m_layoutTableSection
.hasMultipleCellLevels() && !overflowingCells
.size()) {
73 if (paintInfo
.phase
== PaintPhaseCollapsedTableBorders
) {
74 // Collapsed borders are painted from the bottom right to the top left so that precedence
75 // due to cell position is respected.
76 for (unsigned r
= dirtiedRows
.end(); r
> dirtiedRows
.start(); r
--) {
78 for (unsigned c
= dirtiedColumns
.end(); c
> dirtiedColumns
.start(); c
--) {
80 LayoutTableSection::CellStruct
& current
= m_layoutTableSection
.cellAt(row
, col
);
81 LayoutTableCell
* cell
= current
.primaryCell();
82 if (!cell
|| (row
> dirtiedRows
.start() && m_layoutTableSection
.primaryCellAt(row
- 1, col
) == cell
) || (col
> dirtiedColumns
.start() && m_layoutTableSection
.primaryCellAt(row
, col
- 1) == cell
))
84 LayoutPoint cellPoint
= m_layoutTableSection
.flipForWritingModeForChild(cell
, paintOffset
);
85 TableCellPainter(*cell
).paintCollapsedBorders(paintInfo
, cellPoint
);
89 // Draw the dirty cells in the order that they appear.
90 for (unsigned r
= dirtiedRows
.start(); r
< dirtiedRows
.end(); r
++) {
91 LayoutTableRow
* row
= m_layoutTableSection
.rowLayoutObjectAt(r
);
92 if (row
&& !row
->hasSelfPaintingLayer())
93 TableRowPainter(*row
).paintOutlineForRowIfNeeded(paintInfo
, paintOffset
);
94 for (unsigned c
= dirtiedColumns
.start(); c
< dirtiedColumns
.end(); c
++) {
95 LayoutTableSection::CellStruct
& current
= m_layoutTableSection
.cellAt(r
, c
);
96 LayoutTableCell
* cell
= current
.primaryCell();
97 if (!cell
|| (r
> dirtiedRows
.start() && m_layoutTableSection
.primaryCellAt(r
- 1, c
) == cell
) || (c
> dirtiedColumns
.start() && m_layoutTableSection
.primaryCellAt(r
, c
- 1) == cell
))
99 paintCell(cell
, paintInfo
, paintOffset
);
104 // The overflowing cells should be scarce to avoid adding a lot of cells to the HashSet.
106 unsigned totalRows
= m_layoutTableSection
.numRows();
107 unsigned totalCols
= m_layoutTableSection
.table()->columns().size();
108 ASSERT(overflowingCells
.size() < totalRows
* totalCols
* gMaxAllowedOverflowingCellRatioForFastPaintPath
);
111 // To make sure we properly paint invalidate the section, we paint invalidated all the overflowing cells that we collected.
112 Vector
<LayoutTableCell
*> cells
;
113 copyToVector(overflowingCells
, cells
);
115 HashSet
<LayoutTableCell
*> spanningCells
;
117 for (unsigned r
= dirtiedRows
.start(); r
< dirtiedRows
.end(); r
++) {
118 LayoutTableRow
* row
= m_layoutTableSection
.rowLayoutObjectAt(r
);
119 if (row
&& !row
->hasSelfPaintingLayer())
120 TableRowPainter(*row
).paintOutlineForRowIfNeeded(paintInfo
, paintOffset
);
121 for (unsigned c
= dirtiedColumns
.start(); c
< dirtiedColumns
.end(); c
++) {
122 LayoutTableSection::CellStruct
& current
= m_layoutTableSection
.cellAt(r
, c
);
123 if (!current
.hasCells())
125 for (unsigned i
= 0; i
< current
.cells
.size(); ++i
) {
126 if (overflowingCells
.contains(current
.cells
[i
]))
129 if (current
.cells
[i
]->rowSpan() > 1 || current
.cells
[i
]->colSpan() > 1) {
130 if (!spanningCells
.add(current
.cells
[i
]).isNewEntry
)
134 cells
.append(current
.cells
[i
]);
139 // Sort the dirty cells by paint order.
140 if (!overflowingCells
.size())
141 std::stable_sort(cells
.begin(), cells
.end(), compareCellPositions
);
143 std::sort(cells
.begin(), cells
.end(), compareCellPositionsWithOverflowingCells
);
145 if (paintInfo
.phase
== PaintPhaseCollapsedTableBorders
) {
146 for (unsigned i
= cells
.size(); i
> 0; --i
) {
147 LayoutPoint cellPoint
= m_layoutTableSection
.flipForWritingModeForChild(cells
[i
- 1], paintOffset
);
148 TableCellPainter(*cells
[i
- 1]).paintCollapsedBorders(paintInfo
, cellPoint
);
151 for (unsigned i
= 0; i
< cells
.size(); ++i
)
152 paintCell(cells
[i
], paintInfo
, paintOffset
);
158 void TableSectionPainter::paintCell(LayoutTableCell
* cell
, const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
160 LayoutPoint cellPoint
= m_layoutTableSection
.flipForWritingModeForChild(cell
, paintOffset
);
161 PaintPhase paintPhase
= paintInfo
.phase
;
162 LayoutTableRow
* row
= toLayoutTableRow(cell
->parent());
164 if ((paintPhase
== PaintPhaseBlockBackground
|| paintPhase
== PaintPhaseChildBlockBackground
)
165 && BlockPainter(*cell
).intersectsPaintRect(paintInfo
, paintOffset
)) {
166 // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of
167 // the column group, column, row group, row, and then the cell.
168 LayoutTableCol
* column
= m_layoutTableSection
.table()->colElement(cell
->col());
169 LayoutTableCol
* columnGroup
= column
? column
->enclosingColumnGroup() : 0;
171 bool columnHasBackground
= column
&& column
->hasBackground();
172 bool columnGroupHasBackground
= columnGroup
&& columnGroup
->hasBackground();
173 bool sectionHasBackground
= m_layoutTableSection
.hasBackground();
174 bool rowHasBackground
= row
->hasBackground();
176 if (columnHasBackground
|| columnGroupHasBackground
|| sectionHasBackground
|| rowHasBackground
) {
177 TableCellPainter
tableCellPainter(*cell
);
178 if (!LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo
.context
, *cell
, DisplayItem::TableCellBackgroundFromContainers
, paintOffset
)) {
179 LayoutObjectDrawingRecorder
recorder(*paintInfo
.context
, *cell
, DisplayItem::TableCellBackgroundFromContainers
, tableCellPainter
.paintBounds(cellPoint
, TableCellPainter::AddOffsetFromParent
), paintOffset
);
180 // Column groups and columns first.
181 // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
182 // the stack, since we have already opened a transparency layer (potentially) for the table row group.
183 // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
185 if (columnGroupHasBackground
)
186 tableCellPainter
.paintBackgroundsBehindCell(paintInfo
, cellPoint
, columnGroup
);
187 if (columnHasBackground
)
188 tableCellPainter
.paintBackgroundsBehindCell(paintInfo
, cellPoint
, column
);
190 // Paint the row group next.
191 if (sectionHasBackground
)
192 tableCellPainter
.paintBackgroundsBehindCell(paintInfo
, cellPoint
, &m_layoutTableSection
);
194 // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for
195 // painting the row background for the cell.
196 if (rowHasBackground
&& !row
->hasSelfPaintingLayer())
197 tableCellPainter
.paintBackgroundsBehindCell(paintInfo
, cellPoint
, row
);
201 if ((!cell
->hasSelfPaintingLayer() && !row
->hasSelfPaintingLayer()))
202 cell
->paint(paintInfo
, cellPoint
);