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