diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderTableRow.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderTableRow.cpp | 156 |
1 files changed, 106 insertions, 50 deletions
diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp index 741aaac09..9ed1f6a85 100644 --- a/Source/WebCore/rendering/RenderTableRow.cpp +++ b/Source/WebCore/rendering/RenderTableRow.cpp @@ -38,15 +38,15 @@ namespace WebCore { using namespace HTMLNames; -RenderTableRow::RenderTableRow(Element& element, PassRef<RenderStyle> style) - : RenderBox(element, std::move(style), 0) +RenderTableRow::RenderTableRow(Element& element, RenderStyle&& style) + : RenderBox(element, WTFMove(style), 0) , m_rowIndex(unsetRowIndex) { setInline(false); } -RenderTableRow::RenderTableRow(Document& document, PassRef<RenderStyle> style) - : RenderBox(document, std::move(style), 0) +RenderTableRow::RenderTableRow(Document& document, RenderStyle&& style) + : RenderBox(document, WTFMove(style), 0) , m_rowIndex(unsetRowIndex) { setInline(false); @@ -78,12 +78,11 @@ void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* old section()->rowLogicalHeightChanged(rowIndex()); // If border was changed, notify table. - if (parent()) { - RenderTable* table = this->table(); - if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style().border()) + if (RenderTable* table = this->table()) { + if (oldStyle && oldStyle->border() != style().border()) table->invalidateCollapsedBorders(); - - if (table && oldStyle && diff == StyleDifferenceLayout && needsLayout() && table->collapseBorders() && borderWidthChanged(oldStyle, &style())) { + + if (oldStyle && diff == StyleDifferenceLayout && needsLayout() && table->collapseBorders() && borderWidthChanged(oldStyle, &style())) { // If the border width changes on a row, we need to make sure the cells in the row know to lay out again. // This only happens when borders are collapsed, since they end up affecting the border sides of the cell // itself. @@ -93,49 +92,59 @@ void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* old } } -const BorderValue& RenderTableRow::borderAdjoiningStartCell(const RenderTableCell* cell) const +const BorderValue& RenderTableRow::borderAdjoiningStartCell(const RenderTableCell& cell) const { - ASSERT_UNUSED(cell, cell->isFirstOrLastCellInRow()); + ASSERT_UNUSED(cell, cell.isFirstOrLastCellInRow()); // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level. return style().borderStart(); } -const BorderValue& RenderTableRow::borderAdjoiningEndCell(const RenderTableCell* cell) const +const BorderValue& RenderTableRow::borderAdjoiningEndCell(const RenderTableCell& cell) const { - ASSERT_UNUSED(cell, cell->isFirstOrLastCellInRow()); + ASSERT_UNUSED(cell, cell.isFirstOrLastCellInRow()); // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level. return style().borderEnd(); } void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) { - if (!child->isTableCell()) { + if (!is<RenderTableCell>(*child)) { RenderObject* last = beforeChild; if (!last) last = lastCell(); - if (last && last->isAnonymous() && last->isTableCell() && !last->isBeforeOrAfterContent()) { - RenderTableCell* cell = toRenderTableCell(last); - if (beforeChild == cell) - beforeChild = cell->firstChild(); - cell->addChild(child, beforeChild); + if (last && last->isAnonymous() && is<RenderTableCell>(*last) && !last->isBeforeOrAfterContent()) { + RenderTableCell& cell = downcast<RenderTableCell>(*last); + if (beforeChild == &cell) + beforeChild = cell.firstChild(); + cell.addChild(child, beforeChild); return; } if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) { RenderObject* cell = beforeChild->previousSibling(); - if (cell && cell->isTableCell() && cell->isAnonymous()) { - toRenderTableCell(cell)->addChild(child); + if (is<RenderTableCell>(cell) && cell->isAnonymous()) { + downcast<RenderTableCell>(*cell).addChild(child); return; } } - // If beforeChild is inside an anonymous cell, insert into the cell. - if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous() && !last->parent()->isBeforeOrAfterContent()) { - last->parent()->addChild(child, beforeChild); - return; + // Try to find an anonymous container for the child. + if (last && last->parent() && last->parent()->isAnonymous() && !last->parent()->isBeforeOrAfterContent()) { + // If beforeChild is inside an anonymous cell, insert into the cell. + if (!is<RenderTableCell>(*last)) { + last->parent()->addChild(child, beforeChild); + return; + } + // If beforeChild is inside an anonymous row, insert into the row. + auto& parent = *last->parent(); + if (is<RenderTableRow>(parent)) { + auto* cell = RenderTableCell::createAnonymousWithParentRenderer(*this).release(); + parent.addChild(cell, beforeChild); + cell->addChild(child); + return; + } } - - RenderTableCell* cell = RenderTableCell::createAnonymousWithParentRenderer(this); + auto* cell = RenderTableCell::createAnonymousWithParentRenderer(*this).release(); addChild(cell, beforeChild); cell->addChild(child); return; @@ -144,17 +153,19 @@ void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) if (beforeChild && beforeChild->parent() != this) beforeChild = splitAnonymousBoxesAroundChild(beforeChild); - RenderTableCell* cell = toRenderTableCell(child); + RenderTableCell& cell = downcast<RenderTableCell>(*child); // Generated content can result in us having a null section so make sure to null check our parent. - if (parent()) - section()->addCell(cell, this); + if (RenderTableSection* section = this->section()) + section->addCell(&cell, this); - ASSERT(!beforeChild || beforeChild->isTableCell()); - RenderBox::addChild(cell, beforeChild); + ASSERT(!beforeChild || is<RenderTableCell>(*beforeChild)); + RenderBox::addChild(&cell, beforeChild); if (beforeChild || nextRow()) section()->setNeedsCellRecalc(); + if (RenderTable* table = this->table()) + table->invalidateCollapsedBorders(); } void RenderTableRow::layout() @@ -168,15 +179,17 @@ void RenderTableRow::layout() bool paginated = view().layoutState()->isPaginated(); for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) { - if (!cell->needsLayout() && paginated && view().layoutState()->pageLogicalHeight() && view().layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset()) + if (!cell->needsLayout() && paginated && (view().layoutState()->pageLogicalHeightChanged() || (view().layoutState()->pageLogicalHeight() && view().layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset()))) cell->setChildNeedsLayout(MarkOnlyThis); if (cell->needsLayout()) { - cell->computeAndSetBlockDirectionMargins(table()); + cell->computeAndSetBlockDirectionMargins(*table()); cell->layout(); } } + clearOverflow(); + addVisualEffectOverflow(); // We only ever need to repaint if our cells didn't, which menas that they didn't need // layout, so we know that our bounds didn't change. This code is just making up for // the fact that we did not repaint in setStyle() because we had a layout hint. @@ -195,18 +208,16 @@ void RenderTableRow::layout() LayoutRect RenderTableRow::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { ASSERT(parent()); - - if (repaintContainer == this) - return RenderBox::clippedOverflowRectForRepaint(repaintContainer); - - // For now, just repaint the whole table. - // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we - // might have propagated a background color into. - // FIXME: do repaintContainer checks here - if (RenderTable* parentTable = table()) - return parentTable->clippedOverflowRectForRepaint(repaintContainer); - - return LayoutRect(); + // Rows and cells are in the same coordinate space. We need to both compute our overflow rect (which + // will accommodate a row outline and any visual effects on the row itself), but we also need to add in + // the repaint rects of cells. + LayoutRect result = RenderBox::clippedOverflowRectForRepaint(repaintContainer); + for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) { + // Even if a cell is a repaint container, it's the row that paints the background behind it. + // So we don't care if a cell is a repaintContainer here. + result.uniteIfNonZero(cell->clippedOverflowRectForRepaint(repaintContainer)); + } + return result; } // Hit Testing @@ -259,11 +270,56 @@ void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*) repaint(); } -RenderTableRow* RenderTableRow::createAnonymousWithParentRenderer(const RenderObject* parent) +std::unique_ptr<RenderTableRow> RenderTableRow::createTableRowWithStyle(Document& document, const RenderStyle& style) { - auto newRow = new RenderTableRow(parent->document(), RenderStyle::createAnonymousStyleWithDisplay(&parent->style(), TABLE_ROW)); - newRow->initializeStyle(); - return newRow; + auto row = std::make_unique<RenderTableRow>(document, RenderStyle::createAnonymousStyleWithDisplay(style, TABLE_ROW)); + row->initializeStyle(); + return row; +} + +std::unique_ptr<RenderTableRow> RenderTableRow::createAnonymousWithParentRenderer(const RenderTableSection& parent) +{ + return RenderTableRow::createTableRowWithStyle(parent.document(), parent.style()); +} + +void RenderTableRow::destroyAndCollapseAnonymousSiblingRows() +{ + auto collapseAnonymousSiblingRows = [&] { + auto* section = this->section(); + if (!section) + return; + + // All siblings generated? + for (auto* current = section->firstRow(); current; current = current->nextRow()) { + if (current == this) + continue; + if (!current->isAnonymous()) + return; + } + + RenderTableRow* rowToInsertInto = nullptr; + auto* currentRow = section->firstRow(); + while (currentRow) { + if (currentRow == this) { + currentRow = currentRow->nextRow(); + continue; + } + if (!rowToInsertInto) { + rowToInsertInto = currentRow; + currentRow = currentRow->nextRow(); + continue; + } + currentRow->moveAllChildrenTo(rowToInsertInto); + auto* destroyThis = currentRow; + currentRow = currentRow->nextRow(); + destroyThis->destroy(); + } + if (rowToInsertInto) + rowToInsertInto->setNeedsLayout(); + }; + + collapseAnonymousSiblingRows(); + destroy(); } } // namespace WebCore |