summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/RenderTableSection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/rendering/RenderTableSection.cpp')
-rw-r--r--WebCore/rendering/RenderTableSection.cpp274
1 files changed, 150 insertions, 124 deletions
diff --git a/WebCore/rendering/RenderTableSection.cpp b/WebCore/rendering/RenderTableSection.cpp
index fcb6c59..c439a13 100644
--- a/WebCore/rendering/RenderTableSection.cpp
+++ b/WebCore/rendering/RenderTableSection.cpp
@@ -37,6 +37,7 @@
#include "RenderTableRow.h"
#include "RenderView.h"
#include <limits>
+#include <wtf/HashSet.h>
#include <wtf/Vector.h>
#ifdef ANDROID_LAYOUT
#include "Frame.h"
@@ -68,9 +69,10 @@ RenderTableSection::RenderTableSection(Node* node)
, m_outerBorderBottom(0)
, m_needsCellRecalc(false)
, m_hasOverflowingCell(false)
+ , m_hasMultipleCellLevels(false)
{
// init RenderObject attributes
- setInline(false); // our object is not Inline
+ setInline(false); // our object is not Inline
}
RenderTableSection::~RenderTableSection()
@@ -166,12 +168,8 @@ bool RenderTableSection::ensureRows(int numRows)
}
m_gridRows = numRows;
int nCols = max(1, table()->numEffCols());
- CellStruct emptyCellStruct;
- emptyCellStruct.cell = 0;
- emptyCellStruct.inColSpan = false;
for (int r = nRows; r < numRows; r++) {
m_grid[r].row = new Row(nCols);
- m_grid[r].row->fill(emptyCellStruct);
m_grid[r].rowRenderer = 0;
m_grid[r].baseline = 0;
m_grid[r].height = Length();
@@ -194,8 +192,7 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row)
// <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
// <TR><TD colspan="2">5
// </TABLE>
-
- while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).cell || cellAt(m_cRow, m_cCol).inColSpan))
+ while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).hasCells() || cellAt(m_cRow, m_cCol).inColSpan))
m_cCol++;
if (rSpan == 1) {
@@ -229,31 +226,30 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row)
int col = m_cCol;
// tell the cell where it is
- CellStruct currentCell;
- currentCell.cell = cell;
- currentCell.inColSpan = false;
+ bool inColSpan = false;
while (cSpan) {
int currentSpan;
if (m_cCol >= nCols) {
table()->appendColumn(cSpan);
currentSpan = cSpan;
} else {
- if (cSpan < static_cast<int>(columns[m_cCol].span))
+ if (cSpan < (int)columns[m_cCol].span)
table()->splitColumn(m_cCol, cSpan);
currentSpan = columns[m_cCol].span;
}
-
for (int r = 0; r < rSpan; r++) {
CellStruct& c = cellAt(m_cRow + r, m_cCol);
- if (!c.cell)
- c.cell = currentCell.cell;
- if (currentCell.inColSpan)
+ ASSERT(cell);
+ c.cells.append(cell);
+ // If cells overlap then we take the slow path for painting.
+ if (c.cells.size() > 1)
+ m_hasMultipleCellLevels = true;
+ if (inColSpan)
c.inColSpan = true;
}
m_cCol++;
cSpan -= currentSpan;
- currentCell.cell = 0;
- currentCell.inColSpan = true;
+ inColSpan = true;
}
cell->setRow(m_cRow);
cell->setCol(table()->effColToCol(col));
@@ -279,14 +275,14 @@ void RenderTableSection::setCellWidths()
Row& row = *m_grid[i].row;
int cols = row.size();
for (int j = 0; j < cols; j++) {
- CellStruct current = row[j];
- RenderTableCell* cell = current.cell;
-
- if (!cell)
- continue;
+ CellStruct& current = row[j];
+ RenderTableCell* cell = current.primaryCell();
+ if (!cell || current.inColSpan)
+ continue;
int endCol = j;
int cspan = cell->colSpan();
while (cspan && endCol < cols) {
+ ASSERT(endCol < (int)table()->columns().size());
cspan -= table()->columns()[endCol].span;
endCol++;
}
@@ -321,7 +317,7 @@ void RenderTableSection::setCellWidths()
}
}
- statePusher.pop(); // only pops if we pushed
+ statePusher.pop(); // only pops if we pushed
}
int RenderTableSection::calcRowHeight()
@@ -364,11 +360,13 @@ int RenderTableSection::calcRowHeight()
int totalCols = row->size();
for (int c = 0; c < totalCols; c++) {
- CellStruct current = cellAt(r, c);
- cell = current.cell;
+ CellStruct& current = cellAt(r, c);
+ cell = current.primaryCell();
+
if (!cell || current.inColSpan)
continue;
- if (r < m_gridRows - 1 && cellAt(r + 1, c).cell == cell)
+
+ if ((cell->row() + cell->rowSpan() - 1) > r)
continue;
int indx = max(r - cell->rowSpan() + 1, 0);
@@ -410,7 +408,7 @@ int RenderTableSection::calcRowHeight()
}
}
- //do we have baseline aligned elements?
+ // do we have baseline aligned elements?
if (baseline) {
// increase rowheight if baseline requires
m_rowPos[r + 1] = max(m_rowPos[r + 1], baseline + bdesc + (m_grid[r].rowRenderer ? spacing : 0));
@@ -466,11 +464,11 @@ int RenderTableSection::layoutRows(int toAdd)
for (int r = 0; r < totalRows; r++) {
for (int c = 0; c < nEffCols; c++) {
CellStruct current = cellAt(r, c);
- RenderTableCell* cell = current.cell;
+ RenderTableCell* cell = current.primaryCell();
if (!cell || current.inColSpan)
continue;
- if (r > 0 && (cellAt(r-1, c).cell == cell))
+ if (r > 0 && (primaryCellAt(r-1, c) == cell))
continue;
// cell->setCellTopExtra(0);
@@ -564,7 +562,7 @@ int RenderTableSection::layoutRows(int toAdd)
int add = 0;
int prev = m_rowPos[0];
for (int r = 0; r < totalRows; r++) {
- //weight with the original height
+ // weight with the original height
add += dh * (m_rowPos[r + 1] - prev) / tot;
prev = m_rowPos[r + 1];
m_rowPos[r + 1] += add;
@@ -587,16 +585,14 @@ int RenderTableSection::layoutRows(int toAdd)
}
for (int c = 0; c < nEffCols; c++) {
- RenderTableCell* cell = cellAt(r, c).cell;
-
- if (!cell)
- continue;
- if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell)
- continue;
+ CellStruct& cs = cellAt(r, c);
+ RenderTableCell* cell = cs.primaryCell();
- rindx = max(0, r - cell->rowSpan() + 1);
+ if (!cell || cs.inColSpan)
+ continue;
- rHeight = m_rowPos[r + 1] - m_rowPos[rindx] - vspacing;
+ rindx = cell->row();
+ rHeight = m_rowPos[rindx + cell->rowSpan()] - m_rowPos[rindx] - vspacing;
// Force percent height children to lay themselves out again.
// This will cause these children to grow to fill the cell.
@@ -612,8 +608,8 @@ int RenderTableSection::layoutRows(int toAdd)
// match the behavior perfectly, but we'll continue to refine it as we discover new
// bugs. :)
bool cellChildrenFlex = false;
- bool flexAllChildren = cell->style()->height().isFixed() ||
- (!table()->style()->height().isAuto() && rHeight != cell->height());
+ bool flexAllChildren = cell->style()->height().isFixed()
+ || (!table()->style()->height().isAuto() && rHeight != cell->height());
for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) {
if (!o->isText() && o->style()->height().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) {
@@ -706,9 +702,9 @@ int RenderTableSection::layoutRows(int toAdd)
IntRect oldCellRect(cell->x(), cell->y() , cell->width(), cell->height());
- if (style()->direction() == RTL) {
+ if (style()->direction() == RTL)
cell->setLocation(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]);
- } else
+ else
cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]);
// If the cell moved, we have to repaint it as well as any floating/positioned
@@ -730,10 +726,11 @@ int RenderTableSection::layoutRows(int toAdd)
// Now that our height has been determined, add in overflow from cells.
for (int r = 0; r < totalRows; r++) {
for (int c = 0; c < nEffCols; c++) {
- RenderTableCell* cell = cellAt(r, c).cell;
- if (!cell)
+ CellStruct& cs = cellAt(r, c);
+ RenderTableCell* cell = cs.primaryCell();
+ if (!cell || cs.inColSpan)
continue;
- if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell)
+ if (r < totalRows - 1 && cell == primaryCellAt(r + 1, c))
continue;
addOverflowFromChild(cell);
m_hasOverflowingCell |= cell->hasVisibleOverflow();
@@ -821,17 +818,16 @@ int RenderTableSection::calcOuterBorderTop() const
bool allHidden = true;
for (int c = 0; c < totalCols; c++) {
const CellStruct& current = cellAt(0, c);
- if (current.inColSpan || !current.cell)
+ if (current.inColSpan || !current.hasCells())
continue;
- const BorderValue& cb = current.cell->style()->borderTop();
+ const BorderValue& cb = current.primaryCell()->style()->borderTop();
// FIXME: Don't repeat for the same col group
RenderTableCol* colGroup = table()->colElement(c);
if (colGroup) {
const BorderValue& gb = colGroup->style()->borderTop();
if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
continue;
- else
- allHidden = false;
+ allHidden = false;
if (gb.style() > BHIDDEN && gb.width() > borderWidth)
borderWidth = gb.width();
if (cb.style() > BHIDDEN && cb.width() > borderWidth)
@@ -839,8 +835,7 @@ int RenderTableSection::calcOuterBorderTop() const
} else {
if (cb.style() == BHIDDEN)
continue;
- else
- allHidden = false;
+ allHidden = false;
if (cb.style() > BHIDDEN && cb.width() > borderWidth)
borderWidth = cb.width();
}
@@ -874,17 +869,16 @@ int RenderTableSection::calcOuterBorderBottom() const
bool allHidden = true;
for (int c = 0; c < totalCols; c++) {
const CellStruct& current = cellAt(m_gridRows - 1, c);
- if (current.inColSpan || !current.cell)
+ if (current.inColSpan || !current.hasCells())
continue;
- const BorderValue& cb = current.cell->style()->borderBottom();
+ const BorderValue& cb = current.primaryCell()->style()->borderBottom();
// FIXME: Don't repeat for the same col group
RenderTableCol* colGroup = table()->colElement(c);
if (colGroup) {
const BorderValue& gb = colGroup->style()->borderBottom();
if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
continue;
- else
- allHidden = false;
+ allHidden = false;
if (gb.style() > BHIDDEN && gb.width() > borderWidth)
borderWidth = gb.width();
if (cb.style() > BHIDDEN && cb.width() > borderWidth)
@@ -892,8 +886,7 @@ int RenderTableSection::calcOuterBorderBottom() const
} else {
if (cb.style() == BHIDDEN)
continue;
- else
- allHidden = false;
+ allHidden = false;
if (cb.style() > BHIDDEN && cb.width() > borderWidth)
borderWidth = cb.width();
}
@@ -931,15 +924,14 @@ int RenderTableSection::calcOuterBorderLeft(bool rtl) const
bool allHidden = true;
for (int r = 0; r < m_gridRows; r++) {
const CellStruct& current = cellAt(r, leftmostColumn);
- if (!current.cell)
+ if (!current.hasCells())
continue;
// FIXME: Don't repeat for the same cell
- const BorderValue& cb = current.cell->style()->borderLeft();
- const BorderValue& rb = current.cell->parent()->style()->borderLeft();
+ const BorderValue& cb = current.primaryCell()->style()->borderLeft();
+ const BorderValue& rb = current.primaryCell()->parent()->style()->borderLeft();
if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
continue;
- else
- allHidden = false;
+ allHidden = false;
if (cb.style() > BHIDDEN && cb.width() > borderWidth)
borderWidth = cb.width();
if (rb.style() > BHIDDEN && rb.width() > borderWidth)
@@ -978,15 +970,14 @@ int RenderTableSection::calcOuterBorderRight(bool rtl) const
bool allHidden = true;
for (int r = 0; r < m_gridRows; r++) {
const CellStruct& current = cellAt(r, rightmostColumn);
- if (!current.cell)
+ if (!current.hasCells())
continue;
// FIXME: Don't repeat for the same cell
- const BorderValue& cb = current.cell->style()->borderRight();
- const BorderValue& rb = current.cell->parent()->style()->borderRight();
+ const BorderValue& cb = current.primaryCell()->style()->borderRight();
+ const BorderValue& rb = current.primaryCell()->parent()->style()->borderRight();
if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
continue;
- else
- allHidden = false;
+ allHidden = false;
if (cb.style() > BHIDDEN && cb.width() > borderWidth)
borderWidth = cb.width();
if (rb.style() > BHIDDEN && rb.width() > borderWidth)
@@ -1019,7 +1010,8 @@ int RenderTableSection::firstLineBoxBaseline() const
firstLineBaseline = -1;
Row* firstRow = m_grid[0].row;
for (size_t i = 0; i < firstRow->size(); ++i) {
- RenderTableCell* cell = firstRow->at(i).cell;
+ CellStruct& cs = firstRow->at(i);
+ RenderTableCell* cell = cs.primaryCell();
if (cell)
firstLineBaseline = max(firstLineBaseline, cell->y() + cell->paddingTop() + cell->borderTop() + cell->contentHeight());
}
@@ -1051,6 +1043,45 @@ void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty)
popContentsClip(paintInfo, phase, tx, ty);
}
+static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2)
+{
+ return elem1->row() < elem2->row();
+}
+
+void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, int tx, int ty)
+{
+ PaintPhase paintPhase = paintInfo.phase;
+ RenderTableRow* row = toRenderTableRow(cell->parent());
+
+ if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
+ // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of
+ // the column group, column, row group, row, and then the cell.
+ RenderObject* col = table()->colElement(cell->col());
+ RenderObject* colGroup = 0;
+ if (col && col->parent()->style()->display() == TABLE_COLUMN_GROUP)
+ colGroup = col->parent();
+
+ // Column groups and columns first.
+ // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
+ // the stack, since we have already opened a transparency layer (potentially) for the table row group.
+ // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
+ // cell.
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, colGroup);
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, col);
+
+ // Paint the row group next.
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this);
+
+ // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for
+ // painting the row background for the cell.
+ if (!row->hasSelfPaintingLayer())
+ cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row);
+ }
+ if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders)
+ cell->paint(paintInfo, tx, ty);
+
+}
+
void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
{
// Check which rows and cols are visible and only paint these.
@@ -1120,57 +1151,48 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
if (!endcol && tx + table()->columnPositions()[0] - table()->outerBorderLeft() <= y + w + os)
endcol++;
}
+
#ifdef ANDROID_LAYOUT
}
#endif
if (startcol < endcol) {
- // draw the cells
- for (unsigned r = startrow; r < endrow; r++) {
- unsigned c = startcol;
- // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it
- while (c && cellAt(r, c).inColSpan)
- c--;
- for (; c < endcol; c++) {
- CellStruct current = cellAt(r, c);
- RenderTableCell* cell = current.cell;
-
- // Cells must always paint in the order in which they appear taking into account
- // their upper left originating row/column. For cells with rowspans, avoid repainting
- // if we've already seen the cell.
- if (!cell || (r > startrow && (cellAt(r - 1, c).cell == cell)))
- continue;
-
- RenderTableRow* row = toRenderTableRow(cell->parent());
-
- if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
- // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of
- // the column group, column, row group, row, and then the cell.
- RenderObject* col = table()->colElement(c);
- RenderObject* colGroup = 0;
- if (col && col->parent()->style()->display() == TABLE_COLUMN_GROUP)
- colGroup = col->parent();
-
- // Column groups and columns first.
- // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
- // the stack, since we have already opened a transparency layer (potentially) for the table row group.
- // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
- // cell.
- cell->paintBackgroundsBehindCell(paintInfo, tx, ty, colGroup);
- cell->paintBackgroundsBehindCell(paintInfo, tx, ty, col);
-
- // Paint the row group next.
- cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this);
-
- // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for
- // painting the row background for the cell.
- if (!row->hasSelfPaintingLayer())
- cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row);
+ if (!m_hasMultipleCellLevels) {
+ // Draw the dirty cells in the order that they appear.
+ for (unsigned r = startrow; r < endrow; r++) {
+ for (unsigned c = startcol; c < endcol; c++) {
+ CellStruct& current = cellAt(r, c);
+ RenderTableCell* cell = current.primaryCell();
+ if (!cell || (r > startrow && primaryCellAt(r - 1, c) == cell) || (c > startcol && primaryCellAt(r, c - 1) == cell))
+ continue;
+ paintCell(cell, paintInfo, tx, ty);
+ }
+ }
+ } else {
+ // Draw the cells in the correct paint order.
+ Vector<RenderTableCell*> cells;
+ HashSet<RenderTableCell*> spanningCells;
+ for (unsigned r = startrow; r < endrow; r++) {
+ for (unsigned c = startcol; c < endcol; c++) {
+ CellStruct& current = cellAt(r, c);
+ if (!current.hasCells())
+ continue;
+ for (unsigned i = 0; i < current.cells.size(); ++i) {
+ if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) {
+ if (spanningCells.contains(current.cells[i]))
+ continue;
+ spanningCells.add(current.cells[i]);
+ }
+ cells.append(current.cells[i]);
+ }
}
-
- if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders)
- cell->paint(paintInfo, tx, ty);
}
+ // Sort the dirty cells by paint order.
+ std::stable_sort(cells.begin(), cells.end(), compareCellPositions);
+ int size = cells.size();
+ // Paint the cells.
+ for (int i = 0; i < size; ++i)
+ paintCell(cells[i], paintInfo, tx, ty);
}
}
}
@@ -1223,7 +1245,7 @@ int RenderTableSection::numColumns() const
for (int r = 0; r < m_gridRows; ++r) {
for (int c = result; c < table()->numEffCols(); ++c) {
const CellStruct& cell = cellAt(r, c);
- if (cell.cell || cell.inColSpan)
+ if (cell.hasCells() || cell.inColSpan)
result = c;
}
}
@@ -1233,24 +1255,29 @@ int RenderTableSection::numColumns() const
void RenderTableSection::appendColumn(int pos)
{
- for (int row = 0; row < m_gridRows; ++row) {
+ for (int row = 0; row < m_gridRows; ++row)
m_grid[row].row->resize(pos + 1);
- CellStruct& c = cellAt(row, pos);
- c.cell = 0;
- c.inColSpan = false;
- }
}
-void RenderTableSection::splitColumn(int pos, int newSize)
+void RenderTableSection::splitColumn(int pos, int first)
{
if (m_cCol > pos)
m_cCol++;
for (int row = 0; row < m_gridRows; ++row) {
- m_grid[row].row->resize(newSize);
Row& r = *m_grid[row].row;
- memmove(r.data() + pos + 1, r.data() + pos, (newSize - 1 - pos) * sizeof(CellStruct));
- r[pos + 1].cell = 0;
- r[pos + 1].inColSpan = r[pos].inColSpan || r[pos].cell;
+ r.insert(pos + 1, CellStruct());
+ if (r[pos].hasCells()) {
+ r[pos + 1].cells.append(r[pos].cells);
+ RenderTableCell* cell = r[pos].primaryCell();
+ ASSERT(cell);
+ int colleft = cell->colSpan() - r[pos].inColSpan;
+ if (first > colleft)
+ r[pos + 1].inColSpan = 0;
+ else
+ r[pos + 1].inColSpan = first + r[pos].inColSpan;
+ } else {
+ r[pos + 1].inColSpan = 0;
+ }
}
}
@@ -1279,7 +1306,6 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul
return true;
}
}
-
return false;
}