2 * This file is part of the DOM implementation for KDE.
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.
10 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
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.
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.
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.
29 #include "RenderTableSection.h"
30 #include "RenderTableCell.h"
31 #include "RenderTableCol.h"
32 #include "RenderTableRow.h"
33 #include "RenderTableCol.h"
35 #include "HTMLNames.h"
36 #include "KWQTextStream.h"
42 using namespace HTMLNames;
44 RenderTableSection::RenderTableSection(Node* node)
45 : RenderContainer(node)
47 // init RenderObject attributes
48 setInline(false); // our object is not Inline
52 needCellRecalc = false;
53 m_outerBorderLeft = 0;
54 m_outerBorderRight = 0;
56 m_outerBorderBottom = 0;
59 RenderTableSection::~RenderTableSection()
64 void RenderTableSection::destroy()
66 // recalc cell info because RenderTable has unguarded pointers
67 // stored that point to this RenderTableSection.
69 table()->setNeedSectionRecalc();
71 RenderContainer::destroy();
74 void RenderTableSection::setStyle(RenderStyle* _style)
76 // we don't allow changing this one
78 _style->setDisplay(style()->display());
79 else if (_style->display() != TABLE_FOOTER_GROUP && _style->display() != TABLE_HEADER_GROUP)
80 _style->setDisplay(TABLE_ROW_GROUP);
82 RenderContainer::setStyle(_style);
85 void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild)
87 bool isTableSection = element() && (element()->hasTagName(theadTag) || element()->hasTagName(tbodyTag) || element()->hasTagName(tfootTag));
89 if (!child->isTableRow()) {
90 if (isTableSection && child->element() && child->element()->hasTagName(formTag)) {
91 RenderContainer::addChild(child, beforeChild);
95 RenderObject* last = beforeChild;
98 if (last && last->isAnonymous()) {
99 last->addChild(child);
103 // If beforeChild is inside an anonymous cell/row, insert into the cell or into
104 // the anonymous row containing it, if there is one.
105 RenderObject* lastBox = last;
106 while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableRow())
107 lastBox = lastBox->parent();
108 if (lastBox && lastBox->isAnonymous()) {
109 lastBox->addChild(child, beforeChild);
113 RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table */);
114 RenderStyle* newStyle = new (renderArena()) RenderStyle();
115 newStyle->inheritFrom(style());
116 newStyle->setDisplay(TABLE_ROW);
117 row->setStyle(newStyle);
118 addChild(row, beforeChild);
119 row->addChild(child);
129 ensureRows(cRow + 1);
132 grid[cRow].height = child->style()->height();
133 if (grid[cRow].height.isRelative())
134 grid[cRow].height = Length();
137 RenderContainer::addChild(child, beforeChild);
140 bool RenderTableSection::ensureRows(int numRows)
142 int nRows = gridRows;
143 if (numRows > nRows) {
144 if (numRows > static_cast<int>(grid.size()))
145 if (!grid.resize(numRows*2+1))
149 int nCols = table()->numEffCols();
150 CellStruct emptyCellStruct;
151 emptyCellStruct.cell = 0;
152 emptyCellStruct.inColSpan = false;
153 for (int r = nRows; r < numRows; r++) {
154 grid[r].row = new Row(nCols);
155 grid[r].row->fill(emptyCellStruct);
156 grid[r].rowRenderer = 0;
157 grid[r].baseLine = 0;
158 grid[r].height = Length();
165 void RenderTableSection::addCell(RenderTableCell *cell, RenderObject* row)
167 int rSpan = cell->rowSpan();
168 int cSpan = cell->colSpan();
169 DeprecatedArray<RenderTable::ColumnStruct> &columns = table()->columns;
170 int nCols = columns.size();
172 // ### mozilla still seems to do the old HTML way, even for strict DTD
173 // (see the annotation on table cell layouting in the CSS specs and the testcase below:
175 // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
176 // <TR><TD colspan="2">5
179 while (cCol < nCols && (cellAt(cRow, cCol).cell || cellAt(cRow, cCol).inColSpan))
183 // we ignore height settings on rowspan cells
184 Length height = cell->style()->height();
185 if (height.value() > 0 || (height.isRelative() && height.value() >= 0)) {
186 Length cRowHeight = grid[cRow].height;
187 switch (height.type()) {
189 if (!(cRowHeight.isPercent()) ||
190 (cRowHeight.isPercent() && cRowHeight.value() < height.value()))
191 grid[cRow].height = height;
194 if (cRowHeight.type() < Percent ||
195 (cRowHeight.isFixed() && cRowHeight.value() < height.value()))
196 grid[cRow].height = height;
205 // make sure we have enough rows
206 if (!ensureRows(cRow + rSpan))
209 grid[cRow].rowRenderer = row;
212 // tell the cell where it is
213 CellStruct currentCell;
214 currentCell.cell = cell;
215 currentCell.inColSpan = false;
219 table()->appendColumn(cSpan);
222 if (cSpan < columns[cCol].span)
223 table()->splitColumn(cCol, cSpan);
224 currentSpan = columns[cCol].span;
227 for (int r = 0; r < rSpan; r++) {
228 CellStruct& c = cellAt(cRow + r, cCol);
229 if (currentCell.cell && !c.cell)
230 c.cell = currentCell.cell;
231 if (currentCell.inColSpan)
235 cSpan -= currentSpan;
236 currentCell.cell = 0;
237 currentCell.inColSpan = true;
241 cell->setCol(table()->effColToCol(col));
247 void RenderTableSection::setCellWidths()
249 DeprecatedArray<int> &columnPos = table()->columnPos;
252 for (int i = 0; i < rows; i++) {
253 Row &row = *grid[i].row;
254 int cols = row.size();
255 for (int j = 0; j < cols; j++) {
256 CellStruct current = row[j];
257 RenderTableCell *cell = current.cell;
262 int cspan = cell->colSpan();
263 while (cspan && endCol < cols) {
264 cspan -= table()->columns[endCol].span;
267 int w = columnPos[endCol] - columnPos[j] - table()->hBorderSpacing();
268 int oldWidth = cell->width();
270 bool neededLayout = cell->selfNeedsLayout();
271 cell->setNeedsLayout(true);
272 if (!neededLayout && !selfNeedsLayout() && cell->checkForRepaintDuringLayout())
273 cell->repaintObjectsBeforeLayout();
281 void RenderTableSection::calcRowHeight()
284 RenderTableCell *cell;
286 int totalRows = gridRows;
287 int spacing = table()->vBorderSpacing();
289 rowPos.resize(totalRows + 1);
292 for (int r = 0; r < totalRows; r++) {
297 int ch = grid[r].height.calcMinValue(0);
298 int pos = rowPos[r + 1] + ch + spacing;
300 if (pos > rowPos[r + 1])
303 Row *row = grid[r].row;
304 int totalCols = row->size();
305 int totalRows = gridRows;
307 for (int c = 0; c < totalCols; c++) {
308 CellStruct current = cellAt(r, c);
310 if (!cell || current.inColSpan)
312 if (r < totalRows - 1 && cellAt(r + 1, c).cell == cell)
315 if ((indx = r - cell->rowSpan() + 1) < 0)
318 if (cell->overrideSize() != -1) {
319 cell->setOverrideSize(-1);
320 cell->setChildNeedsLayout(true, false);
321 cell->layoutIfNeeded();
324 // Explicit heights use the border box in quirks mode. In strict mode do the right
325 // thing and actually add in the border and padding.
326 ch = cell->style()->height().calcValue(0) +
327 (cell->style()->htmlHacks() ? 0 : (cell->paddingTop() + cell->paddingBottom() +
328 cell->borderTop() + cell->borderBottom()));
329 if (cell->height() > ch)
332 pos = rowPos[ indx ] + ch + spacing;
334 if (pos > rowPos[r + 1])
337 // find out the baseline
338 EVerticalAlign va = cell->style()->verticalAlign();
339 if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP
340 || va == SUPER || va == SUB) {
341 int b = cell->baselinePosition();
342 if (b > cell->borderTop() + cell->paddingTop()) {
346 int td = rowPos[indx] + ch - b;
353 //do we have baseline aligned elements?
355 // increase rowheight if baseline requires
356 int bRowPos = baseline + bdesc + spacing ; // + 2*padding
357 if (rowPos[r + 1] < bRowPos)
358 rowPos[r + 1] = bRowPos;
360 grid[r].baseLine = baseline;
363 if (rowPos[r + 1] < rowPos[r])
364 rowPos[r + 1] = rowPos[r];
368 int RenderTableSection::layoutRows(int toAdd)
372 int totalRows = gridRows;
373 int hspacing = table()->hBorderSpacing();
374 int vspacing = table()->vBorderSpacing();
376 // Set the width of our section now. The rows will also be this width.
377 m_width = table()->contentWidth();
378 if (table()->collapseBorders())
381 if (toAdd && totalRows && (rowPos[totalRows] || !nextSibling())) {
383 int totalHeight = rowPos[totalRows] + toAdd;
386 int totalPercent = 0;
388 for (int r = 0; r < totalRows; r++) {
389 if (grid[r].height.isAuto())
391 else if (grid[r].height.isPercent())
392 totalPercent += grid[r].height.value();
395 // try to satisfy percent
397 if (totalPercent > 100)
399 int rh = rowPos[1] - rowPos[0];
400 for (int r = 0; r < totalRows; r++) {
401 if (totalPercent > 0 && grid[r].height.isPercent()) {
402 int toAdd = min(dh, (totalHeight * grid[r].height.value() / 100) - rh);
403 // If toAdd is negative, then we don't want to shrink the row (this bug
404 // affected Outlook Web Access).
405 toAdd = max(0, toAdd);
408 totalPercent -= grid[r].height.value();
410 if (r < totalRows - 1)
411 rh = rowPos[r + 2] - rowPos[r + 1];
412 rowPos[r + 1] += add;
416 // distribute over variable cols
418 for (int r = 0; r < totalRows; r++) {
419 if (numAuto > 0 && grid[r].height.isAuto()) {
420 int toAdd = dh/numAuto;
425 rowPos[r + 1] += add;
428 if (dh > 0 && rowPos[totalRows]) {
429 // if some left overs, distribute equally.
430 int tot = rowPos[totalRows];
432 int prev = rowPos[0];
433 for (int r = 0; r < totalRows; r++) {
434 //weight with the original height
435 add += dh * (rowPos[r + 1] - prev) / tot;
436 prev = rowPos[r + 1];
437 rowPos[r + 1] += add;
442 int leftOffset = hspacing;
444 int nEffCols = table()->numEffCols();
445 for (int r = 0; r < totalRows; r++) {
446 Row *row = grid[r].row;
447 int totalCols = row->size();
449 // Set the row's x/y position and width/height.
450 if (grid[r].rowRenderer) {
451 grid[r].rowRenderer->setPos(0, rowPos[r]);
452 grid[r].rowRenderer->setWidth(m_width);
453 grid[r].rowRenderer->setHeight(rowPos[r+1] - rowPos[r] - vspacing);
456 for (int c = 0; c < nEffCols; c++) {
457 CellStruct current = cellAt(r, c);
458 RenderTableCell* cell = current.cell;
462 if (r < totalRows - 1 && cell == cellAt(r + 1, c).cell)
465 if ((rindx = r-cell->rowSpan() + 1) < 0)
468 rHeight = rowPos[r + 1] - rowPos[rindx] - vspacing;
470 // Force percent height children to lay themselves out again.
471 // This will cause these children to grow to fill the cell.
472 // FIXME: There is still more work to do here to fully match WinIE (should
473 // it become necessary to do so). In quirks mode, WinIE behaves like we
474 // do, but it will clip the cells that spill out of the table section. In
475 // strict mode, Mozilla and WinIE both regrow the table to accommodate the
476 // new height of the cell (thus letting the percentages cause growth one
477 // time only). We may also not be handling row-spanning cells correctly.
479 // Note also the oddity where replaced elements always flex, and yet blocks/tables do
480 // not necessarily flex. WinIE is crazy and inconsistent, and we can't hope to
481 // match the behavior perfectly, but we'll continue to refine it as we discover new
483 bool cellChildrenFlex = false;
484 bool flexAllChildren = cell->style()->height().isFixed() ||
485 (!table()->style()->height().isAuto() && rHeight != cell->height());
487 for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) {
488 if (!o->isText() && o->style()->height().isPercent() && (o->isReplaced() || o->scrollsOverflow() || flexAllChildren)) {
489 // Tables with no sections do not flex.
490 if (!o->isTable() || static_cast<RenderTable*>(o)->hasSections()) {
491 o->setNeedsLayout(true, false);
492 cell->setChildNeedsLayout(true, false);
493 cellChildrenFlex = true;
497 if (cellChildrenFlex) {
498 // Alignment within a cell is based off the calculated
499 // height, which becomes irrelevant once the cell has
500 // been resized based off its percentage. -dwh
501 cell->setCellTopExtra(0);
502 cell->setCellBottomExtra(0);
504 cell->setOverrideSize(max(0,
505 rHeight - cell->borderTop() - cell->paddingTop() -
506 cell->borderBottom() - cell->paddingBottom()));
507 cell->layoutIfNeeded();
509 EVerticalAlign va = cell->style()->verticalAlign();
517 te = getBaseline(r) - cell->baselinePosition() ;
523 te = (rHeight - cell->height())/2;
526 te = rHeight - cell->height();
532 int oldTe = cell->borderTopExtra();
533 int oldBe = cell->borderBottomExtra();
535 int be = rHeight - cell->height() - te;
536 cell->setCellTopExtra(te);
537 cell->setCellBottomExtra(be);
538 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout() && (te != oldTe || be > oldBe))
542 int oldCellX = cell->xPos();
543 int oldCellY = cell->yPos() - cell->borderTopExtra();
545 if (style()->direction() == RTL) {
547 table()->columnPos[(int)totalCols] -
548 table()->columnPos[table()->colToEffCol(cell->col()+cell->colSpan())] +
552 cell->setPos(table()->columnPos[c] + leftOffset, rowPos[rindx]);
554 // If the cell moved, we have to repaint it as well as any floating/positioned
555 // descendants. An exception is if we need a layout. In this case, we know we're going to
556 // repaint ourselves (and the cell) anyway.
557 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
558 cell->repaintDuringLayoutIfMoved(oldCellX, oldCellY);
562 m_height = rowPos[totalRows];
566 int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
568 int bottom = RenderContainer::lowestPosition(includeOverflowInterior, includeSelf);
569 if (!includeOverflowInterior && hasOverflowClip())
572 for (RenderObject *row = firstChild(); row; row = row->nextSibling()) {
573 for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling())
574 if (cell->isTableCell()) {
575 int bp = cell->yPos() + cell->lowestPosition(false);
576 bottom = max(bottom, bp);
583 int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
585 int right = RenderContainer::rightmostPosition(includeOverflowInterior, includeSelf);
586 if (!includeOverflowInterior && hasOverflowClip())
589 for (RenderObject *row = firstChild(); row; row = row->nextSibling()) {
590 for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling())
591 if (cell->isTableCell()) {
592 int rp = cell->xPos() + cell->rightmostPosition(false);
593 right = max(right, rp);
600 int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
602 int left = RenderContainer::leftmostPosition(includeOverflowInterior, includeSelf);
603 if (!includeOverflowInterior && hasOverflowClip())
606 for (RenderObject *row = firstChild(); row; row = row->nextSibling()) {
607 for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling())
608 if (cell->isTableCell()) {
609 int lp = cell->xPos() + cell->leftmostPosition(false);
610 left = min(left, lp);
617 int RenderTableSection::calcOuterBorderTop() const
619 int totalCols = table()->numEffCols();
620 if (gridRows == 0 || totalCols == 0)
623 unsigned borderWidth = 0;
625 const BorderValue& sb = style()->borderTop();
626 if (sb.style() == BHIDDEN)
628 if (sb.style() > BHIDDEN)
629 borderWidth = sb.width;
631 const BorderValue& rb = firstChild()->style()->borderTop();
632 if (rb.style() == BHIDDEN)
634 if (rb.style() > BHIDDEN && rb.width > borderWidth)
635 borderWidth = rb.width;
637 bool allHidden = true;
638 for (int c = 0; c < totalCols; c++) {
639 const CellStruct& current = cellAt(0, c);
640 if (current.inColSpan || !current.cell)
642 const BorderValue& cb = current.cell->style()->borderTop();
643 // FIXME: Don't repeat for the same col group
644 RenderTableCol* colGroup = table()->colElement(c);
646 const BorderValue& gb = colGroup->style()->borderTop();
647 if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
651 if (gb.style() > BHIDDEN && gb.width > borderWidth)
652 borderWidth = gb.width;
653 if (cb.style() > BHIDDEN && cb.width > borderWidth)
654 borderWidth = cb.width;
656 if (cb.style() == BHIDDEN)
660 if (cb.style() > BHIDDEN && cb.width > borderWidth)
661 borderWidth = cb.width;
667 return borderWidth / 2;
670 int RenderTableSection::calcOuterBorderBottom() const
672 int totalCols = table()->numEffCols();
673 if (gridRows == 0 || totalCols == 0)
676 unsigned borderWidth = 0;
678 const BorderValue& sb = style()->borderBottom();
679 if (sb.style() == BHIDDEN)
681 if (sb.style() > BHIDDEN)
682 borderWidth = sb.width;
684 const BorderValue& rb = lastChild()->style()->borderBottom();
685 if (rb.style() == BHIDDEN)
687 if (rb.style() > BHIDDEN && rb.width > borderWidth)
688 borderWidth = rb.width;
690 bool allHidden = true;
691 for (int c = 0; c < totalCols; c++) {
692 const CellStruct& current = cellAt(gridRows - 1, c);
693 if (current.inColSpan || !current.cell)
695 const BorderValue& cb = current.cell->style()->borderBottom();
696 // FIXME: Don't repeat for the same col group
697 RenderTableCol* colGroup = table()->colElement(c);
699 const BorderValue& gb = colGroup->style()->borderBottom();
700 if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
704 if (gb.style() > BHIDDEN && gb.width > borderWidth)
705 borderWidth = gb.width;
706 if (cb.style() > BHIDDEN && cb.width > borderWidth)
707 borderWidth = cb.width;
709 if (cb.style() == BHIDDEN)
713 if (cb.style() > BHIDDEN && cb.width > borderWidth)
714 borderWidth = cb.width;
720 return (borderWidth + 1) / 2;
723 int RenderTableSection::calcOuterBorderLeft(bool rtl) const
725 int totalCols = table()->numEffCols();
726 if (gridRows == 0 || totalCols == 0)
729 unsigned borderWidth = 0;
731 const BorderValue& sb = style()->borderLeft();
732 if (sb.style() == BHIDDEN)
734 if (sb.style() > BHIDDEN)
735 borderWidth = sb.width;
737 int leftmostColumn = rtl ? totalCols - 1 : 0;
738 RenderTableCol* colGroup = table()->colElement(leftmostColumn);
740 const BorderValue& gb = colGroup->style()->borderLeft();
741 if (gb.style() == BHIDDEN)
743 if (gb.style() > BHIDDEN && gb.width > borderWidth)
744 borderWidth = gb.width;
747 bool allHidden = true;
748 for (int r = 0; r < gridRows; r++) {
749 const CellStruct& current = cellAt(r, leftmostColumn);
752 // FIXME: Don't repeat for the same cell
753 const BorderValue& cb = current.cell->style()->borderLeft();
754 const BorderValue& rb = current.cell->parent()->style()->borderLeft();
755 if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
759 if (cb.style() > BHIDDEN && cb.width > borderWidth)
760 borderWidth = cb.width;
761 if (rb.style() > BHIDDEN && rb.width > borderWidth)
762 borderWidth = rb.width;
767 return borderWidth / 2;
770 int RenderTableSection::calcOuterBorderRight(bool rtl) const
772 int totalCols = table()->numEffCols();
773 if (gridRows == 0 || totalCols == 0)
776 unsigned borderWidth = 0;
778 const BorderValue& sb = style()->borderRight();
779 if (sb.style() == BHIDDEN)
781 if (sb.style() > BHIDDEN)
782 borderWidth = sb.width;
784 int rightmostColumn = rtl ? 0 : totalCols - 1;
785 RenderTableCol* colGroup = table()->colElement(rightmostColumn);
787 const BorderValue& gb = colGroup->style()->borderRight();
788 if (gb.style() == BHIDDEN)
790 if (gb.style() > BHIDDEN && gb.width > borderWidth)
791 borderWidth = gb.width;
794 bool allHidden = true;
795 for (int r = 0; r < gridRows; r++) {
796 const CellStruct& current = cellAt(r, rightmostColumn);
799 // FIXME: Don't repeat for the same cell
800 const BorderValue& cb = current.cell->style()->borderRight();
801 const BorderValue& rb = current.cell->parent()->style()->borderRight();
802 if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
806 if (cb.style() > BHIDDEN && cb.width > borderWidth)
807 borderWidth = cb.width;
808 if (rb.style() > BHIDDEN && rb.width > borderWidth)
809 borderWidth = rb.width;
814 return (borderWidth + 1) / 2;
817 void RenderTableSection::recalcOuterBorder()
819 bool rtl = table()->style()->direction() == RTL;
820 m_outerBorderTop = calcOuterBorderTop();
821 m_outerBorderBottom = calcOuterBorderBottom();
822 m_outerBorderLeft = calcOuterBorderLeft(rtl);
823 m_outerBorderRight = calcOuterBorderRight(rtl);
827 void RenderTableSection::paint(PaintInfo& i, int tx, int ty)
829 unsigned int totalRows = gridRows;
830 unsigned int totalCols = table()->columns.size();
832 if (totalRows == 0 || totalCols == 0)
838 // check which rows and cols are visible and only paint these
839 // ### fixme: could use a binary search here
840 PaintPhase paintPhase = i.phase;
844 int h = i.r.height();
846 int os = 2 * maximalOutlineSize(paintPhase);
847 unsigned int startrow = 0;
848 unsigned int endrow = totalRows;
849 for (; startrow < totalRows; startrow++)
850 if (ty + rowPos[startrow+1] >= y - os)
852 if (startrow == totalRows && ty + rowPos[totalRows] + table()->outerBorderBottom() >= y - os)
855 for (; endrow > 0; endrow--)
856 if ( ty + rowPos[endrow-1] <= y + h + os)
858 if (endrow == 0 && ty + rowPos[0] - table()->outerBorderTop() <= y + h + os)
861 unsigned int startcol = 0;
862 unsigned int endcol = totalCols;
863 if (style()->direction() == LTR) {
864 for (; startcol < totalCols; startcol++) {
865 if (tx + table()->columnPos[startcol + 1] >= x - os)
868 if (startcol == totalCols && tx + table()->columnPos[totalCols] + table()->outerBorderRight() >= x - os)
871 for (; endcol > 0; endcol--) {
872 if (tx + table()->columnPos[endcol - 1] <= x + w + os)
875 if (endcol == 0 && tx + table()->columnPos[0] - table()->outerBorderLeft() <= y + w + os)
879 if (startcol < endcol) {
881 for (unsigned int r = startrow; r < endrow; r++) {
882 unsigned int c = startcol;
883 // since a cell can be -1 (indicating a colspan) we might have to search backwards to include it
884 while (c && cellAt(r, c).inColSpan)
886 for (; c < endcol; c++) {
887 CellStruct current = cellAt(r, c);
888 RenderTableCell *cell = current.cell;
890 // Cells must always paint in the order in which they appear taking into account
891 // their upper left originating row/column. For cells with rowspans, avoid repainting
892 // if we've already seen the cell.
893 if (!cell || (r > startrow && (cellAt(r-1, c).cell == cell)))
896 if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
897 // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of
898 // the column group, column, row group, row, and then the cell.
899 RenderObject* col = table()->colElement(c);
900 RenderObject* colGroup = 0;
902 RenderStyle *style = col->parent()->style();
903 if (style->display() == TABLE_COLUMN_GROUP)
904 colGroup = col->parent();
906 RenderObject* row = cell->parent();
908 // Column groups and columns first.
909 // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
910 // the stack, since we have already opened a transparency layer (potentially) for the table row group.
911 // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
913 cell->paintBackgroundsBehindCell(i, tx, ty, colGroup);
914 cell->paintBackgroundsBehindCell(i, tx, ty, col);
916 // Paint the row group next.
917 cell->paintBackgroundsBehindCell(i, tx, ty, this);
919 // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for
920 // painting the row background for the cell.
922 cell->paintBackgroundsBehindCell(i, tx, ty, row);
925 if ((!cell->layer() && !cell->parent()->layer()) || i.phase == PaintPhaseCollapsedTableBorders)
926 cell->paint(i, tx, ty);
932 void RenderTableSection::recalcCells()
939 for (RenderObject *row = firstChild(); row; row = row->nextSibling()) {
940 if (row->isTableRow()) {
943 ensureRows(cRow + 1);
944 for (RenderObject *cell = row->firstChild(); cell; cell = cell->nextSibling())
945 if (cell->isTableCell())
946 addCell(static_cast<RenderTableCell *>(cell), row);
949 needCellRecalc = false;
950 setNeedsLayout(true);
953 void RenderTableSection::clearGrid()
957 delete grid[rows].row;
960 int RenderTableSection::numColumns() const
964 for (int r = 0; r < gridRows; ++r) {
965 for (int c = result; c < table()->numEffCols(); ++c) {
966 const CellStruct& cell = cellAt(r, c);
967 if (cell.cell || cell.inColSpan)
975 RenderObject* RenderTableSection::removeChildNode(RenderObject* child)
978 return RenderContainer::removeChildNode(child);
982 bool RenderTableSection::nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, HitTestAction action)
984 // Table sections cannot ever be hit tested. Effectively they do not exist.
985 // Just forward to our children always.
989 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
990 // FIXME: We have to skip over inline flows, since they can show up inside table rows
991 // at the moment (a demoted inline <form> for example). If we ever implement a
992 // table-specific hit-test method (which we should do for performance reasons anyway),
993 // then we can remove this check.
994 if (!child->layer() && !child->isInlineFlow() && child->nodeAtPoint(info, x, y, tx, ty, action)) {
1004 void RenderTableSection::dump(QTextStream *stream, DeprecatedString ind) const
1006 *stream << endl << ind << "grid=(" << gridRows << "," << table()->numEffCols() << ")" << endl << ind;
1007 for (int r = 0; r < gridRows; r++) {
1008 for (int c = 0; c < table()->numEffCols(); c++) {
1009 if (cellAt( r, c).cell && !cellAt(r, c).inColSpan)
1010 *stream << "(" << cellAt(r, c).cell->row() << "," << cellAt(r, c).cell->col() << ","
1011 << cellAt(r, c).cell->rowSpan() << "," << cellAt(r, c).cell->colSpan() << ") ";
1013 *stream << cellAt(r, c).cell << "null cell ";
1015 *stream << endl << ind;
1017 RenderContainer::dump(stream,ind);