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