blob: 46c415b8faff5d56e81b0a4953becda7850b5dec [file] [log] [blame]
eseidela043f3d2006-01-20 19:24:53 +00001/**
2 * This file is part of the DOM implementation for KDE.
3 *
4 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
5 * (C) 1997 Torben Weis (weis@kde.org)
6 * (C) 1998 Waldo Bastian (bastian@kde.org)
7 * (C) 1999 Lars Knoll (knoll@kde.org)
8 * (C) 1999 Antti Koivisto (koivisto@kde.org)
9 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
ap50b58352006-01-22 20:32:36 +000010 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
eseidela043f3d2006-01-20 19:24:53 +000011 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
24 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
26 */
27
28#include "config.h"
29#include "RenderTableSection.h"
darin91298e52006-06-12 01:10:17 +000030
bdashb07ae8d2007-02-08 04:56:20 +000031#include "CachedImage.h"
darinb9481ed2006-03-20 02:57:59 +000032#include "Document.h"
darin98fa8b82006-03-20 08:03:57 +000033#include "HTMLNames.h"
darin91298e52006-06-12 01:10:17 +000034#include "RenderTableCell.h"
35#include "RenderTableCol.h"
36#include "RenderTableRow.h"
weinigfef13632007-04-29 20:09:08 +000037#include "RenderView.h"
ddkilzer260f3d22007-01-05 05:56:31 +000038#include "TextStream.h"
darin91298e52006-06-12 01:10:17 +000039#include <limits>
ddkilzer260f3d22007-01-05 05:56:31 +000040#include <wtf/Vector.h>
eseidela043f3d2006-01-20 19:24:53 +000041
darin7bd70952006-04-13 07:07:34 +000042using namespace std;
43
eseidela043f3d2006-01-20 19:24:53 +000044namespace WebCore {
45
46using namespace HTMLNames;
47
darinb9481ed2006-03-20 02:57:59 +000048RenderTableSection::RenderTableSection(Node* node)
eseidela043f3d2006-01-20 19:24:53 +000049 : RenderContainer(node)
ddkilzer260f3d22007-01-05 05:56:31 +000050 , m_gridRows(0)
51 , m_cCol(0)
52 , m_cRow(-1)
53 , m_needsCellRecalc(false)
54 , m_outerBorderLeft(0)
55 , m_outerBorderRight(0)
56 , m_outerBorderTop(0)
57 , m_outerBorderBottom(0)
adeleddfe27f2007-01-05 23:03:50 +000058 , m_overflowLeft(0)
59 , m_overflowWidth(0)
ap292f4df2007-02-18 16:15:07 +000060 , m_overflowTop(0)
61 , m_overflowHeight(0)
adeleddfe27f2007-01-05 23:03:50 +000062 , m_hasOverflowingCell(false)
eseidela043f3d2006-01-20 19:24:53 +000063{
64 // init RenderObject attributes
65 setInline(false); // our object is not Inline
eseidela043f3d2006-01-20 19:24:53 +000066}
67
68RenderTableSection::~RenderTableSection()
69{
70 clearGrid();
71}
72
73void RenderTableSection::destroy()
74{
antti078e87f2007-08-16 16:13:28 +000075 RenderTable* recalcTable = table();
76
77 RenderContainer::destroy();
78
eseidela043f3d2006-01-20 19:24:53 +000079 // recalc cell info because RenderTable has unguarded pointers
80 // stored that point to this RenderTableSection.
antti078e87f2007-08-16 16:13:28 +000081 if (recalcTable)
82 recalcTable->setNeedsSectionRecalc();
eseidela043f3d2006-01-20 19:24:53 +000083}
84
ddkilzer260f3d22007-01-05 05:56:31 +000085void RenderTableSection::setStyle(RenderStyle* newStyle)
eseidela043f3d2006-01-20 19:24:53 +000086{
87 // we don't allow changing this one
88 if (style())
ddkilzer260f3d22007-01-05 05:56:31 +000089 newStyle->setDisplay(style()->display());
90 else if (newStyle->display() != TABLE_FOOTER_GROUP && newStyle->display() != TABLE_HEADER_GROUP)
91 newStyle->setDisplay(TABLE_ROW_GROUP);
eseidela043f3d2006-01-20 19:24:53 +000092
ddkilzer260f3d22007-01-05 05:56:31 +000093 RenderContainer::setStyle(newStyle);
eseidela043f3d2006-01-20 19:24:53 +000094}
95
darin316ed062006-01-23 05:29:14 +000096void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild)
eseidela043f3d2006-01-20 19:24:53 +000097{
hyatt58028f52007-05-01 04:57:01 +000098 // Make sure we don't append things after :after-generated content if we have it.
99 if (!beforeChild && isAfterContent(lastChild()))
100 beforeChild = lastChild();
101
bdakin8a0dd6b2006-02-11 02:08:57 +0000102 bool isTableSection = element() && (element()->hasTagName(theadTag) || element()->hasTagName(tbodyTag) || element()->hasTagName(tfootTag));
103
eseidela043f3d2006-01-20 19:24:53 +0000104 if (!child->isTableRow()) {
mjs6666eee72006-07-14 07:45:13 +0000105 if (isTableSection && child->element() && child->element()->hasTagName(formTag) && document()->isHTMLDocument()) {
darin316ed062006-01-23 05:29:14 +0000106 RenderContainer::addChild(child, beforeChild);
107 return;
eseidela043f3d2006-01-20 19:24:53 +0000108 }
darin316ed062006-01-23 05:29:14 +0000109
110 RenderObject* last = beforeChild;
111 if (!last)
112 last = lastChild();
113 if (last && last->isAnonymous()) {
114 last->addChild(child);
115 return;
116 }
117
darin10ab1352006-01-29 01:29:33 +0000118 // If beforeChild is inside an anonymous cell/row, insert into the cell or into
119 // the anonymous row containing it, if there is one.
darin316ed062006-01-23 05:29:14 +0000120 RenderObject* lastBox = last;
121 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableRow())
122 lastBox = lastBox->parent();
123 if (lastBox && lastBox->isAnonymous()) {
124 lastBox->addChild(child, beforeChild);
125 return;
126 }
127
128 RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table */);
129 RenderStyle* newStyle = new (renderArena()) RenderStyle();
130 newStyle->inheritFrom(style());
131 newStyle->setDisplay(TABLE_ROW);
132 row->setStyle(newStyle);
133 addChild(row, beforeChild);
eseidela043f3d2006-01-20 19:24:53 +0000134 row->addChild(child);
eseidela043f3d2006-01-20 19:24:53 +0000135 return;
136 }
137
138 if (beforeChild)
ddkilzer260f3d22007-01-05 05:56:31 +0000139 setNeedsCellRecalc();
eseidela043f3d2006-01-20 19:24:53 +0000140
ddkilzer260f3d22007-01-05 05:56:31 +0000141 ++m_cRow;
142 m_cCol = 0;
eseidela043f3d2006-01-20 19:24:53 +0000143
larsb5288ad2007-01-13 18:48:29 +0000144 // make sure we have enough rows
145 if (!ensureRows(m_cRow + 1))
146 return;
147
ddkilzer260f3d22007-01-05 05:56:31 +0000148 m_grid[m_cRow].rowRenderer = child;
eseidela043f3d2006-01-20 19:24:53 +0000149
150 if (!beforeChild) {
ddkilzer260f3d22007-01-05 05:56:31 +0000151 m_grid[m_cRow].height = child->style()->height();
152 if (m_grid[m_cRow].height.isRelative())
153 m_grid[m_cRow].height = Length();
eseidela043f3d2006-01-20 19:24:53 +0000154 }
155
ddkilzer260f3d22007-01-05 05:56:31 +0000156 // If the next renderer is actually wrapped in an anonymous table row, we need to go up and find that.
mjs6666eee72006-07-14 07:45:13 +0000157 while (beforeChild && !beforeChild->isTableRow())
158 beforeChild = beforeChild->parent();
159
darin316ed062006-01-23 05:29:14 +0000160 RenderContainer::addChild(child, beforeChild);
eseidela043f3d2006-01-20 19:24:53 +0000161}
162
163bool RenderTableSection::ensureRows(int numRows)
164{
ddkilzer260f3d22007-01-05 05:56:31 +0000165 int nRows = m_gridRows;
eseidela043f3d2006-01-20 19:24:53 +0000166 if (numRows > nRows) {
ddkilzer260f3d22007-01-05 05:56:31 +0000167 if (numRows > static_cast<int>(m_grid.size())) {
larsb5288ad2007-01-13 18:48:29 +0000168 size_t maxSize = numeric_limits<size_t>::max() / sizeof(RowStruct);
169 if (static_cast<size_t>(numRows) > maxSize)
eseidela043f3d2006-01-20 19:24:53 +0000170 return false;
ddkilzer260f3d22007-01-05 05:56:31 +0000171 m_grid.resize(numRows);
darin91298e52006-06-12 01:10:17 +0000172 }
ddkilzer260f3d22007-01-05 05:56:31 +0000173 m_gridRows = numRows;
eseidela043f3d2006-01-20 19:24:53 +0000174 int nCols = table()->numEffCols();
175 CellStruct emptyCellStruct;
176 emptyCellStruct.cell = 0;
177 emptyCellStruct.inColSpan = false;
ap50b58352006-01-22 20:32:36 +0000178 for (int r = nRows; r < numRows; r++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000179 m_grid[r].row = new Row(nCols);
180 m_grid[r].row->fill(emptyCellStruct);
181 m_grid[r].rowRenderer = 0;
hyatt851433b2007-05-12 06:40:14 +0000182 m_grid[r].baseline = 0;
ddkilzer260f3d22007-01-05 05:56:31 +0000183 m_grid[r].height = Length();
ap50b58352006-01-22 20:32:36 +0000184 }
eseidela043f3d2006-01-20 19:24:53 +0000185 }
186
187 return true;
188}
189
darin91298e52006-06-12 01:10:17 +0000190void RenderTableSection::addCell(RenderTableCell* cell, RenderObject* row)
eseidela043f3d2006-01-20 19:24:53 +0000191{
192 int rSpan = cell->rowSpan();
193 int cSpan = cell->colSpan();
ddkilzer260f3d22007-01-05 05:56:31 +0000194 Vector<RenderTable::ColumnStruct>& columns = table()->columns();
eseidela043f3d2006-01-20 19:24:53 +0000195 int nCols = columns.size();
196
197 // ### mozilla still seems to do the old HTML way, even for strict DTD
198 // (see the annotation on table cell layouting in the CSS specs and the testcase below:
199 // <TABLE border>
200 // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
201 // <TR><TD colspan="2">5
202 // </TABLE>
203
ddkilzer260f3d22007-01-05 05:56:31 +0000204 while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).cell || cellAt(m_cRow, m_cCol).inColSpan))
205 m_cCol++;
eseidela043f3d2006-01-20 19:24:53 +0000206
207 if (rSpan == 1) {
ap50b58352006-01-22 20:32:36 +0000208 // we ignore height settings on rowspan cells
209 Length height = cell->style()->height();
ddkilzerd1687ca2007-01-04 05:28:35 +0000210 if (height.isPositive() || (height.isRelative() && height.value() >= 0)) {
ddkilzer260f3d22007-01-05 05:56:31 +0000211 Length cRowHeight = m_grid[m_cRow].height;
darin947a31b2006-02-24 03:08:41 +0000212 switch (height.type()) {
eseidela043f3d2006-01-20 19:24:53 +0000213 case Percent:
darin947a31b2006-02-24 03:08:41 +0000214 if (!(cRowHeight.isPercent()) ||
ddkilzerd1687ca2007-01-04 05:28:35 +0000215 (cRowHeight.isPercent() && cRowHeight.rawValue() < height.rawValue()))
ddkilzer260f3d22007-01-05 05:56:31 +0000216 m_grid[m_cRow].height = height;
eseidela043f3d2006-01-20 19:24:53 +0000217 break;
218 case Fixed:
darin947a31b2006-02-24 03:08:41 +0000219 if (cRowHeight.type() < Percent ||
220 (cRowHeight.isFixed() && cRowHeight.value() < height.value()))
ddkilzer260f3d22007-01-05 05:56:31 +0000221 m_grid[m_cRow].height = height;
eseidela043f3d2006-01-20 19:24:53 +0000222 break;
223 case Relative:
224 default:
225 break;
ap50b58352006-01-22 20:32:36 +0000226 }
227 }
eseidela043f3d2006-01-20 19:24:53 +0000228 }
229
230 // make sure we have enough rows
ddkilzer260f3d22007-01-05 05:56:31 +0000231 if (!ensureRows(m_cRow + rSpan))
eseidela043f3d2006-01-20 19:24:53 +0000232 return;
233
ddkilzer260f3d22007-01-05 05:56:31 +0000234 m_grid[m_cRow].rowRenderer = row;
hyattd866e592006-03-17 09:50:35 +0000235
ddkilzer260f3d22007-01-05 05:56:31 +0000236 int col = m_cCol;
eseidela043f3d2006-01-20 19:24:53 +0000237 // tell the cell where it is
238 CellStruct currentCell;
239 currentCell.cell = cell;
240 currentCell.inColSpan = false;
241 while (cSpan) {
ap50b58352006-01-22 20:32:36 +0000242 int currentSpan;
ddkilzer260f3d22007-01-05 05:56:31 +0000243 if (m_cCol >= nCols) {
ap50b58352006-01-22 20:32:36 +0000244 table()->appendColumn(cSpan);
245 currentSpan = cSpan;
246 } else {
ddkilzer260f3d22007-01-05 05:56:31 +0000247 if (cSpan < columns[m_cCol].span)
248 table()->splitColumn(m_cCol, cSpan);
249 currentSpan = columns[m_cCol].span;
ap50b58352006-01-22 20:32:36 +0000250 }
eseidela043f3d2006-01-20 19:24:53 +0000251
ap50b58352006-01-22 20:32:36 +0000252 for (int r = 0; r < rSpan; r++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000253 CellStruct& c = cellAt(m_cRow + r, m_cCol);
eseidela043f3d2006-01-20 19:24:53 +0000254 if (currentCell.cell && !c.cell)
255 c.cell = currentCell.cell;
256 if (currentCell.inColSpan)
257 c.inColSpan = true;
ap50b58352006-01-22 20:32:36 +0000258 }
ddkilzer260f3d22007-01-05 05:56:31 +0000259 m_cCol++;
ap50b58352006-01-22 20:32:36 +0000260 cSpan -= currentSpan;
eseidela043f3d2006-01-20 19:24:53 +0000261 currentCell.cell = 0;
ap50b58352006-01-22 20:32:36 +0000262 currentCell.inColSpan = true;
eseidela043f3d2006-01-20 19:24:53 +0000263 }
264 if (cell) {
ddkilzer260f3d22007-01-05 05:56:31 +0000265 cell->setRow(m_cRow);
ap50b58352006-01-22 20:32:36 +0000266 cell->setCol(table()->effColToCol(col));
eseidela043f3d2006-01-20 19:24:53 +0000267 }
268}
269
eseidela043f3d2006-01-20 19:24:53 +0000270void RenderTableSection::setCellWidths()
271{
ddkilzer260f3d22007-01-05 05:56:31 +0000272 Vector<int>& columnPos = table()->columnPositions();
weinigfef13632007-04-29 20:09:08 +0000273 bool pushedLayoutState = false;
eseidela043f3d2006-01-20 19:24:53 +0000274
ddkilzer260f3d22007-01-05 05:56:31 +0000275 for (int i = 0; i < m_gridRows; i++) {
276 Row& row = *m_grid[i].row;
ap50b58352006-01-22 20:32:36 +0000277 int cols = row.size();
278 for (int j = 0; j < cols; j++) {
279 CellStruct current = row[j];
ddkilzer260f3d22007-01-05 05:56:31 +0000280 RenderTableCell* cell = current.cell;
eseidela043f3d2006-01-20 19:24:53 +0000281
ap50b58352006-01-22 20:32:36 +0000282 if (!cell)
283 continue;
284 int endCol = j;
285 int cspan = cell->colSpan();
286 while (cspan && endCol < cols) {
ddkilzer260f3d22007-01-05 05:56:31 +0000287 cspan -= table()->columns()[endCol].span;
ap50b58352006-01-22 20:32:36 +0000288 endCol++;
289 }
290 int w = columnPos[endCol] - columnPos[j] - table()->hBorderSpacing();
291 int oldWidth = cell->width();
292 if (w != oldWidth) {
293 cell->setNeedsLayout(true);
weinigfef13632007-04-29 20:09:08 +0000294 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) {
295 if (!pushedLayoutState) {
296 // Technically, we should also push state for the row, but since
297 // rows don't push a coordinate transform, that's not necessary.
298 view()->pushLayoutState(this, IntSize(m_x, m_y));
299 pushedLayoutState = true;
300 }
hyattd72625b2007-04-26 19:51:11 +0000301 cell->repaint();
weinigfef13632007-04-29 20:09:08 +0000302 }
ap50b58352006-01-22 20:32:36 +0000303 cell->setWidth(w);
304 }
305 }
eseidela043f3d2006-01-20 19:24:53 +0000306 }
weinigfef13632007-04-29 20:09:08 +0000307
308 if (pushedLayoutState)
309 view()->popLayoutState();
eseidela043f3d2006-01-20 19:24:53 +0000310}
311
eseidela043f3d2006-01-20 19:24:53 +0000312void RenderTableSection::calcRowHeight()
313{
ddkilzer260f3d22007-01-05 05:56:31 +0000314 RenderTableCell* cell;
eseidela043f3d2006-01-20 19:24:53 +0000315
eseidela043f3d2006-01-20 19:24:53 +0000316 int spacing = table()->vBorderSpacing();
weinigfef13632007-04-29 20:09:08 +0000317 bool pushedLayoutState = false;
eseidela043f3d2006-01-20 19:24:53 +0000318
ddkilzer260f3d22007-01-05 05:56:31 +0000319 m_rowPos.resize(m_gridRows + 1);
320 m_rowPos[0] = spacing;
eseidela043f3d2006-01-20 19:24:53 +0000321
ddkilzer260f3d22007-01-05 05:56:31 +0000322 for (int r = 0; r < m_gridRows; r++) {
323 m_rowPos[r + 1] = 0;
hyatt777b31c2007-07-19 20:01:26 +0000324 m_grid[r].baseline = 0;
ap50b58352006-01-22 20:32:36 +0000325 int baseline = 0;
326 int bdesc = 0;
ddkilzer260f3d22007-01-05 05:56:31 +0000327 int ch = m_grid[r].height.calcMinValue(0);
328 int pos = m_rowPos[r] + ch + (m_grid[r].rowRenderer ? spacing : 0);
eseidela043f3d2006-01-20 19:24:53 +0000329
ddkilzer260f3d22007-01-05 05:56:31 +0000330 m_rowPos[r + 1] = max(m_rowPos[r + 1], pos);
eseidela043f3d2006-01-20 19:24:53 +0000331
ddkilzer260f3d22007-01-05 05:56:31 +0000332 Row* row = m_grid[r].row;
ap50b58352006-01-22 20:32:36 +0000333 int totalCols = row->size();
eseidela043f3d2006-01-20 19:24:53 +0000334
ap50b58352006-01-22 20:32:36 +0000335 for (int c = 0; c < totalCols; c++) {
336 CellStruct current = cellAt(r, c);
eseidela043f3d2006-01-20 19:24:53 +0000337 cell = current.cell;
ap50b58352006-01-22 20:32:36 +0000338 if (!cell || current.inColSpan)
339 continue;
ddkilzer260f3d22007-01-05 05:56:31 +0000340 if (r < m_gridRows - 1 && cellAt(r + 1, c).cell == cell)
ap50b58352006-01-22 20:32:36 +0000341 continue;
eseidela043f3d2006-01-20 19:24:53 +0000342
ddkilzer260f3d22007-01-05 05:56:31 +0000343 int indx = max(r - cell->rowSpan() + 1, 0);
eseidela043f3d2006-01-20 19:24:53 +0000344
345 if (cell->overrideSize() != -1) {
weinigfef13632007-04-29 20:09:08 +0000346 if (!pushedLayoutState) {
347 // Technically, we should also push state for the row, but since
348 // rows don't push a coordinate transform, that's not necessary.
349 view()->pushLayoutState(this, IntSize(m_x, m_y));
350 pushedLayoutState = true;
351 }
eseidela043f3d2006-01-20 19:24:53 +0000352 cell->setOverrideSize(-1);
353 cell->setChildNeedsLayout(true, false);
354 cell->layoutIfNeeded();
355 }
356
357 // Explicit heights use the border box in quirks mode. In strict mode do the right
358 // thing and actually add in the border and padding.
darin947a31b2006-02-24 03:08:41 +0000359 ch = cell->style()->height().calcValue(0) +
eseidela043f3d2006-01-20 19:24:53 +0000360 (cell->style()->htmlHacks() ? 0 : (cell->paddingTop() + cell->paddingBottom() +
361 cell->borderTop() + cell->borderBottom()));
ddkilzer260f3d22007-01-05 05:56:31 +0000362 ch = max(ch, cell->height());
eseidela043f3d2006-01-20 19:24:53 +0000363
ddkilzer260f3d22007-01-05 05:56:31 +0000364 pos = m_rowPos[indx] + ch + (m_grid[r].rowRenderer ? spacing : 0);
eseidela043f3d2006-01-20 19:24:53 +0000365
ddkilzer260f3d22007-01-05 05:56:31 +0000366 m_rowPos[r + 1] = max(m_rowPos[r + 1], pos);
eseidela043f3d2006-01-20 19:24:53 +0000367
ap50b58352006-01-22 20:32:36 +0000368 // find out the baseline
369 EVerticalAlign va = cell->style()->verticalAlign();
ddkilzer260f3d22007-01-05 05:56:31 +0000370 if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) {
ap50b58352006-01-22 20:32:36 +0000371 int b = cell->baselinePosition();
eseidela043f3d2006-01-20 19:24:53 +0000372 if (b > cell->borderTop() + cell->paddingTop()) {
ddkilzer260f3d22007-01-05 05:56:31 +0000373 baseline = max(baseline, b);
374 bdesc = max(bdesc, m_rowPos[indx] + ch - b);
eseidela043f3d2006-01-20 19:24:53 +0000375 }
ap50b58352006-01-22 20:32:36 +0000376 }
377 }
eseidela043f3d2006-01-20 19:24:53 +0000378
ap50b58352006-01-22 20:32:36 +0000379 //do we have baseline aligned elements?
380 if (baseline) {
381 // increase rowheight if baseline requires
ddkilzer260f3d22007-01-05 05:56:31 +0000382 m_rowPos[r + 1] = max(m_rowPos[r + 1], baseline + bdesc + (m_grid[r].rowRenderer ? spacing : 0));
hyatt851433b2007-05-12 06:40:14 +0000383 m_grid[r].baseline = baseline;
ap50b58352006-01-22 20:32:36 +0000384 }
eseidela043f3d2006-01-20 19:24:53 +0000385
ddkilzer260f3d22007-01-05 05:56:31 +0000386 m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]);
eseidela043f3d2006-01-20 19:24:53 +0000387 }
weinigfef13632007-04-29 20:09:08 +0000388
389 if (pushedLayoutState)
390 view()->popLayoutState();
eseidela043f3d2006-01-20 19:24:53 +0000391}
392
393int RenderTableSection::layoutRows(int toAdd)
394{
395 int rHeight;
396 int rindx;
ddkilzer260f3d22007-01-05 05:56:31 +0000397 int totalRows = m_gridRows;
eseidela043f3d2006-01-20 19:24:53 +0000398
hyattd866e592006-03-17 09:50:35 +0000399 // Set the width of our section now. The rows will also be this width.
400 m_width = table()->contentWidth();
adeleddfe27f2007-01-05 23:03:50 +0000401 m_overflowLeft = 0;
402 m_overflowWidth = m_width;
ap292f4df2007-02-18 16:15:07 +0000403 m_overflowTop = 0;
404 m_overflowHeight = 0;
adeleddfe27f2007-01-05 23:03:50 +0000405 m_hasOverflowingCell = false;
406
darin32011102006-05-15 04:42:09 +0000407 if (table()->collapseBorders())
408 recalcOuterBorder();
hyattd866e592006-03-17 09:50:35 +0000409
ddkilzer260f3d22007-01-05 05:56:31 +0000410 if (toAdd && totalRows && (m_rowPos[totalRows] || !nextSibling())) {
411 int totalHeight = m_rowPos[totalRows] + toAdd;
eseidela043f3d2006-01-20 19:24:53 +0000412
413 int dh = toAdd;
ap50b58352006-01-22 20:32:36 +0000414 int totalPercent = 0;
415 int numAuto = 0;
416 for (int r = 0; r < totalRows; r++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000417 if (m_grid[r].height.isAuto())
ap50b58352006-01-22 20:32:36 +0000418 numAuto++;
ddkilzer260f3d22007-01-05 05:56:31 +0000419 else if (m_grid[r].height.isPercent())
420 totalPercent += m_grid[r].height.rawValue();
ap50b58352006-01-22 20:32:36 +0000421 }
422 if (totalPercent) {
423 // try to satisfy percent
424 int add = 0;
ddkilzer260f3d22007-01-05 05:56:31 +0000425 totalPercent = min(totalPercent, 100 * percentScaleFactor);
426 int rh = m_rowPos[1] - m_rowPos[0];
ap50b58352006-01-22 20:32:36 +0000427 for (int r = 0; r < totalRows; r++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000428 if (totalPercent > 0 && m_grid[r].height.isPercent()) {
429 int toAdd = min(dh, (totalHeight * m_grid[r].height.rawValue() / (100 * percentScaleFactor)) - rh);
eseidela043f3d2006-01-20 19:24:53 +0000430 // If toAdd is negative, then we don't want to shrink the row (this bug
431 // affected Outlook Web Access).
darin7bd70952006-04-13 07:07:34 +0000432 toAdd = max(0, toAdd);
ap50b58352006-01-22 20:32:36 +0000433 add += toAdd;
434 dh -= toAdd;
ddkilzer260f3d22007-01-05 05:56:31 +0000435 totalPercent -= m_grid[r].height.rawValue();
ap50b58352006-01-22 20:32:36 +0000436 }
437 if (r < totalRows - 1)
ddkilzer260f3d22007-01-05 05:56:31 +0000438 rh = m_rowPos[r + 2] - m_rowPos[r + 1];
439 m_rowPos[r + 1] += add;
ap50b58352006-01-22 20:32:36 +0000440 }
441 }
442 if (numAuto) {
443 // distribute over variable cols
444 int add = 0;
445 for (int r = 0; r < totalRows; r++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000446 if (numAuto > 0 && m_grid[r].height.isAuto()) {
447 int toAdd = dh / numAuto;
ap50b58352006-01-22 20:32:36 +0000448 add += toAdd;
449 dh -= toAdd;
eseidela043f3d2006-01-20 19:24:53 +0000450 numAuto--;
ap50b58352006-01-22 20:32:36 +0000451 }
ddkilzer260f3d22007-01-05 05:56:31 +0000452 m_rowPos[r + 1] += add;
ap50b58352006-01-22 20:32:36 +0000453 }
454 }
ddkilzer260f3d22007-01-05 05:56:31 +0000455 if (dh > 0 && m_rowPos[totalRows]) {
ap50b58352006-01-22 20:32:36 +0000456 // if some left overs, distribute equally.
ddkilzer260f3d22007-01-05 05:56:31 +0000457 int tot = m_rowPos[totalRows];
eseidela043f3d2006-01-20 19:24:53 +0000458 int add = 0;
ddkilzer260f3d22007-01-05 05:56:31 +0000459 int prev = m_rowPos[0];
eseidela043f3d2006-01-20 19:24:53 +0000460 for (int r = 0; r < totalRows; r++) {
461 //weight with the original height
ddkilzer260f3d22007-01-05 05:56:31 +0000462 add += dh * (m_rowPos[r + 1] - prev) / tot;
463 prev = m_rowPos[r + 1];
464 m_rowPos[r + 1] += add;
eseidela043f3d2006-01-20 19:24:53 +0000465 }
466 }
467 }
468
ddkilzer260f3d22007-01-05 05:56:31 +0000469 int hspacing = table()->hBorderSpacing();
470 int vspacing = table()->vBorderSpacing();
eseidela043f3d2006-01-20 19:24:53 +0000471 int nEffCols = table()->numEffCols();
ddkilzer260f3d22007-01-05 05:56:31 +0000472
weinigfef13632007-04-29 20:09:08 +0000473 view()->pushLayoutState(this, IntSize(m_x, m_y));
474
eseidela043f3d2006-01-20 19:24:53 +0000475 for (int r = 0; r < totalRows; r++) {
hyattd866e592006-03-17 09:50:35 +0000476 // Set the row's x/y position and width/height.
adeleddfe27f2007-01-05 23:03:50 +0000477 if (RenderObject* rowRenderer = m_grid[r].rowRenderer) {
478 rowRenderer->setPos(0, m_rowPos[r]);
479 rowRenderer->setWidth(m_width);
480 rowRenderer->setHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing);
hyattd866e592006-03-17 09:50:35 +0000481 }
482
eseidela043f3d2006-01-20 19:24:53 +0000483 for (int c = 0; c < nEffCols; c++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000484 RenderTableCell* cell = cellAt(r, c).cell;
eseidela043f3d2006-01-20 19:24:53 +0000485
486 if (!cell)
487 continue;
488 if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell)
ap50b58352006-01-22 20:32:36 +0000489 continue;
eseidela043f3d2006-01-20 19:24:53 +0000490
adeleddfe27f2007-01-05 23:03:50 +0000491 rindx = max(0, r - cell->rowSpan() + 1);
eseidela043f3d2006-01-20 19:24:53 +0000492
ddkilzer260f3d22007-01-05 05:56:31 +0000493 rHeight = m_rowPos[r + 1] - m_rowPos[rindx] - vspacing;
eseidela043f3d2006-01-20 19:24:53 +0000494
495 // Force percent height children to lay themselves out again.
496 // This will cause these children to grow to fill the cell.
497 // FIXME: There is still more work to do here to fully match WinIE (should
498 // it become necessary to do so). In quirks mode, WinIE behaves like we
499 // do, but it will clip the cells that spill out of the table section. In
500 // strict mode, Mozilla and WinIE both regrow the table to accommodate the
501 // new height of the cell (thus letting the percentages cause growth one
502 // time only). We may also not be handling row-spanning cells correctly.
503 //
504 // Note also the oddity where replaced elements always flex, and yet blocks/tables do
505 // not necessarily flex. WinIE is crazy and inconsistent, and we can't hope to
506 // match the behavior perfectly, but we'll continue to refine it as we discover new
507 // bugs. :)
508 bool cellChildrenFlex = false;
509 bool flexAllChildren = cell->style()->height().isFixed() ||
510 (!table()->style()->height().isAuto() && rHeight != cell->height());
511
512 for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) {
513 if (!o->isText() && o->style()->height().isPercent() && (o->isReplaced() || o->scrollsOverflow() || flexAllChildren)) {
514 // Tables with no sections do not flex.
515 if (!o->isTable() || static_cast<RenderTable*>(o)->hasSections()) {
516 o->setNeedsLayout(true, false);
517 cell->setChildNeedsLayout(true, false);
518 cellChildrenFlex = true;
519 }
520 }
521 }
522 if (cellChildrenFlex) {
eseidela043f3d2006-01-20 19:24:53 +0000523 // Alignment within a cell is based off the calculated
524 // height, which becomes irrelevant once the cell has
525 // been resized based off its percentage. -dwh
ap7332aaa2006-04-28 16:02:45 +0000526 cell->setOverrideSize(max(0,
527 rHeight - cell->borderTop() - cell->paddingTop() -
528 cell->borderBottom() - cell->paddingBottom()));
529 cell->layoutIfNeeded();
hyatt851433b2007-05-12 06:40:14 +0000530
531 // If the baseline moved, we may have to update the data for our row. Find out the new baseline.
532 EVerticalAlign va = cell->style()->verticalAlign();
533 if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) {
534 int b = cell->baselinePosition();
535 if (b > cell->borderTop() + cell->paddingTop())
536 m_grid[r].baseline = max(m_grid[r].baseline, b);
537 }
eseidela043f3d2006-01-20 19:24:53 +0000538 }
539
bdakinf9936352007-04-19 19:58:20 +0000540 int te = 0;
541 switch (cell->style()->verticalAlign()) {
542 case SUB:
543 case SUPER:
544 case TEXT_TOP:
545 case TEXT_BOTTOM:
546 case BASELINE:
hyatt851433b2007-05-12 06:40:14 +0000547 te = getBaseline(r) - cell->baselinePosition();
bdakinf9936352007-04-19 19:58:20 +0000548 break;
549 case TOP:
550 te = 0;
551 break;
552 case MIDDLE:
553 te = (rHeight - cell->height()) / 2;
554 break;
555 case BOTTOM:
556 te = rHeight - cell->height();
557 break;
558 default:
559 break;
560 }
561
562 int oldTe = cell->borderTopExtra();
563 int oldBe = cell->borderBottomExtra();
564
565 int be = rHeight - cell->height() - te;
566 cell->setCellTopExtra(te);
567 cell->setCellBottomExtra(be);
568 if ((te != oldTe || be > oldBe) && !table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
569 cell->repaint();
570
harrisonb100b8e2006-11-17 01:06:58 +0000571 IntRect oldCellRect(cell->xPos(), cell->yPos() - cell->borderTopExtra() , cell->width(), cell->height());
eseidela043f3d2006-01-20 19:24:53 +0000572
573 if (style()->direction() == RTL) {
ddkilzer260f3d22007-01-05 05:56:31 +0000574 cell->setPos(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]);
eseidela043f3d2006-01-20 19:24:53 +0000575 } else
ddkilzer260f3d22007-01-05 05:56:31 +0000576 cell->setPos(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]);
eseidela043f3d2006-01-20 19:24:53 +0000577
adeleddfe27f2007-01-05 23:03:50 +0000578 m_overflowLeft = min(m_overflowLeft, cell->xPos() + cell->overflowLeft(false));
579 m_overflowWidth = max(m_overflowWidth, cell->xPos() + cell->overflowWidth(false));
ap292f4df2007-02-18 16:15:07 +0000580 m_overflowTop = min(m_overflowTop, cell->yPos() + cell->overflowTop(false));
581 m_overflowHeight = max(m_overflowHeight, cell->yPos() + cell->overflowHeight(false));
582 m_hasOverflowingCell |= cell->overflowLeft(false) || cell->overflowWidth(false) > cell->width() || cell->overflowTop(false) || cell->overflowHeight(false) > cell->height();
adeleddfe27f2007-01-05 23:03:50 +0000583
eseidela043f3d2006-01-20 19:24:53 +0000584 // If the cell moved, we have to repaint it as well as any floating/positioned
585 // descendants. An exception is if we need a layout. In this case, we know we're going to
586 // repaint ourselves (and the cell) anyway.
587 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
harrisonb100b8e2006-11-17 01:06:58 +0000588 cell->repaintDuringLayoutIfMoved(oldCellRect);
eseidela043f3d2006-01-20 19:24:53 +0000589 }
590 }
591
weinigfef13632007-04-29 20:09:08 +0000592 view()->popLayoutState();
593
ddkilzer260f3d22007-01-05 05:56:31 +0000594 m_height = m_rowPos[totalRows];
ap292f4df2007-02-18 16:15:07 +0000595 m_overflowHeight = max(m_overflowHeight, m_height);
eseidela043f3d2006-01-20 19:24:53 +0000596 return m_height;
597}
598
adele04d4ce12006-02-11 20:11:05 +0000599int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
600{
601 int bottom = RenderContainer::lowestPosition(includeOverflowInterior, includeSelf);
602 if (!includeOverflowInterior && hasOverflowClip())
603 return bottom;
604
ddkilzer260f3d22007-01-05 05:56:31 +0000605 for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
606 for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
607 if (cell->isTableCell())
608 bottom = max(bottom, cell->yPos() + cell->lowestPosition(false));
adele04d4ce12006-02-11 20:11:05 +0000609 }
610 }
611
612 return bottom;
613}
614
615int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
616{
617 int right = RenderContainer::rightmostPosition(includeOverflowInterior, includeSelf);
618 if (!includeOverflowInterior && hasOverflowClip())
619 return right;
620
ddkilzer260f3d22007-01-05 05:56:31 +0000621 for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
622 for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
623 if (cell->isTableCell())
624 right = max(right, cell->xPos() + cell->rightmostPosition(false));
adele04d4ce12006-02-11 20:11:05 +0000625 }
626 }
627
628 return right;
629}
630
631int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
632{
633 int left = RenderContainer::leftmostPosition(includeOverflowInterior, includeSelf);
634 if (!includeOverflowInterior && hasOverflowClip())
635 return left;
636
ddkilzer260f3d22007-01-05 05:56:31 +0000637 for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
638 for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
639 if (cell->isTableCell())
640 left = min(left, cell->xPos() + cell->leftmostPosition(false));
adele04d4ce12006-02-11 20:11:05 +0000641 }
642 }
643
644 return left;
645}
eseidela043f3d2006-01-20 19:24:53 +0000646
darin32011102006-05-15 04:42:09 +0000647int RenderTableSection::calcOuterBorderTop() const
648{
649 int totalCols = table()->numEffCols();
ddkilzer260f3d22007-01-05 05:56:31 +0000650 if (!m_gridRows || !totalCols)
darin32011102006-05-15 04:42:09 +0000651 return 0;
652
653 unsigned borderWidth = 0;
654
655 const BorderValue& sb = style()->borderTop();
656 if (sb.style() == BHIDDEN)
657 return -1;
658 if (sb.style() > BHIDDEN)
659 borderWidth = sb.width;
660
661 const BorderValue& rb = firstChild()->style()->borderTop();
662 if (rb.style() == BHIDDEN)
663 return -1;
664 if (rb.style() > BHIDDEN && rb.width > borderWidth)
665 borderWidth = rb.width;
666
667 bool allHidden = true;
668 for (int c = 0; c < totalCols; c++) {
669 const CellStruct& current = cellAt(0, c);
670 if (current.inColSpan || !current.cell)
671 continue;
672 const BorderValue& cb = current.cell->style()->borderTop();
673 // FIXME: Don't repeat for the same col group
674 RenderTableCol* colGroup = table()->colElement(c);
675 if (colGroup) {
676 const BorderValue& gb = colGroup->style()->borderTop();
677 if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
678 continue;
679 else
680 allHidden = false;
681 if (gb.style() > BHIDDEN && gb.width > borderWidth)
682 borderWidth = gb.width;
683 if (cb.style() > BHIDDEN && cb.width > borderWidth)
684 borderWidth = cb.width;
685 } else {
686 if (cb.style() == BHIDDEN)
687 continue;
688 else
689 allHidden = false;
690 if (cb.style() > BHIDDEN && cb.width > borderWidth)
691 borderWidth = cb.width;
692 }
693 }
694 if (allHidden)
695 return -1;
696
697 return borderWidth / 2;
698}
699
700int RenderTableSection::calcOuterBorderBottom() const
701{
702 int totalCols = table()->numEffCols();
ddkilzer260f3d22007-01-05 05:56:31 +0000703 if (!m_gridRows || !totalCols)
darin32011102006-05-15 04:42:09 +0000704 return 0;
705
706 unsigned borderWidth = 0;
707
708 const BorderValue& sb = style()->borderBottom();
709 if (sb.style() == BHIDDEN)
710 return -1;
711 if (sb.style() > BHIDDEN)
712 borderWidth = sb.width;
713
714 const BorderValue& rb = lastChild()->style()->borderBottom();
715 if (rb.style() == BHIDDEN)
716 return -1;
717 if (rb.style() > BHIDDEN && rb.width > borderWidth)
718 borderWidth = rb.width;
719
720 bool allHidden = true;
721 for (int c = 0; c < totalCols; c++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000722 const CellStruct& current = cellAt(m_gridRows - 1, c);
darin32011102006-05-15 04:42:09 +0000723 if (current.inColSpan || !current.cell)
724 continue;
725 const BorderValue& cb = current.cell->style()->borderBottom();
726 // FIXME: Don't repeat for the same col group
727 RenderTableCol* colGroup = table()->colElement(c);
728 if (colGroup) {
729 const BorderValue& gb = colGroup->style()->borderBottom();
730 if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
731 continue;
732 else
733 allHidden = false;
734 if (gb.style() > BHIDDEN && gb.width > borderWidth)
735 borderWidth = gb.width;
736 if (cb.style() > BHIDDEN && cb.width > borderWidth)
737 borderWidth = cb.width;
738 } else {
739 if (cb.style() == BHIDDEN)
740 continue;
741 else
742 allHidden = false;
743 if (cb.style() > BHIDDEN && cb.width > borderWidth)
744 borderWidth = cb.width;
745 }
746 }
747 if (allHidden)
748 return -1;
749
750 return (borderWidth + 1) / 2;
751}
752
753int RenderTableSection::calcOuterBorderLeft(bool rtl) const
754{
755 int totalCols = table()->numEffCols();
ddkilzer260f3d22007-01-05 05:56:31 +0000756 if (!m_gridRows || !totalCols)
darin32011102006-05-15 04:42:09 +0000757 return 0;
758
759 unsigned borderWidth = 0;
760
761 const BorderValue& sb = style()->borderLeft();
762 if (sb.style() == BHIDDEN)
763 return -1;
764 if (sb.style() > BHIDDEN)
765 borderWidth = sb.width;
766
767 int leftmostColumn = rtl ? totalCols - 1 : 0;
768 RenderTableCol* colGroup = table()->colElement(leftmostColumn);
769 if (colGroup) {
770 const BorderValue& gb = colGroup->style()->borderLeft();
771 if (gb.style() == BHIDDEN)
772 return -1;
773 if (gb.style() > BHIDDEN && gb.width > borderWidth)
774 borderWidth = gb.width;
775 }
776
777 bool allHidden = true;
ddkilzer260f3d22007-01-05 05:56:31 +0000778 for (int r = 0; r < m_gridRows; r++) {
darin32011102006-05-15 04:42:09 +0000779 const CellStruct& current = cellAt(r, leftmostColumn);
780 if (!current.cell)
781 continue;
782 // FIXME: Don't repeat for the same cell
783 const BorderValue& cb = current.cell->style()->borderLeft();
784 const BorderValue& rb = current.cell->parent()->style()->borderLeft();
785 if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
786 continue;
787 else
788 allHidden = false;
789 if (cb.style() > BHIDDEN && cb.width > borderWidth)
790 borderWidth = cb.width;
791 if (rb.style() > BHIDDEN && rb.width > borderWidth)
792 borderWidth = rb.width;
793 }
794 if (allHidden)
795 return -1;
796
797 return borderWidth / 2;
798}
799
800int RenderTableSection::calcOuterBorderRight(bool rtl) const
801{
802 int totalCols = table()->numEffCols();
ddkilzer260f3d22007-01-05 05:56:31 +0000803 if (!m_gridRows || !totalCols)
darin32011102006-05-15 04:42:09 +0000804 return 0;
805
806 unsigned borderWidth = 0;
807
808 const BorderValue& sb = style()->borderRight();
809 if (sb.style() == BHIDDEN)
810 return -1;
811 if (sb.style() > BHIDDEN)
812 borderWidth = sb.width;
813
814 int rightmostColumn = rtl ? 0 : totalCols - 1;
815 RenderTableCol* colGroup = table()->colElement(rightmostColumn);
816 if (colGroup) {
817 const BorderValue& gb = colGroup->style()->borderRight();
818 if (gb.style() == BHIDDEN)
819 return -1;
820 if (gb.style() > BHIDDEN && gb.width > borderWidth)
821 borderWidth = gb.width;
822 }
823
824 bool allHidden = true;
ddkilzer260f3d22007-01-05 05:56:31 +0000825 for (int r = 0; r < m_gridRows; r++) {
darin32011102006-05-15 04:42:09 +0000826 const CellStruct& current = cellAt(r, rightmostColumn);
827 if (!current.cell)
828 continue;
829 // FIXME: Don't repeat for the same cell
830 const BorderValue& cb = current.cell->style()->borderRight();
831 const BorderValue& rb = current.cell->parent()->style()->borderRight();
832 if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
833 continue;
834 else
835 allHidden = false;
836 if (cb.style() > BHIDDEN && cb.width > borderWidth)
837 borderWidth = cb.width;
838 if (rb.style() > BHIDDEN && rb.width > borderWidth)
839 borderWidth = rb.width;
840 }
841 if (allHidden)
842 return -1;
843
844 return (borderWidth + 1) / 2;
845}
846
847void RenderTableSection::recalcOuterBorder()
848{
849 bool rtl = table()->style()->direction() == RTL;
850 m_outerBorderTop = calcOuterBorderTop();
851 m_outerBorderBottom = calcOuterBorderBottom();
852 m_outerBorderLeft = calcOuterBorderLeft(rtl);
853 m_outerBorderRight = calcOuterBorderRight(rtl);
854}
855
856
weinig0a635f02006-11-01 21:49:13 +0000857void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty)
eseidela043f3d2006-01-20 19:24:53 +0000858{
anttib3666072007-08-17 23:29:50 +0000859 // put this back in when all layout tests can handle it
860 // ASSERT(!needsLayout());
861 // avoid crashing on bugs that cause us to paint with dirty layout
862 if (needsLayout())
863 return;
864
ddkilzer260f3d22007-01-05 05:56:31 +0000865 unsigned totalRows = m_gridRows;
866 unsigned totalCols = table()->columns().size();
eseidela043f3d2006-01-20 19:24:53 +0000867
ddkilzer260f3d22007-01-05 05:56:31 +0000868 if (!totalRows || !totalCols)
ap0e708ba2006-05-20 08:47:37 +0000869 return;
870
eseidela043f3d2006-01-20 19:24:53 +0000871 tx += m_x;
872 ty += m_y;
873
ddkilzer260f3d22007-01-05 05:56:31 +0000874 // Check which rows and cols are visible and only paint these.
875 // FIXME: Could use a binary search here.
weinig0a635f02006-11-01 21:49:13 +0000876 PaintPhase paintPhase = paintInfo.phase;
877 int x = paintInfo.rect.x();
878 int y = paintInfo.rect.y();
879 int w = paintInfo.rect.width();
880 int h = paintInfo.rect.height();
eseidela043f3d2006-01-20 19:24:53 +0000881
bdakinf061af72006-03-31 01:19:41 +0000882 int os = 2 * maximalOutlineSize(paintPhase);
ddkilzer260f3d22007-01-05 05:56:31 +0000883 unsigned startrow = 0;
884 unsigned endrow = totalRows;
ap292f4df2007-02-18 16:15:07 +0000885
886 // If some cell overflows, just paint all of them.
887 if (!m_hasOverflowingCell) {
888 for (; startrow < totalRows; startrow++) {
889 if (ty + m_rowPos[startrow + 1] >= y - os)
890 break;
891 }
892 if (startrow == totalRows && ty + m_rowPos[totalRows] + table()->outerBorderBottom() >= y - os)
893 startrow--;
eseidela043f3d2006-01-20 19:24:53 +0000894
ap292f4df2007-02-18 16:15:07 +0000895 for (; endrow > 0; endrow--) {
896 if (ty + m_rowPos[endrow - 1] <= y + h + os)
897 break;
898 }
899 if (!endrow && ty + m_rowPos[0] - table()->outerBorderTop() <= y + h + os)
900 endrow++;
weinig0a635f02006-11-01 21:49:13 +0000901 }
eseidela043f3d2006-01-20 19:24:53 +0000902
ddkilzer260f3d22007-01-05 05:56:31 +0000903 unsigned startcol = 0;
904 unsigned endcol = totalCols;
adeleddfe27f2007-01-05 23:03:50 +0000905 // FIXME: Implement RTL.
906 if (!m_hasOverflowingCell && style()->direction() == LTR) {
ap50b58352006-01-22 20:32:36 +0000907 for (; startcol < totalCols; startcol++) {
ddkilzer260f3d22007-01-05 05:56:31 +0000908 if (tx + table()->columnPositions()[startcol + 1] >= x - os)
eseidela043f3d2006-01-20 19:24:53 +0000909 break;
ap50b58352006-01-22 20:32:36 +0000910 }
ddkilzer260f3d22007-01-05 05:56:31 +0000911 if (startcol == totalCols && tx + table()->columnPositions()[totalCols] + table()->outerBorderRight() >= x - os)
darin32011102006-05-15 04:42:09 +0000912 startcol--;
weinig0a635f02006-11-01 21:49:13 +0000913
ap50b58352006-01-22 20:32:36 +0000914 for (; endcol > 0; endcol--) {
ddkilzer260f3d22007-01-05 05:56:31 +0000915 if (tx + table()->columnPositions()[endcol - 1] <= x + w + os)
ap50b58352006-01-22 20:32:36 +0000916 break;
917 }
ddkilzer260f3d22007-01-05 05:56:31 +0000918 if (!endcol && tx + table()->columnPositions()[0] - table()->outerBorderLeft() <= y + w + os)
darin32011102006-05-15 04:42:09 +0000919 endcol++;
eseidela043f3d2006-01-20 19:24:53 +0000920 }
921
922 if (startcol < endcol) {
ap50b58352006-01-22 20:32:36 +0000923 // draw the cells
ddkilzer260f3d22007-01-05 05:56:31 +0000924 for (unsigned r = startrow; r < endrow; r++) {
925 unsigned c = startcol;
ap50b58352006-01-22 20:32:36 +0000926 // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it
927 while (c && cellAt(r, c).inColSpan)
928 c--;
929 for (; c < endcol; c++) {
eseidela043f3d2006-01-20 19:24:53 +0000930 CellStruct current = cellAt(r, c);
weinig0a635f02006-11-01 21:49:13 +0000931 RenderTableCell* cell = current.cell;
hyatte031dd02006-03-18 01:01:06 +0000932
eseidela043f3d2006-01-20 19:24:53 +0000933 // Cells must always paint in the order in which they appear taking into account
934 // their upper left originating row/column. For cells with rowspans, avoid repainting
935 // if we've already seen the cell.
weinig0a635f02006-11-01 21:49:13 +0000936 if (!cell || (r > startrow && (cellAt(r - 1, c).cell == cell)))
ap50b58352006-01-22 20:32:36 +0000937 continue;
eseidela043f3d2006-01-20 19:24:53 +0000938
darin7e7c8e42007-04-25 01:14:03 +0000939 RenderTableRow* row = static_cast<RenderTableRow*>(cell->parent());
940
bdakinf061af72006-03-31 01:19:41 +0000941 if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
hyatte031dd02006-03-18 01:01:06 +0000942 // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of
943 // the column group, column, row group, row, and then the cell.
944 RenderObject* col = table()->colElement(c);
945 RenderObject* colGroup = 0;
ddkilzer260f3d22007-01-05 05:56:31 +0000946 if (col && col->parent()->style()->display() == TABLE_COLUMN_GROUP)
947 colGroup = col->parent();
948
hyatte031dd02006-03-18 01:01:06 +0000949 // Column groups and columns first.
950 // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
951 // the stack, since we have already opened a transparency layer (potentially) for the table row group.
952 // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
953 // cell.
weinig0a635f02006-11-01 21:49:13 +0000954 cell->paintBackgroundsBehindCell(paintInfo, tx, ty, colGroup);
955 cell->paintBackgroundsBehindCell(paintInfo, tx, ty, col);
956
hyatte031dd02006-03-18 01:01:06 +0000957 // Paint the row group next.
weinig0a635f02006-11-01 21:49:13 +0000958 cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this);
959
hyatte031dd02006-03-18 01:01:06 +0000960 // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for
961 // painting the row background for the cell.
darin7e7c8e42007-04-25 01:14:03 +0000962 if (!row->hasLayer())
weinig0a635f02006-11-01 21:49:13 +0000963 cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row);
hyatte031dd02006-03-18 01:01:06 +0000964 }
965
darin7e7c8e42007-04-25 01:14:03 +0000966 if ((!cell->hasLayer() && !row->hasLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders)
weinig0a635f02006-11-01 21:49:13 +0000967 cell->paint(paintInfo, tx, ty);
ap50b58352006-01-22 20:32:36 +0000968 }
969 }
eseidela043f3d2006-01-20 19:24:53 +0000970 }
971}
972
bdashb07ae8d2007-02-08 04:56:20 +0000973void RenderTableSection::imageChanged(CachedImage* image)
974{
975 if (!image || !image->canRender() || !parent())
976 return;
977
978 // FIXME: Examine cells and repaint only the rect the image paints in.
979 repaint();
980}
981
eseidela043f3d2006-01-20 19:24:53 +0000982void RenderTableSection::recalcCells()
983{
ddkilzer260f3d22007-01-05 05:56:31 +0000984 m_cCol = 0;
985 m_cRow = -1;
eseidela043f3d2006-01-20 19:24:53 +0000986 clearGrid();
ddkilzer260f3d22007-01-05 05:56:31 +0000987 m_gridRows = 0;
eseidela043f3d2006-01-20 19:24:53 +0000988
ddkilzer260f3d22007-01-05 05:56:31 +0000989 for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
hyattd866e592006-03-17 09:50:35 +0000990 if (row->isTableRow()) {
ddkilzer260f3d22007-01-05 05:56:31 +0000991 m_cRow++;
992 m_cCol = 0;
larsb5288ad2007-01-13 18:48:29 +0000993 if (!ensureRows(m_cRow + 1))
994 break;
ddkilzer260f3d22007-01-05 05:56:31 +0000995 m_grid[m_cRow].rowRenderer = row;
eseidel05ef0432006-05-25 22:11:36 +0000996
ddkilzer260f3d22007-01-05 05:56:31 +0000997 for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
hyattd866e592006-03-17 09:50:35 +0000998 if (cell->isTableCell())
ddkilzer260f3d22007-01-05 05:56:31 +0000999 addCell(static_cast<RenderTableCell*>(cell), row);
1000 }
hyattd866e592006-03-17 09:50:35 +00001001 }
eseidela043f3d2006-01-20 19:24:53 +00001002 }
ddkilzer260f3d22007-01-05 05:56:31 +00001003 m_needsCellRecalc = false;
eseidela043f3d2006-01-20 19:24:53 +00001004 setNeedsLayout(true);
1005}
1006
1007void RenderTableSection::clearGrid()
1008{
ddkilzer260f3d22007-01-05 05:56:31 +00001009 int rows = m_gridRows;
eseidela043f3d2006-01-20 19:24:53 +00001010 while (rows--)
ddkilzer260f3d22007-01-05 05:56:31 +00001011 delete m_grid[rows].row;
ap50b58352006-01-22 20:32:36 +00001012}
1013
1014int RenderTableSection::numColumns() const
1015{
1016 int result = 0;
1017
ddkilzer260f3d22007-01-05 05:56:31 +00001018 for (int r = 0; r < m_gridRows; ++r) {
ap50b58352006-01-22 20:32:36 +00001019 for (int c = result; c < table()->numEffCols(); ++c) {
1020 const CellStruct& cell = cellAt(r, c);
1021 if (cell.cell || cell.inColSpan)
1022 result = c;
1023 }
1024 }
1025
1026 return result + 1;
eseidela043f3d2006-01-20 19:24:53 +00001027}
1028
ddkilzer260f3d22007-01-05 05:56:31 +00001029void RenderTableSection::appendColumn(int pos)
1030{
1031 for (int row = 0; row < m_gridRows; ++row) {
1032 m_grid[row].row->resize(pos + 1);
1033 CellStruct& c = cellAt(row, pos);
1034 c.cell = 0;
1035 c.inColSpan = false;
1036 }
1037}
1038
1039void RenderTableSection::splitColumn(int pos, int newSize)
1040{
1041 if (m_cCol > pos)
1042 m_cCol++;
1043 for (int row = 0; row < m_gridRows; ++row) {
1044 m_grid[row].row->resize(newSize);
1045 Row& r = *m_grid[row].row;
1046 memmove(r.data() + pos + 1, r.data() + pos, (newSize - 1 - pos) * sizeof(CellStruct));
1047 r[pos + 1].cell = 0;
1048 r[pos + 1].inColSpan = r[pos].inColSpan || r[pos].cell;
1049 }
1050}
1051
hyatt818bb122007-04-25 19:10:24 +00001052RenderObject* RenderTableSection::removeChildNode(RenderObject* child, bool fullRemove)
eseidela043f3d2006-01-20 19:24:53 +00001053{
ddkilzer260f3d22007-01-05 05:56:31 +00001054 setNeedsCellRecalc();
hyatt818bb122007-04-25 19:10:24 +00001055 return RenderContainer::removeChildNode(child, fullRemove);
eseidela043f3d2006-01-20 19:24:53 +00001056}
1057
hyattd866e592006-03-17 09:50:35 +00001058// Hit Testing
bdakinc4d8acc2006-10-31 21:48:20 +00001059bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action)
hyattd866e592006-03-17 09:50:35 +00001060{
1061 // Table sections cannot ever be hit tested. Effectively they do not exist.
1062 // Just forward to our children always.
1063 tx += m_x;
1064 ty += m_y;
1065
1066 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1067 // FIXME: We have to skip over inline flows, since they can show up inside table rows
1068 // at the moment (a demoted inline <form> for example). If we ever implement a
1069 // table-specific hit-test method (which we should do for performance reasons anyway),
1070 // then we can remove this check.
darin4ef3f992007-04-25 06:49:08 +00001071 if (!child->hasLayer() && !child->isInlineFlow() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) {
hyatt6a2ac522007-01-11 07:26:44 +00001072 updateHitTestResult(result, IntPoint(x - tx, y - ty));
hyattd866e592006-03-17 09:50:35 +00001073 return true;
1074 }
1075 }
1076
1077 return false;
1078}
1079
eseidela043f3d2006-01-20 19:24:53 +00001080#ifndef NDEBUG
ddkilzer260f3d22007-01-05 05:56:31 +00001081void RenderTableSection::dump(TextStream* stream, DeprecatedString ind) const
eseidela043f3d2006-01-20 19:24:53 +00001082{
ddkilzer260f3d22007-01-05 05:56:31 +00001083 *stream << endl << ind << "grid=(" << m_gridRows << "," << table()->numEffCols() << ")" << endl << ind;
1084 for (int r = 0; r < m_gridRows; r++) {
ap50b58352006-01-22 20:32:36 +00001085 for (int c = 0; c < table()->numEffCols(); c++) {
ddkilzer260f3d22007-01-05 05:56:31 +00001086 if (cellAt(r, c).cell && !cellAt(r, c).inColSpan)
ap50b58352006-01-22 20:32:36 +00001087 *stream << "(" << cellAt(r, c).cell->row() << "," << cellAt(r, c).cell->col() << ","
1088 << cellAt(r, c).cell->rowSpan() << "," << cellAt(r, c).cell->colSpan() << ") ";
1089 else
1090 *stream << cellAt(r, c).cell << "null cell ";
1091 }
1092 *stream << endl << ind;
eseidela043f3d2006-01-20 19:24:53 +00001093 }
1094 RenderContainer::dump(stream,ind);
1095}
1096#endif
1097
ddkilzer260f3d22007-01-05 05:56:31 +00001098} // namespace WebCore