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