| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1997 Martin Jones (mjones@kde.org) | 2 * Copyright (C) 1997 Martin Jones (mjones@kde.org) |
| 3 * (C) 1997 Torben Weis (weis@kde.org) | 3 * (C) 1997 Torben Weis (weis@kde.org) |
| 4 * (C) 1998 Waldo Bastian (bastian@kde.org) | 4 * (C) 1998 Waldo Bastian (bastian@kde.org) |
| 5 * (C) 1999 Lars Knoll (knoll@kde.org) | 5 * (C) 1999 Lars Knoll (knoll@kde.org) |
| 6 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 6 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 7 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2013 Apple Inc. All r
ights reserved. | 7 * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2013 Apple Inc. All r
ights reserved. |
| 8 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 8 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
| 9 * | 9 * |
| 10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
| 11 * modify it under the terms of the GNU Library General Public | 11 * modify it under the terms of the GNU Library General Public |
| 12 * License as published by the Free Software Foundation; either | 12 * License as published by the Free Software Foundation; either |
| 13 * version 2 of the License, or (at your option) any later version. | 13 * version 2 of the License, or (at your option) any later version. |
| 14 * | 14 * |
| 15 * This library is distributed in the hope that it will be useful, | 15 * This library is distributed in the hope that it will be useful, |
| 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 18 * Library General Public License for more details. | 18 * Library General Public License for more details. |
| 19 * | 19 * |
| 20 * You should have received a copy of the GNU Library General Public License | 20 * You should have received a copy of the GNU Library General Public License |
| 21 * along with this library; see the file COPYING.LIB. If not, write to | 21 * along with this library; see the file COPYING.LIB. If not, write to |
| 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 23 * Boston, MA 02110-1301, USA. | 23 * Boston, MA 02110-1301, USA. |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "config.h" | 26 #include "config.h" |
| 27 #include "core/rendering/RenderTableSection.h" | 27 #include "core/rendering/RenderTableSection.h" |
| 28 | 28 |
| 29 #include "core/paint/TableSectionPainter.h" |
| 29 #include <limits> | 30 #include <limits> |
| 30 #include "core/rendering/GraphicsContextAnnotator.h" | 31 #include "core/rendering/GraphicsContextAnnotator.h" |
| 31 #include "core/rendering/HitTestResult.h" | 32 #include "core/rendering/HitTestResult.h" |
| 32 #include "core/rendering/PaintInfo.h" | 33 #include "core/rendering/PaintInfo.h" |
| 33 #include "core/rendering/RenderTableCell.h" | 34 #include "core/rendering/RenderTableCell.h" |
| 34 #include "core/rendering/RenderTableCol.h" | 35 #include "core/rendering/RenderTableCol.h" |
| 35 #include "core/rendering/RenderTableRow.h" | 36 #include "core/rendering/RenderTableRow.h" |
| 36 #include "core/rendering/RenderView.h" | 37 #include "core/rendering/RenderView.h" |
| 37 #include "core/rendering/SubtreeLayoutScope.h" | 38 #include "core/rendering/SubtreeLayoutScope.h" |
| 38 #include "wtf/HashSet.h" | 39 #include "wtf/HashSet.h" |
| 39 | 40 |
| 40 namespace blink { | 41 namespace blink { |
| 41 | 42 |
| 42 using namespace HTMLNames; | 43 using namespace HTMLNames; |
| 43 | 44 |
| 44 // Those 2 variables are used to balance the memory consumption vs the paint inv
alidation time on big tables. | 45 // This variable is used to balance the memory consumption vs the paint invalida
tion time on big tables. |
| 45 static unsigned gMinTableSizeToUseFastPaintPathWithOverflowingCell = 75 * 75; | 46 static unsigned gMinTableSizeToUseFastPaintPathWithOverflowingCell = 75 * 75; |
| 46 static float gMaxAllowedOverflowingCellRatioForFastPaintPath = 0.1f; | |
| 47 | 47 |
| 48 static inline void setRowLogicalHeightToRowStyleLogicalHeight(RenderTableSection
::RowStruct& row) | 48 static inline void setRowLogicalHeightToRowStyleLogicalHeight(RenderTableSection
::RowStruct& row) |
| 49 { | 49 { |
| 50 ASSERT(row.rowRenderer); | 50 ASSERT(row.rowRenderer); |
| 51 row.logicalHeight = row.rowRenderer->style()->logicalHeight(); | 51 row.logicalHeight = row.rowRenderer->style()->logicalHeight(); |
| 52 } | 52 } |
| 53 | 53 |
| 54 static inline void updateLogicalHeightForCell(RenderTableSection::RowStruct& row
, const RenderTableCell* cell) | 54 static inline void updateLogicalHeightForCell(RenderTableSection::RowStruct& row
, const RenderTableCell* cell) |
| 55 { | 55 { |
| 56 // We ignore height settings on rowspan cells. | 56 // We ignore height settings on rowspan cells. |
| (...skipping 1196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1253 // Only cells with content have a baseline | 1253 // Only cells with content have a baseline |
| 1254 if (cell && cell->contentLogicalHeight()) | 1254 if (cell && cell->contentLogicalHeight()) |
| 1255 firstLineBaseline = std::max<int>(firstLineBaseline, cell->logicalTo
p() + cell->paddingBefore() + cell->borderBefore() + cell->contentLogicalHeight(
)); | 1255 firstLineBaseline = std::max<int>(firstLineBaseline, cell->logicalTo
p() + cell->paddingBefore() + cell->borderBefore() + cell->contentLogicalHeight(
)); |
| 1256 } | 1256 } |
| 1257 | 1257 |
| 1258 return firstLineBaseline; | 1258 return firstLineBaseline; |
| 1259 } | 1259 } |
| 1260 | 1260 |
| 1261 void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOff
set) | 1261 void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOff
set) |
| 1262 { | 1262 { |
| 1263 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); | 1263 TableSectionPainter(*this).paint(paintInfo, paintOffset); |
| 1264 | |
| 1265 ASSERT(!needsLayout()); | |
| 1266 // avoid crashing on bugs that cause us to paint with dirty layout | |
| 1267 if (needsLayout()) | |
| 1268 return; | |
| 1269 | |
| 1270 unsigned totalRows = m_grid.size(); | |
| 1271 unsigned totalCols = table()->columns().size(); | |
| 1272 | |
| 1273 if (!totalRows || !totalCols) | |
| 1274 return; | |
| 1275 | |
| 1276 LayoutPoint adjustedPaintOffset = paintOffset + location(); | |
| 1277 | |
| 1278 PaintPhase phase = paintInfo.phase; | |
| 1279 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, ForceCont
entsClip); | |
| 1280 paintObject(paintInfo, adjustedPaintOffset); | |
| 1281 if (pushedClip) | |
| 1282 popContentsClip(paintInfo, phase, adjustedPaintOffset); | |
| 1283 | |
| 1284 if ((phase == PaintPhaseOutline || phase == PaintPhaseSelfOutline) && style(
)->visibility() == VISIBLE) | |
| 1285 paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size())); | |
| 1286 } | |
| 1287 | |
| 1288 static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell*
elem2) | |
| 1289 { | |
| 1290 return elem1->rowIndex() < elem2->rowIndex(); | |
| 1291 } | |
| 1292 | |
| 1293 // This comparison is used only when we have overflowing cells as we have an uns
orted array to sort. We thus need | |
| 1294 // to sort both on rows and columns to properly issue paint invalidations. | |
| 1295 static inline bool compareCellPositionsWithOverflowingCells(RenderTableCell* ele
m1, RenderTableCell* elem2) | |
| 1296 { | |
| 1297 if (elem1->rowIndex() != elem2->rowIndex()) | |
| 1298 return elem1->rowIndex() < elem2->rowIndex(); | |
| 1299 | |
| 1300 return elem1->col() < elem2->col(); | |
| 1301 } | |
| 1302 | |
| 1303 void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo,
const LayoutPoint& paintOffset) | |
| 1304 { | |
| 1305 LayoutPoint cellPoint = flipForWritingModeForChild(cell, paintOffset); | |
| 1306 PaintPhase paintPhase = paintInfo.phase; | |
| 1307 RenderTableRow* row = toRenderTableRow(cell->parent()); | |
| 1308 | |
| 1309 if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChild
BlockBackground) { | |
| 1310 // We need to handle painting a stack of backgrounds. This stack (from
bottom to top) consists of | |
| 1311 // the column group, column, row group, row, and then the cell. | |
| 1312 RenderTableCol* column = table()->colElement(cell->col()); | |
| 1313 RenderTableCol* columnGroup = column ? column->enclosingColumnGroup() :
0; | |
| 1314 | |
| 1315 // Column groups and columns first. | |
| 1316 // FIXME: Columns and column groups do not currently support opacity, an
d they are being painted "too late" in | |
| 1317 // the stack, since we have already opened a transparency layer (potenti
ally) for the table row group. | |
| 1318 // Note that we deliberately ignore whether or not the cell has a layer,
since these backgrounds paint "behind" the | |
| 1319 // cell. | |
| 1320 cell->paintBackgroundsBehindCell(paintInfo, cellPoint, columnGroup); | |
| 1321 cell->paintBackgroundsBehindCell(paintInfo, cellPoint, column); | |
| 1322 | |
| 1323 // Paint the row group next. | |
| 1324 cell->paintBackgroundsBehindCell(paintInfo, cellPoint, this); | |
| 1325 | |
| 1326 // Paint the row next, but only if it doesn't have a layer. If a row ha
s a layer, it will be responsible for | |
| 1327 // painting the row background for the cell. | |
| 1328 if (!row->hasSelfPaintingLayer()) | |
| 1329 cell->paintBackgroundsBehindCell(paintInfo, cellPoint, row); | |
| 1330 } | |
| 1331 if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer())) | |
| 1332 cell->paint(paintInfo, cellPoint); | |
| 1333 } | 1264 } |
| 1334 | 1265 |
| 1335 LayoutRect RenderTableSection::logicalRectForWritingModeAndDirection(const Layou
tRect& rect) const | 1266 LayoutRect RenderTableSection::logicalRectForWritingModeAndDirection(const Layou
tRect& rect) const |
| 1336 { | 1267 { |
| 1337 LayoutRect tableAlignedRect(rect); | 1268 LayoutRect tableAlignedRect(rect); |
| 1338 | 1269 |
| 1339 flipForWritingMode(tableAlignedRect); | 1270 flipForWritingMode(tableAlignedRect); |
| 1340 | 1271 |
| 1341 if (!style()->isHorizontalWritingMode()) | 1272 if (!style()->isHorizontalWritingMode()) |
| 1342 tableAlignedRect = tableAlignedRect.transposedRect(); | 1273 tableAlignedRect = tableAlignedRect.transposedRect(); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1432 if (endColumn == columnPos.size()) | 1363 if (endColumn == columnPos.size()) |
| 1433 endColumn = columnPos.size() - 1; | 1364 endColumn = columnPos.size() - 1; |
| 1434 } | 1365 } |
| 1435 | 1366 |
| 1436 return CellSpan(startColumn, endColumn); | 1367 return CellSpan(startColumn, endColumn); |
| 1437 } | 1368 } |
| 1438 | 1369 |
| 1439 | 1370 |
| 1440 void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa
intOffset) | 1371 void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa
intOffset) |
| 1441 { | 1372 { |
| 1442 LayoutRect localPaintInvalidationRect = paintInfo.rect; | 1373 TableSectionPainter(*this).paintObject(paintInfo, paintOffset); |
| 1443 localPaintInvalidationRect.moveBy(-paintOffset); | |
| 1444 | |
| 1445 LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(localPai
ntInvalidationRect); | |
| 1446 | |
| 1447 CellSpan dirtiedRows = this->dirtiedRows(tableAlignedRect); | |
| 1448 CellSpan dirtiedColumns = this->dirtiedColumns(tableAlignedRect); | |
| 1449 | |
| 1450 if (dirtiedColumns.start() < dirtiedColumns.end()) { | |
| 1451 if (!m_hasMultipleCellLevels && !m_overflowingCells.size()) { | |
| 1452 if (paintInfo.phase == PaintPhaseCollapsedTableBorders) { | |
| 1453 // Collapsed borders are painted from the bottom right to the to
p left so that precedence | |
| 1454 // due to cell position is respected. | |
| 1455 for (unsigned r = dirtiedRows.end(); r > dirtiedRows.start(); r-
-) { | |
| 1456 unsigned row = r - 1; | |
| 1457 for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.s
tart(); c--) { | |
| 1458 unsigned col = c - 1; | |
| 1459 CellStruct& current = cellAt(row, col); | |
| 1460 RenderTableCell* cell = current.primaryCell(); | |
| 1461 if (!cell || (row > dirtiedRows.start() && primaryCellAt
(row - 1, col) == cell) || (col > dirtiedColumns.start() && primaryCellAt(row, c
ol - 1) == cell)) | |
| 1462 continue; | |
| 1463 LayoutPoint cellPoint = flipForWritingModeForChild(cell,
paintOffset); | |
| 1464 cell->paintCollapsedBorders(paintInfo, cellPoint); | |
| 1465 } | |
| 1466 } | |
| 1467 } else { | |
| 1468 // Draw the dirty cells in the order that they appear. | |
| 1469 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r+
+) { | |
| 1470 RenderTableRow* row = m_grid[r].rowRenderer; | |
| 1471 if (row && !row->hasSelfPaintingLayer()) | |
| 1472 row->paintOutlineForRowIfNeeded(paintInfo, paintOffset); | |
| 1473 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns
.end(); c++) { | |
| 1474 CellStruct& current = cellAt(r, c); | |
| 1475 RenderTableCell* cell = current.primaryCell(); | |
| 1476 if (!cell || (r > dirtiedRows.start() && primaryCellAt(r
- 1, c) == cell) || (c > dirtiedColumns.start() && primaryCellAt(r, c - 1) == c
ell)) | |
| 1477 continue; | |
| 1478 paintCell(cell, paintInfo, paintOffset); | |
| 1479 } | |
| 1480 } | |
| 1481 } | |
| 1482 } else { | |
| 1483 // The overflowing cells should be scarce to avoid adding a lot of c
ells to the HashSet. | |
| 1484 #if ENABLE(ASSERT) | |
| 1485 unsigned totalRows = m_grid.size(); | |
| 1486 unsigned totalCols = table()->columns().size(); | |
| 1487 ASSERT(m_overflowingCells.size() < totalRows * totalCols * gMaxAllow
edOverflowingCellRatioForFastPaintPath); | |
| 1488 #endif | |
| 1489 | |
| 1490 // To make sure we properly paint invalidate the section, we paint i
nvalidated all the overflowing cells that we collected. | |
| 1491 Vector<RenderTableCell*> cells; | |
| 1492 copyToVector(m_overflowingCells, cells); | |
| 1493 | |
| 1494 HashSet<RenderTableCell*> spanningCells; | |
| 1495 | |
| 1496 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { | |
| 1497 RenderTableRow* row = m_grid[r].rowRenderer; | |
| 1498 if (row && !row->hasSelfPaintingLayer()) | |
| 1499 row->paintOutlineForRowIfNeeded(paintInfo, paintOffset); | |
| 1500 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end
(); c++) { | |
| 1501 CellStruct& current = cellAt(r, c); | |
| 1502 if (!current.hasCells()) | |
| 1503 continue; | |
| 1504 for (unsigned i = 0; i < current.cells.size(); ++i) { | |
| 1505 if (m_overflowingCells.contains(current.cells[i])) | |
| 1506 continue; | |
| 1507 | |
| 1508 if (current.cells[i]->rowSpan() > 1 || current.cells[i]-
>colSpan() > 1) { | |
| 1509 if (!spanningCells.add(current.cells[i]).isNewEntry) | |
| 1510 continue; | |
| 1511 } | |
| 1512 | |
| 1513 cells.append(current.cells[i]); | |
| 1514 } | |
| 1515 } | |
| 1516 } | |
| 1517 | |
| 1518 // Sort the dirty cells by paint order. | |
| 1519 if (!m_overflowingCells.size()) | |
| 1520 std::stable_sort(cells.begin(), cells.end(), compareCellPosition
s); | |
| 1521 else | |
| 1522 std::sort(cells.begin(), cells.end(), compareCellPositionsWithOv
erflowingCells); | |
| 1523 | |
| 1524 if (paintInfo.phase == PaintPhaseCollapsedTableBorders) { | |
| 1525 for (unsigned i = cells.size(); i > 0; --i) { | |
| 1526 LayoutPoint cellPoint = flipForWritingModeForChild(cells[i -
1], paintOffset); | |
| 1527 cells[i - 1]->paintCollapsedBorders(paintInfo, cellPoint); | |
| 1528 } | |
| 1529 } else { | |
| 1530 for (unsigned i = 0; i < cells.size(); ++i) | |
| 1531 paintCell(cells[i], paintInfo, paintOffset); | |
| 1532 } | |
| 1533 } | |
| 1534 } | |
| 1535 } | 1374 } |
| 1536 | 1375 |
| 1537 void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*) | 1376 void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*) |
| 1538 { | 1377 { |
| 1539 // FIXME: Examine cells and issue paint invalidations of only the rect the i
mage paints in. | 1378 // FIXME: Examine cells and issue paint invalidations of only the rect the i
mage paints in. |
| 1540 setShouldDoFullPaintInvalidation(true); | 1379 setShouldDoFullPaintInvalidation(true); |
| 1541 } | 1380 } |
| 1542 | 1381 |
| 1543 void RenderTableSection::recalcCells() | 1382 void RenderTableSection::recalcCells() |
| 1544 { | 1383 { |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1770 // FIXME: The table's direction should determine our row's direction, not th
e section's (see bug 96691). | 1609 // FIXME: The table's direction should determine our row's direction, not th
e section's (see bug 96691). |
| 1771 if (!style()->isLeftToRightDirection()) | 1610 if (!style()->isLeftToRightDirection()) |
| 1772 cellLocation.setX(table()->columnPositions()[table()->numEffCols()] - ta
ble()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] +
horizontalBorderSpacing); | 1611 cellLocation.setX(table()->columnPositions()[table()->numEffCols()] - ta
ble()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] +
horizontalBorderSpacing); |
| 1773 else | 1612 else |
| 1774 cellLocation.setX(table()->columnPositions()[effectiveColumn] + horizont
alBorderSpacing); | 1613 cellLocation.setX(table()->columnPositions()[effectiveColumn] + horizont
alBorderSpacing); |
| 1775 | 1614 |
| 1776 cell->setLogicalLocation(cellLocation); | 1615 cell->setLogicalLocation(cellLocation); |
| 1777 } | 1616 } |
| 1778 | 1617 |
| 1779 } // namespace blink | 1618 } // namespace blink |
| OLD | NEW |