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