diff options
author | Nils Jeisecke <jeisecke@saltation.de> | 2015-06-05 17:48:00 +0200 |
---|---|---|
committer | Andy Shaw <andy.shaw@qt.io> | 2017-09-07 20:40:14 +0200 |
commit | 87748cc18e6a0d9e65933aa2462dc78ab8f9f22e (patch) | |
tree | 82fa4b8e8fdcddf3fcdeea5fd8aad2a07cb22034 | |
parent | 20e9422e069a27b7e29b54207447e6ca02b3a55a (diff) |
QTextDocumentLayout: Avoid table border drawing artifacts
As borders are always painted for single cells any rounding errors that
occur when mapping from fixed point numbers to integers during raster
painting will cause ugly drawing artifacts like extra pixels between
cells or borders that overlap.
To avoid this the following values are being rounded:
- table offset
- column positions and widths
- row positions and cell heights
For the column positions and widths the distribution constraints (total
table width) are respected.
Task-number: QTBUG-43589
Change-Id: I6308c113f8f9be3db8e9267629f26b5d65d2d7c7
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
-rw-r--r-- | src/gui/text/qtextdocumentlayout.cpp | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 7873faf2cb..e5cfa7f46e 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -931,7 +931,10 @@ void QTextDocumentLayoutPrivate::drawFrame(const QPointF &offset, QPainter *pain Q_ASSERT(!fd->sizeDirty); Q_ASSERT(!fd->layoutDirty); - const QPointF off = offset + fd->position.toPointF(); + // floor the offset to avoid painting artefacts when drawing adjacent borders + // we later also round table cell heights and widths + const QPointF off = QPointF(QPointF(offset + fd->position.toPointF()).toPoint()); + if (context.clip.isValid() && (off.y() > context.clip.bottom() || off.y() + fd->size.height.toReal() < context.clip.top() || off.x() > context.clip.right() || off.x() + fd->size.width.toReal() < context.clip.left())) @@ -1681,7 +1684,8 @@ recalc_minmax_widths: for (int n = 0; n < cspan; ++n) { const int col = i + n; QFixed w = widthToDistribute / (cspan - n); - td->minWidths[col] = qMax(td->minWidths.at(col), w); + // ceil to avoid going below minWidth when rounding all column widths later + td->minWidths[col] = qMax(td->minWidths.at(col), w).ceil(); widthToDistribute -= td->minWidths.at(col); if (widthToDistribute <= 0) break; @@ -1787,6 +1791,18 @@ recalc_minmax_widths: } } + // in order to get a correct border rendering we must ensure that the distance between + // two cells is exactly 2 * td->border pixel. we do this by rounding the calculated width + // values here. + // to minimize the total rounding error we propagate the rounding error for each width + // to its successor. + QFixed error = 0; + for (int i = 0; i < columns; ++i) { + QFixed orig = td->widths[i]; + td->widths[i] = (td->widths[i] - error).round(); + error = td->widths[i] - orig; + } + td->columnPositions.resize(columns); td->columnPositions[0] = leftMargin /*includes table border*/ + cellSpacing + td->border; @@ -1887,7 +1903,7 @@ relayout: if (cellRow != r) { // the last row gets all the remaining space if (cellRow + rspan - 1 == r) - td->heights[r] = qMax(td->heights.at(r), heightToDistribute.at(c) - dropDistance); + td->heights[r] = qMax(td->heights.at(r), heightToDistribute.at(c) - dropDistance).round(); continue; } } @@ -1908,7 +1924,7 @@ relayout: td, absoluteTableY, /*withPageBreaks =*/true); - const QFixed height = layoutStruct.y + bottomPadding + topPadding; + const QFixed height = (layoutStruct.y + bottomPadding + topPadding).round(); if (rspan > 1) heightToDistribute[c] = height + dropDistance; |