OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/paint/TableSectionPainter.h" | 6 #include "core/paint/TableSectionPainter.h" |
7 | 7 |
8 #include "core/layout/LayoutTable.h" | 8 #include "core/layout/LayoutTable.h" |
9 #include "core/layout/LayoutTableCell.h" | 9 #include "core/layout/LayoutTableCell.h" |
10 #include "core/layout/LayoutTableCol.h" | 10 #include "core/layout/LayoutTableCol.h" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 // This comparison is used only when we have overflowing cells as we have an uns
orted array to sort. We thus need | 50 // This comparison is used only when we have overflowing cells as we have an uns
orted array to sort. We thus need |
51 // to sort both on rows and columns to properly issue paint invalidations. | 51 // to sort both on rows and columns to properly issue paint invalidations. |
52 static inline bool compareCellPositionsWithOverflowingCells(LayoutTableCell* ele
m1, LayoutTableCell* elem2) | 52 static inline bool compareCellPositionsWithOverflowingCells(LayoutTableCell* ele
m1, LayoutTableCell* elem2) |
53 { | 53 { |
54 if (elem1->rowIndex() != elem2->rowIndex()) | 54 if (elem1->rowIndex() != elem2->rowIndex()) |
55 return elem1->rowIndex() < elem2->rowIndex(); | 55 return elem1->rowIndex() < elem2->rowIndex(); |
56 | 56 |
57 return elem1->col() < elem2->col(); | 57 return elem1->col() < elem2->col(); |
58 } | 58 } |
59 | 59 |
| 60 void TableSectionPainter::paintCollapsedBorders(const PaintInfo& paintInfo, cons
t LayoutPoint& paintOffset, const CollapsedBorderValue& currentBorderValue) |
| 61 { |
| 62 if (!m_layoutTableSection.numRows() || !m_layoutTableSection.table()->column
s().size()) |
| 63 return; |
| 64 |
| 65 LayoutPoint adjustedPaintOffset = paintOffset + m_layoutTableSection.locatio
n(); |
| 66 BoxClipper boxClipper(m_layoutTableSection, paintInfo, adjustedPaintOffset,
ForceContentsClip); |
| 67 |
| 68 LayoutRect localPaintInvalidationRect = LayoutRect(paintInfo.rect); |
| 69 localPaintInvalidationRect.moveBy(-adjustedPaintOffset); |
| 70 |
| 71 LayoutRect tableAlignedRect = m_layoutTableSection.logicalRectForWritingMode
AndDirection(localPaintInvalidationRect); |
| 72 |
| 73 CellSpan dirtiedRows = m_layoutTableSection.dirtiedRows(tableAlignedRect); |
| 74 CellSpan dirtiedColumns = m_layoutTableSection.dirtiedColumns(tableAlignedRe
ct); |
| 75 |
| 76 if (dirtiedColumns.start() >= dirtiedColumns.end()) |
| 77 return; |
| 78 |
| 79 // Collapsed borders are painted from the bottom right to the top left so th
at precedence |
| 80 // due to cell position is respected. |
| 81 for (unsigned r = dirtiedRows.end(); r > dirtiedRows.start(); r--) { |
| 82 unsigned row = r - 1; |
| 83 for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.start(); c--)
{ |
| 84 unsigned col = c - 1; |
| 85 const LayoutTableSection::CellStruct& current = m_layoutTableSection
.cellAt(row, col); |
| 86 const LayoutTableCell* cell = current.primaryCell(); |
| 87 if (!cell || (row > dirtiedRows.start() && m_layoutTableSection.prim
aryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start() && m_layoutTab
leSection.primaryCellAt(row, col - 1) == cell)) |
| 88 continue; |
| 89 LayoutPoint cellPoint = m_layoutTableSection.flipForWritingModeForCh
ild(cell, adjustedPaintOffset); |
| 90 TableCellPainter(*cell).paintCollapsedBorders(paintInfo, cellPoint,
currentBorderValue); |
| 91 } |
| 92 } |
| 93 } |
| 94 |
60 void TableSectionPainter::paintObject(const PaintInfo& paintInfo, const LayoutPo
int& paintOffset) | 95 void TableSectionPainter::paintObject(const PaintInfo& paintInfo, const LayoutPo
int& paintOffset) |
61 { | 96 { |
62 LayoutRect localPaintInvalidationRect = LayoutRect(paintInfo.rect); | 97 LayoutRect localPaintInvalidationRect = LayoutRect(paintInfo.rect); |
63 localPaintInvalidationRect.moveBy(-paintOffset); | 98 localPaintInvalidationRect.moveBy(-paintOffset); |
64 | 99 |
65 LayoutRect tableAlignedRect = m_layoutTableSection.logicalRectForWritingMode
AndDirection(localPaintInvalidationRect); | 100 LayoutRect tableAlignedRect = m_layoutTableSection.logicalRectForWritingMode
AndDirection(localPaintInvalidationRect); |
66 | 101 |
67 CellSpan dirtiedRows = m_layoutTableSection.dirtiedRows(tableAlignedRect); | 102 CellSpan dirtiedRows = m_layoutTableSection.dirtiedRows(tableAlignedRect); |
68 CellSpan dirtiedColumns = m_layoutTableSection.dirtiedColumns(tableAlignedRe
ct); | 103 CellSpan dirtiedColumns = m_layoutTableSection.dirtiedColumns(tableAlignedRe
ct); |
69 | 104 |
| 105 if (dirtiedColumns.start() >= dirtiedColumns.end()) |
| 106 return; |
| 107 |
70 const HashSet<LayoutTableCell*>& overflowingCells = m_layoutTableSection.ove
rflowingCells(); | 108 const HashSet<LayoutTableCell*>& overflowingCells = m_layoutTableSection.ove
rflowingCells(); |
71 if (dirtiedColumns.start() < dirtiedColumns.end()) { | 109 if (!m_layoutTableSection.hasMultipleCellLevels() && !overflowingCells.size(
)) { |
72 if (!m_layoutTableSection.hasMultipleCellLevels() && !overflowingCells.s
ize()) { | 110 // Draw the dirty cells in the order that they appear. |
73 if (paintInfo.phase == PaintPhaseCollapsedTableBorders) { | 111 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { |
74 // Collapsed borders are painted from the bottom right to the to
p left so that precedence | 112 const LayoutTableRow* row = m_layoutTableSection.rowLayoutObjectAt(r
); |
75 // due to cell position is respected. | 113 if (row && !row->hasSelfPaintingLayer()) |
76 for (unsigned r = dirtiedRows.end(); r > dirtiedRows.start(); r-
-) { | 114 TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, pain
tOffset); |
77 unsigned row = r - 1; | 115 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end();
c++) { |
78 for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.s
tart(); c--) { | 116 const LayoutTableSection::CellStruct& current = m_layoutTableSec
tion.cellAt(r, c); |
79 unsigned col = c - 1; | 117 const LayoutTableCell* cell = current.primaryCell(); |
80 const LayoutTableSection::CellStruct& current = m_layout
TableSection.cellAt(row, col); | 118 if (!cell || (r > dirtiedRows.start() && m_layoutTableSection.pr
imaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start() && m_layoutTableSe
ction.primaryCellAt(r, c - 1) == cell)) |
81 const LayoutTableCell* cell = current.primaryCell(); | 119 continue; |
82 if (!cell || (row > dirtiedRows.start() && m_layoutTable
Section.primaryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start() &&
m_layoutTableSection.primaryCellAt(row, col - 1) == cell)) | 120 paintCell(*cell, paintInfo, paintOffset); |
| 121 } |
| 122 } |
| 123 } else { |
| 124 // The overflowing cells should be scarce to avoid adding a lot of cells
to the HashSet. |
| 125 #if ENABLE(ASSERT) |
| 126 unsigned totalRows = m_layoutTableSection.numRows(); |
| 127 unsigned totalCols = m_layoutTableSection.table()->columns().size(); |
| 128 ASSERT(overflowingCells.size() < totalRows * totalCols * gMaxAllowedOver
flowingCellRatioForFastPaintPath); |
| 129 #endif |
| 130 |
| 131 // To make sure we properly paint invalidate the section, we paint inval
idated all the overflowing cells that we collected. |
| 132 Vector<LayoutTableCell*> cells; |
| 133 copyToVector(overflowingCells, cells); |
| 134 |
| 135 HashSet<LayoutTableCell*> spanningCells; |
| 136 |
| 137 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { |
| 138 const LayoutTableRow* row = m_layoutTableSection.rowLayoutObjectAt(r
); |
| 139 if (row && !row->hasSelfPaintingLayer()) |
| 140 TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, pain
tOffset); |
| 141 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end();
c++) { |
| 142 const LayoutTableSection::CellStruct& current = m_layoutTableSec
tion.cellAt(r, c); |
| 143 if (!current.hasCells()) |
| 144 continue; |
| 145 for (unsigned i = 0; i < current.cells.size(); ++i) { |
| 146 if (overflowingCells.contains(current.cells[i])) |
| 147 continue; |
| 148 |
| 149 if (current.cells[i]->rowSpan() > 1 || current.cells[i]->col
Span() > 1) { |
| 150 if (!spanningCells.add(current.cells[i]).isNewEntry) |
83 continue; | 151 continue; |
84 LayoutPoint cellPoint = m_layoutTableSection.flipForWrit
ingModeForChild(cell, paintOffset); | |
85 TableCellPainter(*cell).paintCollapsedBorders(paintInfo,
cellPoint); | |
86 } | 152 } |
87 } | 153 |
88 } else { | 154 cells.append(current.cells[i]); |
89 // Draw the dirty cells in the order that they appear. | |
90 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r+
+) { | |
91 const LayoutTableRow* row = m_layoutTableSection.rowLayoutOb
jectAt(r); | |
92 if (row && !row->hasSelfPaintingLayer()) | |
93 TableRowPainter(*row).paintOutlineForRowIfNeeded(paintIn
fo, paintOffset); | |
94 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns
.end(); c++) { | |
95 const LayoutTableSection::CellStruct& current = m_layout
TableSection.cellAt(r, c); | |
96 const LayoutTableCell* cell = current.primaryCell(); | |
97 if (!cell || (r > dirtiedRows.start() && m_layoutTableSe
ction.primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start() && m_layou
tTableSection.primaryCellAt(r, c - 1) == cell)) | |
98 continue; | |
99 paintCell(*cell, paintInfo, paintOffset); | |
100 } | |
101 } | 155 } |
102 } | 156 } |
103 } else { | 157 } |
104 // The overflowing cells should be scarce to avoid adding a lot of c
ells to the HashSet. | |
105 #if ENABLE(ASSERT) | |
106 unsigned totalRows = m_layoutTableSection.numRows(); | |
107 unsigned totalCols = m_layoutTableSection.table()->columns().size(); | |
108 ASSERT(overflowingCells.size() < totalRows * totalCols * gMaxAllowed
OverflowingCellRatioForFastPaintPath); | |
109 #endif | |
110 | 158 |
111 // To make sure we properly paint invalidate the section, we paint i
nvalidated all the overflowing cells that we collected. | 159 // Sort the dirty cells by paint order. |
112 Vector<LayoutTableCell*> cells; | 160 if (!overflowingCells.size()) |
113 copyToVector(overflowingCells, cells); | 161 std::stable_sort(cells.begin(), cells.end(), compareCellPositions); |
| 162 else |
| 163 std::sort(cells.begin(), cells.end(), compareCellPositionsWithOverfl
owingCells); |
114 | 164 |
115 HashSet<LayoutTableCell*> spanningCells; | 165 for (unsigned i = 0; i < cells.size(); ++i) |
116 | 166 paintCell(*cells[i], paintInfo, paintOffset); |
117 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { | |
118 const LayoutTableRow* row = m_layoutTableSection.rowLayoutObject
At(r); | |
119 if (row && !row->hasSelfPaintingLayer()) | |
120 TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo,
paintOffset); | |
121 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end
(); c++) { | |
122 const LayoutTableSection::CellStruct& current = m_layoutTabl
eSection.cellAt(r, c); | |
123 if (!current.hasCells()) | |
124 continue; | |
125 for (unsigned i = 0; i < current.cells.size(); ++i) { | |
126 if (overflowingCells.contains(current.cells[i])) | |
127 continue; | |
128 | |
129 if (current.cells[i]->rowSpan() > 1 || current.cells[i]-
>colSpan() > 1) { | |
130 if (!spanningCells.add(current.cells[i]).isNewEntry) | |
131 continue; | |
132 } | |
133 | |
134 cells.append(current.cells[i]); | |
135 } | |
136 } | |
137 } | |
138 | |
139 // Sort the dirty cells by paint order. | |
140 if (!overflowingCells.size()) | |
141 std::stable_sort(cells.begin(), cells.end(), compareCellPosition
s); | |
142 else | |
143 std::sort(cells.begin(), cells.end(), compareCellPositionsWithOv
erflowingCells); | |
144 | |
145 if (paintInfo.phase == PaintPhaseCollapsedTableBorders) { | |
146 for (unsigned i = cells.size(); i > 0; --i) { | |
147 LayoutPoint cellPoint = m_layoutTableSection.flipForWritingM
odeForChild(cells[i - 1], paintOffset); | |
148 TableCellPainter(*cells[i - 1]).paintCollapsedBorders(paintI
nfo, cellPoint); | |
149 } | |
150 } else { | |
151 for (unsigned i = 0; i < cells.size(); ++i) | |
152 paintCell(*cells[i], paintInfo, paintOffset); | |
153 } | |
154 } | |
155 } | 167 } |
156 } | 168 } |
157 | 169 |
158 void TableSectionPainter::paintCell(const LayoutTableCell& cell, const PaintInfo
& paintInfo, const LayoutPoint& paintOffset) | 170 void TableSectionPainter::paintCell(const LayoutTableCell& cell, const PaintInfo
& paintInfo, const LayoutPoint& paintOffset) |
159 { | 171 { |
160 LayoutPoint cellPoint = m_layoutTableSection.flipForWritingModeForChild(&cel
l, paintOffset); | 172 LayoutPoint cellPoint = m_layoutTableSection.flipForWritingModeForChild(&cel
l, paintOffset); |
161 PaintPhase paintPhase = paintInfo.phase; | 173 PaintPhase paintPhase = paintInfo.phase; |
162 const LayoutTableRow* row = toLayoutTableRow(cell.parent()); | 174 const LayoutTableRow* row = toLayoutTableRow(cell.parent()); |
163 | 175 |
164 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChil
dBlockBackground) | 176 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChil
dBlockBackground) |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 if (rowHasBackground && !row->hasSelfPaintingLayer()) | 208 if (rowHasBackground && !row->hasSelfPaintingLayer()) |
197 tableCellPainter.paintBackgroundsBehindCell(paintInfo, cellP
oint, row); | 209 tableCellPainter.paintBackgroundsBehindCell(paintInfo, cellP
oint, row); |
198 } | 210 } |
199 } | 211 } |
200 } | 212 } |
201 if ((!cell.hasSelfPaintingLayer() && !row->hasSelfPaintingLayer())) | 213 if ((!cell.hasSelfPaintingLayer() && !row->hasSelfPaintingLayer())) |
202 cell.paint(paintInfo, cellPoint); | 214 cell.paint(paintInfo, cellPoint); |
203 } | 215 } |
204 | 216 |
205 } // namespace blink | 217 } // namespace blink |
OLD | NEW |