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