diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderTableSection.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderTableSection.cpp | 397 |
1 files changed, 209 insertions, 188 deletions
diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index 39f594c84..7b47d6ce6 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -29,9 +29,12 @@ #include "HitTestResult.h" #include "HTMLNames.h" #include "PaintInfo.h" +#include "RenderChildIterator.h" +#include "RenderNamedFlowFragment.h" #include "RenderTableCell.h" #include "RenderTableCol.h" #include "RenderTableRow.h" +#include "RenderTextControl.h" #include "RenderView.h" #include "StyleInheritedData.h" #include <limits> @@ -43,8 +46,8 @@ namespace WebCore { using namespace HTMLNames; // Those 2 variables are used to balance the memory consumption vs the repaint time on big tables. -static unsigned gMinTableSizeToUseFastPaintPathWithOverflowingCell = 75 * 75; -static float gMaxAllowedOverflowingCellRatioForFastPaintPath = 0.1f; +static const unsigned gMinTableSizeToUseFastPaintPathWithOverflowingCell = 75 * 75; +static const float gMaxAllowedOverflowingCellRatioForFastPaintPath = 0.1f; static inline void setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(RenderTableSection::RowStruct& row) { @@ -65,12 +68,11 @@ static inline void updateLogicalHeightForCell(RenderTableSection::RowStruct& row Length cRowLogicalHeight = row.logicalHeight; switch (logicalHeight.type()) { case Percent: - if (!(cRowLogicalHeight.isPercent()) - || (cRowLogicalHeight.isPercent() && cRowLogicalHeight.percent() < logicalHeight.percent())) + if (!cRowLogicalHeight.isPercent() || cRowLogicalHeight.percent() < logicalHeight.percent()) row.logicalHeight = logicalHeight; break; case Fixed: - if (cRowLogicalHeight.type() < Percent + if (cRowLogicalHeight.isAuto() || cRowLogicalHeight.isRelative() || (cRowLogicalHeight.isFixed() && cRowLogicalHeight.value() < logicalHeight.value())) row.logicalHeight = logicalHeight; break; @@ -81,30 +83,14 @@ static inline void updateLogicalHeightForCell(RenderTableSection::RowStruct& row } } -RenderTableSection::RenderTableSection(Element& element, PassRef<RenderStyle> style) - : RenderBox(element, std::move(style), 0) - , m_cCol(0) - , m_cRow(0) - , m_outerBorderStart(0) - , m_outerBorderEnd(0) - , m_outerBorderBefore(0) - , m_outerBorderAfter(0) - , m_needsCellRecalc(false) - , m_hasMultipleCellLevels(false) +RenderTableSection::RenderTableSection(Element& element, RenderStyle&& style) + : RenderBox(element, WTFMove(style), 0) { setInline(false); } -RenderTableSection::RenderTableSection(Document& document, PassRef<RenderStyle> style) - : RenderBox(document, std::move(style), 0) - , m_cCol(0) - , m_cRow(0) - , m_outerBorderStart(0) - , m_outerBorderEnd(0) - , m_outerBorderBefore(0) - , m_outerBorderAfter(0) - , m_needsCellRecalc(false) - , m_hasMultipleCellLevels(false) +RenderTableSection::RenderTableSection(Document& document, RenderStyle&& style) + : RenderBox(document, WTFMove(style), 0) { setInline(false); } @@ -120,7 +106,7 @@ void RenderTableSection::styleDidChange(StyleDifference diff, const RenderStyle* // If border was changed, notify table. RenderTable* table = this->table(); - if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style().border()) + if (table && oldStyle && oldStyle->border() != style().border()) table->invalidateCollapsedBorders(); } @@ -135,22 +121,22 @@ void RenderTableSection::willBeRemovedFromTree() void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild) { - if (!child->isTableRow()) { + if (!is<RenderTableRow>(*child)) { RenderObject* last = beforeChild; if (!last) last = lastRow(); if (last && last->isAnonymous() && !last->isBeforeOrAfterContent()) { - RenderTableRow* row = toRenderTableRow(last); - if (beforeChild == row) - beforeChild = row->firstCell(); - row->addChild(child, beforeChild); + RenderTableRow& row = downcast<RenderTableRow>(*last); + if (beforeChild == &row) + beforeChild = row.firstCell(); + row.addChild(child, beforeChild); return; } if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) { RenderObject* row = beforeChild->previousSibling(); - if (row && row->isTableRow() && row->isAnonymous()) { - toRenderTableRow(row)->addChild(child); + if (is<RenderTableRow>(row) && row->isAnonymous()) { + downcast<RenderTableRow>(*row).addChild(child); return; } } @@ -158,14 +144,14 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild // If beforeChild is inside an anonymous cell/row, insert into the cell or into // the anonymous row containing it, if there is one. RenderObject* lastBox = last; - while (lastBox && lastBox->parent()->isAnonymous() && !lastBox->isTableRow()) + while (lastBox && lastBox->parent()->isAnonymous() && !is<RenderTableRow>(*lastBox)) lastBox = lastBox->parent(); if (lastBox && lastBox->isAnonymous() && !lastBox->isBeforeOrAfterContent()) { - toRenderTableRow(lastBox)->addChild(child, beforeChild); + downcast<RenderTableRow>(*lastBox).addChild(child, beforeChild); return; } - RenderTableRow* row = RenderTableRow::createAnonymousWithParentRenderer(this); + auto* row = RenderTableRow::createAnonymousWithParentRenderer(*this).release(); addChild(row, beforeChild); row->addChild(child); return; @@ -180,9 +166,9 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild ensureRows(m_cRow); - RenderTableRow* row = toRenderTableRow(child); - m_grid[insertionRow].rowRenderer = row; - row->setRowIndex(insertionRow); + RenderTableRow& row = downcast<RenderTableRow>(*child); + m_grid[insertionRow].rowRenderer = &row; + row.setRowIndex(insertionRow); if (!beforeChild) setRowLogicalHeightToRowStyleLogicalHeightIfNotRelative(m_grid[insertionRow]); @@ -190,7 +176,7 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild if (beforeChild && beforeChild->parent() != this) beforeChild = splitAnonymousBoxesAroundChild(beforeChild); - ASSERT(!beforeChild || beforeChild->isTableRow()); + ASSERT(!beforeChild || is<RenderTableRow>(*beforeChild)); RenderBox::addChild(child, beforeChild); } @@ -266,7 +252,16 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) cell->setCol(table()->effColToCol(col)); } -int RenderTableSection::calcRowLogicalHeight() +static LayoutUnit resolveLogicalHeightForRow(const Length& rowLogicalHeight) +{ + if (rowLogicalHeight.isFixed()) + return rowLogicalHeight.value(); + if (rowLogicalHeight.isCalculated()) + return rowLogicalHeight.nonNanCalculatedValue(0); + return 0; +} + +LayoutUnit RenderTableSection::calcRowLogicalHeight() { #ifndef NDEBUG SetLayoutNeededForbiddenScope layoutForbiddenScope(this); @@ -277,7 +272,7 @@ int RenderTableSection::calcRowLogicalHeight() RenderTableCell* cell; // We ignore the border-spacing on any non-top section as it is already included in the previous section's last row position. - int spacing = 0; + LayoutUnit spacing = 0; if (this == table()->topSection()) spacing = table()->vBorderSpacing(); @@ -293,7 +288,7 @@ int RenderTableSection::calcRowLogicalHeight() LayoutUnit baselineDescent = 0; // Our base size is the biggest logical height from our cells' styles (excluding row spanning cells). - m_rowPos[r + 1] = std::max(m_rowPos[r] + minimumValueForLength(m_grid[r].logicalHeight, 0).round(), 0); + m_rowPos[r + 1] = std::max(m_rowPos[r] + resolveLogicalHeightForRow(m_grid[r].logicalHeight), LayoutUnit::fromPixel(0)); Row& row = m_grid[r].row; unsigned totalCols = row.size(); @@ -331,7 +326,7 @@ int RenderTableSection::calcRowLogicalHeight() // For row spanning cells, |r| is the last row in the span. unsigned cellStartRow = cell->rowIndex(); - if (cell->hasOverrideHeight()) { + if (cell->hasOverrideLogicalContentHeight()) { if (!statePusher.didPush()) { // Technically, we should also push state for the row, but since // rows don't push a coordinate transform, that's not necessary. @@ -343,23 +338,24 @@ int RenderTableSection::calcRowLogicalHeight() cell->layoutIfNeeded(); } - int cellLogicalHeight = cell->logicalHeightForRowSizing(); + LayoutUnit cellLogicalHeight = cell->logicalHeightForRowSizing(); m_rowPos[r + 1] = std::max(m_rowPos[r + 1], m_rowPos[cellStartRow] + cellLogicalHeight); // Find out the baseline. The baseline is set on the first row in a rowspan. if (cell->isBaselineAligned()) { - LayoutUnit baselinePosition = cell->cellBaselinePosition(); - if (baselinePosition > cell->borderAndPaddingBefore()) { + LayoutUnit baselinePosition = cell->cellBaselinePosition() - cell->intrinsicPaddingBefore(); + LayoutUnit borderAndComputedPaddingBefore = cell->borderAndPaddingBefore() - cell->intrinsicPaddingBefore(); + if (baselinePosition > borderAndComputedPaddingBefore) { m_grid[cellStartRow].baseline = std::max(m_grid[cellStartRow].baseline, baselinePosition); // 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 // become the baseline descent applied to the rest of the row. Also we don't account for the baseline descent of // non-spanning cells when computing a spanning cell's extent. - int cellStartRowBaselineDescent = 0; + LayoutUnit cellStartRowBaselineDescent = 0; if (cell->rowSpan() == 1) { - baselineDescent = std::max(baselineDescent, cellLogicalHeight - (baselinePosition - cell->intrinsicPaddingBefore())); + baselineDescent = std::max(baselineDescent, cellLogicalHeight - baselinePosition); cellStartRowBaselineDescent = baselineDescent; } - m_rowPos[cellStartRow + 1] = std::max<int>(m_rowPos[cellStartRow + 1], m_rowPos[cellStartRow] + m_grid[cellStartRow].baseline + cellStartRowBaselineDescent); + m_rowPos[cellStartRow + 1] = std::max(m_rowPos[cellStartRow + 1], m_rowPos[cellStartRow] + m_grid[cellStartRow].baseline + cellStartRowBaselineDescent); } } } @@ -368,7 +364,7 @@ int RenderTableSection::calcRowLogicalHeight() // Add the border-spacing to our final position. // Use table border-spacing even in non-top sections spacing = table()->vBorderSpacing(); - m_rowPos[r + 1] += m_grid[r].rowRenderer ? spacing : 0; + m_rowPos[r + 1] += m_grid[r].rowRenderer ? spacing : LayoutUnit::fromPixel(0); m_rowPos[r + 1] = std::max(m_rowPos[r + 1], m_rowPos[r]); } @@ -386,14 +382,16 @@ void RenderTableSection::layout() ASSERT(!needsCellRecalc()); ASSERT(!table()->needsSectionRecalc()); + m_forceSlowPaintPathWithOverflowingCell = false; // addChild may over-grow m_grid but we don't want to throw away the memory too early as addChild // can be called in a loop (e.g during parsing). Doing it now ensures we have a stable-enough structure. m_grid.shrinkToFit(); LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode()); - - const Vector<int>& columnPos = table()->columnPositions(); - + bool paginated = view().layoutState()->isPaginated(); + + const Vector<LayoutUnit>& columnPos = table()->columnPositions(); + for (unsigned r = 0; r < m_grid.size(); ++r) { Row& row = m_grid[r].row; unsigned cols = row.size(); @@ -412,34 +410,38 @@ void RenderTableSection::layout() cspan -= table()->columns()[endCol].span; endCol++; } - int tableLayoutLogicalWidth = columnPos[endCol] - columnPos[startColumn] - table()->hBorderSpacing(); + LayoutUnit tableLayoutLogicalWidth = columnPos[endCol] - columnPos[startColumn] - table()->hBorderSpacing(); cell->setCellLogicalWidth(tableLayoutLogicalWidth); } - if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) + if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) { + if (!rowRenderer->needsLayout() && paginated && view().layoutState()->pageLogicalHeightChanged()) + rowRenderer->setChildNeedsLayout(MarkOnlyThis); + rowRenderer->layoutIfNeeded(); + } } statePusher.pop(); clearNeedsLayout(); } -void RenderTableSection::distributeExtraLogicalHeightToPercentRows(int& extraLogicalHeight, int totalPercent) +void RenderTableSection::distributeExtraLogicalHeightToPercentRows(LayoutUnit& extraLogicalHeight, int totalPercent) { if (!totalPercent) return; unsigned totalRows = m_grid.size(); - int totalHeight = m_rowPos[totalRows] + extraLogicalHeight; - int totalLogicalHeightAdded = 0; + LayoutUnit totalHeight = m_rowPos[totalRows] + extraLogicalHeight; + LayoutUnit totalLogicalHeightAdded = 0; totalPercent = std::min(totalPercent, 100); - int rowHeight = m_rowPos[1] - m_rowPos[0]; + LayoutUnit rowHeight = m_rowPos[1] - m_rowPos[0]; for (unsigned r = 0; r < totalRows; ++r) { if (totalPercent > 0 && m_grid[r].logicalHeight.isPercent()) { - int toAdd = std::min<int>(extraLogicalHeight, (totalHeight * m_grid[r].logicalHeight.percent() / 100) - rowHeight); + LayoutUnit toAdd = std::min<LayoutUnit>(extraLogicalHeight, (totalHeight * m_grid[r].logicalHeight.percent() / 100) - rowHeight); // If toAdd is negative, then we don't want to shrink the row (this bug // affected Outlook Web Access). - toAdd = std::max(0, toAdd); + toAdd = std::max(LayoutUnit::fromPixel(0), toAdd); totalLogicalHeightAdded += toAdd; extraLogicalHeight -= toAdd; totalPercent -= m_grid[r].logicalHeight.percent(); @@ -451,16 +453,16 @@ void RenderTableSection::distributeExtraLogicalHeightToPercentRows(int& extraLog } } -void RenderTableSection::distributeExtraLogicalHeightToAutoRows(int& extraLogicalHeight, unsigned autoRowsCount) +void RenderTableSection::distributeExtraLogicalHeightToAutoRows(LayoutUnit& extraLogicalHeight, unsigned autoRowsCount) { if (!autoRowsCount) return; - int totalLogicalHeightAdded = 0; + LayoutUnit totalLogicalHeightAdded = 0; for (unsigned r = 0; r < m_grid.size(); ++r) { if (autoRowsCount > 0 && m_grid[r].logicalHeight.isAuto()) { // Recomputing |extraLogicalHeightForRow| guarantees that we properly ditribute round |extraLogicalHeight|. - int extraLogicalHeightForRow = extraLogicalHeight / autoRowsCount; + LayoutUnit extraLogicalHeightForRow = extraLogicalHeight / autoRowsCount; totalLogicalHeightAdded += extraLogicalHeightForRow; extraLogicalHeight -= extraLogicalHeightForRow; --autoRowsCount; @@ -469,7 +471,7 @@ void RenderTableSection::distributeExtraLogicalHeightToAutoRows(int& extraLogica } } -void RenderTableSection::distributeRemainingExtraLogicalHeight(int& extraLogicalHeight) +void RenderTableSection::distributeRemainingExtraLogicalHeight(LayoutUnit& extraLogicalHeight) { unsigned totalRows = m_grid.size(); @@ -477,9 +479,9 @@ void RenderTableSection::distributeRemainingExtraLogicalHeight(int& extraLogical return; // FIXME: m_rowPos[totalRows] - m_rowPos[0] is the total rows' size. - int totalRowSize = m_rowPos[totalRows]; - int totalLogicalHeightAdded = 0; - int previousRowPosition = m_rowPos[0]; + LayoutUnit totalRowSize = m_rowPos[totalRows]; + LayoutUnit totalLogicalHeightAdded = 0; + LayoutUnit previousRowPosition = m_rowPos[0]; for (unsigned r = 0; r < totalRows; r++) { // weight with the original height totalLogicalHeightAdded += extraLogicalHeight * (m_rowPos[r + 1] - previousRowPosition) / totalRowSize; @@ -490,7 +492,7 @@ void RenderTableSection::distributeRemainingExtraLogicalHeight(int& extraLogical extraLogicalHeight -= totalLogicalHeightAdded; } -int RenderTableSection::distributeExtraLogicalHeightToRows(int extraLogicalHeight) +LayoutUnit RenderTableSection::distributeExtraLogicalHeightToRows(LayoutUnit extraLogicalHeight) { if (!extraLogicalHeight) return extraLogicalHeight; @@ -511,7 +513,7 @@ int RenderTableSection::distributeExtraLogicalHeightToRows(int extraLogicalHeigh totalPercent += m_grid[r].logicalHeight.percent(); } - int remainingExtraLogicalHeight = extraLogicalHeight; + LayoutUnit remainingExtraLogicalHeight = extraLogicalHeight; distributeExtraLogicalHeightToPercentRows(remainingExtraLogicalHeight, totalPercent); distributeExtraLogicalHeightToAutoRows(remainingExtraLogicalHeight, autoRowsCount); distributeRemainingExtraLogicalHeight(remainingExtraLogicalHeight); @@ -532,7 +534,7 @@ void RenderTableSection::layoutRows() setLogicalWidth(table()->contentLogicalWidth()); m_forceSlowPaintPathWithOverflowingCell = false; - int vspacing = table()->vBorderSpacing(); + LayoutUnit vspacing = table()->vBorderSpacing(); unsigned nEffCols = table()->numEffCols(); LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || style().isFlippedBlocksWritingMode()); @@ -546,9 +548,11 @@ void RenderTableSection::layoutRows() rowRenderer->setLogicalWidth(logicalWidth()); rowRenderer->setLogicalHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing); rowRenderer->updateLayerTransform(); + rowRenderer->clearOverflow(); + rowRenderer->addVisualEffectOverflow(); } - int rowHeightIncreaseForPagination = 0; + LayoutUnit rowHeightIncreaseForPagination = 0; for (unsigned c = 0; c < nEffCols; c++) { CellStruct& cs = cellAt(r, c); @@ -558,7 +562,7 @@ void RenderTableSection::layoutRows() continue; int rowIndex = cell->rowIndex(); - int rHeight = m_rowPos[rowIndex + cell->rowSpan()] - m_rowPos[rowIndex] - vspacing; + LayoutUnit rHeight = m_rowPos[rowIndex + cell->rowSpan()] - m_rowPos[rowIndex] - vspacing; // Force percent height children to lay themselves out again. // This will cause these children to grow to fill the cell. @@ -577,11 +581,11 @@ void RenderTableSection::layoutRows() bool flexAllChildren = cell->style().logicalHeight().isFixed() || (!table()->style().logicalHeight().isAuto() && rHeight != cell->logicalHeight()); - for (RenderObject* o = cell->firstChild(); o; o = o->nextSibling()) { - if (!o->isText() && o->style().logicalHeight().isPercent() && (flexAllChildren || ((o->isReplaced() || (o->isBox() && toRenderBox(o)->scrollsOverflow())) && !o->isTextControl()))) { + for (auto& renderer : childrenOfType<RenderObject>(*cell)) { + if (!is<RenderText>(renderer) && renderer.style().logicalHeight().isPercentOrCalculated() && (flexAllChildren || ((renderer.isReplaced() || (is<RenderBox>(renderer) && downcast<RenderBox>(renderer).scrollsOverflow())) && !is<RenderTextControl>(renderer)))) { // Tables with no sections do not flex. - if (!o->isTable() || toRenderTable(o)->hasSections()) { - o->setNeedsLayout(MarkOnlyThis); + if (!is<RenderTable>(renderer) || downcast<RenderTable>(renderer).hasSections()) { + renderer.setNeedsLayout(MarkOnlyThis); cellChildrenFlex = true; } } @@ -640,7 +644,7 @@ void RenderTableSection::layoutRows() // 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 // either. It's at least stable though and won't result in an infinite # of relayouts that may never stabilize. if (cell->logicalHeight() > rHeight) - rowHeightIncreaseForPagination = std::max<int>(rowHeightIncreaseForPagination, cell->logicalHeight() - rHeight); + rowHeightIncreaseForPagination = std::max(rowHeightIncreaseForPagination, cell->logicalHeight() - rHeight); cell->setLogicalHeight(rHeight); } @@ -687,7 +691,7 @@ void RenderTableSection::computeOverflowFromCells(unsigned totalRows, unsigned n clearOverflow(); m_overflowingCells.clear(); unsigned totalCellsCount = nEffCols * totalRows; - int maxAllowedOverflowingCellsCount = totalCellsCount < gMinTableSizeToUseFastPaintPathWithOverflowingCell ? 0 : gMaxAllowedOverflowingCellRatioForFastPaintPath * totalCellsCount; + unsigned maxAllowedOverflowingCellsCount = totalCellsCount < gMinTableSizeToUseFastPaintPathWithOverflowingCell ? 0 : gMaxAllowedOverflowingCellRatioForFastPaintPath * totalCellsCount; #ifndef NDEBUG bool hasOverflowingCell = false; @@ -716,17 +720,16 @@ void RenderTableSection::computeOverflowFromCells(unsigned totalRows, unsigned n } } } - ASSERT(hasOverflowingCell == this->hasOverflowingCell()); } -int RenderTableSection::calcOuterBorderBefore() const +LayoutUnit RenderTableSection::calcOuterBorderBefore() const { unsigned totalCols = table()->numEffCols(); if (!m_grid.size() || !totalCols) return 0; - unsigned borderWidth = 0; + LayoutUnit borderWidth = 0; const BorderValue& sb = style().borderBefore(); if (sb.style() == BHIDDEN) @@ -767,17 +770,16 @@ int RenderTableSection::calcOuterBorderBefore() const } if (allHidden) return -1; - - return borderWidth / 2; + return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), false); } -int RenderTableSection::calcOuterBorderAfter() const +LayoutUnit RenderTableSection::calcOuterBorderAfter() const { unsigned totalCols = table()->numEffCols(); if (!m_grid.size() || !totalCols) return 0; - unsigned borderWidth = 0; + LayoutUnit borderWidth = 0; const BorderValue& sb = style().borderAfter(); if (sb.style() == BHIDDEN) @@ -818,17 +820,16 @@ int RenderTableSection::calcOuterBorderAfter() const } if (allHidden) return -1; - - return (borderWidth + 1) / 2; + return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), true); } -int RenderTableSection::calcOuterBorderStart() const +LayoutUnit RenderTableSection::calcOuterBorderStart() const { unsigned totalCols = table()->numEffCols(); if (!m_grid.size() || !totalCols) return 0; - unsigned borderWidth = 0; + LayoutUnit borderWidth = 0; const BorderValue& sb = style().borderStart(); if (sb.style() == BHIDDEN) @@ -862,17 +863,16 @@ int RenderTableSection::calcOuterBorderStart() const } if (allHidden) return -1; - - return (borderWidth + (table()->style().isLeftToRightDirection() ? 0 : 1)) / 2; + return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), !table()->style().isLeftToRightDirection()); } -int RenderTableSection::calcOuterBorderEnd() const +LayoutUnit RenderTableSection::calcOuterBorderEnd() const { unsigned totalCols = table()->numEffCols(); if (!m_grid.size() || !totalCols) return 0; - unsigned borderWidth = 0; + LayoutUnit borderWidth = 0; const BorderValue& sb = style().borderEnd(); if (sb.style() == BHIDDEN) @@ -906,8 +906,7 @@ int RenderTableSection::calcOuterBorderEnd() const } if (allHidden) return -1; - - return (borderWidth + (table()->style().isLeftToRightDirection() ? 1 : 0)) / 2; + return CollapsedBorderValue::adjustedCollapsedBorderWidth(borderWidth, document().deviceScaleFactor(), table()->style().isLeftToRightDirection()); } void RenderTableSection::recalcOuterBorder() @@ -918,32 +917,33 @@ void RenderTableSection::recalcOuterBorder() m_outerBorderEnd = calcOuterBorderEnd(); } -int RenderTableSection::firstLineBaseline() const +std::optional<int> RenderTableSection::firstLineBaseline() const { if (!m_grid.size()) - return -1; + return std::optional<int>(); int firstLineBaseline = m_grid[0].baseline; if (firstLineBaseline) - return firstLineBaseline + m_rowPos[0]; + return firstLineBaseline + roundToInt(m_rowPos[0]); - firstLineBaseline = -1; + std::optional<int> result; const Row& firstRow = m_grid[0].row; for (size_t i = 0; i < firstRow.size(); ++i) { const CellStruct& cs = firstRow.at(i); const RenderTableCell* cell = cs.primaryCell(); // Only cells with content have a baseline - if (cell && cell->contentLogicalHeight()) - firstLineBaseline = std::max<int>(firstLineBaseline, cell->logicalTop() + cell->borderAndPaddingBefore() + cell->contentLogicalHeight()); + if (cell && cell->contentLogicalHeight()) { + int candidate = roundToInt(cell->logicalTop() + cell->borderAndPaddingBefore() + cell->contentLogicalHeight()); + result = std::max(result.value_or(candidate), candidate); + } } - return firstLineBaseline; + return result; } void RenderTableSection::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - // put this back in when all layout tests can handle it - // ASSERT(!needsLayout()); + ASSERT(!needsLayout()); // avoid crashing on bugs that cause us to paint with dirty layout if (needsLayout()) return; @@ -985,13 +985,13 @@ void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, { LayoutPoint cellPoint = flipForWritingModeForChild(cell, paintOffset); PaintPhase paintPhase = paintInfo.phase; - RenderTableRow* row = toRenderTableRow(cell->parent()); + RenderTableRow& row = downcast<RenderTableRow>(*cell->parent()); if (paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) { // We need to handle painting a stack of backgrounds. This stack (from bottom to top) consists of // the column group, column, row group, row, and then the cell. RenderTableCol* column = table()->colElement(cell->col()); - RenderTableCol* columnGroup = column ? column->enclosingColumnGroup() : 0; + RenderTableCol* columnGroup = column ? column->enclosingColumnGroup() : nullptr; // Column groups and columns first. // FIXME: Columns and column groups do not currently support opacity, and they are being painted "too late" in @@ -1006,10 +1006,10 @@ void RenderTableSection::paintCell(RenderTableCell* cell, PaintInfo& paintInfo, // Paint the row next, but only if it doesn't have a layer. If a row has a layer, it will be responsible for // painting the row background for the cell. - if (!row->hasSelfPaintingLayer()) - cell->paintBackgroundsBehindCell(paintInfo, cellPoint, row); + if (!row.hasSelfPaintingLayer()) + cell->paintBackgroundsBehindCell(paintInfo, cellPoint, &row); } - if ((!cell->hasSelfPaintingLayer() && !row->hasSelfPaintingLayer())) + if ((!cell->hasSelfPaintingLayer() && !row.hasSelfPaintingLayer())) cell->paint(paintInfo, cellPoint); } @@ -1022,7 +1022,7 @@ LayoutRect RenderTableSection::logicalRectForWritingModeAndDirection(const Layou if (!style().isHorizontalWritingMode()) tableAlignedRect = tableAlignedRect.transposedRect(); - const Vector<int>& columnPos = table()->columnPositions(); + const Vector<LayoutUnit>& columnPos = table()->columnPositions(); // FIXME: The table's direction should determine our row's direction, not the section's (see bug 96691). if (!style().isLeftToRightDirection()) tableAlignedRect.setX(columnPos[columnPos.size() - 1] - tableAlignedRect.maxX()); @@ -1035,14 +1035,14 @@ CellSpan RenderTableSection::dirtiedRows(const LayoutRect& damageRect) const if (m_forceSlowPaintPathWithOverflowingCell) return fullTableRowSpan(); - CellSpan coveredRows = spannedRows(damageRect); + CellSpan coveredRows = spannedRows(damageRect, IncludeAllIntersectingCells); // To repaint the border we might need to repaint first or last row even if they are not spanned themselves. - if (coveredRows.start() >= m_rowPos.size() - 1 && m_rowPos[m_rowPos.size() - 1] + table()->outerBorderAfter() >= damageRect.y()) - --coveredRows.start(); + if (coveredRows.start >= m_rowPos.size() - 1 && m_rowPos[m_rowPos.size() - 1] + table()->outerBorderAfter() >= damageRect.y()) + --coveredRows.start; - if (!coveredRows.end() && m_rowPos[0] - table()->outerBorderBefore() <= damageRect.maxY()) - ++coveredRows.end(); + if (!coveredRows.end && m_rowPos[0] - table()->outerBorderBefore() <= damageRect.maxY()) + ++coveredRows.end; return coveredRows; } @@ -1052,23 +1052,25 @@ CellSpan RenderTableSection::dirtiedColumns(const LayoutRect& damageRect) const if (m_forceSlowPaintPathWithOverflowingCell) return fullTableColumnSpan(); - CellSpan coveredColumns = spannedColumns(damageRect); + CellSpan coveredColumns = spannedColumns(damageRect, IncludeAllIntersectingCells); - const Vector<int>& columnPos = table()->columnPositions(); + const Vector<LayoutUnit>& columnPos = table()->columnPositions(); // To repaint the border we might need to repaint first or last column even if they are not spanned themselves. - if (coveredColumns.start() >= columnPos.size() - 1 && columnPos[columnPos.size() - 1] + table()->outerBorderEnd() >= damageRect.x()) - --coveredColumns.start(); + if (coveredColumns.start >= columnPos.size() - 1 && columnPos[columnPos.size() - 1] + table()->outerBorderEnd() >= damageRect.x()) + --coveredColumns.start; - if (!coveredColumns.end() && columnPos[0] - table()->outerBorderStart() <= damageRect.maxX()) - ++coveredColumns.end(); + if (!coveredColumns.end && columnPos[0] - table()->outerBorderStart() <= damageRect.maxX()) + ++coveredColumns.end; return coveredColumns; } -CellSpan RenderTableSection::spannedRows(const LayoutRect& flippedRect) const +CellSpan RenderTableSection::spannedRows(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells shouldIncludeAllIntersectionCells) const { // Find the first row that starts after rect top. unsigned nextRow = std::upper_bound(m_rowPos.begin(), m_rowPos.end(), flippedRect.y()) - m_rowPos.begin(); + if (shouldIncludeAllIntersectionCells == IncludeAllIntersectingCells && nextRow && m_rowPos[nextRow - 1] == flippedRect.y()) + --nextRow; if (nextRow == m_rowPos.size()) return CellSpan(m_rowPos.size() - 1, m_rowPos.size() - 1); // After all rows. @@ -1080,7 +1082,7 @@ CellSpan RenderTableSection::spannedRows(const LayoutRect& flippedRect) const if (m_rowPos[nextRow] >= flippedRect.maxY()) endRow = nextRow; else { - endRow = std::upper_bound(m_rowPos.begin() + nextRow, m_rowPos.end(), flippedRect.maxY()) - m_rowPos.begin(); + endRow = std::upper_bound(m_rowPos.begin() + static_cast<int32_t>(nextRow), m_rowPos.end(), flippedRect.maxY()) - m_rowPos.begin(); if (endRow == m_rowPos.size()) endRow = m_rowPos.size() - 1; } @@ -1088,9 +1090,9 @@ CellSpan RenderTableSection::spannedRows(const LayoutRect& flippedRect) const return CellSpan(startRow, endRow); } -CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect) const +CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells shouldIncludeAllIntersectionCells) const { - const Vector<int>& columnPos = table()->columnPositions(); + const Vector<LayoutUnit>& columnPos = table()->columnPositions(); // Find the first column that starts after rect left. // lower_bound doesn't handle the edge between two cells properly as it would wrongly return the @@ -1098,6 +1100,8 @@ CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect) const // upper_bound on the other hand properly returns the cell on the logical bottom/right, which also // matches the behavior of other browsers. unsigned nextColumn = std::upper_bound(columnPos.begin(), columnPos.end(), flippedRect.x()) - columnPos.begin(); + if (shouldIncludeAllIntersectionCells == IncludeAllIntersectingCells && nextColumn && columnPos[nextColumn - 1] == flippedRect.x()) + --nextColumn; if (nextColumn == columnPos.size()) return CellSpan(columnPos.size() - 1, columnPos.size() - 1); // After all columns. @@ -1109,7 +1113,7 @@ CellSpan RenderTableSection::spannedColumns(const LayoutRect& flippedRect) const if (columnPos[nextColumn] >= flippedRect.maxX()) endColumn = nextColumn; else { - endColumn = std::upper_bound(columnPos.begin() + nextColumn, columnPos.end(), flippedRect.maxX()) - columnPos.begin(); + endColumn = std::upper_bound(columnPos.begin() + static_cast<int32_t>(nextColumn), columnPos.end(), flippedRect.maxX()) - columnPos.begin(); if (endColumn == columnPos.size()) endColumn = columnPos.size() - 1; } @@ -1124,62 +1128,62 @@ void RenderTableSection::paintRowGroupBorder(const PaintInfo& paintInfo, bool an rect.intersect(paintInfo.rect); if (rect.isEmpty()) return; - drawLineForBoxSide(paintInfo.context, rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(), side, style().visitedDependentColor(borderColor), borderStyle, 0, 0, antialias); + drawLineForBoxSide(paintInfo.context(), rect, side, style().visitedDependentColor(borderColor), borderStyle, 0, 0, antialias); } -int RenderTableSection::offsetLeftForRowGroupBorder(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row) +LayoutUnit RenderTableSection::offsetLeftForRowGroupBorder(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row) { if (style().isHorizontalWritingMode()) { if (style().isLeftToRightDirection()) - return cell ? cell->x().toInt() + cell->width().toInt() : 0; + return cell ? cell->x() + cell->width() : LayoutUnit::fromPixel(0); return -outerBorderLeft(&style()); } bool isLastRow = row + 1 == m_grid.size(); - return rowGroupRect.width().toInt() - m_rowPos[row + 1] + (isLastRow ? -outerBorderLeft(&style()) : 0); + return rowGroupRect.width() - m_rowPos[row + 1] + (isLastRow ? -outerBorderLeft(&style()) : LayoutUnit::fromPixel(0)); } -int RenderTableSection::offsetTopForRowGroupBorder(RenderTableCell* cell, BoxSide borderSide, unsigned row) +LayoutUnit RenderTableSection::offsetTopForRowGroupBorder(RenderTableCell* cell, BoxSide borderSide, unsigned row) { bool isLastRow = row + 1 == m_grid.size(); if (style().isHorizontalWritingMode()) - return m_rowPos[row] + (!row && borderSide == BSRight ? -outerBorderTop(&style()) : isLastRow && borderSide == BSLeft ? outerBorderTop(&style()) : 0); + return m_rowPos[row] + (!row && borderSide == BSRight ? -outerBorderTop(&style()) : isLastRow && borderSide == BSLeft ? outerBorderTop(&style()) : LayoutUnit::fromPixel(0)); if (style().isLeftToRightDirection()) - return (cell ? cell->y().toInt() + cell->height().toInt() : 0) + (borderSide == BSLeft ? outerBorderTop(&style()) : 0); - return borderSide == BSRight ? -outerBorderTop(&style()) : 0; + return (cell ? cell->y() + cell->height() : LayoutUnit::fromPixel(0)) + (borderSide == BSLeft ? outerBorderTop(&style()) : LayoutUnit::fromPixel(0)); + return borderSide == BSRight ? -outerBorderTop(&style()) : LayoutUnit::fromPixel(0); } -int RenderTableSection::verticalRowGroupBorderHeight(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row) +LayoutUnit RenderTableSection::verticalRowGroupBorderHeight(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row) { bool isLastRow = row + 1 == m_grid.size(); if (style().isHorizontalWritingMode()) - return m_rowPos[row + 1] - m_rowPos[row] + (!row ? outerBorderTop(&style()) : isLastRow ? outerBorderBottom(&style()) : 0); + return m_rowPos[row + 1] - m_rowPos[row] + (!row ? outerBorderTop(&style()) : isLastRow ? outerBorderBottom(&style()) : LayoutUnit::fromPixel(0)); if (style().isLeftToRightDirection()) - return rowGroupRect.height().toInt() - (cell ? cell->y().toInt() + cell->height().toInt() : 0) + outerBorderBottom(&style()); - return cell ? rowGroupRect.height().toInt() - (cell->y().toInt() - cell->height().toInt()) : 0; + return rowGroupRect.height() - (cell ? cell->y() + cell->height() : LayoutUnit::fromPixel(0)) + outerBorderBottom(&style()); + return cell ? rowGroupRect.height() - (cell->y() - cell->height()) : LayoutUnit::fromPixel(0); } -int RenderTableSection::horizontalRowGroupBorderWidth(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row, unsigned column) +LayoutUnit RenderTableSection::horizontalRowGroupBorderWidth(RenderTableCell* cell, const LayoutRect& rowGroupRect, unsigned row, unsigned column) { if (style().isHorizontalWritingMode()) { if (style().isLeftToRightDirection()) - return rowGroupRect.width().toInt() - (cell ? cell->x().toInt() + cell->width().toInt() : 0) + (!column ? outerBorderLeft(&style()) : column == table()->numEffCols() ? outerBorderRight(&style()) : 0); - return cell ? rowGroupRect.width().toInt() - (cell->x().toInt() - cell->width().toInt()) : 0; + return rowGroupRect.width() - (cell ? cell->x() + cell->width() : LayoutUnit::fromPixel(0)) + (!column ? outerBorderLeft(&style()) : column == table()->numEffCols() ? outerBorderRight(&style()) : LayoutUnit::fromPixel(0)); + return cell ? rowGroupRect.width() - (cell->x() - cell->width()) : LayoutUnit::fromPixel(0); } bool isLastRow = row + 1 == m_grid.size(); - return m_rowPos[row + 1] - m_rowPos[row] + (isLastRow ? outerBorderLeft(&style()) : !row ? outerBorderRight(&style()) : 0); + return m_rowPos[row + 1] - m_rowPos[row] + (isLastRow ? outerBorderLeft(&style()) : !row ? outerBorderRight(&style()) : LayoutUnit::fromPixel(0)); } void RenderTableSection::paintRowGroupBorderIfRequired(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, unsigned row, unsigned column, BoxSide borderSide, RenderTableCell* cell) { if (table()->currentBorderValue()->precedence() > BROWGROUP) return; - if (paintInfo.context->paintingDisabled()) + if (paintInfo.context().paintingDisabled()) return; const RenderStyle& style = this->style(); - bool antialias = shouldAntialiasLines(paintInfo.context); + bool antialias = shouldAntialiasLines(paintInfo.context()); LayoutRect rowGroupRect = LayoutRect(paintOffset, size()); - rowGroupRect.moveBy(-LayoutPoint(outerBorderLeft(&style), (borderSide == BSRight) ? 0 : outerBorderTop(&style))); + rowGroupRect.moveBy(-LayoutPoint(outerBorderLeft(&style), (borderSide == BSRight) ? LayoutUnit::fromPixel(0) : outerBorderTop(&style))); switch (borderSide) { case BSTop: @@ -1204,7 +1208,7 @@ void RenderTableSection::paintRowGroupBorderIfRequired(const PaintInfo& paintInf } -static BoxSide physicalBorderForDirection(RenderStyle* styleForCellFlow, CollapsedBorderSide side) +static BoxSide physicalBorderForDirection(const RenderStyle* styleForCellFlow, CollapsedBorderSide side) { switch (side) { @@ -1232,28 +1236,25 @@ static BoxSide physicalBorderForDirection(RenderStyle* styleForCellFlow, Collaps void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { - PaintPhase paintPhase = paintInfo.phase; - LayoutRect localRepaintRect = paintInfo.rect; localRepaintRect.moveBy(-paintOffset); - localRepaintRect.inflate(maximalOutlineSize(paintPhase)); LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(localRepaintRect); CellSpan dirtiedRows = this->dirtiedRows(tableAlignedRect); CellSpan dirtiedColumns = this->dirtiedColumns(tableAlignedRect); - if (dirtiedColumns.start() < dirtiedColumns.end()) { + if (dirtiedColumns.start < dirtiedColumns.end) { if (!m_hasMultipleCellLevels && !m_overflowingCells.size()) { if (paintInfo.phase == PaintPhaseCollapsedTableBorders) { // Collapsed borders are painted from the bottom right to the top left so that precedence // due to cell position is respected. We need to paint one row beyond the topmost dirtied // row to calculate its collapsed border value. - unsigned startRow = dirtiedRows.start() ? dirtiedRows.start() - 1 : 0; - for (unsigned r = dirtiedRows.end(); r > startRow; r--) { + unsigned startRow = dirtiedRows.start ? dirtiedRows.start - 1 : 0; + for (unsigned r = dirtiedRows.end; r > startRow; r--) { unsigned row = r - 1; bool shouldPaintRowGroupBorder = false; - for (unsigned c = dirtiedColumns.end(); c > dirtiedColumns.start(); c--) { + for (unsigned c = dirtiedColumns.end; c > dirtiedColumns.start; c--) { unsigned col = c - 1; CellStruct& current = cellAt(row, col); RenderTableCell* cell = current.primaryCell(); @@ -1265,7 +1266,7 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa shouldPaintRowGroupBorder = true; continue; } - if ((row > dirtiedRows.start() && primaryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start() && primaryCellAt(row, col - 1) == cell)) + if ((row > dirtiedRows.start && primaryCellAt(row - 1, col) == cell) || (col > dirtiedColumns.start && primaryCellAt(row, col - 1) == cell)) continue; // If we had a run of null cells paint their corresponding section of the row group's border if necessary. Note that @@ -1284,14 +1285,14 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa } } else { // Draw the dirty cells in the order that they appear. - for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { + for (unsigned r = dirtiedRows.start; r < dirtiedRows.end; r++) { RenderTableRow* row = m_grid[r].rowRenderer; if (row && !row->hasSelfPaintingLayer()) row->paintOutlineForRowIfNeeded(paintInfo, paintOffset); - for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) { + for (unsigned c = dirtiedColumns.start; c < dirtiedColumns.end; c++) { CellStruct& current = cellAt(r, c); RenderTableCell* cell = current.primaryCell(); - if (!cell || (r > dirtiedRows.start() && primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start() && primaryCellAt(r, c - 1) == cell)) + if (!cell || (r > dirtiedRows.start && primaryCellAt(r - 1, c) == cell) || (c > dirtiedColumns.start && primaryCellAt(r, c - 1) == cell)) continue; paintCell(cell, paintInfo, paintOffset); } @@ -1311,11 +1312,11 @@ void RenderTableSection::paintObject(PaintInfo& paintInfo, const LayoutPoint& pa HashSet<RenderTableCell*> spanningCells; - for (unsigned r = dirtiedRows.start(); r < dirtiedRows.end(); r++) { + for (unsigned r = dirtiedRows.start; r < dirtiedRows.end; r++) { RenderTableRow* row = m_grid[r].rowRenderer; if (row && !row->hasSelfPaintingLayer()) row->paintOutlineForRowIfNeeded(paintInfo, paintOffset); - for (unsigned c = dirtiedColumns.start(); c < dirtiedColumns.end(); c++) { + for (unsigned c = dirtiedColumns.start; c < dirtiedColumns.end; c++) { CellStruct& current = cellAt(r, c); if (!current.hasCells()) continue; @@ -1361,9 +1362,9 @@ void RenderTableSection::imageChanged(WrappedImagePtr, const IntRect*) void RenderTableSection::recalcCells() { ASSERT(m_needsCellRecalc); - // We reset the flag here to ensure that |addCell| works. This is safe to do as - // fillRowsWithDefaultStartingAtPosition makes sure we match the table's columns - // representation. + // We reset the flag here to ensure that addCell() works. This is safe to do because we clear the grid + // and update its dimensions to be consistent with the table's column representation before we rebuild + // the grid using addCell(). m_needsCellRecalc = false; m_cCol = 0; @@ -1403,12 +1404,17 @@ void RenderTableSection::rowLogicalHeightChanged(unsigned rowIndex) void RenderTableSection::setNeedsCellRecalc() { m_needsCellRecalc = true; + + // Clear the grid now to ensure that we don't hold onto any stale pointers (e.g. a cell renderer that is being removed). + m_grid.clear(); + if (RenderTable* t = table()) t->setNeedsSectionRecalc(); } unsigned RenderTableSection::numColumns() const { + ASSERT(!m_needsCellRecalc); unsigned result = 0; for (unsigned r = 0; r < m_grid.size(); ++r) { @@ -1422,27 +1428,27 @@ unsigned RenderTableSection::numColumns() const return result + 1; } -const BorderValue& RenderTableSection::borderAdjoiningStartCell(const RenderTableCell* cell) const +const BorderValue& RenderTableSection::borderAdjoiningStartCell(const RenderTableCell& cell) const { - ASSERT(cell->isFirstOrLastCellInRow()); - return hasSameDirectionAs(cell) ? style().borderStart() : style().borderEnd(); + ASSERT(cell.isFirstOrLastCellInRow()); + return isDirectionSame(this, &cell) ? style().borderStart() : style().borderEnd(); } -const BorderValue& RenderTableSection::borderAdjoiningEndCell(const RenderTableCell* cell) const +const BorderValue& RenderTableSection::borderAdjoiningEndCell(const RenderTableCell& cell) const { - ASSERT(cell->isFirstOrLastCellInRow()); - return hasSameDirectionAs(cell) ? style().borderEnd() : style().borderStart(); + ASSERT(cell.isFirstOrLastCellInRow()); + return isDirectionSame(this, &cell) ? style().borderEnd() : style().borderStart(); } const RenderTableCell* RenderTableSection::firstRowCellAdjoiningTableStart() const { - unsigned adjoiningStartCellColumnIndex = hasSameDirectionAs(table()) ? 0 : table()->lastColumnIndex(); + unsigned adjoiningStartCellColumnIndex = isDirectionSame(this, table()) ? 0 : table()->lastColumnIndex(); return cellAt(0, adjoiningStartCellColumnIndex).primaryCell(); } const RenderTableCell* RenderTableSection::firstRowCellAdjoiningTableEnd() const { - unsigned adjoiningEndCellColumnIndex = hasSameDirectionAs(table()) ? table()->lastColumnIndex() : 0; + unsigned adjoiningEndCellColumnIndex = isDirectionSame(this, table()) ? table()->lastColumnIndex() : 0; return cellAt(0, adjoiningEndCellColumnIndex).primaryCell(); } @@ -1490,7 +1496,7 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul // Just forward to our children always. LayoutPoint adjustedLocation = accumulatedOffset + location(); - if (hasOverflowClip() && !locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) + if (hasOverflowClip() && !locationInContainer.intersects(overflowClipRect(adjustedLocation, currentRenderNamedFlowFragment()))) return false; if (hasOverflowingCell()) { @@ -1516,12 +1522,12 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul hitTestRect.moveBy(-adjustedLocation); LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(hitTestRect); - CellSpan rowSpan = spannedRows(tableAlignedRect); - CellSpan columnSpan = spannedColumns(tableAlignedRect); + CellSpan rowSpan = spannedRows(tableAlignedRect, DoNotIncludeAllIntersectingCells); + CellSpan columnSpan = spannedColumns(tableAlignedRect, DoNotIncludeAllIntersectingCells); // Now iterate over the spanned rows and columns. - for (unsigned hitRow = rowSpan.start(); hitRow < rowSpan.end(); ++hitRow) { - for (unsigned hitColumn = columnSpan.start(); hitColumn < columnSpan.end(); ++hitColumn) { + for (unsigned hitRow = rowSpan.start; hitRow < rowSpan.end; ++hitRow) { + for (unsigned hitColumn = columnSpan.start; hitColumn < columnSpan.end; ++hitColumn) { CellStruct& current = cellAt(hitRow, hitColumn); // If the cell is empty, there's nothing to do @@ -1547,42 +1553,57 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul return false; } -void RenderTableSection::removeCachedCollapsedBorders(const RenderTableCell* cell) +void RenderTableSection::clearCachedCollapsedBorders() +{ + if (!table()->collapseBorders()) + return; + m_cellsCollapsedBorders.clear(); +} + +void RenderTableSection::removeCachedCollapsedBorders(const RenderTableCell& cell) { if (!table()->collapseBorders()) return; for (int side = CBSBefore; side <= CBSEnd; ++side) - m_cellsCollapsedBorders.remove(std::make_pair(cell, side)); + m_cellsCollapsedBorders.remove(std::make_pair(&cell, side)); } -void RenderTableSection::setCachedCollapsedBorder(const RenderTableCell* cell, CollapsedBorderSide side, CollapsedBorderValue border) +void RenderTableSection::setCachedCollapsedBorder(const RenderTableCell& cell, CollapsedBorderSide side, CollapsedBorderValue border) { ASSERT(table()->collapseBorders()); - m_cellsCollapsedBorders.set(std::make_pair(cell, side), border); + ASSERT(border.width()); + m_cellsCollapsedBorders.set(std::make_pair(&cell, side), border); } -CollapsedBorderValue& RenderTableSection::cachedCollapsedBorder(const RenderTableCell* cell, CollapsedBorderSide side) +CollapsedBorderValue RenderTableSection::cachedCollapsedBorder(const RenderTableCell& cell, CollapsedBorderSide side) { - ASSERT(table()->collapseBorders()); - HashMap<std::pair<const RenderTableCell*, int>, CollapsedBorderValue>::iterator it = m_cellsCollapsedBorders.find(std::make_pair(cell, side)); - ASSERT(it != m_cellsCollapsedBorders.end()); + ASSERT(table()->collapseBorders() && table()->collapsedBordersAreValid()); + auto it = m_cellsCollapsedBorders.find(std::make_pair(&cell, side)); + // Only non-empty collapsed borders are in the hashmap. + if (it == m_cellsCollapsedBorders.end()) + return CollapsedBorderValue(BorderValue(), Color(), BCELL); return it->value; } -RenderTableSection* RenderTableSection::createAnonymousWithParentRenderer(const RenderObject* parent) +std::unique_ptr<RenderTableSection> RenderTableSection::createTableSectionWithStyle(Document& document, const RenderStyle& style) { - auto section = new RenderTableSection(parent->document(), RenderStyle::createAnonymousStyleWithDisplay(&parent->style(), TABLE_ROW_GROUP)); + auto section = std::make_unique<RenderTableSection>(document, RenderStyle::createAnonymousStyleWithDisplay(style, TABLE_ROW_GROUP)); section->initializeStyle(); return section; } +std::unique_ptr<RenderTableSection> RenderTableSection::createAnonymousWithParentRenderer(const RenderTable& parent) +{ + return RenderTableSection::createTableSectionWithStyle(parent.document(), parent.style()); +} + void RenderTableSection::setLogicalPositionForCell(RenderTableCell* cell, unsigned effectiveColumn) const { LayoutPoint oldCellLocation = cell->location(); LayoutPoint cellLocation(0, m_rowPos[cell->rowIndex()]); - int horizontalBorderSpacing = table()->hBorderSpacing(); + LayoutUnit horizontalBorderSpacing = table()->hBorderSpacing(); // FIXME: The table's direction should determine our row's direction, not the section's (see bug 96691). if (!style().isLeftToRightDirection()) |