7c4d0c4bac19760c5c5328987256380423ab33e9
[WebKit-https.git] / WebCore / rendering / RenderTableSection.cpp
1 /*
2  * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3  *           (C) 1997 Torben Weis (weis@kde.org)
4  *           (C) 1998 Waldo Bastian (bastian@kde.org)
5  *           (C) 1999 Lars Knoll (knoll@kde.org)
6  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
7  * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
8  * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "RenderTableSection.h"
28 #include "CachedImage.h"
29 #include "Document.h"
30 #include "HitTestResult.h"
31 #include "HTMLNames.h"
32 #include "RenderTableCell.h"
33 #include "RenderTableCol.h"
34 #include "RenderTableRow.h"
35 #include "RenderView.h"
36 #include <limits>
37 #include <wtf/HashSet.h>
38 #include <wtf/Vector.h>
39
40 using namespace std;
41
42 namespace WebCore {
43
44 using namespace HTMLNames;
45
46 static inline void setRowHeightToRowStyleHeightIfNotRelative(RenderTableSection::RowStruct* row)
47 {
48     ASSERT(row && row->rowRenderer);
49     row->height = row->rowRenderer->style()->height();
50     if (row->height.isRelative())
51         row->height = Length();
52 }
53
54 RenderTableSection::RenderTableSection(Node* node)
55     : RenderBox(node)
56     , m_gridRows(0)
57     , m_cCol(0)
58     , m_cRow(-1)
59     , m_outerBorderLeft(0)
60     , m_outerBorderRight(0)
61     , m_outerBorderTop(0)
62     , m_outerBorderBottom(0)
63     , m_needsCellRecalc(false)
64     , m_hasOverflowingCell(false)
65     , m_hasMultipleCellLevels(false)
66 {
67     // init RenderObject attributes
68     setInline(false); // our object is not Inline
69 }
70
71 RenderTableSection::~RenderTableSection()
72 {
73     clearGrid();
74 }
75
76 void RenderTableSection::destroy()
77 {
78     RenderTable* recalcTable = table();
79     
80     RenderBox::destroy();
81     
82     // recalc cell info because RenderTable has unguarded pointers
83     // stored that point to this RenderTableSection.
84     if (recalcTable)
85         recalcTable->setNeedsSectionRecalc();
86 }
87
88 void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild)
89 {
90     // Make sure we don't append things after :after-generated content if we have it.
91     if (!beforeChild && isAfterContent(lastChild()))
92         beforeChild = lastChild();
93
94     if (!child->isTableRow()) {
95         RenderObject* last = beforeChild;
96         if (!last)
97             last = lastChild();
98         if (last && last->isAnonymous()) {
99             last->addChild(child);
100             return;
101         }
102
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);
110             return;
111         }
112
113         RenderObject* row = new (renderArena()) RenderTableRow(document() /* anonymous table row */);
114         RefPtr<RenderStyle> newStyle = RenderStyle::create();
115         newStyle->inheritFrom(style());
116         newStyle->setDisplay(TABLE_ROW);
117         row->setStyle(newStyle.release());
118         addChild(row, beforeChild);
119         row->addChild(child);
120         return;
121     }
122
123     if (beforeChild)
124         setNeedsCellRecalc();
125
126     ++m_cRow;
127     m_cCol = 0;
128
129     // make sure we have enough rows
130     if (!ensureRows(m_cRow + 1))
131         return;
132
133     m_grid[m_cRow].rowRenderer = toRenderTableRow(child);
134
135     if (!beforeChild)
136         setRowHeightToRowStyleHeightIfNotRelative(&m_grid[m_cRow]);
137
138     // If the next renderer is actually wrapped in an anonymous table row, we need to go up and find that.
139     while (beforeChild && beforeChild->parent() != this)
140         beforeChild = beforeChild->parent();
141
142     ASSERT(!beforeChild || beforeChild->isTableRow());
143     RenderBox::addChild(child, beforeChild);
144 }
145
146 void RenderTableSection::removeChild(RenderObject* oldChild)
147 {
148     setNeedsCellRecalc();
149     RenderBox::removeChild(oldChild);
150 }
151
152 bool RenderTableSection::ensureRows(int numRows)
153 {
154     int nRows = m_gridRows;
155     if (numRows > nRows) {
156         if (numRows > static_cast<int>(m_grid.size())) {
157             size_t maxSize = numeric_limits<size_t>::max() / sizeof(RowStruct);
158             if (static_cast<size_t>(numRows) > maxSize)
159                 return false;
160             m_grid.grow(numRows);
161         }
162         m_gridRows = numRows;
163         int nCols = max(1, table()->numEffCols());
164         for (int r = nRows; r < numRows; r++) {
165             m_grid[r].row = new Row(nCols);
166             m_grid[r].rowRenderer = 0;
167             m_grid[r].baseline = 0;
168             m_grid[r].height = Length();
169         }
170     }
171
172     return true;
173 }
174
175 void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row)
176 {
177     int rSpan = cell->rowSpan();
178     int cSpan = cell->colSpan();
179     Vector<RenderTable::ColumnStruct>& columns = table()->columns();
180     int nCols = columns.size();
181
182     // ### mozilla still seems to do the old HTML way, even for strict DTD
183     // (see the annotation on table cell layouting in the CSS specs and the testcase below:
184     // <TABLE border>
185     // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
186     // <TR><TD colspan="2">5
187     // </TABLE>
188     while (m_cCol < nCols && (cellAt(m_cRow, m_cCol).hasCells() || cellAt(m_cRow, m_cCol).inColSpan))
189         m_cCol++;
190
191     if (rSpan == 1) {
192         // we ignore height settings on rowspan cells
193         Length height = cell->style()->height();
194         if (height.isPositive() || (height.isRelative() && height.value() >= 0)) {
195             Length cRowHeight = m_grid[m_cRow].height;
196             switch (height.type()) {
197                 case Percent:
198                     if (!(cRowHeight.isPercent()) ||
199                         (cRowHeight.isPercent() && cRowHeight.rawValue() < height.rawValue()))
200                         m_grid[m_cRow].height = height;
201                         break;
202                 case Fixed:
203                     if (cRowHeight.type() < Percent ||
204                         (cRowHeight.isFixed() && cRowHeight.value() < height.value()))
205                         m_grid[m_cRow].height = height;
206                     break;
207                 case Relative:
208                 default:
209                     break;
210             }
211         }
212     }
213
214     // make sure we have enough rows
215     if (!ensureRows(m_cRow + rSpan))
216         return;
217
218     m_grid[m_cRow].rowRenderer = row;
219
220     int col = m_cCol;
221     // tell the cell where it is
222     bool inColSpan = false;
223     while (cSpan) {
224         int currentSpan;
225         if (m_cCol >= nCols) {
226             table()->appendColumn(cSpan);
227             currentSpan = cSpan;
228         } else {
229             if (cSpan < (int)columns[m_cCol].span)
230                 table()->splitColumn(m_cCol, cSpan);
231             currentSpan = columns[m_cCol].span;
232         }
233         for (int r = 0; r < rSpan; r++) {
234             CellStruct& c = cellAt(m_cRow + r, m_cCol);
235             ASSERT(cell);
236             c.cells.append(cell);
237             // If cells overlap then we take the slow path for painting.
238             if (c.cells.size() > 1)
239                 m_hasMultipleCellLevels = true;
240             if (inColSpan)
241                 c.inColSpan = true;
242         }
243         m_cCol++;
244         cSpan -= currentSpan;
245         inColSpan = true;
246     }
247     cell->setRow(m_cRow);
248     cell->setCol(table()->effColToCol(col));
249 }
250
251 void RenderTableSection::setCellWidths()
252 {
253     Vector<int>& columnPos = table()->columnPositions();
254
255     LayoutStateMaintainer statePusher(view());
256     
257     for (int i = 0; i < m_gridRows; i++) {
258         Row& row = *m_grid[i].row;
259         int cols = row.size();
260         for (int j = 0; j < cols; j++) {
261             CellStruct& current = row[j];
262             RenderTableCell* cell = current.primaryCell();
263             if (!cell || current.inColSpan)
264               continue;
265             int endCol = j;
266             int cspan = cell->colSpan();
267             while (cspan && endCol < cols) {
268                 ASSERT(endCol < (int)table()->columns().size());
269                 cspan -= table()->columns()[endCol].span;
270                 endCol++;
271             }
272             int w = columnPos[endCol] - columnPos[j] - table()->hBorderSpacing();
273             int oldWidth = cell->width();
274             if (w != oldWidth) {
275                 cell->setNeedsLayout(true);
276                 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout()) {
277                     if (!statePusher.didPush()) {
278                         // Technically, we should also push state for the row, but since
279                         // rows don't push a coordinate transform, that's not necessary.
280                         statePusher.push(this, IntSize(x(), y()));
281                     }
282                     cell->repaint();
283                 }
284                 cell->updateWidth(w);
285             }
286         }
287     }
288     
289     statePusher.pop(); // only pops if we pushed
290 }
291
292 int RenderTableSection::calcRowHeight()
293 {
294 #ifndef NDEBUG
295     setNeedsLayoutIsForbidden(true);
296 #endif
297
298     ASSERT(!needsLayout());
299
300     RenderTableCell* cell;
301
302     int spacing = table()->vBorderSpacing();
303
304     LayoutStateMaintainer statePusher(view());
305
306     m_rowPos.resize(m_gridRows + 1);
307     m_rowPos[0] = spacing;
308
309     for (int r = 0; r < m_gridRows; r++) {
310         m_rowPos[r + 1] = 0;
311         m_grid[r].baseline = 0;
312         int baseline = 0;
313         int bdesc = 0;
314         int ch = m_grid[r].height.calcMinValue(0);
315         int pos = m_rowPos[r] + ch + (m_grid[r].rowRenderer ? spacing : 0);
316
317         m_rowPos[r + 1] = max(m_rowPos[r + 1], pos);
318
319         Row* row = m_grid[r].row;
320         int totalCols = row->size();
321
322         for (int c = 0; c < totalCols; c++) {
323             CellStruct& current = cellAt(r, c);
324             cell = current.primaryCell();
325
326             if (!cell || current.inColSpan)
327                 continue;
328
329             if ((cell->row() + cell->rowSpan() - 1) > r)
330                 continue;
331
332             int indx = max(r - cell->rowSpan() + 1, 0);
333
334             if (cell->overrideSize() != -1) {
335                 if (!statePusher.didPush()) {
336                     // Technically, we should also push state for the row, but since
337                     // rows don't push a coordinate transform, that's not necessary.
338                     statePusher.push(this, IntSize(x(), y()));
339                 }
340                 cell->setOverrideSize(-1);
341                 cell->setChildNeedsLayout(true, false);
342                 cell->layoutIfNeeded();
343             }
344             
345             int adjustedPaddingTop = cell->paddingTop() - cell->intrinsicPaddingBefore();
346             int adjustedPaddingBottom = cell->paddingBottom() - cell->intrinsicPaddingAfter();
347             int adjustedHeight = cell->height() - (cell->intrinsicPaddingBefore() + cell->intrinsicPaddingAfter());
348         
349             // Explicit heights use the border box in quirks mode.  In strict mode do the right
350             // thing and actually add in the border and padding.
351             ch = cell->style()->height().calcValue(0) + 
352                 (document()->inQuirksMode() ? 0 : (adjustedPaddingTop + adjustedPaddingBottom +
353                                                    cell->borderTop() + cell->borderBottom()));
354             ch = max(ch, adjustedHeight);
355
356             pos = m_rowPos[indx] + ch + (m_grid[r].rowRenderer ? spacing : 0);
357
358             m_rowPos[r + 1] = max(m_rowPos[r + 1], pos);
359
360             // find out the baseline
361             EVerticalAlign va = cell->style()->verticalAlign();
362             if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) {
363                 int b = cell->baselinePosition();
364                 if (b > cell->borderTop() + cell->paddingTop()) {
365                     baseline = max(baseline, b - cell->intrinsicPaddingBefore());
366                     bdesc = max(bdesc, m_rowPos[indx] + ch - (b - cell->intrinsicPaddingBefore()));
367                 }
368             }
369         }
370
371         // do we have baseline aligned elements?
372         if (baseline) {
373             // increase rowheight if baseline requires
374             m_rowPos[r + 1] = max(m_rowPos[r + 1], baseline + bdesc + (m_grid[r].rowRenderer ? spacing : 0));
375             m_grid[r].baseline = baseline;
376         }
377
378         m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]);
379     }
380
381 #ifndef NDEBUG
382     setNeedsLayoutIsForbidden(false);
383 #endif
384
385     ASSERT(!needsLayout());
386
387     statePusher.pop();
388
389     return m_rowPos[m_gridRows];
390 }
391
392 void RenderTableSection::layout()
393 {
394     ASSERT(needsLayout());
395
396     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
397     for (RenderObject* child = children()->firstChild(); child; child = child->nextSibling()) {
398         if (child->isTableRow()) {
399             child->layoutIfNeeded();
400             ASSERT(!child->needsLayout());
401         }
402     }
403     statePusher.pop();
404     setNeedsLayout(false);
405 }
406
407 int RenderTableSection::layoutRows(int toAdd)
408 {
409 #ifndef NDEBUG
410     setNeedsLayoutIsForbidden(true);
411 #endif
412
413     ASSERT(!needsLayout());
414
415     int rHeight;
416     int rindx;
417     int totalRows = m_gridRows;
418     
419     // Set the width of our section now.  The rows will also be this width.
420     setWidth(table()->contentWidth());
421     m_overflow.clear();
422     m_hasOverflowingCell = false;
423
424     if (toAdd && totalRows && (m_rowPos[totalRows] || !nextSibling())) {
425         int totalHeight = m_rowPos[totalRows] + toAdd;
426
427         int dh = toAdd;
428         int totalPercent = 0;
429         int numAuto = 0;
430         for (int r = 0; r < totalRows; r++) {
431             if (m_grid[r].height.isAuto())
432                 numAuto++;
433             else if (m_grid[r].height.isPercent())
434                 totalPercent += m_grid[r].height.rawValue();
435         }
436         if (totalPercent) {
437             // try to satisfy percent
438             int add = 0;
439             totalPercent = min(totalPercent, 100 * percentScaleFactor);
440             int rh = m_rowPos[1] - m_rowPos[0];
441             for (int r = 0; r < totalRows; r++) {
442                 if (totalPercent > 0 && m_grid[r].height.isPercent()) {
443                     int toAdd = min(dh, (totalHeight * m_grid[r].height.rawValue() / (100 * percentScaleFactor)) - rh);
444                     // If toAdd is negative, then we don't want to shrink the row (this bug
445                     // affected Outlook Web Access).
446                     toAdd = max(0, toAdd);
447                     add += toAdd;
448                     dh -= toAdd;
449                     totalPercent -= m_grid[r].height.rawValue();
450                 }
451                 if (r < totalRows - 1)
452                     rh = m_rowPos[r + 2] - m_rowPos[r + 1];
453                 m_rowPos[r + 1] += add;
454             }
455         }
456         if (numAuto) {
457             // distribute over variable cols
458             int add = 0;
459             for (int r = 0; r < totalRows; r++) {
460                 if (numAuto > 0 && m_grid[r].height.isAuto()) {
461                     int toAdd = dh / numAuto;
462                     add += toAdd;
463                     dh -= toAdd;
464                     numAuto--;
465                 }
466                 m_rowPos[r + 1] += add;
467             }
468         }
469         if (dh > 0 && m_rowPos[totalRows]) {
470             // if some left overs, distribute equally.
471             int tot = m_rowPos[totalRows];
472             int add = 0;
473             int prev = m_rowPos[0];
474             for (int r = 0; r < totalRows; r++) {
475                 // weight with the original height
476                 add += dh * (m_rowPos[r + 1] - prev) / tot;
477                 prev = m_rowPos[r + 1];
478                 m_rowPos[r + 1] += add;
479             }
480         }
481     }
482
483     int hspacing = table()->hBorderSpacing();
484     int vspacing = table()->vBorderSpacing();
485     int nEffCols = table()->numEffCols();
486
487     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
488
489     for (int r = 0; r < totalRows; r++) {
490         // Set the row's x/y position and width/height.
491         if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) {
492             rowRenderer->setLocation(0, m_rowPos[r]);
493             rowRenderer->setWidth(width());
494             rowRenderer->setHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing);
495         }
496
497         for (int c = 0; c < nEffCols; c++) {
498             CellStruct& cs = cellAt(r, c);
499             RenderTableCell* cell = cs.primaryCell();
500
501             if (!cell || cs.inColSpan)
502                 continue;
503
504             rindx = cell->row();
505             rHeight = m_rowPos[rindx + cell->rowSpan()] - m_rowPos[rindx] - vspacing;
506             
507             // Force percent height children to lay themselves out again.
508             // This will cause these children to grow to fill the cell.
509             // FIXME: There is still more work to do here to fully match WinIE (should
510             // it become necessary to do so).  In quirks mode, WinIE behaves like we
511             // do, but it will clip the cells that spill out of the table section.  In
512             // strict mode, Mozilla and WinIE both regrow the table to accommodate the
513             // new height of the cell (thus letting the percentages cause growth one
514             // time only).  We may also not be handling row-spanning cells correctly.
515             //
516             // Note also the oddity where replaced elements always flex, and yet blocks/tables do
517             // not necessarily flex.  WinIE is crazy and inconsistent, and we can't hope to
518             // match the behavior perfectly, but we'll continue to refine it as we discover new
519             // bugs. :)
520             bool cellChildrenFlex = false;
521             bool flexAllChildren = cell->style()->height().isFixed()
522                 || (!table()->style()->height().isAuto() && rHeight != cell->height());
523
524             for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) {
525                 if (!o->isText() && o->style()->height().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) {
526                     // Tables with no sections do not flex.
527                     if (!o->isTable() || toRenderTable(o)->hasSections()) {
528                         o->setNeedsLayout(true, false);
529                         cellChildrenFlex = true;
530                     }
531                 }
532             }
533
534             if (HashSet<RenderBox*>* percentHeightDescendants = cell->percentHeightDescendants()) {
535                 HashSet<RenderBox*>::iterator end = percentHeightDescendants->end();
536                 for (HashSet<RenderBox*>::iterator it = percentHeightDescendants->begin(); it != end; ++it) {
537                     RenderBox* box = *it;
538                     if (!box->isReplaced() && !box->scrollsOverflow() && !flexAllChildren)
539                         continue;
540
541                     while (box != cell) {
542                         if (box->normalChildNeedsLayout())
543                             break;
544                         box->setChildNeedsLayout(true, false);
545                         box = box->containingBlock();
546                         ASSERT(box);
547                         if (!box)
548                             break;
549                     }
550                     cellChildrenFlex = true;
551                 }
552             }
553
554             if (cellChildrenFlex) {
555                 cell->setChildNeedsLayout(true, false);
556                 // Alignment within a cell is based off the calculated
557                 // height, which becomes irrelevant once the cell has
558                 // been resized based off its percentage.
559                 cell->setOverrideSize(max(0, 
560                                            rHeight - cell->borderTop() - cell->paddingTop() - 
561                                                      cell->borderBottom() - cell->paddingBottom()));
562                 cell->layoutIfNeeded();
563                 
564                 // If the baseline moved, we may have to update the data for our row. Find out the new baseline.
565                 EVerticalAlign va = cell->style()->verticalAlign();
566                 if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) {
567                     int b = cell->baselinePosition();
568                     if (b > cell->borderTop() + cell->paddingTop())
569                         m_grid[r].baseline = max(m_grid[r].baseline, b);
570                 }
571             }
572             
573             int oldTe = cell->intrinsicPaddingBefore();
574             int oldBe = cell->intrinsicPaddingAfter();
575             int heightWithoutIntrinsicPadding = cell->height() - oldTe - oldBe;
576             
577             int te = 0;
578             switch (cell->style()->verticalAlign()) {
579                 case SUB:
580                 case SUPER:
581                 case TEXT_TOP:
582                 case TEXT_BOTTOM:
583                 case BASELINE: {
584                     int b = cell->baselinePosition();
585                     if (b > cell->borderTop() + cell->paddingTop())
586                         te = getBaseline(r) - (b - oldTe);
587                     break;
588                 }
589                 case TOP:
590                     te = 0;
591                     break;
592                 case MIDDLE:
593                     te = (rHeight - heightWithoutIntrinsicPadding) / 2;
594                     break;
595                 case BOTTOM:
596                     te = rHeight - heightWithoutIntrinsicPadding;
597                     break;
598                 default:
599                     break;
600             }
601             
602             int be = rHeight - heightWithoutIntrinsicPadding - te;
603             cell->setIntrinsicPaddingBefore(te);
604             cell->setIntrinsicPaddingAfter(be);
605             
606             IntRect oldCellRect(cell->x(), cell->y() , cell->width(), cell->height());
607             
608             if (!style()->isLeftToRightDirection())
609                 cell->setLocation(table()->columnPositions()[nEffCols] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + hspacing, m_rowPos[rindx]);
610             else
611                 cell->setLocation(table()->columnPositions()[c] + hspacing, m_rowPos[rindx]);
612             view()->addLayoutDelta(IntSize(oldCellRect.x() - cell->x(), oldCellRect.y() - cell->y()));
613
614             if (te != oldTe || be != oldBe)
615                 cell->setNeedsLayout(true, false);
616             
617             if (!cell->needsLayout() && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(cell->y()) != cell->pageY())
618                 cell->setChildNeedsLayout(true, false);
619             
620             cell->layoutIfNeeded();
621             
622             if (view()->layoutState()->m_pageHeight && cell->height() != rHeight)
623                 cell->setHeight(rHeight); // FIXME: Pagination might have made us change size.  For now just shrink or grow the cell to fit without doing a relayout.
624         
625             IntSize childOffset(cell->x() - oldCellRect.x(), cell->y() - oldCellRect.y());
626             if (childOffset.width() || childOffset.height()) {
627                 view()->addLayoutDelta(childOffset);
628
629                 // If the child moved, we have to repaint it as well as any floating/positioned
630                 // descendants.  An exception is if we need a layout.  In this case, we know we're going to
631                 // repaint ourselves (and the child) anyway.
632                 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
633                     cell->repaintDuringLayoutIfMoved(oldCellRect);
634             }
635         }
636     }
637
638 #ifndef NDEBUG
639     setNeedsLayoutIsForbidden(false);
640 #endif
641
642     ASSERT(!needsLayout());
643
644     setHeight(m_rowPos[totalRows]);
645
646     // Now that our height has been determined, add in overflow from cells.
647     for (int r = 0; r < totalRows; r++) {
648         for (int c = 0; c < nEffCols; c++) {
649             CellStruct& cs = cellAt(r, c);
650             RenderTableCell* cell = cs.primaryCell();
651             if (!cell || cs.inColSpan)
652                 continue;
653             if (r < totalRows - 1 && cell == primaryCellAt(r + 1, c))
654                 continue;
655             addOverflowFromChild(cell);
656             m_hasOverflowingCell |= cell->hasVisibleOverflow();
657         }
658     }
659
660     statePusher.pop();
661     return height();
662 }
663
664 int RenderTableSection::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
665 {
666     int bottom = RenderBox::lowestPosition(includeOverflowInterior, includeSelf);
667     if (!includeOverflowInterior && hasOverflowClip())
668         return bottom;
669
670     for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
671         for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) {
672             if (curr->isTableCell()) {
673                 RenderTableCell* cell = toRenderTableCell(curr);
674                 bottom = max(bottom, cell->y() + cell->lowestPosition(false));
675             }
676         }
677     }
678     
679     return bottom;
680 }
681
682 int RenderTableSection::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
683 {
684     int right = RenderBox::rightmostPosition(includeOverflowInterior, includeSelf);
685     if (!includeOverflowInterior && hasOverflowClip())
686         return right;
687
688     for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
689         for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) {
690             if (curr->isTableCell()) {
691                 RenderTableCell* cell = toRenderTableCell(curr);
692                 right = max(right, cell->x() + cell->rightmostPosition(false));
693             }
694         }
695     }
696     
697     return right;
698 }
699
700 int RenderTableSection::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
701 {
702     int left = RenderBox::leftmostPosition(includeOverflowInterior, includeSelf);
703     if (!includeOverflowInterior && hasOverflowClip())
704         return left;
705     
706     for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
707         for (RenderObject* curr = row->firstChild(); curr; curr = curr->nextSibling()) {
708             if (curr->isTableCell()) {
709                 RenderTableCell* cell = toRenderTableCell(curr);
710                 left = min(left, cell->x() + cell->leftmostPosition(false));
711             }
712         }
713     }
714     
715     return left;
716 }
717
718 int RenderTableSection::calcOuterBorderTop() const
719 {
720     int totalCols = table()->numEffCols();
721     if (!m_gridRows || !totalCols)
722         return 0;
723
724     unsigned borderWidth = 0;
725
726     const BorderValue& sb = style()->borderTop();
727     if (sb.style() == BHIDDEN)
728         return -1;
729     if (sb.style() > BHIDDEN)
730         borderWidth = sb.width();
731
732     const BorderValue& rb = firstChild()->style()->borderTop();
733     if (rb.style() == BHIDDEN)
734         return -1;
735     if (rb.style() > BHIDDEN && rb.width() > borderWidth)
736         borderWidth = rb.width();
737
738     bool allHidden = true;
739     for (int c = 0; c < totalCols; c++) {
740         const CellStruct& current = cellAt(0, c);
741         if (current.inColSpan || !current.hasCells())
742             continue;
743         const BorderValue& cb = current.primaryCell()->style()->borderTop();
744         // FIXME: Don't repeat for the same col group
745         RenderTableCol* colGroup = table()->colElement(c);
746         if (colGroup) {
747             const BorderValue& gb = colGroup->style()->borderTop();
748             if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
749                 continue;
750             allHidden = false;
751             if (gb.style() > BHIDDEN && gb.width() > borderWidth)
752                 borderWidth = gb.width();
753             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
754                 borderWidth = cb.width();
755         } else {
756             if (cb.style() == BHIDDEN)
757                 continue;
758             allHidden = false;
759             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
760                 borderWidth = cb.width();
761         }
762     }
763     if (allHidden)
764         return -1;
765
766     return borderWidth / 2;
767 }
768
769 int RenderTableSection::calcOuterBorderBottom() const
770 {
771     int totalCols = table()->numEffCols();
772     if (!m_gridRows || !totalCols)
773         return 0;
774
775     unsigned borderWidth = 0;
776
777     const BorderValue& sb = style()->borderBottom();
778     if (sb.style() == BHIDDEN)
779         return -1;
780     if (sb.style() > BHIDDEN)
781         borderWidth = sb.width();
782
783     const BorderValue& rb = lastChild()->style()->borderBottom();
784     if (rb.style() == BHIDDEN)
785         return -1;
786     if (rb.style() > BHIDDEN && rb.width() > borderWidth)
787         borderWidth = rb.width();
788
789     bool allHidden = true;
790     for (int c = 0; c < totalCols; c++) {
791         const CellStruct& current = cellAt(m_gridRows - 1, c);
792         if (current.inColSpan || !current.hasCells())
793             continue;
794         const BorderValue& cb = current.primaryCell()->style()->borderBottom();
795         // FIXME: Don't repeat for the same col group
796         RenderTableCol* colGroup = table()->colElement(c);
797         if (colGroup) {
798             const BorderValue& gb = colGroup->style()->borderBottom();
799             if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
800                 continue;
801             allHidden = false;
802             if (gb.style() > BHIDDEN && gb.width() > borderWidth)
803                 borderWidth = gb.width();
804             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
805                 borderWidth = cb.width();
806         } else {
807             if (cb.style() == BHIDDEN)
808                 continue;
809             allHidden = false;
810             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
811                 borderWidth = cb.width();
812         }
813     }
814     if (allHidden)
815         return -1;
816
817     return (borderWidth + 1) / 2;
818 }
819
820 int RenderTableSection::calcOuterBorderLeft(bool rtl) const
821 {
822     int totalCols = table()->numEffCols();
823     if (!m_gridRows || !totalCols)
824         return 0;
825
826     unsigned borderWidth = 0;
827
828     const BorderValue& sb = style()->borderLeft();
829     if (sb.style() == BHIDDEN)
830         return -1;
831     if (sb.style() > BHIDDEN)
832         borderWidth = sb.width();
833
834     int leftmostColumn = rtl ? totalCols - 1 : 0;
835     RenderTableCol* colGroup = table()->colElement(leftmostColumn);
836     if (colGroup) {
837         const BorderValue& gb = colGroup->style()->borderLeft();
838         if (gb.style() == BHIDDEN)
839             return -1;
840         if (gb.style() > BHIDDEN && gb.width() > borderWidth)
841             borderWidth = gb.width();
842     }
843
844     bool allHidden = true;
845     for (int r = 0; r < m_gridRows; r++) {
846         const CellStruct& current = cellAt(r, leftmostColumn);
847         if (!current.hasCells())
848             continue;
849         // FIXME: Don't repeat for the same cell
850         const BorderValue& cb = current.primaryCell()->style()->borderLeft();
851         const BorderValue& rb = current.primaryCell()->parent()->style()->borderLeft();
852         if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
853             continue;
854         allHidden = false;
855         if (cb.style() > BHIDDEN && cb.width() > borderWidth)
856             borderWidth = cb.width();
857         if (rb.style() > BHIDDEN && rb.width() > borderWidth)
858             borderWidth = rb.width();
859     }
860     if (allHidden)
861         return -1;
862
863     return borderWidth / 2;
864 }
865
866 int RenderTableSection::calcOuterBorderRight(bool rtl) const
867 {
868     int totalCols = table()->numEffCols();
869     if (!m_gridRows || !totalCols)
870         return 0;
871
872     unsigned borderWidth = 0;
873
874     const BorderValue& sb = style()->borderRight();
875     if (sb.style() == BHIDDEN)
876         return -1;
877     if (sb.style() > BHIDDEN)
878         borderWidth = sb.width();
879
880     int rightmostColumn = rtl ? 0 : totalCols - 1;
881     RenderTableCol* colGroup = table()->colElement(rightmostColumn);
882     if (colGroup) {
883         const BorderValue& gb = colGroup->style()->borderRight();
884         if (gb.style() == BHIDDEN)
885             return -1;
886         if (gb.style() > BHIDDEN && gb.width() > borderWidth)
887             borderWidth = gb.width();
888     }
889
890     bool allHidden = true;
891     for (int r = 0; r < m_gridRows; r++) {
892         const CellStruct& current = cellAt(r, rightmostColumn);
893         if (!current.hasCells())
894             continue;
895         // FIXME: Don't repeat for the same cell
896         const BorderValue& cb = current.primaryCell()->style()->borderRight();
897         const BorderValue& rb = current.primaryCell()->parent()->style()->borderRight();
898         if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
899             continue;
900         allHidden = false;
901         if (cb.style() > BHIDDEN && cb.width() > borderWidth)
902             borderWidth = cb.width();
903         if (rb.style() > BHIDDEN && rb.width() > borderWidth)
904             borderWidth = rb.width();
905     }
906     if (allHidden)
907         return -1;
908
909     return (borderWidth + 1) / 2;
910 }
911
912 void RenderTableSection::recalcOuterBorder()
913 {
914     bool rtl = !table()->style()->isLeftToRightDirection();
915     m_outerBorderTop = calcOuterBorderTop();
916     m_outerBorderBottom = calcOuterBorderBottom();
917     m_outerBorderLeft = calcOuterBorderLeft(rtl);
918     m_outerBorderRight = calcOuterBorderRight(rtl);
919 }
920
921 int RenderTableSection::firstLineBoxBaseline() const
922 {
923     if (!m_gridRows)
924         return -1;
925
926     int firstLineBaseline = m_grid[0].baseline;
927     if (firstLineBaseline)
928         return firstLineBaseline + m_rowPos[0];
929
930     firstLineBaseline = -1;
931     Row* firstRow = m_grid[0].row;
932     for (size_t i = 0; i < firstRow->size(); ++i) {
933         CellStruct& cs = firstRow->at(i);
934         RenderTableCell* cell = cs.primaryCell();
935         if (cell)
936             firstLineBaseline = max(firstLineBaseline, cell->y() + cell->paddingTop() + cell->borderTop() + cell->contentHeight());
937     }
938
939     return firstLineBaseline;
940 }
941
942 void RenderTableSection::paint(PaintInfo& paintInfo, int tx, int ty)
943 {
944     // put this back in when all layout tests can handle it
945     // ASSERT(!needsLayout());
946     // avoid crashing on bugs that cause us to paint with dirty layout
947     if (needsLayout())
948         return;
949     
950     unsigned totalRows = m_gridRows;
951     unsigned totalCols = table()->columns().size();
952
953     if (!totalRows || !totalCols)
954         return;
955
956     tx += x();
957     ty += y();
958
959     PaintPhase phase = paintInfo.phase;
960     bool pushedClip = pushContentsClip(paintInfo, tx, ty);
961     paintObject(paintInfo, tx, ty);
962     if (pushedClip)
963         popContentsClip(paintInfo, phase, tx, ty);
964 }
965
966 static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2)
967 {
968     return elem1->row() < elem2->row();
969 }
970
971 void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, int tx, int ty)
972 {
973     PaintPhase paintPhase = paintInfo.phase;
974     RenderTableRow* row = toRenderTableRow(cell->parent());
975
976     if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
977         // We need to handle painting a stack of backgrounds.  This stack (from bottom to top) consists of
978         // the column group, column, row group, row, and then the cell.
979         RenderObject* col = table()->colElement(cell->col());
980         RenderObject* colGroup = 0;
981         if (col && col->parent()->style()->display() == TABLE_COLUMN_GROUP)
982             colGroup = col->parent();
983
984         // Column groups and columns first.
985         // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
986         // the stack, since we have already opened a transparency layer (potentially) for the table row group.
987         // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
988         // cell.
989         cell->paintBackgroundsBehindCell(paintInfo, tx, ty, colGroup);
990         cell->paintBackgroundsBehindCell(paintInfo, tx, ty, col);
991
992         // Paint the row group next.
993         cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this);
994
995         // Paint the row next, but only if it doesn't have a layer.  If a row has a layer, it will be responsible for
996         // painting the row background for the cell.
997         if (!row->hasSelfPaintingLayer())
998             cell->paintBackgroundsBehindCell(paintInfo, tx, ty, row);
999     }
1000     if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()) || paintInfo.phase == PaintPhaseCollapsedTableBorders)
1001         cell->paint(paintInfo, tx, ty);
1002
1003 }
1004
1005 void RenderTableSection::paintObject(PaintInfo& paintInfo, int tx, int ty)
1006 {
1007     // Check which rows and cols are visible and only paint these.
1008     // FIXME: Could use a binary search here.
1009     unsigned totalRows = m_gridRows;
1010     unsigned totalCols = table()->columns().size();
1011
1012     PaintPhase paintPhase = paintInfo.phase;
1013     int x = paintInfo.rect.x();
1014     int y = paintInfo.rect.y();
1015     int w = paintInfo.rect.width();
1016     int h = paintInfo.rect.height();
1017
1018     int os = 2 * maximalOutlineSize(paintPhase);
1019     unsigned startrow = 0;
1020     unsigned endrow = totalRows;
1021     
1022     // If some cell overflows, just paint all of them.
1023     if (!m_hasOverflowingCell) {
1024         int relativeY = y - ty;
1025         int top = relativeY - os;
1026         // binary search to find a row
1027         startrow = std::lower_bound(m_rowPos.begin(), m_rowPos.end(), top) - m_rowPos.begin();
1028
1029         // The binary search above gives us the first row with
1030         // a y position >= the top of the paint rect. Thus, the previous
1031         // may need to be repainted as well.
1032         if (startrow == m_rowPos.size() || (startrow > 0 && (m_rowPos[startrow] >  top)))
1033           --startrow;
1034
1035         int bottom = relativeY + h + os - 1;
1036         endrow = std::lower_bound(m_rowPos.begin(), m_rowPos.end(), bottom) - m_rowPos.begin();
1037         if ((endrow == m_rowPos.size()) || (endrow > 0 && m_rowPos[endrow - 1] == bottom))
1038           --endrow;
1039
1040         if (!endrow && ty + m_rowPos[0] - table()->outerBorderTop() <= y + h + os)
1041             ++endrow;
1042     }
1043     unsigned startcol = 0;
1044     unsigned endcol = totalCols;
1045     // FIXME: Implement RTL.
1046     if (!m_hasOverflowingCell && style()->isLeftToRightDirection()) {
1047         int relativeX = x - tx;
1048         int left = relativeX - os;
1049         Vector<int>& columnPos = table()->columnPositions();
1050         startcol = std::lower_bound(columnPos.begin(), columnPos.end(), left) - columnPos.begin();
1051         if ((startcol == columnPos.size()) || (startcol > 0 && (columnPos[startcol] > left)))
1052             --startcol;
1053
1054         int right = relativeX + w + os - 1;
1055         endcol = std::lower_bound(columnPos.begin(), columnPos.end(), right) - columnPos.begin();
1056         if (endcol == columnPos.size() || (endcol > 0 && (columnPos[endcol - 1] == right)))
1057             --endcol;
1058
1059         if (!endcol && tx + table()->columnPositions()[0] - table()->outerBorderLeft() <= y + w + os)
1060             ++endcol;
1061     }
1062     if (startcol < endcol) {
1063         if (!m_hasMultipleCellLevels) {
1064             // Draw the dirty cells in the order that they appear.
1065             for (unsigned r = startrow; r < endrow; r++) {
1066                 for (unsigned c = startcol; c < endcol; c++) {
1067                     CellStruct& current = cellAt(r, c);
1068                     RenderTableCell* cell = current.primaryCell();
1069                     if (!cell || (r > startrow && primaryCellAt(r - 1, c) == cell) || (c > startcol && primaryCellAt(r, c - 1) == cell))
1070                         continue;
1071                     paintCell(cell, paintInfo, tx, ty);
1072                 }
1073             }
1074         } else {
1075             // Draw the cells in the correct paint order.
1076             Vector<RenderTableCell*> cells;
1077             HashSet<RenderTableCell*> spanningCells;
1078             for (unsigned r = startrow; r < endrow; r++) {
1079                 for (unsigned c = startcol; c < endcol; c++) {
1080                     CellStruct& current = cellAt(r, c);
1081                     if (!current.hasCells())
1082                         continue;
1083                     for (unsigned i = 0; i < current.cells.size(); ++i) {
1084                         if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) {
1085                             if (spanningCells.contains(current.cells[i]))
1086                                 continue;
1087                             spanningCells.add(current.cells[i]);
1088                         }
1089                         cells.append(current.cells[i]);
1090                     }
1091                 }
1092             }
1093             // Sort the dirty cells by paint order.
1094             std::stable_sort(cells.begin(), cells.end(), compareCellPositions);
1095             int size = cells.size();
1096             // Paint the cells.
1097             for (int i = 0; i < size; ++i)
1098                 paintCell(cells[i], paintInfo, tx, ty);
1099         }
1100     }
1101 }
1102
1103 void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*)
1104 {
1105     // FIXME: Examine cells and repaint only the rect the image paints in.
1106     repaint();
1107 }
1108
1109 void RenderTableSection::recalcCells()
1110 {
1111     m_cCol = 0;
1112     m_cRow = -1;
1113     clearGrid();
1114     m_gridRows = 0;
1115
1116     for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
1117         if (row->isTableRow()) {
1118             m_cRow++;
1119             m_cCol = 0;
1120             if (!ensureRows(m_cRow + 1))
1121                 break;
1122             
1123             RenderTableRow* tableRow = toRenderTableRow(row);
1124             m_grid[m_cRow].rowRenderer = tableRow;
1125             setRowHeightToRowStyleHeightIfNotRelative(&m_grid[m_cRow]);
1126
1127             for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
1128                 if (cell->isTableCell())
1129                     addCell(toRenderTableCell(cell), tableRow);
1130             }
1131         }
1132     }
1133     m_needsCellRecalc = false;
1134     setNeedsLayout(true);
1135 }
1136
1137 void RenderTableSection::clearGrid()
1138 {
1139     int rows = m_gridRows;
1140     while (rows--)
1141         delete m_grid[rows].row;
1142 }
1143
1144 int RenderTableSection::numColumns() const
1145 {
1146     int result = 0;
1147     
1148     for (int r = 0; r < m_gridRows; ++r) {
1149         for (int c = result; c < table()->numEffCols(); ++c) {
1150             const CellStruct& cell = cellAt(r, c);
1151             if (cell.hasCells() || cell.inColSpan)
1152                 result = c;
1153         }
1154     }
1155     
1156     return result + 1;
1157 }
1158
1159 void RenderTableSection::appendColumn(int pos)
1160 {
1161     for (int row = 0; row < m_gridRows; ++row)
1162         m_grid[row].row->resize(pos + 1);
1163 }
1164
1165 void RenderTableSection::splitColumn(int pos, int first)
1166 {
1167     if (m_cCol > pos)
1168         m_cCol++;
1169     for (int row = 0; row < m_gridRows; ++row) {
1170         Row& r = *m_grid[row].row;
1171         r.insert(pos + 1, CellStruct());
1172         if (r[pos].hasCells()) {
1173             r[pos + 1].cells.append(r[pos].cells);
1174             RenderTableCell* cell = r[pos].primaryCell();
1175             ASSERT(cell);
1176             int colleft = cell->colSpan() - r[pos].inColSpan;
1177             if (first > colleft)
1178               r[pos + 1].inColSpan = 0;
1179             else
1180               r[pos + 1].inColSpan = first + r[pos].inColSpan;
1181         } else {
1182             r[pos + 1].inColSpan = 0;
1183         }
1184     }
1185 }
1186
1187 // Hit Testing
1188 bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction action)
1189 {
1190     // If we have no children then we have nothing to do.
1191     if (!firstChild())
1192         return false;
1193
1194     // Table sections cannot ever be hit tested.  Effectively they do not exist.
1195     // Just forward to our children always.
1196     tx += x();
1197     ty += y();
1198
1199     if (hasOverflowClip() && !overflowClipRect(tx, ty).intersects(result.rectFromPoint(xPos, yPos)))
1200         return false;
1201
1202     if (m_hasOverflowingCell) {
1203         for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1204             // FIXME: We have to skip over inline flows, since they can show up inside table rows
1205             // at the moment (a demoted inline <form> for example). If we ever implement a
1206             // table-specific hit-test method (which we should do for performance reasons anyway),
1207             // then we can remove this check.
1208             if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && child->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
1209                 updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
1210                 return true;
1211             }
1212         }
1213         return false;
1214     }
1215
1216     int relativeY = yPos - ty;
1217     // leftrow corresponds to the first row that starts after the y mouse position
1218     unsigned leftrow = std::upper_bound(m_rowPos.begin(), m_rowPos.end(), relativeY) - m_rowPos.begin();
1219     if (leftrow == m_rowPos.size())
1220         return false;
1221     // Grab the last row that starts before the y mouse position.
1222     if (leftrow > 0)
1223         --leftrow;
1224
1225     Vector<int>& columnPos = table()->columnPositions();
1226     bool rtl = !style()->isLeftToRightDirection();
1227     int relativeX = xPos - tx;
1228     if (rtl)
1229         relativeX = columnPos[columnPos.size() - 1] - relativeX;
1230
1231     unsigned leftcol = std::lower_bound(columnPos.begin(), columnPos.end(), relativeX) - columnPos.begin();
1232     if (leftcol == columnPos.size())
1233         return false;
1234     if (leftcol > 0)
1235         --leftcol;
1236
1237     CellStruct& current = cellAt(leftrow, leftcol);
1238
1239     // If the cell is empty, there's nothing to do
1240     if (!current.hasCells())
1241         return false;
1242
1243     for (int i = current.cells.size() - 1; i >= 0; --i) {
1244         RenderTableCell* cell = current.cells[i];
1245         if (static_cast<RenderObject*>(cell)->nodeAtPoint(request, result, xPos, yPos, tx, ty, action)) {
1246             updateHitTestResult(result, IntPoint(xPos - tx, yPos - ty));
1247             return true;
1248         }
1249     }
1250     return false;
1251
1252 }
1253
1254 } // namespace WebCore