~ubuntu-branches/ubuntu/maverick/webkit/maverick

« back to all changes in this revision

Viewing changes to WebCore/rendering/RenderTableSection.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2007-08-19 15:54:12 UTC
  • Revision ID: james.westby@ubuntu.com-20070819155412-uxxg1h9plpghmtbi
Tags: upstream-0~svn25144
ImportĀ upstreamĀ versionĀ 0~svn25144

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place - Suite 330,
 
25
 * Boston, MA 02111-1307, 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) {
 
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