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 "core/rendering/RenderTableSection.h"
     28 
     29 // FIXME: Remove 'RuntimeEnabledFeatures.h' when http://crbug.com/78724 is closed.
     30 #include "RuntimeEnabledFeatures.h"
     31 #include <limits>
     32 #include "core/rendering/HitTestResult.h"
     33 #include "core/rendering/PaintInfo.h"
     34 #include "core/rendering/RenderTableCell.h"
     35 #include "core/rendering/RenderTableCol.h"
     36 #include "core/rendering/RenderTableRow.h"
     37 #include "core/rendering/RenderView.h"
     38 #include "wtf/HashSet.h"
     39 #include "wtf/Vector.h"
     40 
     41 using namespace std;
     42 
     43 namespace WebCore {
     44 
     45 using namespace HTMLNames;
     46 
     47 // Those 2 variables are used to balance the memory consumption vs the repaint time on big tables.
     48 static unsigned gMinTableSizeToUseFastPaintPathWithOverflowingCell = 75 * 75;
     49 static float gMaxAllowedOverflowingCellRatioForFastPaintPath = 0.1f;
     50 
     51 static inline void setRowLogicalHeightToRowStyleLogicalHeight(RenderTableSection::RowStruct& row)
     52 {
     53     ASSERT(row.rowRenderer);
     54     row.logicalHeight = row.rowRenderer->style()->logicalHeight();
     55 }
     56 
     57 static inline void updateLogicalHeightForCell(RenderTableSection::RowStruct& row, const RenderTableCell* cell)
     58 {
     59     // We ignore height settings on rowspan cells.
     60     if (cell->rowSpan() != 1)
     61         return;
     62 
     63     Length logicalHeight = cell->style()->logicalHeight();
     64     if (logicalHeight.isPositive()) {
     65         Length cRowLogicalHeight = row.logicalHeight;
     66         switch (logicalHeight.type()) {
     67         case Percent:
     68             if (!(cRowLogicalHeight.isPercent())
     69                 || (cRowLogicalHeight.isPercent() && cRowLogicalHeight.percent() < logicalHeight.percent()))
     70                 row.logicalHeight = logicalHeight;
     71             break;
     72         case Fixed:
     73             if (cRowLogicalHeight.type() < Percent
     74                 || (cRowLogicalHeight.isFixed() && cRowLogicalHeight.value() < logicalHeight.value()))
     75                 row.logicalHeight = logicalHeight;
     76             break;
     77         default:
     78             break;
     79         }
     80     }
     81 }
     82 
     83 
     84 RenderTableSection::RenderTableSection(Element* element)
     85     : RenderBox(element)
     86     , m_cCol(0)
     87     , m_cRow(0)
     88     , m_outerBorderStart(0)
     89     , m_outerBorderEnd(0)
     90     , m_outerBorderBefore(0)
     91     , m_outerBorderAfter(0)
     92     , m_needsCellRecalc(false)
     93     , m_hasMultipleCellLevels(false)
     94 {
     95     // init RenderObject attributes
     96     setInline(false); // our object is not Inline
     97 }
     98 
     99 RenderTableSection::~RenderTableSection()
    100 {
    101 }
    102 
    103 void RenderTableSection::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    104 {
    105     RenderBox::styleDidChange(diff, oldStyle);
    106     propagateStyleToAnonymousChildren();
    107 
    108     // If border was changed, notify table.
    109     RenderTable* table = this->table();
    110     if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border())
    111         table->invalidateCollapsedBorders();
    112 }
    113 
    114 void RenderTableSection::willBeRemovedFromTree()
    115 {
    116     RenderBox::willBeRemovedFromTree();
    117 
    118     // Preventively invalidate our cells as we may be re-inserted into
    119     // a new table which would require us to rebuild our structure.
    120     setNeedsCellRecalc();
    121 }
    122 
    123 void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild)
    124 {
    125     if (!child->isTableRow()) {
    126         RenderObject* last = beforeChild;
    127         if (!last)
    128             last = lastChild();
    129         if (last && last->isAnonymous() && !last->isBeforeOrAfterContent()) {
    130             if (beforeChild == last)
    131                 beforeChild = last->firstChild();
    132             last->addChild(child, beforeChild);
    133             return;
    134         }
    135 
    136         if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
    137             RenderObject* row = beforeChild->previousSibling();
    138             if (row && row->isTableRow() && row->isAnonymous()) {
    139                 row->addChild(child);
    140                 return;
    141             }
    142         }
    143 
    144         // If beforeChild is inside an anonymous cell/row, insert into the cell or into
    145         // the anonymous row containing it, if there is one.
    146         RenderObject* lastBox = last;
    147         while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableRow())
    148             lastBox = lastBox->parent();
    149         if (lastBox && lastBox->isAnonymous() && !lastBox->isBeforeOrAfterContent()) {
    150             lastBox->addChild(child, beforeChild);
    151             return;
    152         }
    153 
    154         RenderObject* row = RenderTableRow::createAnonymousWithParentRenderer(this);
    155         addChild(row, beforeChild);
    156         row->addChild(child);
    157         return;
    158     }
    159 
    160     if (beforeChild)
    161         setNeedsCellRecalc();
    162 
    163     unsigned insertionRow = m_cRow;
    164     ++m_cRow;
    165     m_cCol = 0;
    166 
    167     ensureRows(m_cRow);
    168 
    169     RenderTableRow* row = toRenderTableRow(child);
    170     m_grid[insertionRow].rowRenderer = row;
    171     row->setRowIndex(insertionRow);
    172 
    173     if (!beforeChild)
    174         setRowLogicalHeightToRowStyleLogicalHeight(m_grid[insertionRow]);
    175 
    176     if (beforeChild && beforeChild->parent() != this)
    177         beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
    178 
    179     ASSERT(!beforeChild || beforeChild->isTableRow());
    180     RenderBox::addChild(child, beforeChild);
    181 }
    182 
    183 void RenderTableSection::ensureRows(unsigned numRows)
    184 {
    185     if (numRows <= m_grid.size())
    186         return;
    187 
    188     unsigned oldSize = m_grid.size();
    189     m_grid.grow(numRows);
    190 
    191     unsigned effectiveColumnCount = max(1u, table()->numEffCols());
    192     for (unsigned row = oldSize; row < m_grid.size(); ++row)
    193         m_grid[row].row.grow(effectiveColumnCount);
    194 }
    195 
    196 void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row)
    197 {
    198     // We don't insert the cell if we need cell recalc as our internal columns' representation
    199     // will have drifted from the table's representation. Also recalcCells will call addCell
    200     // at a later time after sync'ing our columns' with the table's.
    201     if (needsCellRecalc())
    202         return;
    203 
    204     unsigned rSpan = cell->rowSpan();
    205     unsigned cSpan = cell->colSpan();
    206     const Vector<RenderTable::ColumnStruct>& columns = table()->columns();
    207     unsigned nCols = columns.size();
    208     unsigned insertionRow = row->rowIndex();
    209 
    210     // ### mozilla still seems to do the old HTML way, even for strict DTD
    211     // (see the annotation on table cell layouting in the CSS specs and the testcase below:
    212     // <TABLE border>
    213     // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
    214     // <TR><TD colspan="2">5
    215     // </TABLE>
    216     while (m_cCol < nCols && (cellAt(insertionRow, m_cCol).hasCells() || cellAt(insertionRow, m_cCol).inColSpan))
    217         m_cCol++;
    218 
    219     updateLogicalHeightForCell(m_grid[insertionRow], cell);
    220 
    221     ensureRows(insertionRow + rSpan);
    222 
    223     m_grid[insertionRow].rowRenderer = row;
    224 
    225     unsigned col = m_cCol;
    226     // tell the cell where it is
    227     bool inColSpan = false;
    228     while (cSpan) {
    229         unsigned currentSpan;
    230         if (m_cCol >= nCols) {
    231             table()->appendColumn(cSpan);
    232             currentSpan = cSpan;
    233         } else {
    234             if (cSpan < columns[m_cCol].span)
    235                 table()->splitColumn(m_cCol, cSpan);
    236             currentSpan = columns[m_cCol].span;
    237         }
    238         for (unsigned r = 0; r < rSpan; r++) {
    239             CellStruct& c = cellAt(insertionRow + r, m_cCol);
    240             ASSERT(cell);
    241             c.cells.append(cell);
    242             // If cells overlap then we take the slow path for painting.
    243             if (c.cells.size() > 1)
    244                 m_hasMultipleCellLevels = true;
    245             if (inColSpan)
    246                 c.inColSpan = true;
    247         }
    248         m_cCol++;
    249         cSpan -= currentSpan;
    250         inColSpan = true;
    251     }
    252     cell->setCol(table()->effColToCol(col));
    253 }
    254 
    255 void RenderTableSection::populateSpanningRowsHeightFromCell(RenderTableCell* cell, struct SpanningRowsHeight& spanningRowsHeight)
    256 {
    257     const unsigned rowSpan = cell->rowSpan();
    258     const unsigned rowIndex = cell->rowIndex();
    259 
    260     spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing = cell->logicalHeightForRowSizing();
    261 
    262     spanningRowsHeight.rowHeight.resize(rowSpan);
    263     spanningRowsHeight.totalRowsHeight = 0;
    264     for (unsigned row = 0; row < rowSpan; row++) {
    265         unsigned actualRow = row + rowIndex;
    266         spanningRowsHeight.rowHeight[row] = m_rowPos[actualRow + 1] - m_rowPos[actualRow] - borderSpacingForRow(actualRow);
    267         spanningRowsHeight.totalRowsHeight += spanningRowsHeight.rowHeight[row];
    268         spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing -= borderSpacingForRow(actualRow);
    269     }
    270     // We don't span the following row so its border-spacing (if any) should be included.
    271     spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing += borderSpacingForRow(rowIndex + rowSpan - 1);
    272 }
    273 
    274 void RenderTableSection::distributeExtraRowSpanHeightToPercentRows(RenderTableCell* cell, int totalPercent, int& extraRowSpanningHeight, Vector<int>& rowsHeight)
    275 {
    276     if (!extraRowSpanningHeight || !totalPercent)
    277         return;
    278 
    279     const unsigned rowSpan = cell->rowSpan();
    280     const unsigned rowIndex = cell->rowIndex();
    281     int percent = min(totalPercent, 100);
    282     const int tableHeight = m_rowPos[m_grid.size()] + extraRowSpanningHeight;
    283 
    284     // Our algorithm matches Firefox. Extra spanning height would be distributed Only in first percent height rows
    285     // those total percent is 100. Other percent rows would be uneffected even extra spanning height is remain.
    286     int accumulatedPositionIncrease = 0;
    287     for (unsigned row = rowIndex; row < (rowIndex + rowSpan); row++) {
    288         if (percent > 0 && extraRowSpanningHeight > 0) {
    289             if (m_grid[row].logicalHeight.isPercent()) {
    290                 int toAdd = (tableHeight * m_grid[row].logicalHeight.percent() / 100) - rowsHeight[row - rowIndex];
    291                 // FIXME: Note that this is wrong if we have a percentage above 100% and may make us grow
    292                 // above the available space.
    293 
    294                 toAdd = min(toAdd, extraRowSpanningHeight);
    295                 accumulatedPositionIncrease += toAdd;
    296                 extraRowSpanningHeight -= toAdd;
    297                 percent -= m_grid[row].logicalHeight.percent();
    298             }
    299         }
    300         m_rowPos[row + 1] += accumulatedPositionIncrease;
    301     }
    302 }
    303 
    304 void RenderTableSection::distributeExtraRowSpanHeightToAutoRows(RenderTableCell* cell, int totalAutoRowsHeight, int& extraRowSpanningHeight, Vector<int>& rowsHeight)
    305 {
    306     if (!extraRowSpanningHeight || !totalAutoRowsHeight)
    307         return;
    308 
    309     const unsigned rowSpan = cell->rowSpan();
    310     const unsigned rowIndex = cell->rowIndex();
    311     int accumulatedPositionIncrease = 0;
    312     int remainder = 0;
    313 
    314     // Aspect ratios of auto rows should not change otherwise table may look different than user expected.
    315     // So extra height distributed in auto spanning rows based on their weight in spanning cell.
    316     for (unsigned row = rowIndex; row < (rowIndex + rowSpan); row++) {
    317         if (m_grid[row].logicalHeight.isAuto()) {
    318             accumulatedPositionIncrease += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) / totalAutoRowsHeight;
    319             remainder += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) % totalAutoRowsHeight;
    320 
    321             // While whole extra spanning height is distributing in auto spanning rows, rational parts remains
    322             // in every integer division. So accumulating all remainder part in integer division and when total remainder
    323             // is equvalent to divisor then 1 unit increased in row position.
    324             // Note that this algorithm is biased towards adding more space towards the lower rows.
    325             if (remainder >= totalAutoRowsHeight) {
    326                 remainder -= totalAutoRowsHeight;
    327                 accumulatedPositionIncrease++;
    328             }
    329         }
    330         m_rowPos[row + 1] += accumulatedPositionIncrease;
    331     }
    332 
    333     ASSERT(!remainder);
    334 
    335     extraRowSpanningHeight -= accumulatedPositionIncrease;
    336 }
    337 
    338 void RenderTableSection::distributeExtraRowSpanHeightToRemainingRows(RenderTableCell* cell, int totalRemainingRowsHeight, int& extraRowSpanningHeight, Vector<int>& rowsHeight)
    339 {
    340     if (!extraRowSpanningHeight || !totalRemainingRowsHeight)
    341         return;
    342 
    343     const unsigned rowSpan = cell->rowSpan();
    344     const unsigned rowIndex = cell->rowIndex();
    345     int accumulatedPositionIncrease = 0;
    346     int remainder = 0;
    347 
    348     // Aspect ratios of the rows should not change otherwise table may look different than user expected.
    349     // So extra height distribution in remaining spanning rows based on their weight in spanning cell.
    350     for (unsigned row = rowIndex; row < (rowIndex + rowSpan); row++) {
    351         if (!m_grid[row].logicalHeight.isPercent()) {
    352             accumulatedPositionIncrease += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) / totalRemainingRowsHeight;
    353             remainder += (extraRowSpanningHeight * rowsHeight[row - rowIndex]) % totalRemainingRowsHeight;
    354 
    355             // While whole extra spanning height is distributing in remaining spanning rows, rational parts remains
    356             // in every integer division. So accumulating all remainder part in integer division and when total remainder
    357             // is equvalent to divisor then 1 unit increased in row position.
    358             // Note that this algorithm is biased towards adding more space towards the lower rows.
    359             if (remainder >= totalRemainingRowsHeight) {
    360                 remainder -= totalRemainingRowsHeight;
    361                 accumulatedPositionIncrease++;
    362             }
    363         }
    364         m_rowPos[row + 1] += accumulatedPositionIncrease;
    365     }
    366 
    367     ASSERT(!remainder);
    368 
    369     extraRowSpanningHeight -= accumulatedPositionIncrease;
    370 }
    371 
    372 // To avoid unneeded extra height distributions, we apply the following sorting algorithm:
    373 // 1. We sort by increasing start row but decreasing last row (ie the top-most, shortest cells first).
    374 // 2. For cells spanning the same rows, we sort by intrinsic size.
    375 static bool compareRowSpanCellsInHeightDistributionOrder(const RenderTableCell* cell2, const RenderTableCell* cell1)
    376 {
    377     unsigned cellRowIndex1 = cell1->rowIndex();
    378     unsigned cellRowSpan1 = cell1->rowSpan();
    379     unsigned cellRowIndex2 = cell2->rowIndex();
    380     unsigned cellRowSpan2 = cell2->rowSpan();
    381 
    382     if (cellRowIndex1 == cellRowIndex2 && cellRowSpan1 == cellRowSpan2)
    383         return (cell2->logicalHeightForRowSizing() > cell1->logicalHeightForRowSizing());
    384 
    385     return (cellRowIndex2 >= cellRowIndex1 && (cellRowIndex2 + cellRowSpan2) <= (cellRowIndex1 + cellRowSpan1));
    386 }
    387 
    388 // Distribute rowSpan cell height in rows those comes in rowSpan cell based on the ratio of row's height if
    389 // 1. RowSpan cell height is greater then the total height of rows in rowSpan cell
    390 void RenderTableSection::distributeRowSpanHeightToRows(SpanningRenderTableCells& rowSpanCells)
    391 {
    392     ASSERT(rowSpanCells.size());
    393 
    394     // 'rowSpanCells' list is already sorted based on the cells rowIndex in ascending order
    395     // Arrange row spanning cell in the order in which we need to process first.
    396     std::sort(rowSpanCells.begin(), rowSpanCells.end(), compareRowSpanCellsInHeightDistributionOrder);
    397 
    398     unsigned extraHeightToPropagate = 0;
    399     unsigned lastRowIndex = 0;
    400     unsigned lastRowSpan = 0;
    401 
    402     for (unsigned i = 0; i < rowSpanCells.size(); i++) {
    403         RenderTableCell* cell = rowSpanCells[i];
    404 
    405         unsigned rowIndex = cell->rowIndex();
    406 
    407         unsigned rowSpan = cell->rowSpan();
    408 
    409         unsigned spanningCellEndIndex = rowIndex + rowSpan;
    410         unsigned lastSpanningCellEndIndex = lastRowIndex + lastRowSpan;
    411 
    412         // Only heightest spanning cell will distribute it's extra height in row if more then one spanning cells
    413         // present at same level.
    414         if (rowIndex == lastRowIndex && rowSpan == lastRowSpan)
    415             continue;
    416 
    417         int originalBeforePosition = m_rowPos[spanningCellEndIndex];
    418 
    419         // When 2 spanning cells are ending at same row index then while extra height distribution of first spanning
    420         // cell updates position of the last row so getting the original position of the last row in second spanning
    421         // cell need to reduce the height changed by first spanning cell.
    422         if (spanningCellEndIndex == lastSpanningCellEndIndex)
    423             originalBeforePosition -= extraHeightToPropagate;
    424 
    425         if (extraHeightToPropagate) {
    426             for (unsigned row = lastSpanningCellEndIndex + 1; row <= spanningCellEndIndex; row++)
    427                 m_rowPos[row] += extraHeightToPropagate;
    428         }
    429 
    430         lastRowIndex = rowIndex;
    431         lastRowSpan = rowSpan;
    432 
    433         struct SpanningRowsHeight spanningRowsHeight;
    434 
    435         populateSpanningRowsHeightFromCell(cell, spanningRowsHeight);
    436 
    437         if (!spanningRowsHeight.totalRowsHeight || spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing <= spanningRowsHeight.totalRowsHeight)
    438             continue;
    439 
    440         int totalPercent = 0;
    441         int totalAutoRowsHeight = 0;
    442         int totalRemainingRowsHeight = spanningRowsHeight.totalRowsHeight;
    443 
    444         // FIXME: Inner spanning cell height should not change if it have fixed height when it's parent spanning cell
    445         // is distributing it's extra height in rows.
    446 
    447         // Calculate total percentage, total auto rows height and total rows height except percent rows.
    448         for (unsigned row = rowIndex; row < spanningCellEndIndex; row++) {
    449             if (m_grid[row].logicalHeight.isPercent()) {
    450                 totalPercent += m_grid[row].logicalHeight.percent();
    451                 totalRemainingRowsHeight -= spanningRowsHeight.rowHeight[row - rowIndex];
    452             } else if (m_grid[row].logicalHeight.isAuto()) {
    453                 totalAutoRowsHeight += spanningRowsHeight.rowHeight[row - rowIndex];
    454             }
    455         }
    456 
    457         int extraRowSpanningHeight = spanningRowsHeight.spanningCellHeightIgnoringBorderSpacing - spanningRowsHeight.totalRowsHeight;
    458 
    459         distributeExtraRowSpanHeightToPercentRows(cell, totalPercent, extraRowSpanningHeight, spanningRowsHeight.rowHeight);
    460         distributeExtraRowSpanHeightToAutoRows(cell, totalAutoRowsHeight, extraRowSpanningHeight, spanningRowsHeight.rowHeight);
    461         distributeExtraRowSpanHeightToRemainingRows(cell, totalRemainingRowsHeight, extraRowSpanningHeight, spanningRowsHeight.rowHeight);
    462 
    463         ASSERT(!extraRowSpanningHeight);
    464 
    465         // Getting total changed height in the table
    466         extraHeightToPropagate = m_rowPos[spanningCellEndIndex] - originalBeforePosition;
    467     }
    468 
    469     if (extraHeightToPropagate) {
    470         // Apply changed height by rowSpan cells to rows present at the end of the table
    471         for (unsigned row = lastRowIndex + lastRowSpan + 1; row <= m_grid.size(); row++)
    472             m_rowPos[row] += extraHeightToPropagate;
    473     }
    474 }
    475 
    476 // Find out the baseline of the cell
    477 // If the cell's baseline is more then the row's baseline then the cell's baseline become the row's baseline
    478 // and if the row's baseline goes out of the row's boundries then adjust row height accordingly.
    479 void RenderTableSection::updateBaselineForCell(RenderTableCell* cell, unsigned row, LayoutUnit& baselineDescent)
    480 {
    481     if (!cell->isBaselineAligned())
    482         return;
    483 
    484     // Ignoring the intrinsic padding as it depends on knowing the row's baseline, which won't be accurate
    485     // until the end of this function.
    486     LayoutUnit baselinePosition = cell->cellBaselinePosition() - cell->intrinsicPaddingBefore();
    487     if (baselinePosition > cell->borderBefore() + (cell->paddingBefore() - cell->intrinsicPaddingBefore())) {
    488         m_grid[row].baseline = max(m_grid[row].baseline, baselinePosition);
    489 
    490         int cellStartRowBaselineDescent = 0;
    491         if (cell->rowSpan() == 1) {
    492             baselineDescent = max(baselineDescent, cell->logicalHeightForRowSizing() - baselinePosition);
    493             cellStartRowBaselineDescent = baselineDescent;
    494         }
    495         m_rowPos[row + 1] = max<int>(m_rowPos[row + 1], m_rowPos[row] + m_grid[row].baseline + cellStartRowBaselineDescent);
    496     }
    497 }
    498 
    499 int RenderTableSection::calcRowLogicalHeight()
    500 {
    501 #ifndef NDEBUG
    502     SetLayoutNeededForbiddenScope layoutForbiddenScope(this);
    503 #endif
    504 
    505     ASSERT(!needsLayout());
    506 
    507     RenderTableCell* cell;
    508 
    509     RenderView* viewRenderer = view();
    510     LayoutStateMaintainer statePusher(viewRenderer);
    511 
    512     m_rowPos.resize(m_grid.size() + 1);
    513     m_rowPos[0] = table()->vBorderSpacing();
    514 
    515     SpanningRenderTableCells rowSpanCells;
    516 
    517     for (unsigned r = 0; r < m_grid.size(); r++) {
    518         m_grid[r].baseline = 0;
    519         LayoutUnit baselineDescent = 0;
    520 
    521         // Our base size is the biggest logical height from our cells' styles (excluding row spanning cells).
    522         m_rowPos[r + 1] = max(m_rowPos[r] + minimumValueForLength(m_grid[r].logicalHeight, 0, viewRenderer).round(), 0);
    523 
    524         Row& row = m_grid[r].row;
    525         unsigned totalCols = row.size();
    526 
    527         for (unsigned c = 0; c < totalCols; c++) {
    528             CellStruct& current = cellAt(r, c);
    529             for (unsigned i = 0; i < current.cells.size(); i++) {
    530                 cell = current.cells[i];
    531                 if (current.inColSpan && cell->rowSpan() == 1)
    532                     continue;
    533 
    534                 if (RuntimeEnabledFeatures::rowSpanLogicalHeightSpreadingEnabled()) {
    535                     if (cell->rowSpan() > 1) {
    536                         // For row spanning cells, we only handle them for the first row they span. This ensures we take their baseline into account.
    537                         if (cell->rowIndex() == r) {
    538                             rowSpanCells.append(cell);
    539 
    540                             // Find out the baseline. The baseline is set on the first row in a rowSpan.
    541                             updateBaselineForCell(cell, r, baselineDescent);
    542                         }
    543                         continue;
    544                     }
    545 
    546                     ASSERT(cell->rowSpan() == 1);
    547                 } else {
    548                     // FIXME: We add all the logical row of a rowspan to the last rows
    549                     // until crbug.com/78724 is fixed and the runtime flag removed.
    550                     // This avoids propagating temporary regressions while we fix the bug.
    551                     if ((cell->rowIndex() + cell->rowSpan() - 1) != r)
    552                         continue;
    553                 }
    554 
    555                 if (cell->hasOverrideHeight()) {
    556                     if (!statePusher.didPush()) {
    557                         // Technically, we should also push state for the row, but since
    558                         // rows don't push a coordinate transform, that's not necessary.
    559                         statePusher.push(this, locationOffset());
    560                     }
    561                     cell->clearIntrinsicPadding();
    562                     cell->clearOverrideSize();
    563                     cell->forceChildLayout();
    564                 }
    565 
    566                 if (RuntimeEnabledFeatures::rowSpanLogicalHeightSpreadingEnabled()) {
    567                     m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r] + cell->logicalHeightForRowSizing());
    568 
    569                     // Find out the baseline.
    570                     updateBaselineForCell(cell, r, baselineDescent);
    571                 } else {
    572                     // For row spanning cells, |r| is the last row in the span.
    573                     unsigned cellStartRow = cell->rowIndex();
    574 
    575                     m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[cellStartRow] + cell->logicalHeightForRowSizing());
    576 
    577                     // Find out the baseline.
    578                     updateBaselineForCell(cell, cellStartRow, baselineDescent);
    579                 }
    580             }
    581         }
    582 
    583         // Add the border-spacing to our final position.
    584         m_rowPos[r + 1] += borderSpacingForRow(r);
    585         m_rowPos[r + 1] = max(m_rowPos[r + 1], m_rowPos[r]);
    586     }
    587 
    588     if (!rowSpanCells.isEmpty()) {
    589         ASSERT(RuntimeEnabledFeatures::rowSpanLogicalHeightSpreadingEnabled());
    590         distributeRowSpanHeightToRows(rowSpanCells);
    591     }
    592 
    593     ASSERT(!needsLayout());
    594 
    595     statePusher.pop();
    596 
    597     return m_rowPos[m_grid.size()];
    598 }
    599 
    600 void RenderTableSection::layout()
    601 {
    602     StackStats::LayoutCheckPoint layoutCheckPoint;
    603     ASSERT(needsLayout());
    604     ASSERT(!needsCellRecalc());
    605     ASSERT(!table()->needsSectionRecalc());
    606 
    607     // addChild may over-grow m_grid but we don't want to throw away the memory too early as addChild
    608     // can be called in a loop (e.g during parsing). Doing it now ensures we have a stable-enough structure.
    609     m_grid.shrinkToFit();
    610 
    611     LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
    612 
    613     const Vector<int>& columnPos = table()->columnPositions();
    614 
    615     for (unsigned r = 0; r < m_grid.size(); ++r) {
    616         Row& row = m_grid[r].row;
    617         unsigned cols = row.size();
    618         // First, propagate our table layout's information to the cells. This will mark the row as needing layout
    619         // if there was a column logical width change.
    620         for (unsigned startColumn = 0; startColumn < cols; ++startColumn) {
    621             CellStruct& current = row[startColumn];
    622             RenderTableCell* cell = current.primaryCell();
    623             if (!cell || current.inColSpan)
    624                 continue;
    625 
    626             unsigned endCol = startColumn;
    627             unsigned cspan = cell->colSpan();
    628             while (cspan && endCol < cols) {
    629                 ASSERT(endCol < table()->columns().size());
    630                 cspan -= table()->columns()[endCol].span;
    631                 endCol++;
    632             }
    633             int tableLayoutLogicalWidth = columnPos[endCol] - columnPos[startColumn] - table()->hBorderSpacing();
    634             cell->setCellLogicalWidth(tableLayoutLogicalWidth);
    635         }
    636 
    637         if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer)
    638             rowRenderer->layoutIfNeeded();
    639     }
    640 
    641     statePusher.pop();
    642     clearNeedsLayout();
    643 }
    644 
    645 void RenderTableSection::distributeExtraLogicalHeightToPercentRows(int& extraLogicalHeight, int totalPercent)
    646 {
    647     if (!totalPercent)
    648         return;
    649 
    650     unsigned totalRows = m_grid.size();
    651     int totalHeight = m_rowPos[totalRows] + extraLogicalHeight;
    652     int totalLogicalHeightAdded = 0;
    653     totalPercent = min(totalPercent, 100);
    654     int rowHeight = m_rowPos[1] - m_rowPos[0];
    655     for (unsigned r = 0; r < totalRows; ++r) {
    656         if (totalPercent > 0 && m_grid[r].logicalHeight.isPercent()) {
    657             int toAdd = min<int>(extraLogicalHeight, (totalHeight * m_grid[r].logicalHeight.percent() / 100) - rowHeight);
    658             // If toAdd is negative, then we don't want to shrink the row (this bug
    659             // affected Outlook Web Access).
    660             toAdd = max(0, toAdd);
    661             totalLogicalHeightAdded += toAdd;
    662             extraLogicalHeight -= toAdd;
    663             totalPercent -= m_grid[r].logicalHeight.percent();
    664         }
    665         ASSERT(totalRows >= 1);
    666         if (r < totalRows - 1)
    667             rowHeight = m_rowPos[r + 2] - m_rowPos[r + 1];
    668         m_rowPos[r + 1] += totalLogicalHeightAdded;
    669     }
    670 }
    671 
    672 void RenderTableSection::distributeExtraLogicalHeightToAutoRows(int& extraLogicalHeight, unsigned autoRowsCount)
    673 {
    674     if (!autoRowsCount)
    675         return;
    676 
    677     int totalLogicalHeightAdded = 0;
    678     for (unsigned r = 0; r < m_grid.size(); ++r) {
    679         if (autoRowsCount > 0 && m_grid[r].logicalHeight.isAuto()) {
    680             // Recomputing |extraLogicalHeightForRow| guarantees that we properly ditribute round |extraLogicalHeight|.
    681             int extraLogicalHeightForRow = extraLogicalHeight / autoRowsCount;
    682             totalLogicalHeightAdded += extraLogicalHeightForRow;
    683             extraLogicalHeight -= extraLogicalHeightForRow;
    684             --autoRowsCount;
    685         }
    686         m_rowPos[r + 1] += totalLogicalHeightAdded;
    687     }
    688 }
    689 
    690 void RenderTableSection::distributeRemainingExtraLogicalHeight(int& extraLogicalHeight)
    691 {
    692     unsigned totalRows = m_grid.size();
    693 
    694     if (extraLogicalHeight <= 0 || !m_rowPos[totalRows])
    695         return;
    696 
    697     // FIXME: m_rowPos[totalRows] - m_rowPos[0] is the total rows' size.
    698     int totalRowSize = m_rowPos[totalRows];
    699     int totalLogicalHeightAdded = 0;
    700     int previousRowPosition = m_rowPos[0];
    701     for (unsigned r = 0; r < totalRows; r++) {
    702         // weight with the original height
    703         totalLogicalHeightAdded += extraLogicalHeight * (m_rowPos[r + 1] - previousRowPosition) / totalRowSize;
    704         previousRowPosition = m_rowPos[r + 1];
    705         m_rowPos[r + 1] += totalLogicalHeightAdded;
    706     }
    707 
    708     extraLogicalHeight -= totalLogicalHeightAdded;
    709 }
    710 
    711 int RenderTableSection::distributeExtraLogicalHeightToRows(int extraLogicalHeight)
    712 {
    713     if (!extraLogicalHeight)
    714         return extraLogicalHeight;
    715 
    716     unsigned totalRows = m_grid.size();
    717     if (!totalRows)
    718         return extraLogicalHeight;
    719 
    720     if (!m_rowPos[totalRows] && nextSibling())
    721         return extraLogicalHeight;
    722 
    723     unsigned autoRowsCount = 0;
    724     int totalPercent = 0;
    725     for (unsigned r = 0; r < totalRows; r++) {
    726         if (m_grid[r].logicalHeight.isAuto())
    727             ++autoRowsCount;
    728         else if (m_grid[r].logicalHeight.isPercent())
    729             totalPercent += m_grid[r].logicalHeight.percent();
    730     }
    731 
    732     int remainingExtraLogicalHeight = extraLogicalHeight;
    733     distributeExtraLogicalHeightToPercentRows(remainingExtraLogicalHeight, totalPercent);
    734     distributeExtraLogicalHeightToAutoRows(remainingExtraLogicalHeight, autoRowsCount);
    735     distributeRemainingExtraLogicalHeight(remainingExtraLogicalHeight);
    736     return extraLogicalHeight - remainingExtraLogicalHeight;
    737 }
    738 
    739 void RenderTableSection::layoutRows()
    740 {
    741 #ifndef NDEBUG
    742     SetLayoutNeededForbiddenScope layoutForbiddenScope(this);
    743 #endif
    744 
    745     ASSERT(!needsLayout());
    746 
    747     unsigned totalRows = m_grid.size();
    748 
    749     // Set the width of our section now.  The rows will also be this width.
    750     setLogicalWidth(table()->contentLogicalWidth());
    751     m_overflow.clear();
    752     m_overflowingCells.clear();
    753     m_forceSlowPaintPathWithOverflowingCell = false;
    754 
    755     int vspacing = table()->vBorderSpacing();
    756     unsigned nEffCols = table()->numEffCols();
    757 
    758     LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode());
    759 
    760     for (unsigned r = 0; r < totalRows; r++) {
    761         // Set the row's x/y position and width/height.
    762         if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) {
    763             rowRenderer->setLocation(LayoutPoint(0, m_rowPos[r]));
    764             rowRenderer->setLogicalWidth(logicalWidth());
    765             rowRenderer->setLogicalHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing);
    766             rowRenderer->updateLayerTransform();
    767         }
    768 
    769         int rowHeightIncreaseForPagination = 0;
    770 
    771         for (unsigned c = 0; c < nEffCols; c++) {
    772             CellStruct& cs = cellAt(r, c);
    773             RenderTableCell* cell = cs.primaryCell();
    774 
    775             if (!cell || cs.inColSpan)
    776                 continue;
    777 
    778             int rowIndex = cell->rowIndex();
    779             int rHeight = m_rowPos[rowIndex + cell->rowSpan()] - m_rowPos[rowIndex] - vspacing;
    780 
    781             // Force percent height children to lay themselves out again.
    782             // This will cause these children to grow to fill the cell.
    783             // FIXME: There is still more work to do here to fully match WinIE (should
    784             // it become necessary to do so).  In quirks mode, WinIE behaves like we
    785             // do, but it will clip the cells that spill out of the table section.  In
    786             // strict mode, Mozilla and WinIE both regrow the table to accommodate the
    787             // new height of the cell (thus letting the percentages cause growth one
    788             // time only).  We may also not be handling row-spanning cells correctly.
    789             //
    790             // Note also the oddity where replaced elements always flex, and yet blocks/tables do
    791             // not necessarily flex.  WinIE is crazy and inconsistent, and we can't hope to
    792             // match the behavior perfectly, but we'll continue to refine it as we discover new
    793             // bugs. :)
    794             bool cellChildrenFlex = false;
    795             bool flexAllChildren = cell->style()->logicalHeight().isFixed()
    796                 || (!table()->style()->logicalHeight().isAuto() && rHeight != cell->logicalHeight());
    797 
    798             for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) {
    799                 if (!o->isText() && o->style()->logicalHeight().isPercent() && (flexAllChildren || o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow()))) {
    800                     // Tables with no sections do not flex.
    801                     if (!o->isTable() || toRenderTable(o)->hasSections()) {
    802                         o->setNeedsLayout(MarkOnlyThis);
    803                         cellChildrenFlex = true;
    804                     }
    805                 }
    806             }
    807 
    808             if (TrackedRendererListHashSet* percentHeightDescendants = cell->percentHeightDescendants()) {
    809                 TrackedRendererListHashSet::iterator end = percentHeightDescendants->end();
    810                 for (TrackedRendererListHashSet::iterator it = percentHeightDescendants->begin(); it != end; ++it) {
    811                     RenderBox* box = *it;
    812                     if (!box->isReplaced() && !box->scrollsOverflow() && !flexAllChildren)
    813                         continue;
    814 
    815                     while (box != cell) {
    816                         if (box->normalChildNeedsLayout())
    817                             break;
    818                         box->setChildNeedsLayout(MarkOnlyThis);
    819                         box = box->containingBlock();
    820                         ASSERT(box);
    821                         if (!box)
    822                             break;
    823                     }
    824                     cellChildrenFlex = true;
    825                 }
    826             }
    827 
    828             if (cellChildrenFlex) {
    829                 // Alignment within a cell is based off the calculated
    830                 // height, which becomes irrelevant once the cell has
    831                 // been resized based off its percentage.
    832                 cell->setOverrideLogicalContentHeightFromRowHeight(rHeight);
    833                 cell->forceChildLayout();
    834 
    835                 // If the baseline moved, we may have to update the data for our row. Find out the new baseline.
    836                 if (cell->isBaselineAligned()) {
    837                     LayoutUnit baseline = cell->cellBaselinePosition();
    838                     if (baseline > cell->borderBefore() + cell->paddingBefore())
    839                         m_grid[r].baseline = max(m_grid[r].baseline, baseline);
    840                 }
    841             }
    842 
    843             cell->computeIntrinsicPadding(rHeight);
    844 
    845             LayoutRect oldCellRect = cell->frameRect();
    846 
    847             setLogicalPositionForCell(cell, c);
    848 
    849             if (!cell->needsLayout() && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset())
    850                 cell->setChildNeedsLayout(MarkOnlyThis);
    851 
    852             cell->layoutIfNeeded();
    853 
    854             // FIXME: Make pagination work with vertical tables.
    855             if (view()->layoutState()->pageLogicalHeight() && cell->logicalHeight() != rHeight) {
    856                 // FIXME: Pagination might have made us change size. For now just shrink or grow the cell to fit without doing a relayout.
    857                 // We'll also do a basic increase of the row height to accommodate the cell if it's bigger, but this isn't quite right
    858                 // either. It's at least stable though and won't result in an infinite # of relayouts that may never stabilize.
    859                 if (cell->logicalHeight() > rHeight)
    860                     rowHeightIncreaseForPagination = max<int>(rowHeightIncreaseForPagination, cell->logicalHeight() - rHeight);
    861                 cell->setLogicalHeight(rHeight);
    862             }
    863 
    864             LayoutSize childOffset(cell->location() - oldCellRect.location());
    865             if (childOffset.width() || childOffset.height()) {
    866                 view()->addLayoutDelta(childOffset);
    867 
    868                 // If the child moved, we have to repaint it as well as any floating/positioned
    869                 // descendants.  An exception is if we need a layout.  In this case, we know we're going to
    870                 // repaint ourselves (and the child) anyway.
    871                 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
    872                     cell->repaintDuringLayoutIfMoved(oldCellRect);
    873             }
    874         }
    875         if (rowHeightIncreaseForPagination) {
    876             for (unsigned rowIndex = r + 1; rowIndex <= totalRows; rowIndex++)
    877                 m_rowPos[rowIndex] += rowHeightIncreaseForPagination;
    878             for (unsigned c = 0; c < nEffCols; ++c) {
    879                 Vector<RenderTableCell*, 1>& cells = cellAt(r, c).cells;
    880                 for (size_t i = 0; i < cells.size(); ++i)
    881                     cells[i]->setLogicalHeight(cells[i]->logicalHeight() + rowHeightIncreaseForPagination);
    882             }
    883         }
    884     }
    885 
    886     ASSERT(!needsLayout());
    887 
    888     setLogicalHeight(m_rowPos[totalRows]);
    889 
    890     computeOverflowFromCells(totalRows, nEffCols);
    891 
    892     statePusher.pop();
    893 }
    894 
    895 void RenderTableSection::computeOverflowFromCells()
    896 {
    897     unsigned totalRows = m_grid.size();
    898     unsigned nEffCols = table()->numEffCols();
    899     computeOverflowFromCells(totalRows, nEffCols);
    900 }
    901 
    902 void RenderTableSection::computeOverflowFromCells(unsigned totalRows, unsigned nEffCols)
    903 {
    904     unsigned totalCellsCount = nEffCols * totalRows;
    905     int maxAllowedOverflowingCellsCount = totalCellsCount < gMinTableSizeToUseFastPaintPathWithOverflowingCell ? 0 : gMaxAllowedOverflowingCellRatioForFastPaintPath * totalCellsCount;
    906 
    907 #ifndef NDEBUG
    908     bool hasOverflowingCell = false;
    909 #endif
    910     // Now that our height has been determined, add in overflow from cells.
    911     for (unsigned r = 0; r < totalRows; r++) {
    912         for (unsigned c = 0; c < nEffCols; c++) {
    913             CellStruct& cs = cellAt(r, c);
    914             RenderTableCell* cell = cs.primaryCell();
    915             if (!cell || cs.inColSpan)
    916                 continue;
    917             if (r < totalRows - 1 && cell == primaryCellAt(r + 1, c))
    918                 continue;
    919             addOverflowFromChild(cell);
    920 #ifndef NDEBUG
    921             hasOverflowingCell |= cell->hasVisualOverflow();
    922 #endif
    923             if (cell->hasVisualOverflow() && !m_forceSlowPaintPathWithOverflowingCell) {
    924                 m_overflowingCells.add(cell);
    925                 if (m_overflowingCells.size() > maxAllowedOverflowingCellsCount) {
    926                     // We need to set m_forcesSlowPaintPath only if there is a least one overflowing cells as the hit testing code rely on this information.
    927                     m_forceSlowPaintPathWithOverflowingCell = true;
    928                     // The slow path does not make any use of the overflowing cells info, don't hold on to the memory.
    929                     m_overflowingCells.clear();
    930                 }
    931             }
    932         }
    933     }
    934 
    935     ASSERT(hasOverflowingCell == this->hasOverflowingCell());
    936 }
    937 
    938 int RenderTableSection::calcOuterBorderBefore() const
    939 {
    940     unsigned totalCols = table()->numEffCols();
    941     if (!m_grid.size() || !totalCols)
    942         return 0;
    943 
    944     unsigned borderWidth = 0;
    945 
    946     const BorderValue& sb = style()->borderBefore();
    947     if (sb.style() == BHIDDEN)
    948         return -1;
    949     if (sb.style() > BHIDDEN)
    950         borderWidth = sb.width();
    951 
    952     const BorderValue& rb = firstChild()->style()->borderBefore();
    953     if (rb.style() == BHIDDEN)
    954         return -1;
    955     if (rb.style() > BHIDDEN && rb.width() > borderWidth)
    956         borderWidth = rb.width();
    957 
    958     bool allHidden = true;
    959     for (unsigned c = 0; c < totalCols; c++) {
    960         const CellStruct& current = cellAt(0, c);
    961         if (current.inColSpan || !current.hasCells())
    962             continue;
    963         const BorderValue& cb = current.primaryCell()->style()->borderBefore(); // FIXME: Make this work with perpendicular and flipped cells.
    964         // FIXME: Don't repeat for the same col group
    965         RenderTableCol* colGroup = table()->colElement(c);
    966         if (colGroup) {
    967             const BorderValue& gb = colGroup->style()->borderBefore();
    968             if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
    969                 continue;
    970             allHidden = false;
    971             if (gb.style() > BHIDDEN && gb.width() > borderWidth)
    972                 borderWidth = gb.width();
    973             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
    974                 borderWidth = cb.width();
    975         } else {
    976             if (cb.style() == BHIDDEN)
    977                 continue;
    978             allHidden = false;
    979             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
    980                 borderWidth = cb.width();
    981         }
    982     }
    983     if (allHidden)
    984         return -1;
    985 
    986     return borderWidth / 2;
    987 }
    988 
    989 int RenderTableSection::calcOuterBorderAfter() const
    990 {
    991     unsigned totalCols = table()->numEffCols();
    992     if (!m_grid.size() || !totalCols)
    993         return 0;
    994 
    995     unsigned borderWidth = 0;
    996 
    997     const BorderValue& sb = style()->borderAfter();
    998     if (sb.style() == BHIDDEN)
    999         return -1;
   1000     if (sb.style() > BHIDDEN)
   1001         borderWidth = sb.width();
   1002 
   1003     const BorderValue& rb = lastChild()->style()->borderAfter();
   1004     if (rb.style() == BHIDDEN)
   1005         return -1;
   1006     if (rb.style() > BHIDDEN && rb.width() > borderWidth)
   1007         borderWidth = rb.width();
   1008 
   1009     bool allHidden = true;
   1010     for (unsigned c = 0; c < totalCols; c++) {
   1011         const CellStruct& current = cellAt(m_grid.size() - 1, c);
   1012         if (current.inColSpan || !current.hasCells())
   1013             continue;
   1014         const BorderValue& cb = current.primaryCell()->style()->borderAfter(); // FIXME: Make this work with perpendicular and flipped cells.
   1015         // FIXME: Don't repeat for the same col group
   1016         RenderTableCol* colGroup = table()->colElement(c);
   1017         if (colGroup) {
   1018             const BorderValue& gb = colGroup->style()->borderAfter();
   1019             if (gb.style() == BHIDDEN || cb.style() == BHIDDEN)
   1020                 continue;
   1021             allHidden = false;
   1022             if (gb.style() > BHIDDEN && gb.width() > borderWidth)
   1023                 borderWidth = gb.width();
   1024             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
   1025                 borderWidth = cb.width();
   1026         } else {
   1027             if (cb.style() == BHIDDEN)
   1028                 continue;
   1029             allHidden = false;
   1030             if (cb.style() > BHIDDEN && cb.width() > borderWidth)
   1031                 borderWidth = cb.width();
   1032         }
   1033     }
   1034     if (allHidden)
   1035         return -1;
   1036 
   1037     return (borderWidth + 1) / 2;
   1038 }
   1039 
   1040 int RenderTableSection::calcOuterBorderStart() const
   1041 {
   1042     unsigned totalCols = table()->numEffCols();
   1043     if (!m_grid.size() || !totalCols)
   1044         return 0;
   1045 
   1046     unsigned borderWidth = 0;
   1047 
   1048     const BorderValue& sb = style()->borderStart();
   1049     if (sb.style() == BHIDDEN)
   1050         return -1;
   1051     if (sb.style() > BHIDDEN)
   1052         borderWidth = sb.width();
   1053 
   1054     if (RenderTableCol* colGroup = table()->colElement(0)) {
   1055         const BorderValue& gb = colGroup->style()->borderStart();
   1056         if (gb.style() == BHIDDEN)
   1057             return -1;
   1058         if (gb.style() > BHIDDEN && gb.width() > borderWidth)
   1059             borderWidth = gb.width();
   1060     }
   1061 
   1062     bool allHidden = true;
   1063     for (unsigned r = 0; r < m_grid.size(); r++) {
   1064         const CellStruct& current = cellAt(r, 0);
   1065         if (!current.hasCells())
   1066             continue;
   1067         // FIXME: Don't repeat for the same cell
   1068         const BorderValue& cb = current.primaryCell()->style()->borderStart(); // FIXME: Make this work with perpendicular and flipped cells.
   1069         const BorderValue& rb = current.primaryCell()->parent()->style()->borderStart();
   1070         if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
   1071             continue;
   1072         allHidden = false;
   1073         if (cb.style() > BHIDDEN && cb.width() > borderWidth)
   1074             borderWidth = cb.width();
   1075         if (rb.style() > BHIDDEN && rb.width() > borderWidth)
   1076             borderWidth = rb.width();
   1077     }
   1078     if (allHidden)
   1079         return -1;
   1080 
   1081     return (borderWidth + (table()->style()->isLeftToRightDirection() ? 0 : 1)) / 2;
   1082 }
   1083 
   1084 int RenderTableSection::calcOuterBorderEnd() const
   1085 {
   1086     unsigned totalCols = table()->numEffCols();
   1087     if (!m_grid.size() || !totalCols)
   1088         return 0;
   1089 
   1090     unsigned borderWidth = 0;
   1091 
   1092     const BorderValue& sb = style()->borderEnd();
   1093     if (sb.style() == BHIDDEN)
   1094         return -1;
   1095     if (sb.style() > BHIDDEN)
   1096         borderWidth = sb.width();
   1097 
   1098     if (RenderTableCol* colGroup = table()->colElement(totalCols - 1)) {
   1099         const BorderValue& gb = colGroup->style()->borderEnd();
   1100         if (gb.style() == BHIDDEN)
   1101             return -1;
   1102         if (gb.style() > BHIDDEN && gb.width() > borderWidth)
   1103             borderWidth = gb.width();
   1104     }
   1105 
   1106     bool allHidden = true;
   1107     for (unsigned r = 0; r < m_grid.size(); r++) {
   1108         const CellStruct& current = cellAt(r, totalCols - 1);
   1109         if (!current.hasCells())
   1110             continue;
   1111         // FIXME: Don't repeat for the same cell
   1112         const BorderValue& cb = current.primaryCell()->style()->borderEnd(); // FIXME: Make this work with perpendicular and flipped cells.
   1113         const BorderValue& rb = current.primaryCell()->parent()->style()->borderEnd();
   1114         if (cb.style() == BHIDDEN || rb.style() == BHIDDEN)
   1115             continue;
   1116         allHidden = false;
   1117         if (cb.style() > BHIDDEN && cb.width() > borderWidth)
   1118             borderWidth = cb.width();
   1119         if (rb.style() > BHIDDEN && rb.width() > borderWidth)
   1120             borderWidth = rb.width();
   1121     }
   1122     if (allHidden)
   1123         return -1;
   1124 
   1125     return (borderWidth + (table()->style()->isLeftToRightDirection() ? 1 : 0)) / 2;
   1126 }
   1127 
   1128 void RenderTableSection::recalcOuterBorder()
   1129 {
   1130     m_outerBorderBefore = calcOuterBorderBefore();
   1131     m_outerBorderAfter = calcOuterBorderAfter();
   1132     m_outerBorderStart = calcOuterBorderStart();
   1133     m_outerBorderEnd = calcOuterBorderEnd();
   1134 }
   1135 
   1136 int RenderTableSection::firstLineBoxBaseline() const
   1137 {
   1138     if (!m_grid.size())
   1139         return -1;
   1140 
   1141     int firstLineBaseline = m_grid[0].baseline;
   1142     if (firstLineBaseline)
   1143         return firstLineBaseline + m_rowPos[0];
   1144 
   1145     firstLineBaseline = -1;
   1146     const Row& firstRow = m_grid[0].row;
   1147     for (size_t i = 0; i < firstRow.size(); ++i) {
   1148         const CellStruct& cs = firstRow.at(i);
   1149         const RenderTableCell* cell = cs.primaryCell();
   1150         // Only cells with content have a baseline
   1151         if (cell && cell->contentLogicalHeight())
   1152             firstLineBaseline = max<int>(firstLineBaseline, cell->logicalTop() + cell->paddingBefore() + cell->borderBefore() + cell->contentLogicalHeight());
   1153     }
   1154 
   1155     return firstLineBaseline;
   1156 }
   1157 
   1158 void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1159 {
   1160     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
   1161 
   1162     // put this back in when all layout tests can handle it
   1163     // ASSERT(!needsLayout());
   1164     // avoid crashing on bugs that cause us to paint with dirty layout
   1165     if (needsLayout())
   1166         return;
   1167 
   1168     unsigned totalRows = m_grid.size();
   1169     unsigned totalCols = table()->columns().size();
   1170 
   1171     if (!totalRows || !totalCols)
   1172         return;
   1173 
   1174     LayoutPoint adjustedPaintOffset = paintOffset + location();
   1175 
   1176     PaintPhase phase = paintInfo.phase;
   1177     bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, ForceContentsClip);
   1178     paintObject(paintInfo, adjustedPaintOffset);
   1179     if (pushedClip)
   1180         popContentsClip(paintInfo, phase, adjustedPaintOffset);
   1181 
   1182     if ((phase == PaintPhaseOutline || phase == PaintPhaseSelfOutline) && style()->visibility() == VISIBLE)
   1183         paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
   1184 }
   1185 
   1186 static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2)
   1187 {
   1188     return elem1->rowIndex() < elem2->rowIndex();
   1189 }
   1190 
   1191 // This comparison is used only when we have overflowing cells as we have an unsorted array to sort. We thus need
   1192 // to sort both on rows and columns to properly repaint.
   1193 static inline bool compareCellPositionsWithOverflowingCells(RenderTableCell* elem1, RenderTableCell* elem2)
   1194 {
   1195     if (elem1->rowIndex() != elem2->rowIndex())
   1196         return elem1->rowIndex() < elem2->rowIndex();
   1197 
   1198     return elem1->col() < elem2->col();
   1199 }
   1200 
   1201 void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1202 {
   1203     LayoutPoint cellPoint = flipForWritingModeForChild(cell, paintOffset);
   1204     PaintPhase paintPhase = paintInfo.phase;
   1205     RenderTableRow* row = toRenderTableRow(cell->parent());
   1206 
   1207     if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) {
   1208         // We need to handle painting a stack of backgrounds.  This stack (from bottom to top) consists of
   1209         // the column group, column, row group, row, and then the cell.
   1210         RenderTableCol* column = table()->colElement(cell->col());
   1211         RenderTableCol* columnGroup = column ? column->enclosingColumnGroup() : 0;
   1212 
   1213         // Column groups and columns first.
   1214         // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
   1215         // the stack, since we have already opened a transparency layer (potentially) for the table row group.
   1216         // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
   1217         // cell.
   1218         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, columnGroup);
   1219         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, column);
   1220 
   1221         // Paint the row group next.
   1222         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, this);
   1223 
   1224         // Paint the row next, but only if it doesn't have a layer.  If a row has a layer, it will be responsible for
   1225         // painting the row background for the cell.
   1226         if (!row->hasSelfPaintingLayer())
   1227             cell->paintBackgroundsBehindCell(paintInfo, cellPoint, row);
   1228     }
   1229     if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer()))
   1230         cell->paint(paintInfo, cellPoint);
   1231 }
   1232 
   1233 LayoutRect RenderTableSection::logicalRectForWritingModeAndDirection(const LayoutRect& rect) const
   1234 {
   1235     LayoutRect tableAlignedRect(rect);
   1236 
   1237     flipForWritingMode(tableAlignedRect);
   1238 
   1239     if (!style()->isHorizontalWritingMode())
   1240         tableAlignedRect = tableAlignedRect.transposedRect();
   1241 
   1242     const Vector<int>& columnPos = table()->columnPositions();
   1243     // FIXME: The table's direction should determine our row's direction, not the section's (see bug 96691).
   1244     if (!style()->isLeftToRightDirection())
   1245         tableAlignedRect.setX(columnPos[columnPos.size() - 1] - tableAlignedRect.maxX());
   1246 
   1247     return tableAlignedRect;
   1248 }
   1249 
   1250 CellSpan RenderTableSection::dirtiedRows(const LayoutRect& damageRect) const
   1251 {
   1252     if (m_forceSlowPaintPathWithOverflowingCell)
   1253         return fullTableRowSpan();
   1254 
   1255     CellSpan coveredRows = spannedRows(damageRect);
   1256 
   1257     // To repaint the border we might need to repaint first or last row even if they are not spanned themselves.
   1258     if (coveredRows.start() >= m_rowPos.size() - 1 && m_rowPos[m_rowPos.size() - 1] + table()->outerBorderAfter() >= damageRect.y())
   1259         --coveredRows.start();
   1260 
   1261     if (!coveredRows.end() && m_rowPos[0] - table()->outerBorderBefore() <= damageRect.maxY())
   1262         ++coveredRows.end();
   1263 
   1264     return coveredRows;
   1265 }
   1266 
   1267 CellSpan RenderTableSection::dirtiedColumns(const LayoutRect& damageRect) const
   1268 {
   1269     if (m_forceSlowPaintPathWithOverflowingCell)
   1270         return fullTableColumnSpan();
   1271 
   1272     CellSpan coveredColumns = spannedColumns(damageRect);
   1273 
   1274     const Vector<int>& columnPos = table()->columnPositions();
   1275     // To repaint the border we might need to repaint first or last column even if they are not spanned themselves.
   1276     if (coveredColumns.start() >= columnPos.size() - 1 && columnPos[columnPos.size() - 1] + table()->outerBorderEnd() >= damageRect.x())
   1277         --coveredColumns.start();
   1278 
   1279     if (!coveredColumns.end() && columnPos[0] - table()->outerBorderStart() <= damageRect.maxX())
   1280         ++coveredColumns.end();
   1281 
   1282     return coveredColumns;
   1283 }
   1284 
   1285 CellSpan RenderTableSection::spannedRows(const LayoutRect& flippedRect) const
   1286 {
   1287     // Find the first row that starts after rect top.
   1288     unsigned nextRow = std::upper_bound(m_rowPos.begin(), m_rowPos.end(), flippedRect.y()) - m_rowPos.begin();
   1289 
   1290     if (nextRow == m_rowPos.size())
   1291         return CellSpan(m_rowPos.size() - 1, m_rowPos.size() - 1); // After all rows.
   1292 
   1293     unsigned startRow = nextRow > 0 ? nextRow - 1 : 0;
   1294 
   1295     // Find the first row that starts after rect bottom.
   1296     unsigned endRow;
   1297     if (m_rowPos[nextRow] >= flippedRect.maxY())
   1298         endRow = nextRow;
   1299     else {
   1300         endRow = std::upper_bound(m_rowPos.begin() + nextRow, m_rowPos.end(), flippedRect.maxY()) - m_rowPos.begin();
   1301         if (endRow == m_rowPos.size())
   1302             endRow = m_rowPos.size() - 1;
   1303     }
   1304 
   1305     return CellSpan(startRow, endRow);
   1306 }
   1307 
   1308 CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect) const
   1309 {
   1310     const Vector<int>& columnPos = table()->columnPositions();
   1311 
   1312     // Find the first column that starts after rect left.
   1313     // lower_bound doesn't handle the edge between two cells properly as it would wrongly return the
   1314     // cell on the logical top/left.
   1315     // upper_bound on the other hand properly returns the cell on the logical bottom/right, which also
   1316     // matches the behavior of other browsers.
   1317     unsigned nextColumn = std::upper_bound(columnPos.begin(), columnPos.end(), flippedRect.x()) - columnPos.begin();
   1318 
   1319     if (nextColumn == columnPos.size())
   1320         return CellSpan(columnPos.size() - 1, columnPos.size() - 1); // After all columns.
   1321 
   1322     unsigned startColumn = nextColumn > 0 ? nextColumn - 1 : 0;
   1323 
   1324     // Find the first column that starts after rect right.
   1325     unsigned endColumn;
   1326     if (columnPos[nextColumn] >= flippedRect.maxX())
   1327         endColumn = nextColumn;
   1328     else {
   1329         endColumn = std::upper_bound(columnPos.begin() + nextColumn, columnPos.end(), flippedRect.maxX()) - columnPos.begin();
   1330         if (endColumn == columnPos.size())
   1331             endColumn = columnPos.size() - 1;
   1332     }
   1333 
   1334     return CellSpan(startColumn, endColumn);
   1335 }
   1336 
   1337 
   1338 void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
   1339 {
   1340     PaintPhase paintPhase = paintInfo.phase;
   1341 
   1342     LayoutRect localRepaintRect = paintInfo.rect;
   1343     localRepaintRect.moveBy(-paintOffset);
   1344     localRepaintRect.inflate(maximalOutlineSize(paintPhase));
   1345 
   1346     LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(localRepaintRect);
   1347 
   1348     CellSpan dirtiedRows = this->dirtiedRows(tableAlignedRect);
   1349     CellSpan dirtiedColumns = this->dirtiedColumns(tableAlignedRect);
   1350 
   1351     if (dirtiedColumns.start() < dirtiedColumns.end()) {
   1352         if (!m_hasMultipleCellLevels && !m_overflowingCells.size()) {
   1353             if (paintInfo.phase == PaintPhaseCollapsedTableBorders) {
   1354                 // Collapsed borders are painted from the bottom right to the top left so that precedence
   1355                 // due to cell position is respected.
   1356                 for (unsigned r = dirtiedRows.end(); r > dirtiedRows.start(); r--) {
   1357                     unsigned row = r - 1;
   1358                     for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.start(); c--) {
   1359                         unsigned col = c - 1;
   1360                         CellStruct& current = cellAt(row, col);
   1361                         RenderTableCell* cell = current.primaryCell();
   1362                         if (!cell || (row > dirtiedRows.start() && primaryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start() && primaryCellAt(row, col - 1) == cell))
   1363                             continue;
   1364                         LayoutPoint cellPoint = flipForWritingModeForChild(cell, paintOffset);
   1365                         cell->paintCollapsedBorders(paintInfo, cellPoint);
   1366                     }
   1367                 }
   1368             } else {
   1369                 // Draw the dirty cells in the order that they appear.
   1370                 for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) {
   1371                     RenderTableRow* row = m_grid[r].rowRenderer;
   1372                     if (row && !row->hasSelfPaintingLayer())
   1373                         row->paintOutlineForRowIfNeeded(paintInfo, paintOffset);
   1374                     for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) {
   1375                         CellStruct& current = cellAt(r, c);
   1376                         RenderTableCell* cell = current.primaryCell();
   1377                         if (!cell || (r > dirtiedRows.start() && primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start() && primaryCellAt(r, c - 1) == cell))
   1378                             continue;
   1379                         paintCell(cell, paintInfo, paintOffset);
   1380                     }
   1381                 }
   1382             }
   1383         } else {
   1384             // The overflowing cells should be scarce to avoid adding a lot of cells to the HashSet.
   1385 #ifndef NDEBUG
   1386             unsigned totalRows = m_grid.size();
   1387             unsigned totalCols = table()->columns().size();
   1388             ASSERT(m_overflowingCells.size() < totalRows * totalCols * gMaxAllowedOverflowingCellRatioForFastPaintPath);
   1389 #endif
   1390 
   1391             // To make sure we properly repaint the section, we repaint all the overflowing cells that we collected.
   1392             Vector<RenderTableCell*> cells;
   1393             copyToVector(m_overflowingCells, cells);
   1394 
   1395             HashSet<RenderTableCell*> spanningCells;
   1396 
   1397             for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) {
   1398                 RenderTableRow* row = m_grid[r].rowRenderer;
   1399                 if (row && !row->hasSelfPaintingLayer())
   1400                     row->paintOutlineForRowIfNeeded(paintInfo, paintOffset);
   1401                 for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) {
   1402                     CellStruct& current = cellAt(r, c);
   1403                     if (!current.hasCells())
   1404                         continue;
   1405                     for (unsigned i = 0; i < current.cells.size(); ++i) {
   1406                         if (m_overflowingCells.contains(current.cells[i]))
   1407                             continue;
   1408 
   1409                         if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) {
   1410                             if (!spanningCells.add(current.cells[i]).isNewEntry)
   1411                                 continue;
   1412                         }
   1413 
   1414                         cells.append(current.cells[i]);
   1415                     }
   1416                 }
   1417             }
   1418 
   1419             // Sort the dirty cells by paint order.
   1420             if (!m_overflowingCells.size())
   1421                 std::stable_sort(cells.begin(), cells.end(), compareCellPositions);
   1422             else
   1423                 std::sort(cells.begin(), cells.end(), compareCellPositionsWithOverflowingCells);
   1424 
   1425             if (paintInfo.phase == PaintPhaseCollapsedTableBorders) {
   1426                 for (unsigned i = cells.size(); i > 0; --i) {
   1427                     LayoutPoint cellPoint = flipForWritingModeForChild(cells[i - 1], paintOffset);
   1428                     cells[i - 1]->paintCollapsedBorders(paintInfo, cellPoint);
   1429                 }
   1430             } else {
   1431                 for (unsigned i = 0; i < cells.size(); ++i)
   1432                     paintCell(cells[i], paintInfo, paintOffset);
   1433             }
   1434         }
   1435     }
   1436 }
   1437 
   1438 void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*)
   1439 {
   1440     // FIXME: Examine cells and repaint only the rect the image paints in.
   1441     repaint();
   1442 }
   1443 
   1444 void RenderTableSection::recalcCells()
   1445 {
   1446     ASSERT(m_needsCellRecalc);
   1447     // We reset the flag here to ensure that |addCell| works. This is safe to do as
   1448     // fillRowsWithDefaultStartingAtPosition makes sure we match the table's columns
   1449     // representation.
   1450     m_needsCellRecalc = false;
   1451 
   1452     m_cCol = 0;
   1453     m_cRow = 0;
   1454     m_grid.clear();
   1455 
   1456     for (RenderObject* row = firstChild(); row; row = row->nextSibling()) {
   1457         if (row->isTableRow()) {
   1458             unsigned insertionRow = m_cRow;
   1459             m_cRow++;
   1460             m_cCol = 0;
   1461             ensureRows(m_cRow);
   1462 
   1463             RenderTableRow* tableRow = toRenderTableRow(row);
   1464             m_grid[insertionRow].rowRenderer = tableRow;
   1465             tableRow->setRowIndex(insertionRow);
   1466             setRowLogicalHeightToRowStyleLogicalHeight(m_grid[insertionRow]);
   1467 
   1468             for (RenderObject* cell = row->firstChild(); cell; cell = cell->nextSibling()) {
   1469                 if (!cell->isTableCell())
   1470                     continue;
   1471 
   1472                 RenderTableCell* tableCell = toRenderTableCell(cell);
   1473                 addCell(tableCell, tableRow);
   1474             }
   1475         }
   1476     }
   1477 
   1478     m_grid.shrinkToFit();
   1479     setNeedsLayout();
   1480 }
   1481 
   1482 // FIXME: This function could be made O(1) in certain cases (like for the non-most-constrainive cells' case).
   1483 void RenderTableSection::rowLogicalHeightChanged(unsigned rowIndex)
   1484 {
   1485     if (needsCellRecalc())
   1486         return;
   1487 
   1488     setRowLogicalHeightToRowStyleLogicalHeight(m_grid[rowIndex]);
   1489 
   1490     for (RenderObject* cell = m_grid[rowIndex].rowRenderer->firstChild(); cell; cell = cell->nextSibling()) {
   1491         if (!cell->isTableCell())
   1492             continue;
   1493 
   1494         updateLogicalHeightForCell(m_grid[rowIndex], toRenderTableCell(cell));
   1495     }
   1496 }
   1497 
   1498 void RenderTableSection::setNeedsCellRecalc()
   1499 {
   1500     m_needsCellRecalc = true;
   1501     if (RenderTable* t = table())
   1502         t->setNeedsSectionRecalc();
   1503 }
   1504 
   1505 unsigned RenderTableSection::numColumns() const
   1506 {
   1507     unsigned result = 0;
   1508 
   1509     for (unsigned r = 0; r < m_grid.size(); ++r) {
   1510         for (unsigned c = result; c < table()->numEffCols(); ++c) {
   1511             const CellStruct& cell = cellAt(r, c);
   1512             if (cell.hasCells() || cell.inColSpan)
   1513                 result = c;
   1514         }
   1515     }
   1516 
   1517     return result + 1;
   1518 }
   1519 
   1520 const BorderValue& RenderTableSection::borderAdjoiningStartCell(const RenderTableCell* cell) const
   1521 {
   1522     ASSERT(cell->isFirstOrLastCellInRow());
   1523     return hasSameDirectionAs(cell) ? style()->borderStart() : style()->borderEnd();
   1524 }
   1525 
   1526 const BorderValue& RenderTableSection::borderAdjoiningEndCell(const RenderTableCell* cell) const
   1527 {
   1528     ASSERT(cell->isFirstOrLastCellInRow());
   1529     return hasSameDirectionAs(cell) ? style()->borderEnd() : style()->borderStart();
   1530 }
   1531 
   1532 const RenderTableCell* RenderTableSection::firstRowCellAdjoiningTableStart() const
   1533 {
   1534     unsigned adjoiningStartCellColumnIndex = hasSameDirectionAs(table()) ? 0 : table()->lastColumnIndex();
   1535     return cellAt(0, adjoiningStartCellColumnIndex).primaryCell();
   1536 }
   1537 
   1538 const RenderTableCell* RenderTableSection::firstRowCellAdjoiningTableEnd() const
   1539 {
   1540     unsigned adjoiningEndCellColumnIndex = hasSameDirectionAs(table()) ? table()->lastColumnIndex() : 0;
   1541     return cellAt(0, adjoiningEndCellColumnIndex).primaryCell();
   1542 }
   1543 
   1544 void RenderTableSection::appendColumn(unsigned pos)
   1545 {
   1546     ASSERT(!m_needsCellRecalc);
   1547 
   1548     for (unsigned row = 0; row < m_grid.size(); ++row)
   1549         m_grid[row].row.resize(pos + 1);
   1550 }
   1551 
   1552 void RenderTableSection::splitColumn(unsigned pos, unsigned first)
   1553 {
   1554     ASSERT(!m_needsCellRecalc);
   1555 
   1556     if (m_cCol > pos)
   1557         m_cCol++;
   1558     for (unsigned row = 0; row < m_grid.size(); ++row) {
   1559         Row& r = m_grid[row].row;
   1560         r.insert(pos + 1, CellStruct());
   1561         if (r[pos].hasCells()) {
   1562             r[pos + 1].cells.append(r[pos].cells);
   1563             RenderTableCell* cell = r[pos].primaryCell();
   1564             ASSERT(cell);
   1565             ASSERT(cell->colSpan() >= (r[pos].inColSpan ? 1u : 0));
   1566             unsigned colleft = cell->colSpan() - r[pos].inColSpan;
   1567             if (first > colleft)
   1568               r[pos + 1].inColSpan = 0;
   1569             else
   1570               r[pos + 1].inColSpan = first + r[pos].inColSpan;
   1571         } else {
   1572             r[pos + 1].inColSpan = 0;
   1573         }
   1574     }
   1575 }
   1576 
   1577 // Hit Testing
   1578 bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
   1579 {
   1580     // If we have no children then we have nothing to do.
   1581     if (!firstChild())
   1582         return false;
   1583 
   1584     // Table sections cannot ever be hit tested.  Effectively they do not exist.
   1585     // Just forward to our children always.
   1586     LayoutPoint adjustedLocation = accumulatedOffset + location();
   1587 
   1588     if (hasOverflowClip() && !locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region())))
   1589         return false;
   1590 
   1591     if (hasOverflowingCell()) {
   1592         for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
   1593             // FIXME: We have to skip over inline flows, since they can show up inside table rows
   1594             // at the moment (a demoted inline <form> for example). If we ever implement a
   1595             // table-specific hit-test method (which we should do for performance reasons anyway),
   1596             // then we can remove this check.
   1597             if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer()) {
   1598                 LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation);
   1599                 if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
   1600                     updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
   1601                     return true;
   1602                 }
   1603             }
   1604         }
   1605         return false;
   1606     }
   1607 
   1608     recalcCellsIfNeeded();
   1609 
   1610     LayoutRect hitTestRect = locationInContainer.boundingBox();
   1611     hitTestRect.moveBy(-adjustedLocation);
   1612 
   1613     LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(hitTestRect);
   1614     CellSpan rowSpan = spannedRows(tableAlignedRect);
   1615     CellSpan columnSpan = spannedColumns(tableAlignedRect);
   1616 
   1617     // Now iterate over the spanned rows and columns.
   1618     for (unsigned hitRow = rowSpan.start(); hitRow < rowSpan.end(); ++hitRow) {
   1619         for (unsigned hitColumn = columnSpan.start(); hitColumn < columnSpan.end(); ++hitColumn) {
   1620             CellStruct& current = cellAt(hitRow, hitColumn);
   1621 
   1622             // If the cell is empty, there's nothing to do
   1623             if (!current.hasCells())
   1624                 continue;
   1625 
   1626             for (unsigned i = current.cells.size() ; i; ) {
   1627                 --i;
   1628                 RenderTableCell* cell = current.cells[i];
   1629                 LayoutPoint cellPoint = flipForWritingModeForChild(cell, adjustedLocation);
   1630                 if (static_cast<RenderObject*>(cell)->nodeAtPoint(request, result, locationInContainer, cellPoint, action)) {
   1631                     updateHitTestResult(result, locationInContainer.point() - toLayoutSize(cellPoint));
   1632                     return true;
   1633                 }
   1634             }
   1635             if (!result.isRectBasedTest())
   1636                 break;
   1637         }
   1638         if (!result.isRectBasedTest())
   1639             break;
   1640     }
   1641 
   1642     return false;
   1643 }
   1644 
   1645 void RenderTableSection::removeCachedCollapsedBorders(const RenderTableCell* cell)
   1646 {
   1647     if (!table()->collapseBorders())
   1648         return;
   1649 
   1650     for (int side = CBSBefore; side <= CBSEnd; ++side)
   1651         m_cellsCollapsedBorders.remove(make_pair(cell, side));
   1652 }
   1653 
   1654 void RenderTableSection::setCachedCollapsedBorder(const RenderTableCell* cell, CollapsedBorderSide side, CollapsedBorderValue border)
   1655 {
   1656     ASSERT(table()->collapseBorders());
   1657     m_cellsCollapsedBorders.set(make_pair(cell, side), border);
   1658 }
   1659 
   1660 CollapsedBorderValue& RenderTableSection::cachedCollapsedBorder(const RenderTableCell* cell, CollapsedBorderSide side)
   1661 {
   1662     ASSERT(table()->collapseBorders());
   1663     HashMap<pair<const RenderTableCell*, int>, CollapsedBorderValue>::iterator it = m_cellsCollapsedBorders.find(make_pair(cell, side));
   1664     ASSERT(it != m_cellsCollapsedBorders.end());
   1665     return it->value;
   1666 }
   1667 
   1668 RenderTableSection* RenderTableSection::createAnonymousWithParentRenderer(const RenderObject* parent)
   1669 {
   1670     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_ROW_GROUP);
   1671     RenderTableSection* newSection = new RenderTableSection(0);
   1672     newSection->setDocumentForAnonymous(parent->document());
   1673     newSection->setStyle(newStyle.release());
   1674     return newSection;
   1675 }
   1676 
   1677 void RenderTableSection::setLogicalPositionForCell(RenderTableCell* cell, unsigned effectiveColumn) const
   1678 {
   1679     LayoutPoint oldCellLocation = cell->location();
   1680 
   1681     LayoutPoint cellLocation(0, m_rowPos[cell->rowIndex()]);
   1682     int horizontalBorderSpacing = table()->hBorderSpacing();
   1683 
   1684     // FIXME: The table's direction should determine our row's direction, not the section's (see bug 96691).
   1685     if (!style()->isLeftToRightDirection())
   1686         cellLocation.setX(table()->columnPositions()[table()->numEffCols()] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + horizontalBorderSpacing);
   1687     else
   1688         cellLocation.setX(table()->columnPositions()[effectiveColumn] + horizontalBorderSpacing);
   1689 
   1690     cell->setLogicalLocation(cellLocation);
   1691     view()->addLayoutDelta(oldCellLocation - cell->location());
   1692 }
   1693 
   1694 } // namespace WebCore
   1695