Home | History | Annotate | Download | only in paint
      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.
      4 
      5 #include "config.h"
      6 #include "core/paint/TableSectionPainter.h"
      7 
      8 #include "core/paint/TableRowPainter.h"
      9 #include "core/rendering/GraphicsContextAnnotator.h"
     10 #include "core/rendering/PaintInfo.h"
     11 #include "core/rendering/RenderTable.h"
     12 #include "core/rendering/RenderTableCell.h"
     13 #include "core/rendering/RenderTableCol.h"
     14 #include "core/rendering/RenderTableRow.h"
     15 
     16 namespace blink {
     17 
     18 void TableSectionPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
     19 {
     20     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderTableSection);
     21 
     22     ASSERT(!m_renderTableSection.needsLayout());
     23     // avoid crashing on bugs that cause us to paint with dirty layout
     24     if (m_renderTableSection.needsLayout())
     25         return;
     26 
     27     unsigned totalRows = m_renderTableSection.numRows();
     28     unsigned totalCols = m_renderTableSection.table()->columns().size();
     29 
     30     if (!totalRows || !totalCols)
     31         return;
     32 
     33     LayoutPoint adjustedPaintOffset = paintOffset + m_renderTableSection.location();
     34 
     35     PaintPhase phase = paintInfo.phase;
     36     bool pushedClip = m_renderTableSection.pushContentsClip(paintInfo, adjustedPaintOffset, ForceContentsClip);
     37     paintObject(paintInfo, adjustedPaintOffset);
     38     if (pushedClip)
     39         m_renderTableSection.popContentsClip(paintInfo, phase, adjustedPaintOffset);
     40 
     41     if ((phase == PaintPhaseOutline || phase == PaintPhaseSelfOutline) && m_renderTableSection.style()->visibility() == VISIBLE)
     42         m_renderTableSection.paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, m_renderTableSection.size()));
     43 }
     44 
     45 static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2)
     46 {
     47     return elem1->rowIndex() < elem2->rowIndex();
     48 }
     49 
     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(RenderTableCell* elem1, RenderTableCell* elem2)
     53 {
     54     if (elem1->rowIndex() != elem2->rowIndex())
     55         return elem1->rowIndex() < elem2->rowIndex();
     56 
     57     return elem1->col() < elem2->col();
     58 }
     59 
     60 void TableSectionPainter::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
     61 {
     62     LayoutRect localPaintInvalidationRect = paintInfo.rect;
     63     localPaintInvalidationRect.moveBy(-paintOffset);
     64 
     65     LayoutRect tableAlignedRect = m_renderTableSection.logicalRectForWritingModeAndDirection(localPaintInvalidationRect);
     66 
     67     CellSpan dirtiedRows = m_renderTableSection.dirtiedRows(tableAlignedRect);
     68     CellSpan dirtiedColumns = m_renderTableSection.dirtiedColumns(tableAlignedRect);
     69 
     70     WillBeHeapHashSet<RawPtrWillBeMember<RenderTableCell> > overflowingCells = m_renderTableSection.overflowingCells();
     71     if (dirtiedColumns.start() < dirtiedColumns.end()) {
     72         if (!m_renderTableSection.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--) {
     77                     unsigned row = r - 1;
     78                     for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.start(); c--) {
     79                         unsigned col = c - 1;
     80                         RenderTableSection::CellStruct& current = m_renderTableSection.cellAt(row, col);
     81                         RenderTableCell* cell = current.primaryCell();
     82                         if (!cell || (row > dirtiedRows.start() && m_renderTableSection.primaryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start() && m_renderTableSection.primaryCellAt(row, col - 1) == cell))
     83                             continue;
     84                         LayoutPoint cellPoint = m_renderTableSection.flipForWritingModeForChild(cell, paintOffset);
     85                         cell->paintCollapsedBorders(paintInfo, cellPoint);
     86                     }
     87                 }
     88             } else {
     89                 // Draw the dirty cells in the order that they appear.
     90                 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) {
     91                     RenderTableRow* row = m_renderTableSection.rowRendererAt(r);
     92                     if (row && !row->hasSelfPaintingLayer())
     93                         TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, paintOffset);
     94                     for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) {
     95                         RenderTableSection::CellStruct& current = m_renderTableSection.cellAt(r, c);
     96                         RenderTableCell* cell = current.primaryCell();
     97                         if (!cell || (r > dirtiedRows.start() && m_renderTableSection.primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start() && m_renderTableSection.primaryCellAt(r, c - 1) == cell))
     98                             continue;
     99                         paintCell(cell, paintInfo, paintOffset);
    100                     }
    101                 }
    102             }
    103         } else {
    104             // The overflowing cells should be scarce to avoid adding a lot of cells to the HashSet.
    105 #if ENABLE(ASSERT)
    106             unsigned totalRows = m_renderTableSection.numRows();
    107             unsigned totalCols = m_renderTableSection.table()->columns().size();
    108             ASSERT(overflowingCells.size() < totalRows * totalCols * gMaxAllowedOverflowingCellRatioForFastPaintPath);
    109 #endif
    110 
    111             // To make sure we properly paint invalidate the section, we paint invalidated all the overflowing cells that we collected.
    112             Vector<RenderTableCell*> cells;
    113             copyToVector(overflowingCells, cells);
    114 
    115             HashSet<RenderTableCell*> spanningCells;
    116 
    117             for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) {
    118                 RenderTableRow* row = m_renderTableSection.rowRendererAt(r);
    119                 if (row && !row->hasSelfPaintingLayer())
    120                     TableRowPainter(*row).paintOutlineForRowIfNeeded(paintInfo, paintOffset);
    121                 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) {
    122                     RenderTableSection::CellStruct& current = m_renderTableSection.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(), compareCellPositions);
    142             else
    143                 std::sort(cells.begin(), cells.end(), compareCellPositionsWithOverflowingCells);
    144 
    145             if (paintInfo.phase == PaintPhaseCollapsedTableBorders) {
    146                 for (unsigned i = cells.size(); i > 0; --i) {
    147                     LayoutPoint cellPoint = m_renderTableSection.flipForWritingModeForChild(cells[i - 1], paintOffset);
    148                     cells[i - 1]->paintCollapsedBorders(paintInfo, cellPoint);
    149                 }
    150             } else {
    151                 for (unsigned i = 0; i < cells.size(); ++i)
    152                     paintCell(cells[i], paintInfo, paintOffset);
    153             }
    154         }
    155     }
    156 }
    157 
    158 void TableSectionPainter::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    159 {
    160     LayoutPoint cellPoint = m_renderTableSection.flipForWritingModeForChild(cell, paintOffset);
    161     PaintPhase paintPhase = paintInfo.phase;
    162     RenderTableRow* row = toRenderTableRow(cell->parent());
    163 
    164     if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
    165         // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of
    166         // the column group, column, row group, row, and then the cell.
    167         RenderTableCol* column = m_renderTableSection.table()->colElement(cell->col());
    168         RenderTableCol* columnGroup = column ? column->enclosingColumnGroup() : 0;
    169 
    170         // Column groups and columns first.
    171         // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
    172         // the stack, since we have already opened a transparency layer (potentially) for the table row group.
    173         // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
    174         // cell.
    175         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, columnGroup);
    176         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, column);
    177 
    178         // Paint the row group next.
    179         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, &m_renderTableSection);
    180 
    181         // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for
    182         // painting the row background for the cell.
    183         if (!row->hasSelfPaintingLayer())
    184             cell->paintBackgroundsBehindCell(paintInfo, cellPoint, row);
    185     }
    186     if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()))
    187         cell->paint(paintInfo, cellPoint);
    188 }
    189 
    190 } // namespace blink
    191