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