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