Use enum classes and OptionSets for PaintPhase and PaintBehavior
[WebKit-https.git] / Source / WebCore / rendering / RenderTableSection.cpp
1 /*
2  * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3  *           (C) 1997 Torben Weis (weis@kde.org)
4  *           (C) 1998 Waldo Bastian (bastian@kde.org)
5  *           (C) 1999 Lars Knoll (knoll@kde.org)
6  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
7  * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
8  * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "RenderTableSection.h"
28 #include "Document.h"
29 #include "HitTestResult.h"
30 #include "HTMLNames.h"
31 #include "LayoutState.h"
32 #include "PaintInfo.h"
33 #include "RenderChildIterator.h"
34 #include "RenderTableCell.h"
35 #include "RenderTableCol.h"
36 #include "RenderTableRow.h"
37 #include "RenderTextControl.h"
38 #include "RenderTreeBuilder.h"
39 #include "RenderView.h"
40 #include "StyleInheritedData.h"
41 #include <limits>
42 #include <wtf/IsoMallocInlines.h>
43 #include <wtf/HashSet.h>
44 #include <wtf/StackStats.h>
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
50 WTF_MAKE_ISO_ALLOCATED_IMPL(RenderTableSection);
51
52 // Those 2 variables are used to balance the memory consumption vs the repaint time on big tables.
53 static const unsigned gMinTableSizeToUseFastPaintPathWithOverflowingCell = 75 * 75;
54 static const float gMaxAllowedOverflowingCellRatioForFastPaintPath = 0.1f;
55
56 static inline void setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(RenderTableSection::RowStruct& row)
57 {
58     ASSERT(row.rowRenderer);
59     row.logicalHeight = row.rowRenderer->style().logicalHeight();
60     if (row.logicalHeight.isRelative())
61         row.logicalHeight = Length();
62 }
63
64 static inline void updateLogicalHeightForCell(RenderTableSection::RowStruct& row, const RenderTableCell* cell)
65 {
66     // We ignore height settings on rowspan cells.
67     if (cell->rowSpan() != 1)
68         return;
69
70     Length logicalHeight = cell->style().logicalHeight();
71     if (logicalHeight.isPositive() || (logicalHeight.isRelative() && logicalHeight.value() >= 0)) {
72         Length cRowLogicalHeight = row.logicalHeight;
73         switch (logicalHeight.type()) {
74         case Percent:
75             if (!cRowLogicalHeight.isPercent() || cRowLogicalHeight.percent() < logicalHeight.percent())
76                 row.logicalHeight = logicalHeight;
77             break;
78         case Fixed:
79             if (cRowLogicalHeight.isAuto() || cRowLogicalHeight.isRelative()
80                 || (cRowLogicalHeight.isFixed() && cRowLogicalHeight.value() < logicalHeight.value()))
81                 row.logicalHeight = logicalHeight;
82             break;
83         case Relative:
84         default:
85             break;
86         }
87     }
88 }
89
90 RenderTableSection::RenderTableSection(Element& element, RenderStyle&& style)
91     : RenderBox(element, WTFMove(style), 0)
92 {
93     setInline(false);
94 }
95
96 RenderTableSection::RenderTableSection(Document& document, RenderStyle&& style)
97     : RenderBox(document, WTFMove(style), 0)
98 {
99     setInline(false);
100 }
101
102 RenderTableSection::~RenderTableSection() = default;
103
104 void RenderTableSection::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
105 {
106     RenderBox::styleDidChange(diff, oldStyle);
107     propagateStyleToAnonymousChildren(PropagateToAllChildren);
108
109     // If border was changed, notify table.
110     RenderTable* table = this->table();
111     if (table && oldStyle && oldStyle->border() != style().border())
112         table->invalidateCollapsedBorders();
113 }
114
115 void RenderTableSection::willBeRemovedFromTree()
116 {
117     RenderBox::willBeRemovedFromTree();
118
119     // Preventively invalidate our cells as we may be re-inserted into
120     // a new table which would require us to rebuild our structure.
121     setNeedsCellRecalc();
122 }
123
124 void RenderTableSection::willInsertTableRow(RenderTableRow& child, RenderObject* beforeChild)
125 {
126     if (beforeChild)
127         setNeedsCellRecalc();
128
129     unsigned insertionRow = m_cRow;
130     ++m_cRow;
131     m_cCol = 0;
132
133     ensureRows(m_cRow);
134
135     m_grid[insertionRow].rowRenderer = &child;
136     child.setRowIndex(insertionRow);
137
138     if (!beforeChild)
139         setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(m_grid[insertionRow]);
140 }
141
142 void RenderTableSection::ensureRows(unsigned numRows)
143 {
144     if (numRows <= m_grid.size())
145         return;
146
147     unsigned oldSize = m_grid.size();
148     m_grid.grow(numRows);
149
150     unsigned effectiveColumnCount = std::max(1u, table()->numEffCols());
151     for (unsigned row = oldSize; row < m_grid.size(); ++row)
152         m_grid[row].row.resizeToFit(effectiveColumnCount);
153 }
154
155 void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row)
156 {
157     // We don't insert the cell if we need cell recalc as our internal columns' representation
158     // will have drifted from the table's representation. Also recalcCells will call addCell
159     // at a later time after sync'ing our columns' with the table's.
160     if (needsCellRecalc())
161         return;
162
163     unsigned rSpan = cell->rowSpan();
164     unsigned cSpan = cell->colSpan();
165     const Vector<RenderTable::ColumnStruct>& columns = table()->columns();
166     unsigned nCols = columns.size();
167     unsigned insertionRow = row->rowIndex();
168
169     // ### mozilla still seems to do the old HTML way, even for strict DTD
170     // (see the annotation on table cell layouting in the CSS specs and the testcase below:
171     // <TABLE border>
172     // <TR><TD>1 <TD rowspan="2">2 <TD>3 <TD>4
173     // <TR><TD colspan="2">5
174     // </TABLE>
175     while (m_cCol < nCols && (cellAt(insertionRow, m_cCol).hasCells() || cellAt(insertionRow, m_cCol).inColSpan))
176         m_cCol++;
177
178     updateLogicalHeightForCell(m_grid[insertionRow], cell);
179
180     ensureRows(insertionRow + rSpan);
181
182     m_grid[insertionRow].rowRenderer = row;
183
184     unsigned col = m_cCol;
185     // tell the cell where it is
186     bool inColSpan = false;
187     while (cSpan) {
188         unsigned currentSpan;
189         if (m_cCol >= nCols) {
190             table()->appendColumn(cSpan);
191             currentSpan = cSpan;
192         } else {
193             if (cSpan < columns[m_cCol].span)
194                 table()->splitColumn(m_cCol, cSpan);
195             currentSpan = columns[m_cCol].span;
196         }
197         for (unsigned r = 0; r < rSpan; r++) {
198             CellStruct& c = cellAt(insertionRow + r, m_cCol);
199             ASSERT(cell);
200             c.cells.append(cell);
201             // If cells overlap then we take the slow path for painting.
202             if (c.cells.size() > 1)
203                 m_hasMultipleCellLevels = true;
204             if (inColSpan)
205                 c.inColSpan = true;
206         }
207         m_cCol++;
208         cSpan -= currentSpan;
209         inColSpan = true;
210     }
211     cell->setCol(table()->effColToCol(col));
212 }
213
214 static LayoutUnit resolveLogicalHeightForRow(const Length& rowLogicalHeight)
215 {
216     if (rowLogicalHeight.isFixed())
217         return rowLogicalHeight.value();
218     if (rowLogicalHeight.isCalculated())
219         return rowLogicalHeight.nonNanCalculatedValue(0);
220     return 0;
221 }
222
223 LayoutUnit RenderTableSection::calcRowLogicalHeight()
224 {
225 #ifndef NDEBUG
226     SetLayoutNeededForbiddenScope layoutForbiddenScope(this);
227 #endif
228
229     ASSERT(!needsLayout());
230
231     RenderTableCell* cell;
232
233     // We ignore the border-spacing on any non-top section as it is already included in the previous section's last row position.
234     LayoutUnit spacing = 0;
235     if (this == table()->topSection())
236         spacing = table()->vBorderSpacing();
237
238     LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode());
239
240     m_rowPos.resize(m_grid.size() + 1);
241     m_rowPos[0] = spacing;
242
243     unsigned totalRows = m_grid.size();
244
245     for (unsigned r = 0; r < totalRows; r++) {
246         m_grid[r].baseline = 0;
247         LayoutUnit baselineDescent = 0;
248
249         // Our base size is the biggest logical height from our cells' styles (excluding row spanning cells).
250         m_rowPos[r + 1] = std::max(m_rowPos[r] + resolveLogicalHeightForRow(m_grid[r].logicalHeight), LayoutUnit::fromPixel(0));
251
252         Row& row = m_grid[r].row;
253         unsigned totalCols = row.size();
254
255         for (unsigned c = 0; c < totalCols; c++) {
256             CellStruct& current = cellAt(r, c);
257             for (unsigned i = 0; i < current.cells.size(); i++) {
258                 cell = current.cells[i];
259                 if (current.inColSpan && cell->rowSpan() == 1)
260                     continue;
261
262                 // FIXME: We are always adding the height of a rowspan to the last rows which doesn't match
263                 // other browsers. See webkit.org/b/52185 for example.
264                 if ((cell->rowIndex() + cell->rowSpan() - 1) != r) {
265                     // We will apply the height of the rowspan to the current row if next row is not valid.
266                     if ((r + 1) < totalRows) {
267                         unsigned col = 0;
268                         CellStruct nextRowCell = cellAt(r + 1, col);
269
270                         // We are trying to find that next row is valid or not.
271                         while (nextRowCell.cells.size() && nextRowCell.cells[0]->rowSpan() > 1 && nextRowCell.cells[0]->rowIndex() < (r + 1)) {
272                             col++;
273                             if (col < totalCols)
274                                 nextRowCell = cellAt(r + 1, col);
275                             else
276                                 break;
277                         }
278
279                         // We are adding the height of the rowspan to the current row if next row is not valid.
280                         if (col < totalCols && nextRowCell.cells.size())
281                             continue;
282                     }
283                 }
284
285                 // For row spanning cells, |r| is the last row in the span.
286                 unsigned cellStartRow = cell->rowIndex();
287
288                 if (cell->hasOverrideContentLogicalHeight()) {
289                     cell->clearIntrinsicPadding();
290                     cell->clearOverrideContentSize();
291                     cell->setChildNeedsLayout(MarkOnlyThis);
292                     cell->layoutIfNeeded();
293                 }
294
295                 LayoutUnit cellLogicalHeight = cell->logicalHeightForRowSizing();
296                 m_rowPos[r + 1] = std::max(m_rowPos[r + 1], m_rowPos[cellStartRow] + cellLogicalHeight);
297
298                 // Find out the baseline. The baseline is set on the first row in a rowspan.
299                 if (cell->isBaselineAligned()) {
300                     LayoutUnit baselinePosition = cell->cellBaselinePosition() - cell->intrinsicPaddingBefore();
301                     LayoutUnit borderAndComputedPaddingBefore = cell->borderAndPaddingBefore() - cell->intrinsicPaddingBefore();
302                     if (baselinePosition > borderAndComputedPaddingBefore) {
303                         m_grid[cellStartRow].baseline = std::max(m_grid[cellStartRow].baseline, baselinePosition);
304                         // The descent of a cell that spans multiple rows does not affect the height of the first row it spans, so don't let it
305                         // become the baseline descent applied to the rest of the row. Also we don't account for the baseline descent of
306                         // non-spanning cells when computing a spanning cell's extent.
307                         LayoutUnit cellStartRowBaselineDescent = 0;
308                         if (cell->rowSpan() == 1) {
309                             baselineDescent = std::max(baselineDescent, cellLogicalHeight - baselinePosition);
310                             cellStartRowBaselineDescent = baselineDescent;
311                         }
312                         m_rowPos[cellStartRow + 1] = std::max(m_rowPos[cellStartRow + 1], m_rowPos[cellStartRow] + m_grid[cellStartRow].baseline + cellStartRowBaselineDescent);
313                     }
314                 }
315             }
316         }
317
318         // Add the border-spacing to our final position.
319         // Use table border-spacing even in non-top sections
320         spacing = table()->vBorderSpacing();
321         m_rowPos[r + 1] += m_grid[r].rowRenderer ? spacing : LayoutUnit::fromPixel(0);
322         m_rowPos[r + 1] = std::max(m_rowPos[r + 1], m_rowPos[r]);
323     }
324
325     ASSERT(!needsLayout());
326
327     return m_rowPos[m_grid.size()];
328 }
329
330 void RenderTableSection::layout()
331 {
332     StackStats::LayoutCheckPoint layoutCheckPoint;
333     ASSERT(needsLayout());
334     ASSERT(!needsCellRecalc());
335     ASSERT(!table()->needsSectionRecalc());
336
337     m_forceSlowPaintPathWithOverflowingCell = false;
338     // addChild may over-grow m_grid but we don't want to throw away the memory too early as addChild
339     // can be called in a loop (e.g during parsing). Doing it now ensures we have a stable-enough structure.
340     m_grid.shrinkToFit();
341
342     LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode());
343     bool paginated = view().frameView().layoutContext().layoutState()->isPaginated();
344     
345     const Vector<LayoutUnit>& columnPos = table()->columnPositions();
346     
347     for (unsigned r = 0; r < m_grid.size(); ++r) {
348         Row& row = m_grid[r].row;
349         unsigned cols = row.size();
350         // First, propagate our table layout's information to the cells. This will mark the row as needing layout
351         // if there was a column logical width change.
352         for (unsigned startColumn = 0; startColumn < cols; ++startColumn) {
353             CellStruct& current = row[startColumn];
354             RenderTableCell* cell = current.primaryCell();
355             if (!cell || current.inColSpan)
356                 continue;
357
358             unsigned endCol = startColumn;
359             unsigned cspan = cell->colSpan();
360             while (cspan && endCol < cols) {
361                 ASSERT(endCol < table()->columns().size());
362                 cspan -= table()->columns()[endCol].span;
363                 endCol++;
364             }
365             LayoutUnit tableLayoutLogicalWidth = columnPos[endCol] - columnPos[startColumn] - table()->hBorderSpacing();
366             cell->setCellLogicalWidth(tableLayoutLogicalWidth);
367         }
368
369         if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) {
370             if (!rowRenderer->needsLayout() && paginated && view().frameView().layoutContext().layoutState()->pageLogicalHeightChanged())
371                 rowRenderer->setChildNeedsLayout(MarkOnlyThis);
372
373             rowRenderer->layoutIfNeeded();
374         }
375     }
376     clearNeedsLayout();
377 }
378
379 void RenderTableSection::distributeExtraLogicalHeightToPercentRows(LayoutUnit& extraLogicalHeight, int totalPercent)
380 {
381     if (!totalPercent)
382         return;
383
384     unsigned totalRows = m_grid.size();
385     LayoutUnit totalHeight = m_rowPos[totalRows] + extraLogicalHeight;
386     LayoutUnit totalLogicalHeightAdded = 0;
387     totalPercent = std::min(totalPercent, 100);
388     LayoutUnit rowHeight = m_rowPos[1] - m_rowPos[0];
389     for (unsigned r = 0; r < totalRows; ++r) {
390         if (totalPercent > 0 && m_grid[r].logicalHeight.isPercent()) {
391             LayoutUnit toAdd = std::min<LayoutUnit>(extraLogicalHeight, (totalHeight * m_grid[r].logicalHeight.percent() / 100) - rowHeight);
392             // If toAdd is negative, then we don't want to shrink the row (this bug
393             // affected Outlook Web Access).
394             toAdd = std::max(LayoutUnit::fromPixel(0), toAdd);
395             totalLogicalHeightAdded += toAdd;
396             extraLogicalHeight -= toAdd;
397             totalPercent -= m_grid[r].logicalHeight.percent();
398         }
399         ASSERT(totalRows >= 1);
400         if (r < totalRows - 1)
401             rowHeight = m_rowPos[r + 2] - m_rowPos[r + 1];
402         m_rowPos[r + 1] += totalLogicalHeightAdded;
403     }
404 }
405
406 void RenderTableSection::distributeExtraLogicalHeightToAutoRows(LayoutUnit& extraLogicalHeight, unsigned autoRowsCount)
407 {
408     if (!autoRowsCount)
409         return;
410
411     LayoutUnit totalLogicalHeightAdded = 0;
412     for (unsigned r = 0; r < m_grid.size(); ++r) {
413         if (autoRowsCount > 0 && m_grid[r].logicalHeight.isAuto()) {
414             // Recomputing |extraLogicalHeightForRow| guarantees that we properly ditribute round |extraLogicalHeight|.
415             LayoutUnit extraLogicalHeightForRow = extraLogicalHeight / autoRowsCount;
416             totalLogicalHeightAdded += extraLogicalHeightForRow;
417             extraLogicalHeight -= extraLogicalHeightForRow;
418             --autoRowsCount;
419         }
420         m_rowPos[r + 1] += totalLogicalHeightAdded;
421     }
422 }
423
424 void RenderTableSection::distributeRemainingExtraLogicalHeight(LayoutUnit& extraLogicalHeight)
425 {
426     unsigned totalRows = m_grid.size();
427
428     if (extraLogicalHeight <= 0 || !m_rowPos[totalRows])
429         return;
430
431     // FIXME: m_rowPos[totalRows] - m_rowPos[0] is the total rows' size.
432     LayoutUnit totalRowSize = m_rowPos[totalRows];
433     LayoutUnit totalLogicalHeightAdded = 0;
434     LayoutUnit previousRowPosition = m_rowPos[0];
435     for (unsigned r = 0; r < totalRows; r++) {
436         // weight with the original height
437         totalLogicalHeightAdded += extraLogicalHeight * (m_rowPos[r + 1] - previousRowPosition) / totalRowSize;
438         previousRowPosition = m_rowPos[r + 1];
439         m_rowPos[r + 1] += totalLogicalHeightAdded;
440     }
441
442     extraLogicalHeight -= totalLogicalHeightAdded;
443 }
444
445 LayoutUnit RenderTableSection::distributeExtraLogicalHeightToRows(LayoutUnit extraLogicalHeight)
446 {
447     if (!extraLogicalHeight)
448         return extraLogicalHeight;
449
450     unsigned totalRows = m_grid.size();
451     if (!totalRows)
452         return extraLogicalHeight;
453
454     if (!m_rowPos[totalRows] && nextSibling())
455         return extraLogicalHeight;
456
457     unsigned autoRowsCount = 0;
458     int totalPercent = 0;
459     for (unsigned r = 0; r < totalRows; r++) {
460         if (m_grid[r].logicalHeight.isAuto())
461             ++autoRowsCount;
462         else if (m_grid[r].logicalHeight.isPercent())
463             totalPercent += m_grid[r].logicalHeight.percent();
464     }
465
466     LayoutUnit remainingExtraLogicalHeight = extraLogicalHeight;
467     distributeExtraLogicalHeightToPercentRows(remainingExtraLogicalHeight, totalPercent);
468     distributeExtraLogicalHeightToAutoRows(remainingExtraLogicalHeight, autoRowsCount);
469     distributeRemainingExtraLogicalHeight(remainingExtraLogicalHeight);
470     return extraLogicalHeight - remainingExtraLogicalHeight;
471 }
472
473 static bool shouldFlexCellChild(const RenderTableCell& cell, const RenderBox& cellDescendant)
474 {
475     if (!cell.style().logicalHeight().isSpecified())
476         return false;
477     if (cellDescendant.scrollsOverflowY())
478         return true;
479     return cellDescendant.shouldTreatChildAsReplacedInTableCells();
480 }
481
482 void RenderTableSection::relayoutCellIfFlexed(RenderTableCell& cell, int rowIndex, int rowHeight)
483 {
484     // Force percent height children to lay themselves out again.
485     // This will cause these children to grow to fill the cell.
486     // FIXME: There is still more work to do here to fully match WinIE (should
487     // it become necessary to do so). In quirks mode, WinIE behaves like we
488     // do, but it will clip the cells that spill out of the table section. In
489     // strict mode, Mozilla and WinIE both regrow the table to accommodate the
490     // new height of the cell (thus letting the percentages cause growth one
491     // time only). We may also not be handling row-spanning cells correctly.
492     //
493     // Note also the oddity where replaced elements always flex, and yet blocks/tables do
494     // not necessarily flex. WinIE is crazy and inconsistent, and we can't hope to
495     // match the behavior perfectly, but we'll continue to refine it as we discover new
496     // bugs. :)
497     bool cellChildrenFlex = false;
498     bool flexAllChildren = cell.style().logicalHeight().isFixed() || (!table()->style().logicalHeight().isAuto() && rowHeight != cell.logicalHeight());
499     
500     for (auto& renderer : childrenOfType<RenderBox>(cell)) {
501         if (renderer.style().logicalHeight().isPercentOrCalculated()
502             && (flexAllChildren || shouldFlexCellChild(cell, renderer))
503             && (!is<RenderTable>(renderer) || downcast<RenderTable>(renderer).hasSections())) {
504             cellChildrenFlex = true;
505             break;
506         }
507     }
508
509     if (!cellChildrenFlex) {
510         if (TrackedRendererListHashSet* percentHeightDescendants = cell.percentHeightDescendants()) {
511             for (auto* descendant : *percentHeightDescendants) {
512                 if (flexAllChildren || shouldFlexCellChild(cell, *descendant)) {
513                     cellChildrenFlex = true;
514                     break;
515                 }
516             }
517         }
518     }
519     
520     if (!cellChildrenFlex)
521         return;
522
523     cell.setChildNeedsLayout(MarkOnlyThis);
524         // Alignment within a cell is based off the calculated
525     // height, which becomes irrelevant once the cell has
526     // been resized based off its percentage.
527     cell.setOverrideContentLogicalHeightFromRowHeight(rowHeight);
528     cell.layoutIfNeeded();
529     
530     if (!cell.isBaselineAligned())
531         return;
532     
533     // If the baseline moved, we may have to update the data for our row. Find out the new baseline.
534     LayoutUnit baseline = cell.cellBaselinePosition();
535     if (baseline > cell.borderAndPaddingBefore())
536         m_grid[rowIndex].baseline = std::max(m_grid[rowIndex].baseline, baseline);
537 }
538
539 void RenderTableSection::layoutRows()
540 {
541 #ifndef NDEBUG
542     SetLayoutNeededForbiddenScope layoutForbiddenScope(this);
543 #endif
544
545     ASSERT(!needsLayout());
546
547     unsigned totalRows = m_grid.size();
548
549     // Set the width of our section now.  The rows will also be this width.
550     setLogicalWidth(table()->contentLogicalWidth());
551     m_forceSlowPaintPathWithOverflowingCell = false;
552
553     LayoutUnit vspacing = table()->vBorderSpacing();
554     unsigned nEffCols = table()->numEffCols();
555
556     LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || style().isFlippedBlocksWritingMode());
557
558     for (unsigned r = 0; r < totalRows; r++) {
559         // Set the row's x/y position and width/height.
560         if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) {
561             // FIXME: the x() position of the row should be table()->hBorderSpacing() so that it can 
562             // report the correct offsetLeft. However, that will require a lot of rebaselining of test results.
563             rowRenderer->setLocation(LayoutPoint(0, m_rowPos[r]));
564             rowRenderer->setLogicalWidth(logicalWidth());
565             rowRenderer->setLogicalHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing);
566             rowRenderer->updateLayerTransform();
567             rowRenderer->clearOverflow();
568             rowRenderer->addVisualEffectOverflow();
569         }
570
571         LayoutUnit rowHeightIncreaseForPagination = 0;
572
573         for (unsigned c = 0; c < nEffCols; c++) {
574             CellStruct& cs = cellAt(r, c);
575             RenderTableCell* cell = cs.primaryCell();
576
577             if (!cell || cs.inColSpan)
578                 continue;
579
580             int rowIndex = cell->rowIndex();
581             LayoutUnit rHeight = m_rowPos[rowIndex + cell->rowSpan()] - m_rowPos[rowIndex] - vspacing;
582
583             relayoutCellIfFlexed(*cell, r, rHeight);
584
585             cell->computeIntrinsicPadding(rHeight);
586
587             LayoutRect oldCellRect = cell->frameRect();
588
589             setLogicalPositionForCell(cell, c);
590
591             auto* layoutState = view().frameView().layoutContext().layoutState();
592             if (!cell->needsLayout() && layoutState->pageLogicalHeight() && layoutState->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset())
593                 cell->setChildNeedsLayout(MarkOnlyThis);
594
595             cell->layoutIfNeeded();
596
597             // FIXME: Make pagination work with vertical tables.
598             if (layoutState->pageLogicalHeight() && cell->logicalHeight() != rHeight) {
599                 // FIXME: Pagination might have made us change size. For now just shrink or grow the cell to fit without doing a relayout.
600                 // 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
601                 // either. It's at least stable though and won't result in an infinite # of relayouts that may never stabilize.
602                 if (cell->logicalHeight() > rHeight)
603                     rowHeightIncreaseForPagination = std::max(rowHeightIncreaseForPagination, cell->logicalHeight() - rHeight);
604                 cell->setLogicalHeight(rHeight);
605             }
606
607             LayoutSize childOffset(cell->location() - oldCellRect.location());
608             if (childOffset.width() || childOffset.height()) {
609                 view().frameView().layoutContext().addLayoutDelta(childOffset);
610
611                 // If the child moved, we have to repaint it as well as any floating/positioned
612                 // descendants.  An exception is if we need a layout.  In this case, we know we're going to
613                 // repaint ourselves (and the child) anyway.
614                 if (!table()->selfNeedsLayout() && cell->checkForRepaintDuringLayout())
615                     cell->repaintDuringLayoutIfMoved(oldCellRect);
616             }
617         }
618         if (rowHeightIncreaseForPagination) {
619             for (unsigned rowIndex = r + 1; rowIndex <= totalRows; rowIndex++)
620                 m_rowPos[rowIndex] += rowHeightIncreaseForPagination;
621             for (unsigned c = 0; c < nEffCols; ++c) {
622                 Vector<RenderTableCell*, 1>& cells = cellAt(r, c).cells;
623                 for (size_t i = 0; i < cells.size(); ++i)
624                     cells[i]->setLogicalHeight(cells[i]->logicalHeight() + rowHeightIncreaseForPagination);
625             }
626         }
627     }
628
629     ASSERT(!needsLayout());
630
631     setLogicalHeight(m_rowPos[totalRows]);
632
633     computeOverflowFromCells(totalRows, nEffCols);
634 }
635
636 void RenderTableSection::computeOverflowFromCells()
637 {
638     unsigned totalRows = m_grid.size();
639     unsigned nEffCols = table()->numEffCols();
640     computeOverflowFromCells(totalRows, nEffCols);
641 }
642
643 void RenderTableSection::computeOverflowFromCells(unsigned totalRows, unsigned nEffCols)
644 {
645     clearOverflow();
646     m_overflowingCells.clear();
647     unsigned totalCellsCount = nEffCols * totalRows;
648     unsigned maxAllowedOverflowingCellsCount = totalCellsCount < gMinTableSizeToUseFastPaintPathWithOverflowingCell ? 0 : gMaxAllowedOverflowingCellRatioForFastPaintPath * totalCellsCount;
649
650 #ifndef NDEBUG
651     bool hasOverflowingCell = false;
652 #endif
653     // Now that our height has been determined, add in overflow from cells.
654     for (unsigned r = 0; r < totalRows; r++) {
655         for (unsigned c = 0; c < nEffCols; c++) {
656             CellStruct& cs = cellAt(r, c);
657             RenderTableCell* cell = cs.primaryCell();
658             if (!cell || cs.inColSpan)
659                 continue;
660             if (r < totalRows - 1 && cell == primaryCellAt(r + 1, c))
661                 continue;
662             addOverflowFromChild(cell);
663 #ifndef NDEBUG
664             hasOverflowingCell |= cell->hasVisualOverflow();
665 #endif
666             if (cell->hasVisualOverflow() && !m_forceSlowPaintPathWithOverflowingCell) {
667                 m_overflowingCells.add(cell);
668                 if (m_overflowingCells.size() > maxAllowedOverflowingCellsCount) {
669                     // We need to set m_forcesSlowPaintPath only if there is a least one overflowing cells as the hit testing code rely on this information.
670                     m_forceSlowPaintPathWithOverflowingCell = true;
671                     // The slow path does not make any use of the overflowing cells info, don't hold on to the memory.
672                     m_overflowingCells.clear();
673                 }
674             }
675         }
676     }
677     ASSERT(hasOverflowingCell == this->hasOverflowingCell());
678 }
679
680 LayoutUnit RenderTableSection::calcOuterBorderBefore() const
681 {
682     unsigned totalCols = table()->numEffCols();
683     if (!m_grid.size() || !totalCols)
684         return 0;
685
686     LayoutUnit borderWidth = 0;
687
688     const BorderValue& sb = style().borderBefore();
689     if (sb.style() == BorderStyle::Hidden)
690         return -1;
691     if (sb.style() > BorderStyle::Hidden)
692         borderWidth = sb.width();
693
694     const BorderValue& rb = firstRow()->style().borderBefore();
695     if (rb.style() == BorderStyle::Hidden)
696         return -1;
697     if (rb.style() > BorderStyle::Hidden && rb.width() > borderWidth)
698         borderWidth = rb.width();
699
700     bool allHidden = true;
701     for (unsigned c = 0; c < totalCols; c++) {
702         const CellStruct& current = cellAt(0, c);
703         if (current.inColSpan || !current.hasCells())
704             continue;
705         const BorderValue& cb = current.primaryCell()->style().borderBefore(); // FIXME: Make this work with perpendicular and flipped cells.
706         // FIXME: Don't repeat for the same col group
707         RenderTableCol* colGroup = table()->colElement(c);
708         if (colGroup) {
709             const BorderValue& gb = colGroup->style().borderBefore();
710             if (gb.style() == BorderStyle::Hidden || cb.style() == BorderStyle::Hidden)
711                 continue;
712             allHidden = false;
713             if (gb.style() > BorderStyle::Hidden && gb.width() > borderWidth)
714                 borderWidth = gb.width();
715             if (cb.style() > BorderStyle::Hidden && cb.width() > borderWidth)
716                 borderWidth = cb.width();
717         } else {
718             if (cb.style() == BorderStyle::Hidden)
719                 continue;
720             allHidden = false;
721             if (cb.style() > BorderStyle::Hidden && cb.width() > borderWidth)
722                 borderWidth = cb.width();
723         }
724     }
725     if (allHidden)
726         return -1;
727     return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), false);
728 }
729
730 LayoutUnit RenderTableSection::calcOuterBorderAfter() const
731 {
732     unsigned totalCols = table()->numEffCols();
733     if (!m_grid.size() || !totalCols)
734         return 0;
735
736     LayoutUnit borderWidth = 0;
737
738     const BorderValue& sb = style().borderAfter();
739     if (sb.style() == BorderStyle::Hidden)
740         return -1;
741     if (sb.style() > BorderStyle::Hidden)
742         borderWidth = sb.width();
743
744     const BorderValue& rb = lastRow()->style().borderAfter();
745     if (rb.style() == BorderStyle::Hidden)
746         return -1;
747     if (rb.style() > BorderStyle::Hidden && rb.width() > borderWidth)
748         borderWidth = rb.width();
749
750     bool allHidden = true;
751     for (unsigned c = 0; c < totalCols; c++) {
752         const CellStruct& current = cellAt(m_grid.size() - 1, c);
753         if (current.inColSpan || !current.hasCells())
754             continue;
755         const BorderValue& cb = current.primaryCell()->style().borderAfter(); // FIXME: Make this work with perpendicular and flipped cells.
756         // FIXME: Don't repeat for the same col group
757         RenderTableCol* colGroup = table()->colElement(c);
758         if (colGroup) {
759             const BorderValue& gb = colGroup->style().borderAfter();
760             if (gb.style() == BorderStyle::Hidden || cb.style() == BorderStyle::Hidden)
761                 continue;
762             allHidden = false;
763             if (gb.style() > BorderStyle::Hidden && gb.width() > borderWidth)
764                 borderWidth = gb.width();
765             if (cb.style() > BorderStyle::Hidden && cb.width() > borderWidth)
766                 borderWidth = cb.width();
767         } else {
768             if (cb.style() == BorderStyle::Hidden)
769                 continue;
770             allHidden = false;
771             if (cb.style() > BorderStyle::Hidden && cb.width() > borderWidth)
772                 borderWidth = cb.width();
773         }
774     }
775     if (allHidden)
776         return -1;
777     return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), true);
778 }
779
780 LayoutUnit RenderTableSection::calcOuterBorderStart() const
781 {
782     unsigned totalCols = table()->numEffCols();
783     if (!m_grid.size() || !totalCols)
784         return 0;
785
786     LayoutUnit borderWidth = 0;
787
788     const BorderValue& sb = style().borderStart();
789     if (sb.style() == BorderStyle::Hidden)
790         return -1;
791     if (sb.style() > BorderStyle::Hidden)
792         borderWidth = sb.width();
793
794     if (RenderTableCol* colGroup = table()->colElement(0)) {
795         const BorderValue& gb = colGroup->style().borderStart();
796         if (gb.style() == BorderStyle::Hidden)
797             return -1;
798         if (gb.style() > BorderStyle::Hidden && gb.width() > borderWidth)
799             borderWidth = gb.width();
800     }
801
802     bool allHidden = true;
803     for (unsigned r = 0; r < m_grid.size(); r++) {
804         const CellStruct& current = cellAt(r, 0);
805         if (!current.hasCells())
806             continue;
807         // FIXME: Don't repeat for the same cell
808         const BorderValue& cb = current.primaryCell()->style().borderStart(); // FIXME: Make this work with perpendicular and flipped cells.
809         const BorderValue& rb = current.primaryCell()->parent()->style().borderStart();
810         if (cb.style() == BorderStyle::Hidden || rb.style() == BorderStyle::Hidden)
811             continue;
812         allHidden = false;
813         if (cb.style() > BorderStyle::Hidden && cb.width() > borderWidth)
814             borderWidth = cb.width();
815         if (rb.style() > BorderStyle::Hidden && rb.width() > borderWidth)
816             borderWidth = rb.width();
817     }
818     if (allHidden)
819         return -1;
820     return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), !table()->style().isLeftToRightDirection());
821 }
822
823 LayoutUnit RenderTableSection::calcOuterBorderEnd() const
824 {
825     unsigned totalCols = table()->numEffCols();
826     if (!m_grid.size() || !totalCols)
827         return 0;
828
829     LayoutUnit borderWidth = 0;
830
831     const BorderValue& sb = style().borderEnd();
832     if (sb.style() == BorderStyle::Hidden)
833         return -1;
834     if (sb.style() > BorderStyle::Hidden)
835         borderWidth = sb.width();
836
837     if (RenderTableCol* colGroup = table()->colElement(totalCols - 1)) {
838         const BorderValue& gb = colGroup->style().borderEnd();
839         if (gb.style() == BorderStyle::Hidden)
840             return -1;
841         if (gb.style() > BorderStyle::Hidden && gb.width() > borderWidth)
842             borderWidth = gb.width();
843     }
844
845     bool allHidden = true;
846     for (unsigned r = 0; r < m_grid.size(); r++) {
847         const CellStruct& current = cellAt(r, totalCols - 1);
848         if (!current.hasCells())
849             continue;
850         // FIXME: Don't repeat for the same cell
851         const BorderValue& cb = current.primaryCell()->style().borderEnd(); // FIXME: Make this work with perpendicular and flipped cells.
852         const BorderValue& rb = current.primaryCell()->parent()->style().borderEnd();
853         if (cb.style() == BorderStyle::Hidden || rb.style() == BorderStyle::Hidden)
854             continue;
855         allHidden = false;
856         if (cb.style() > BorderStyle::Hidden && cb.width() > borderWidth)
857             borderWidth = cb.width();
858         if (rb.style() > BorderStyle::Hidden && rb.width() > borderWidth)
859             borderWidth = rb.width();
860     }
861     if (allHidden)
862         return -1;
863     return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), table()->style().isLeftToRightDirection());
864 }
865
866 void RenderTableSection::recalcOuterBorder()
867 {
868     m_outerBorderBefore = calcOuterBorderBefore();
869     m_outerBorderAfter = calcOuterBorderAfter();
870     m_outerBorderStart = calcOuterBorderStart();
871     m_outerBorderEnd = calcOuterBorderEnd();
872 }
873
874 std::optional<int> RenderTableSection::firstLineBaseline() const
875 {
876     if (!m_grid.size())
877         return std::optional<int>();
878
879     int firstLineBaseline = m_grid[0].baseline;
880     if (firstLineBaseline)
881         return firstLineBaseline + roundToInt(m_rowPos[0]);
882
883     std::optional<int> result;
884     const Row& firstRow = m_grid[0].row;
885     for (size_t i = 0; i < firstRow.size(); ++i) {
886         const CellStruct& cs = firstRow.at(i);
887         const RenderTableCell* cell = cs.primaryCell();
888         // Only cells with content have a baseline
889         if (cell && cell->contentLogicalHeight()) {
890             int candidate = roundToInt(cell->logicalTop() + cell->borderAndPaddingBefore() + cell->contentLogicalHeight());
891             result = std::max(result.value_or(candidate), candidate);
892         }
893     }
894
895     return result;
896 }
897
898 void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
899 {
900     ASSERT(!needsLayout());
901     // avoid crashing on bugs that cause us to paint with dirty layout
902     if (needsLayout())
903         return;
904     
905     unsigned totalRows = m_grid.size();
906     unsigned totalCols = table()->columns().size();
907
908     if (!totalRows || !totalCols)
909         return;
910
911     LayoutPoint adjustedPaintOffset = paintOffset + location();
912
913     PaintPhase phase = paintInfo.phase;
914     bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
915     paintObject(paintInfo, adjustedPaintOffset);
916     if (pushedClip)
917         popContentsClip(paintInfo, phase, adjustedPaintOffset);
918
919     if ((phase == PaintPhase::Outline || phase == PaintPhase::SelfOutline) && style().visibility() == Visibility::Visible)
920         paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
921 }
922
923 static inline bool compareCellPositions(RenderTableCell* elem1, RenderTableCell* elem2)
924 {
925     return elem1->rowIndex() < elem2->rowIndex();
926 }
927
928 // This comparison is used only when we have overflowing cells as we have an unsorted array to sort. We thus need
929 // to sort both on rows and columns to properly repaint.
930 static inline bool compareCellPositionsWithOverflowingCells(RenderTableCell* elem1, RenderTableCell* elem2)
931 {
932     if (elem1->rowIndex() != elem2->rowIndex())
933         return elem1->rowIndex() < elem2->rowIndex();
934
935     return elem1->col() < elem2->col();
936 }
937
938 void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
939 {
940     LayoutPoint cellPoint = flipForWritingModeForChild(cell, paintOffset);
941     PaintPhase paintPhase = paintInfo.phase;
942     RenderTableRow& row = downcast<RenderTableRow>(*cell->parent());
943
944     if (paintPhase == PaintPhase::BlockBackground || paintPhase == PaintPhase::ChildBlockBackground) {
945         // We need to handle painting a stack of backgrounds.  This stack (from bottom to top) consists of
946         // the column group, column, row group, row, and then the cell.
947         RenderTableCol* column = table()->colElement(cell->col());
948         RenderTableCol* columnGroup = column ? column->enclosingColumnGroup() : nullptr;
949
950         // Column groups and columns first.
951         // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in
952         // the stack, since we have already opened a transparency layer (potentially) for the table row group.
953         // Note that we deliberately ignore whether or not the cell has a layer, since these backgrounds paint "behind" the
954         // cell.
955         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, columnGroup);
956         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, column);
957
958         // Paint the row group next.
959         cell->paintBackgroundsBehindCell(paintInfo, cellPoint, this);
960
961         // Paint the row next, but only if it doesn't have a layer.  If a row has a layer, it will be responsible for
962         // painting the row background for the cell.
963         if (!row.hasSelfPaintingLayer())
964             cell->paintBackgroundsBehindCell(paintInfo, cellPoint, &row);
965     }
966     if ((!cell->hasSelfPaintingLayer() && !row.hasSelfPaintingLayer()))
967         cell->paint(paintInfo, cellPoint);
968 }
969
970 LayoutRect RenderTableSection::logicalRectForWritingModeAndDirection(const LayoutRect& rect) const
971 {
972     LayoutRect tableAlignedRect(rect);
973
974     flipForWritingMode(tableAlignedRect);
975
976     if (!style().isHorizontalWritingMode())
977         tableAlignedRect = tableAlignedRect.transposedRect();
978
979     const Vector<LayoutUnit>& columnPos = table()->columnPositions();
980     // FIXME: The table's direction should determine our row's direction, not the section's (see bug 96691).
981     if (!style().isLeftToRightDirection())
982         tableAlignedRect.setX(columnPos[columnPos.size() - 1] - tableAlignedRect.maxX());
983
984     return tableAlignedRect;
985 }
986
987 CellSpan RenderTableSection::dirtiedRows(const LayoutRect& damageRect) const
988 {
989     if (m_forceSlowPaintPathWithOverflowingCell) 
990         return fullTableRowSpan();
991
992     CellSpan coveredRows = spannedRows(damageRect, IncludeAllIntersectingCells);
993
994     // To repaint the border we might need to repaint first or last row even if they are not spanned themselves.
995     if (coveredRows.start >= m_rowPos.size() - 1 && m_rowPos[m_rowPos.size() - 1] + table()->outerBorderAfter() >= damageRect.y())
996         --coveredRows.start;
997
998     if (!coveredRows.end && m_rowPos[0] - table()->outerBorderBefore() <= damageRect.maxY())
999         ++coveredRows.end;
1000
1001     return coveredRows;
1002 }
1003
1004 CellSpan RenderTableSection::dirtiedColumns(const LayoutRect& damageRect) const
1005 {
1006     if (m_forceSlowPaintPathWithOverflowingCell) 
1007         return fullTableColumnSpan();
1008
1009     CellSpan coveredColumns = spannedColumns(damageRect, IncludeAllIntersectingCells);
1010
1011     const Vector<LayoutUnit>& columnPos = table()->columnPositions();
1012     // To repaint the border we might need to repaint first or last column even if they are not spanned themselves.
1013     if (coveredColumns.start >= columnPos.size() - 1 && columnPos[columnPos.size() - 1] + table()->outerBorderEnd() >= damageRect.x())
1014         --coveredColumns.start;
1015
1016     if (!coveredColumns.end && columnPos[0] - table()->outerBorderStart() <= damageRect.maxX())
1017         ++coveredColumns.end;
1018
1019     return coveredColumns;
1020 }
1021
1022 CellSpan RenderTableSection::spannedRows(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells shouldIncludeAllIntersectionCells) const
1023 {
1024     // Find the first row that starts after rect top.
1025     unsigned nextRow = std::upper_bound(m_rowPos.begin(), m_rowPos.end(), flippedRect.y()) - m_rowPos.begin();
1026     if (shouldIncludeAllIntersectionCells == IncludeAllIntersectingCells && nextRow && m_rowPos[nextRow - 1] == flippedRect.y())
1027         --nextRow;
1028
1029     if (nextRow == m_rowPos.size())
1030         return CellSpan(m_rowPos.size() - 1, m_rowPos.size() - 1); // After all rows.
1031
1032     unsigned startRow = nextRow > 0 ? nextRow - 1 : 0;
1033
1034     // Find the first row that starts after rect bottom.
1035     unsigned endRow;
1036     if (m_rowPos[nextRow] >= flippedRect.maxY())
1037         endRow = nextRow;
1038     else {
1039         endRow = std::upper_bound(m_rowPos.begin() + static_cast<int32_t>(nextRow), m_rowPos.end(), flippedRect.maxY()) - m_rowPos.begin();
1040         if (endRow == m_rowPos.size())
1041             endRow = m_rowPos.size() - 1;
1042     }
1043
1044     return CellSpan(startRow, endRow);
1045 }
1046
1047 CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells shouldIncludeAllIntersectionCells) const
1048 {
1049     const Vector<LayoutUnit>& columnPos = table()->columnPositions();
1050
1051     // Find the first column that starts after rect left.
1052     // lower_bound doesn't handle the edge between two cells properly as it would wrongly return the
1053     // cell on the logical top/left.
1054     // upper_bound on the other hand properly returns the cell on the logical bottom/right, which also
1055     // matches the behavior of other browsers.
1056     unsigned nextColumn = std::upper_bound(columnPos.begin(), columnPos.end(), flippedRect.x()) - columnPos.begin();
1057     if (shouldIncludeAllIntersectionCells == IncludeAllIntersectingCells && nextColumn && columnPos[nextColumn - 1] == flippedRect.x())
1058         --nextColumn;
1059
1060     if (nextColumn == columnPos.size())
1061         return CellSpan(columnPos.size() - 1, columnPos.size() - 1); // After all columns.
1062
1063     unsigned startColumn = nextColumn > 0 ? nextColumn - 1 : 0;
1064
1065     // Find the first column that starts after rect right.
1066     unsigned endColumn;
1067     if (columnPos[nextColumn] >= flippedRect.maxX())
1068         endColumn = nextColumn;
1069     else {
1070         endColumn = std::upper_bound(columnPos.begin() + static_cast<int32_t>(nextColumn), columnPos.end(), flippedRect.maxX()) - columnPos.begin();
1071         if (endColumn == columnPos.size())
1072             endColumn = columnPos.size() - 1;
1073     }
1074
1075     return CellSpan(startColumn, endColumn);
1076 }
1077
1078 void RenderTableSection::paintRowGroupBorder(const PaintInfo& paintInfo, bool antialias, LayoutRect rect, BoxSide side, CSSPropertyID borderColor, BorderStyle borderStyle, BorderStyle tableBorderStyle)
1079 {
1080     if (tableBorderStyle == BorderStyle::Hidden)
1081         return;
1082     rect.intersect(paintInfo.rect);
1083     if (rect.isEmpty())
1084         return;
1085     drawLineForBoxSide(paintInfo.context(), rect, side, style().visitedDependentColorWithColorFilter(borderColor), borderStyle, 0, 0, antialias);
1086 }
1087
1088 LayoutUnit RenderTableSection::offsetLeftForRowGroupBorder(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row)
1089 {
1090     if (style().isHorizontalWritingMode()) {
1091         if (style().isLeftToRightDirection())
1092             return cell ? cell->x() + cell->width() : LayoutUnit::fromPixel(0);
1093         return -outerBorderLeft(&style());
1094     }
1095     bool isLastRow = row + 1 == m_grid.size();
1096     return rowGroupRect.width() - m_rowPos[row + 1] + (isLastRow ? -outerBorderLeft(&style()) : LayoutUnit::fromPixel(0));
1097 }
1098
1099 LayoutUnit RenderTableSection::offsetTopForRowGroupBorder(RenderTableCell* cell, BoxSide borderSide, unsigned row)
1100 {
1101     bool isLastRow = row + 1 == m_grid.size();
1102     if (style().isHorizontalWritingMode())
1103         return m_rowPos[row] + (!row && borderSide == BSRight ? -outerBorderTop(&style()) : isLastRow && borderSide == BSLeft ? outerBorderTop(&style()) : LayoutUnit::fromPixel(0));
1104     if (style().isLeftToRightDirection())
1105         return (cell ? cell->y() + cell->height() : LayoutUnit::fromPixel(0)) + (borderSide == BSLeft ? outerBorderTop(&style()) : LayoutUnit::fromPixel(0));
1106     return borderSide == BSRight ? -outerBorderTop(&style()) : LayoutUnit::fromPixel(0);
1107 }
1108
1109 LayoutUnit RenderTableSection::verticalRowGroupBorderHeight(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row)
1110 {
1111     bool isLastRow = row + 1 == m_grid.size();
1112     if (style().isHorizontalWritingMode())
1113         return m_rowPos[row + 1] - m_rowPos[row] + (!row ? outerBorderTop(&style()) : isLastRow ? outerBorderBottom(&style()) : LayoutUnit::fromPixel(0));
1114     if (style().isLeftToRightDirection())
1115         return rowGroupRect.height() - (cell ? cell->y() + cell->height() : LayoutUnit::fromPixel(0)) + outerBorderBottom(&style());
1116     return cell ? rowGroupRect.height() - (cell->y() - cell->height()) : LayoutUnit::fromPixel(0);
1117 }
1118
1119 LayoutUnit RenderTableSection::horizontalRowGroupBorderWidth(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row, unsigned column)
1120 {
1121     if (style().isHorizontalWritingMode()) {
1122         if (style().isLeftToRightDirection())
1123             return rowGroupRect.width() - (cell ? cell->x() + cell->width() : LayoutUnit::fromPixel(0)) + (!column ? outerBorderLeft(&style()) : column == table()->numEffCols() ? outerBorderRight(&style()) : LayoutUnit::fromPixel(0));
1124         return cell ? rowGroupRect.width() - (cell->x() - cell->width()) : LayoutUnit::fromPixel(0);
1125     }
1126     bool isLastRow = row + 1 == m_grid.size();
1127     return m_rowPos[row + 1] - m_rowPos[row] + (isLastRow ? outerBorderLeft(&style()) : !row ? outerBorderRight(&style()) : LayoutUnit::fromPixel(0));
1128 }
1129
1130 void RenderTableSection::paintRowGroupBorderIfRequired(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, unsigned row, unsigned column, BoxSide borderSide, RenderTableCell* cell)
1131 {
1132     if (table()->currentBorderValue()->precedence() > BorderPrecedence::RowGroup)
1133         return;
1134     if (paintInfo.context().paintingDisabled())
1135         return;
1136
1137     const RenderStyle& style = this->style();
1138     bool antialias = shouldAntialiasLines(paintInfo.context());
1139     LayoutRect rowGroupRect = LayoutRect(paintOffset, size());
1140     rowGroupRect.moveBy(-LayoutPoint(outerBorderLeft(&style), (borderSide == BSRight) ? LayoutUnit::fromPixel(0) : outerBorderTop(&style)));
1141
1142     switch (borderSide) {
1143     case BSTop:
1144         paintRowGroupBorder(paintInfo, antialias, LayoutRect(paintOffset.x() + offsetLeftForRowGroupBorder(cell, rowGroupRect, row), rowGroupRect.y(), 
1145             horizontalRowGroupBorderWidth(cell, rowGroupRect, row, column), style.borderTop().width()), BSTop, CSSPropertyBorderTopColor, style.borderTopStyle(), table()->style().borderTopStyle());
1146         break;
1147     case BSBottom:
1148         paintRowGroupBorder(paintInfo, antialias, LayoutRect(paintOffset.x() + offsetLeftForRowGroupBorder(cell, rowGroupRect, row), rowGroupRect.y() + rowGroupRect.height(), 
1149             horizontalRowGroupBorderWidth(cell, rowGroupRect, row, column), style.borderBottom().width()), BSBottom, CSSPropertyBorderBottomColor, style.borderBottomStyle(), table()->style().borderBottomStyle());
1150         break;
1151     case BSLeft:
1152         paintRowGroupBorder(paintInfo, antialias, LayoutRect(rowGroupRect.x(), rowGroupRect.y() + offsetTopForRowGroupBorder(cell, borderSide, row), style.borderLeft().width(),
1153             verticalRowGroupBorderHeight(cell, rowGroupRect, row)), BSLeft, CSSPropertyBorderLeftColor, style.borderLeftStyle(), table()->style().borderLeftStyle());
1154         break;
1155     case BSRight:
1156         paintRowGroupBorder(paintInfo, antialias, LayoutRect(rowGroupRect.x() + rowGroupRect.width(), rowGroupRect.y() + offsetTopForRowGroupBorder(cell, borderSide, row), style.borderRight().width(),
1157             verticalRowGroupBorderHeight(cell, rowGroupRect, row)), BSRight, CSSPropertyBorderRightColor, style.borderRightStyle(), table()->style().borderRightStyle());
1158         break;
1159     default:
1160         break;
1161     }
1162
1163 }
1164
1165 static BoxSide physicalBorderForDirection(const RenderStyle* styleForCellFlow, CollapsedBorderSide side)
1166 {
1167
1168     switch (side) {
1169     case CBSStart:
1170         if (styleForCellFlow->isHorizontalWritingMode())
1171             return styleForCellFlow->isLeftToRightDirection() ? BSLeft : BSRight;
1172         return styleForCellFlow->isLeftToRightDirection() ? BSTop : BSBottom;
1173     case CBSEnd:
1174         if (styleForCellFlow->isHorizontalWritingMode())
1175             return styleForCellFlow->isLeftToRightDirection() ? BSRight : BSLeft;
1176         return styleForCellFlow->isLeftToRightDirection() ? BSBottom : BSTop;
1177     case CBSBefore:
1178         if (styleForCellFlow->isHorizontalWritingMode())
1179             return BSTop;
1180         return styleForCellFlow->isLeftToRightDirection() ? BSRight : BSLeft;
1181     case CBSAfter:
1182         if (styleForCellFlow->isHorizontalWritingMode())
1183             return BSBottom;
1184         return styleForCellFlow->isLeftToRightDirection() ? BSLeft : BSRight;
1185     default:
1186         ASSERT_NOT_REACHED();
1187         return BSLeft;
1188     }
1189 }
1190
1191 void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1192 {
1193     LayoutRect localRepaintRect = paintInfo.rect;
1194     localRepaintRect.moveBy(-paintOffset);
1195
1196     LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(localRepaintRect);
1197
1198     CellSpan dirtiedRows = this->dirtiedRows(tableAlignedRect);
1199     CellSpan dirtiedColumns = this->dirtiedColumns(tableAlignedRect);
1200
1201     if (dirtiedColumns.start < dirtiedColumns.end) {
1202         if (!m_hasMultipleCellLevels && !m_overflowingCells.size()) {
1203             if (paintInfo.phase == PaintPhase::CollapsedTableBorders) {
1204                 // Collapsed borders are painted from the bottom right to the top left so that precedence
1205                 // due to cell position is respected. We need to paint one row beyond the topmost dirtied
1206                 // row to calculate its collapsed border value.
1207                 unsigned startRow = dirtiedRows.start ? dirtiedRows.start - 1 : 0;
1208                 for (unsigned r = dirtiedRows.end; r > startRow; r--) {
1209                     unsigned row = r - 1;
1210                     bool shouldPaintRowGroupBorder = false;
1211                     for (unsigned c = dirtiedColumns.end; c > dirtiedColumns.start; c--) {
1212                         unsigned col = c - 1;
1213                         CellStruct& current = cellAt(row, col);
1214                         RenderTableCell* cell = current.primaryCell();
1215                         if (!cell) {
1216                             if (!c)
1217                                 paintRowGroupBorderIfRequired(paintInfo, paintOffset, row, col, physicalBorderForDirection(&style(), CBSStart));
1218                             else if (c == table()->numEffCols())
1219                                 paintRowGroupBorderIfRequired(paintInfo, paintOffset, row, col, physicalBorderForDirection(&style(), CBSEnd));
1220                             shouldPaintRowGroupBorder = true;
1221                             continue;
1222                         }
1223                         if ((row > dirtiedRows.start && primaryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start && primaryCellAt(row, col - 1) == cell))
1224                             continue;
1225                         
1226                         // If we had a run of null cells paint their corresponding section of the row group's border if necessary. Note that
1227                         // this will only happen once within a row as the null cells will always be clustered together on one end of the row.
1228                         if (shouldPaintRowGroupBorder) {
1229                             if (r == m_grid.size())
1230                                 paintRowGroupBorderIfRequired(paintInfo, paintOffset, row, col, physicalBorderForDirection(&style(), CBSAfter), cell);
1231                             else if (!row && !table()->sectionAbove(this))
1232                                 paintRowGroupBorderIfRequired(paintInfo, paintOffset, row, col, physicalBorderForDirection(&style(), CBSBefore), cell);
1233                             shouldPaintRowGroupBorder = false;
1234                         }
1235
1236                         LayoutPoint cellPoint = flipForWritingModeForChild(cell, paintOffset);
1237                         cell->paintCollapsedBorders(paintInfo, cellPoint);
1238                     }
1239                 }
1240             } else {
1241                 // Draw the dirty cells in the order that they appear.
1242                 for (unsigned r = dirtiedRows.start; r < dirtiedRows.end; r++) {
1243                     RenderTableRow* row = m_grid[r].rowRenderer;
1244                     if (row && !row->hasSelfPaintingLayer())
1245                         row->paintOutlineForRowIfNeeded(paintInfo, paintOffset);
1246                     for (unsigned c = dirtiedColumns.start; c < dirtiedColumns.end; c++) {
1247                         CellStruct& current = cellAt(r, c);
1248                         RenderTableCell* cell = current.primaryCell();
1249                         if (!cell || (r > dirtiedRows.start && primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start && primaryCellAt(r, c - 1) == cell))
1250                             continue;
1251                         paintCell(cell, paintInfo, paintOffset);
1252                     }
1253                 }
1254             }
1255         } else {
1256             // The overflowing cells should be scarce to avoid adding a lot of cells to the HashSet.
1257 #ifndef NDEBUG
1258             unsigned totalRows = m_grid.size();
1259             unsigned totalCols = table()->columns().size();
1260             ASSERT(m_overflowingCells.size() < totalRows * totalCols * gMaxAllowedOverflowingCellRatioForFastPaintPath);
1261 #endif
1262
1263             // To make sure we properly repaint the section, we repaint all the overflowing cells that we collected.
1264             auto cells = copyToVector(m_overflowingCells);
1265
1266             HashSet<RenderTableCell*> spanningCells;
1267
1268             for (unsigned r = dirtiedRows.start; r < dirtiedRows.end; r++) {
1269                 RenderTableRow* row = m_grid[r].rowRenderer;
1270                 if (row && !row->hasSelfPaintingLayer())
1271                     row->paintOutlineForRowIfNeeded(paintInfo, paintOffset);
1272                 for (unsigned c = dirtiedColumns.start; c < dirtiedColumns.end; c++) {
1273                     CellStruct& current = cellAt(r, c);
1274                     if (!current.hasCells())
1275                         continue;
1276                     for (unsigned i = 0; i < current.cells.size(); ++i) {
1277                         if (m_overflowingCells.contains(current.cells[i]))
1278                             continue;
1279
1280                         if (current.cells[i]->rowSpan() > 1 || current.cells[i]->colSpan() > 1) {
1281                             if (!spanningCells.add(current.cells[i]).isNewEntry)
1282                                 continue;
1283                         }
1284
1285                         cells.append(current.cells[i]);
1286                     }
1287                 }
1288             }
1289
1290             // Sort the dirty cells by paint order.
1291             if (!m_overflowingCells.size())
1292                 std::stable_sort(cells.begin(), cells.end(), compareCellPositions);
1293             else
1294                 std::sort(cells.begin(), cells.end(), compareCellPositionsWithOverflowingCells);
1295
1296             if (paintInfo.phase == PaintPhase::CollapsedTableBorders) {
1297                 for (unsigned i = cells.size(); i > 0; --i) {
1298                     LayoutPoint cellPoint = flipForWritingModeForChild(cells[i - 1], paintOffset);
1299                     cells[i - 1]->paintCollapsedBorders(paintInfo, cellPoint);
1300                 }
1301             } else {
1302                 for (unsigned i = 0; i < cells.size(); ++i)
1303                     paintCell(cells[i], paintInfo, paintOffset);
1304             }
1305         }
1306     }
1307 }
1308
1309 void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*)
1310 {
1311     // FIXME: Examine cells and repaint only the rect the image paints in.
1312     repaint();
1313 }
1314
1315 void RenderTableSection::recalcCells()
1316 {
1317     ASSERT(m_needsCellRecalc);
1318     // We reset the flag here to ensure that addCell() works. This is safe to do because we clear the grid
1319     // and update its dimensions to be consistent with the table's column representation before we rebuild
1320     // the grid using addCell().
1321     m_needsCellRecalc = false;
1322
1323     m_cCol = 0;
1324     m_cRow = 0;
1325     m_grid.clear();
1326
1327     for (RenderTableRow* row = firstRow(); row; row = row->nextRow()) {
1328         unsigned insertionRow = m_cRow;
1329         m_cRow++;
1330         m_cCol = 0;
1331         ensureRows(m_cRow);
1332
1333         m_grid[insertionRow].rowRenderer = row;
1334         row->setRowIndex(insertionRow);
1335         setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(m_grid[insertionRow]);
1336
1337         for (RenderTableCell* cell = row->firstCell(); cell; cell = cell->nextCell())
1338             addCell(cell, row);
1339     }
1340
1341     m_grid.shrinkToFit();
1342     setNeedsLayout();
1343 }
1344
1345 void RenderTableSection::removeRedundantColumns()
1346 {
1347     auto maximumNumberOfColumns = table()->numEffCols();
1348     for (auto& rowItem : m_grid) {
1349         if (rowItem.row.size() <= maximumNumberOfColumns)
1350             continue;
1351         rowItem.row.resize(maximumNumberOfColumns);
1352     }
1353 }
1354
1355 // FIXME: This function could be made O(1) in certain cases (like for the non-most-constrainive cells' case).
1356 void RenderTableSection::rowLogicalHeightChanged(unsigned rowIndex)
1357 {
1358     if (needsCellRecalc())
1359         return;
1360
1361     setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(m_grid[rowIndex]);
1362
1363     for (RenderTableCell* cell = m_grid[rowIndex].rowRenderer->firstCell(); cell; cell = cell->nextCell())
1364         updateLogicalHeightForCell(m_grid[rowIndex], cell);
1365 }
1366
1367 void RenderTableSection::setNeedsCellRecalc()
1368 {
1369     m_needsCellRecalc = true;
1370
1371     // Clear the grid now to ensure that we don't hold onto any stale pointers (e.g. a cell renderer that is being removed).
1372     m_grid.clear();
1373
1374     if (RenderTable* t = table())
1375         t->setNeedsSectionRecalc();
1376 }
1377
1378 unsigned RenderTableSection::numColumns() const
1379 {
1380     ASSERT(!m_needsCellRecalc);
1381     unsigned result = 0;
1382     
1383     for (unsigned r = 0; r < m_grid.size(); ++r) {
1384         for (unsigned c = result; c < table()->numEffCols(); ++c) {
1385             const CellStruct& cell = cellAt(r, c);
1386             if (cell.hasCells() || cell.inColSpan)
1387                 result = c;
1388         }
1389     }
1390     
1391     return result + 1;
1392 }
1393
1394 const BorderValue& RenderTableSection::borderAdjoiningStartCell(const RenderTableCell& cell) const
1395 {
1396     ASSERT(cell.isFirstOrLastCellInRow());
1397     return isDirectionSame(this, &cell) ? style().borderStart() : style().borderEnd();
1398 }
1399
1400 const BorderValue& RenderTableSection::borderAdjoiningEndCell(const RenderTableCell& cell) const
1401 {
1402     ASSERT(cell.isFirstOrLastCellInRow());
1403     return isDirectionSame(this, &cell) ? style().borderEnd() : style().borderStart();
1404 }
1405
1406 const RenderTableCell* RenderTableSection::firstRowCellAdjoiningTableStart() const
1407 {
1408     unsigned adjoiningStartCellColumnIndex = isDirectionSame(this, table()) ? 0 : table()->lastColumnIndex();
1409     return cellAt(0, adjoiningStartCellColumnIndex).primaryCell();
1410 }
1411
1412 const RenderTableCell* RenderTableSection::firstRowCellAdjoiningTableEnd() const
1413 {
1414     unsigned adjoiningEndCellColumnIndex = isDirectionSame(this, table()) ? table()->lastColumnIndex() : 0;
1415     return cellAt(0, adjoiningEndCellColumnIndex).primaryCell();
1416 }
1417
1418 void RenderTableSection::appendColumn(unsigned pos)
1419 {
1420     ASSERT(!m_needsCellRecalc);
1421
1422     for (unsigned row = 0; row < m_grid.size(); ++row)
1423         m_grid[row].row.resize(pos + 1);
1424 }
1425
1426 void RenderTableSection::splitColumn(unsigned pos, unsigned first)
1427 {
1428     ASSERT(!m_needsCellRecalc);
1429
1430     if (m_cCol > pos)
1431         m_cCol++;
1432     for (unsigned row = 0; row < m_grid.size(); ++row) {
1433         Row& r = m_grid[row].row;
1434         r.insert(pos + 1, CellStruct());
1435         if (r[pos].hasCells()) {
1436             r[pos + 1].cells.appendVector(r[pos].cells);
1437             RenderTableCell* cell = r[pos].primaryCell();
1438             ASSERT(cell);
1439             ASSERT(cell->colSpan() >= (r[pos].inColSpan ? 1u : 0));
1440             unsigned colleft = cell->colSpan() - r[pos].inColSpan;
1441             if (first > colleft)
1442               r[pos + 1].inColSpan = 0;
1443             else
1444               r[pos + 1].inColSpan = first + r[pos].inColSpan;
1445         } else {
1446             r[pos + 1].inColSpan = 0;
1447         }
1448     }
1449 }
1450
1451 // Hit Testing
1452 bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1453 {
1454     // If we have no children then we have nothing to do.
1455     if (!firstRow())
1456         return false;
1457
1458     // Table sections cannot ever be hit tested.  Effectively they do not exist.
1459     // Just forward to our children always.
1460     LayoutPoint adjustedLocation = accumulatedOffset + location();
1461
1462     if (hasOverflowClip() && !locationInContainer.intersects(overflowClipRect(adjustedLocation, nullptr)))
1463         return false;
1464
1465     if (hasOverflowingCell()) {
1466         for (RenderTableRow* row = lastRow(); row; row = row->previousRow()) {
1467             // FIXME: We have to skip over inline flows, since they can show up inside table rows
1468             // at the moment (a demoted inline <form> for example). If we ever implement a
1469             // table-specific hit-test method (which we should do for performance reasons anyway),
1470             // then we can remove this check.
1471             if (!row->hasSelfPaintingLayer()) {
1472                 LayoutPoint childPoint = flipForWritingModeForChild(row, adjustedLocation);
1473                 if (row->nodeAtPoint(request, result, locationInContainer, childPoint, action)) {
1474                     updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint));
1475                     return true;
1476                 }
1477             }
1478         }
1479         return false;
1480     }
1481
1482     recalcCellsIfNeeded();
1483
1484     LayoutRect hitTestRect = locationInContainer.boundingBox();
1485     hitTestRect.moveBy(-adjustedLocation);
1486
1487     LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(hitTestRect);
1488     CellSpan rowSpan = spannedRows(tableAlignedRect, DoNotIncludeAllIntersectingCells);
1489     CellSpan columnSpan = spannedColumns(tableAlignedRect, DoNotIncludeAllIntersectingCells);
1490
1491     // Now iterate over the spanned rows and columns.
1492     for (unsigned hitRow = rowSpan.start; hitRow < rowSpan.end; ++hitRow) {
1493         for (unsigned hitColumn = columnSpan.start; hitColumn < columnSpan.end; ++hitColumn) {
1494             CellStruct& current = cellAt(hitRow, hitColumn);
1495
1496             // If the cell is empty, there's nothing to do
1497             if (!current.hasCells())
1498                 continue;
1499
1500             for (unsigned i = current.cells.size() ; i; ) {
1501                 --i;
1502                 RenderTableCell* cell = current.cells[i];
1503                 LayoutPoint cellPoint = flipForWritingModeForChild(cell, adjustedLocation);
1504                 if (static_cast<RenderObject*>(cell)->nodeAtPoint(request, result, locationInContainer, cellPoint, action)) {
1505                     updateHitTestResult(result, locationInContainer.point() - toLayoutSize(cellPoint));
1506                     return true;
1507                 }
1508             }
1509             if (!request.resultIsElementList())
1510                 break;
1511         }
1512         if (!request.resultIsElementList())
1513             break;
1514     }
1515
1516     return false;
1517 }
1518
1519 void RenderTableSection::clearCachedCollapsedBorders()
1520 {
1521     if (!table()->collapseBorders())
1522         return;
1523     m_cellsCollapsedBorders.clear();
1524 }
1525
1526 void RenderTableSection::removeCachedCollapsedBorders(const RenderTableCell& cell)
1527 {
1528     if (!table()->collapseBorders())
1529         return;
1530     
1531     for (int side = CBSBefore; side <= CBSEnd; ++side)
1532         m_cellsCollapsedBorders.remove(std::make_pair(&cell, side));
1533 }
1534
1535 void RenderTableSection::setCachedCollapsedBorder(const RenderTableCell& cell, CollapsedBorderSide side, CollapsedBorderValue border)
1536 {
1537     ASSERT(table()->collapseBorders());
1538     ASSERT(border.width());
1539     m_cellsCollapsedBorders.set(std::make_pair(&cell, side), border);
1540 }
1541
1542 CollapsedBorderValue RenderTableSection::cachedCollapsedBorder(const RenderTableCell& cell, CollapsedBorderSide side)
1543 {
1544     ASSERT(table()->collapseBorders() && table()->collapsedBordersAreValid());
1545     auto it = m_cellsCollapsedBorders.find(std::make_pair(&cell, side));
1546     // Only non-empty collapsed borders are in the hashmap.
1547     if (it == m_cellsCollapsedBorders.end())
1548         return CollapsedBorderValue(BorderValue(), Color(), BorderPrecedence::Cell);
1549     return it->value;
1550 }
1551
1552 RenderPtr<RenderTableSection> RenderTableSection::createTableSectionWithStyle(Document& document, const RenderStyle& style)
1553 {
1554     auto section = createRenderer<RenderTableSection>(document, RenderStyle::createAnonymousStyleWithDisplay(style, DisplayType::TableRowGroup));
1555     section->initializeStyle();
1556     return section;
1557 }
1558
1559 RenderPtr<RenderTableSection> RenderTableSection::createAnonymousWithParentRenderer(const RenderTable& parent)
1560 {
1561     return RenderTableSection::createTableSectionWithStyle(parent.document(), parent.style());
1562 }
1563
1564 void RenderTableSection::setLogicalPositionForCell(RenderTableCell* cell, unsigned effectiveColumn) const
1565 {
1566     LayoutPoint oldCellLocation = cell->location();
1567
1568     LayoutPoint cellLocation(0, m_rowPos[cell->rowIndex()]);
1569     LayoutUnit horizontalBorderSpacing = table()->hBorderSpacing();
1570
1571     // FIXME: The table's direction should determine our row's direction, not the section's (see bug 96691).
1572     if (!style().isLeftToRightDirection())
1573         cellLocation.setX(table()->columnPositions()[table()->numEffCols()] - table()->columnPositions()[table()->colToEffCol(cell->col() + cell->colSpan())] + horizontalBorderSpacing);
1574     else
1575         cellLocation.setX(table()->columnPositions()[effectiveColumn] + horizontalBorderSpacing);
1576
1577     cell->setLogicalLocation(cellLocation);
1578     view().frameView().layoutContext().addLayoutDelta(oldCellLocation - cell->location());
1579 }
1580
1581 } // namespace WebCore