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