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