From 662e3488d8108815a5c4fdeef11b3e644976e5c0 Mon Sep 17 00:00:00 2001 From: Artem Baranovskiy Date: Mon, 6 May 2013 08:01:01 +0400 Subject: [PATCH] Table page-break improvements Bump tables to the next page if we cannot fit the caption, thead and first cell on the current page. Ideally this should be checking the height of all cells in the first row in the same manner as is done in the table section render but as this is more of a nice to have I've done the minimal amount of work for now. We now only layout section rows once each section has been positioned within the table, and only supply head and foot reservation heights to the appropriate sections. When re-drawing the thead and tfoot only do so if the rect we are painting is explicitly before/after the "original" thead/tfoot rather than simply outside of its boundaries. This prevents issues with re-drawing a redundant head when bumping tables to the next page. Re-work the table section row layout code so that it's a bit more streamlined. Additionally, to cater for cells spanning multiple rows we avoid page breaks in the middle of their content. Note that rows are always bumped to the next page even if their content doesn't fit on a full page so as to avoid daft situtations like having the first 1px on the preceeding page. --- .../Source/WebCore/rendering/RenderTable.cpp | 37 ++++++++++---- .../WebCore/rendering/RenderTableSection.cpp | 51 +++++++++++-------- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp b/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp index 94ca61a536..bbc9a1cab7 100644 --- a/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp +++ b/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTable.cpp @@ -329,6 +329,28 @@ void RenderTable::layout() if (m_caption) m_caption->layoutIfNeeded(); + // Bump table to next page if we can't fit the caption, thead and first body cell + setPaginationStrut(0); + if (view()->layoutState()->pageLogicalHeight()) { + LayoutState* layoutState = view()->layoutState(); + const int pageLogicalHeight = layoutState->m_pageLogicalHeight; + const int remainingLogicalHeight = pageLogicalHeight - layoutState->pageLogicalOffset(0) % pageLogicalHeight; + if (remainingLogicalHeight > 0) { + int requiredHeight = headHeight; + if (m_caption && m_caption->style()->captionSide() != CAPBOTTOM) { + requiredHeight += m_caption->logicalHeight() + m_caption->marginBefore() + m_caption->marginAfter(); + } + if (m_firstBody) { + // FIXME: Calculate maximum required height across all cells in first body row + RenderTableCell* firstCell = m_firstBody->primaryCellAt(0, 0); + requiredHeight += firstCell->contentLogicalHeight() + firstCell->paddingTop(false) + firstCell->paddingBottom(false) + vBorderSpacing(); + } + if (requiredHeight > remainingLogicalHeight) { + setPaginationStrut(remainingLogicalHeight); + } + } + } + // If any table section moved vertically, we will just repaint everything from that // section down (it is quite unlikely that any of the following sections // did not shift). @@ -361,12 +383,6 @@ void RenderTable::layout() computedLogicalHeight = computePercentageLogicalHeight(logicalHeightLength); computedLogicalHeight = max(0, computedLogicalHeight); - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->isTableSection()) - // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. - toRenderTableSection(child)->layoutRows(child == m_firstBody ? max(0, computedLogicalHeight - totalSectionLogicalHeight) : 0, headHeight, footHeight); - } - if (!m_firstBody && computedLogicalHeight > totalSectionLogicalHeight && !document()->inQuirksMode()) { // Completely empty tables (with no sections or anything) should at least honor specified height // in strict mode. @@ -386,6 +402,9 @@ void RenderTable::layout() } section->setLogicalLocation(sectionLogicalLeft, logicalHeight()); + // FIXME: Distribute extra height between all table body sections instead of giving it all to the first one. + section->layoutRows(section == m_firstBody ? max(0, computedLogicalHeight - totalSectionLogicalHeight) : 0, section == m_head ? 0 : headHeight, section == m_foot ? 0 : footHeight); + setLogicalHeight(logicalHeight() + section->logicalHeight()); section = sectionBelow(section); } @@ -521,7 +540,7 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) // re-paint header/footer if table is split over multiple pages if (m_head) { IntPoint childPoint = flipForWritingMode(m_head, IntPoint(tx, ty), ParentToChildFlippingAdjustment); - if (!info.rect.contains(childPoint.x() + m_head->x(), childPoint.y() + m_head->y())) { + if (info.rect.y() > childPoint.y() + m_head->y()) { repaintedHeadPoint = IntPoint(childPoint.x(), info.rect.y() - m_head->y()); repaintedHead = true; dynamic_cast(m_head)->paint(info, repaintedHeadPoint.x(), repaintedHeadPoint.y()); @@ -529,7 +548,7 @@ void RenderTable::paintObject(PaintInfo& paintInfo, int tx, int ty) } if (m_foot) { IntPoint childPoint = flipForWritingMode(m_foot, IntPoint(tx, ty), ParentToChildFlippingAdjustment); - if (!info.rect.contains(childPoint.x() + m_foot->x(), childPoint.y() + m_foot->y())) { + if (info.rect.y() + info.rect.height() < childPoint.y() + m_foot->y()) { // find actual end of table on current page int dy = 0; const int max_dy = info.rect.y() + info.rect.height(); @@ -1291,4 +1310,4 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu return false; } -} +} \ No newline at end of file diff --git a/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp b/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp index 1e90ac6198..b41db298e5 100644 --- a/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp +++ b/src/qt/src/3rdparty/webkit/Source/WebCore/rendering/RenderTableSection.cpp @@ -496,23 +496,34 @@ int RenderTableSection::layoutRows(int toAdd, int headHeight, int footHeight) LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), style()->isFlippedBlocksWritingMode()); - WTF::Vector logicalHeightsForPrinting; - // make sure that rows do not overlap a page break + // Calculate logical row heights + Vector logicalRowHeights; + logicalRowHeights.resize(totalRows); + for (int r = 0; r < totalRows; r++) { + logicalRowHeights[r] = m_rowPos[r + 1] - m_rowPos[r] - vspacing; + } + + // Make sure that cell contents do not overlap a page break if (view()->layoutState()->pageLogicalHeight()) { - logicalHeightsForPrinting.resize(totalRows); + LayoutState* layoutState = view()->layoutState(); + int pageLogicalHeight = layoutState->m_pageLogicalHeight; int pageOffset = 0; - for(int r = 0; r < totalRows; ++r) { - const int childLogicalHeight = m_rowPos[r + 1] - m_rowPos[r] - (m_grid[r].rowRenderer ? vspacing : 0); - logicalHeightsForPrinting[r] = childLogicalHeight; - LayoutState* layoutState = view()->layoutState(); - const int pageLogicalHeight = layoutState->m_pageLogicalHeight; - if (childLogicalHeight < pageLogicalHeight - footHeight) { - const IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset; - const int logicalOffset = m_rowPos[r] + pageOffset; - const int offset = isHorizontalWritingMode() ? delta.height() : delta.width(); - const int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight; - if (remainingLogicalHeight - footHeight < childLogicalHeight) { + + for (int r = 0; r < totalRows; ++r) { + int rowLogicalOffset = m_rowPos[r] + pageOffset; + int remainingLogicalHeight = pageLogicalHeight - layoutState->pageLogicalOffset(rowLogicalOffset) % pageLogicalHeight; + + for (int c = 0; c < nEffCols; c++) { + CellStruct& cs = cellAt(r, c); + RenderTableCell* cell = cs.primaryCell(); + + if (!cell || cs.inColSpan || cell->row() != r) + continue; + + int cellRequiredHeight = cell->contentLogicalHeight() + cell->paddingTop(false) + cell->paddingBottom(false); + if (max(logicalRowHeights[r], cellRequiredHeight) > remainingLogicalHeight - footHeight - vspacing) { pageOffset += remainingLogicalHeight + headHeight; + break; } } m_rowPos[r] += pageOffset; @@ -525,11 +536,7 @@ int RenderTableSection::layoutRows(int toAdd, int headHeight, int footHeight) if (RenderTableRow* rowRenderer = m_grid[r].rowRenderer) { rowRenderer->setLocation(0, m_rowPos[r]); rowRenderer->setLogicalWidth(logicalWidth()); - if (view()->layoutState()->pageLogicalHeight()) { - rowRenderer->setLogicalHeight(logicalHeightsForPrinting[r]); - } else { - rowRenderer->setLogicalHeight(m_rowPos[r + 1] - m_rowPos[r] - vspacing); - } + rowRenderer->setLogicalHeight(logicalRowHeights[r]); rowRenderer->updateLayerTransform(); } @@ -541,8 +548,8 @@ int RenderTableSection::layoutRows(int toAdd, int headHeight, int footHeight) continue; rindx = cell->row(); - if (view()->layoutState()->pageLogicalHeight() && cell->rowSpan() == 1) { - rHeight = logicalHeightsForPrinting[rindx]; + if (cell->rowSpan() == 1) { + rHeight = logicalRowHeights[rindx]; } else { rHeight = m_rowPos[rindx + cell->rowSpan()] - m_rowPos[rindx] - vspacing; } @@ -1253,4 +1260,4 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul } -} // namespace WebCore +} // namespace WebCore \ No newline at end of file