From 8c61b6a2b487f848659b8b63eb1c980adcb22b75 Mon Sep 17 00:00:00 2001 From: Max Mueggler Date: Thu, 24 Nov 2022 13:02:26 -0500 Subject: [PATCH] Fixed issue with occasional mis-sized tile It turns out that there were two issues at play here: rounding errors meant that pixmaps were almost never the same size as pagePainter thought the tiles should be, and the tile-is-the-size-it-should-be code path was broken (but only hit in rare cases, seemingly at random). To help with rounding errors in the future, I added a geometryF function to NormalizedRect that returns a QRectF. In general, device-independent-pixel points/rects should be floating point, and device-pixel rects should be integer. --- core/area.cpp | 7 +++++++ core/area.h | 5 +++++ gui/pagepainter.cpp | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/core/area.cpp b/core/area.cpp index e921e8cda..aa4eeac15 100644 --- a/core/area.cpp +++ b/core/area.cpp @@ -243,6 +243,13 @@ QRect NormalizedRect::roundedGeometry(int xScale, int yScale) const return QRect(l, t, r - l + 1, b - t + 1); } +QRectF NormalizedRect::geometryF(float xScale, float yScale) const +{ + float l = (left * xScale), t = (top * yScale), r = (right * xScale), b = (bottom * yScale); + + return QRectF(l, t, r - l, b - t); +} + void NormalizedRect::transform(const QTransform &matrix) { QRectF rect(left, top, right - left, bottom - top); diff --git a/core/area.h b/core/area.h index 8c2a51b82..60f687eb7 100644 --- a/core/area.h +++ b/core/area.h @@ -282,6 +282,11 @@ public: */ QRect roundedGeometry(int xScale, int yScale) const; + /** + * Same functionality as geometry, but nothing is converted into int. + */ + QRectF geometryF(float xScale, float yScale) const; + /** * Returns the normalized bounding rectangle of the normalized rectangle * combined with the @p other normalized rectangle. diff --git a/gui/pagepainter.cpp b/gui/pagepainter.cpp index 26cb9c145..395df2ea0 100644 --- a/gui/pagepainter.cpp +++ b/gui/pagepainter.cpp @@ -247,18 +247,18 @@ void PagePainter::paintCroppedPageOnPainter(QPainter *destPainter, QList::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd(); while (tIt != tEnd) { const Okular::Tile &tile = *tIt; - QRect tileRect = tile.rect().geometry(scaledWidth, scaledHeight).translated(-scaledCrop.topLeft()); - QRect dTileRect = QRectF(tileRect.x() * dpr, tileRect.y() * dpr, tileRect.width() * dpr, tileRect.height() * dpr).toAlignedRect(); - QRect limitsInTile = limits & tileRect; - QRectF dLimitsInTile = dLimits & dTileRect; + QRectF tileRect = tile.rect().geometryF(scaledWidth, scaledHeight).translated(-scaledCrop.topLeft()); + QRect dTileRect = tile.rect().geometry(dScaledWidth, dScaledHeight).translated(-dScaledCrop.topLeft()); + QRectF limitsInTile = QRectF(limits) & tileRect; + QRect dLimitsInTile = dLimits & dTileRect; if (!limitsInTile.isEmpty()) { QPixmap *tilePixmap = tile.pixmap(); if (tilePixmap->width() == dTileRect.width() && tilePixmap->height() == dTileRect.height()) { - destPainter->drawPixmap(limitsInTile.topLeft(), *tilePixmap, dLimitsInTile.translated(-dTileRect.topLeft())); + destPainter->drawPixmap(limitsInTile, *tilePixmap, dLimitsInTile.translated(-dTileRect.topLeft())); } else { - destPainter->drawPixmap(tileRect, *tilePixmap); + destPainter->drawPixmap(tileRect, *tilePixmap, tilePixmap->rect()); } } tIt++; @@ -284,16 +284,16 @@ void PagePainter::paintCroppedPageOnPainter(QPainter *destPainter, QList::const_iterator tIt = tiles.constBegin(), tEnd = tiles.constEnd(); while (tIt != tEnd) { const Okular::Tile &tile = *tIt; - QRect tileRect = tile.rect().geometry(scaledWidth, scaledHeight).translated(-scaledCrop.topLeft()); - QRect dTileRect(QRectF(tileRect.x() * dpr, tileRect.y() * dpr, tileRect.width() * dpr, tileRect.height() * dpr).toAlignedRect()); - QRect limitsInTile = limits & tileRect; + QRectF tileRect = tile.rect().geometryF(scaledWidth, scaledHeight).translated(-scaledCrop.topLeft()); + QRect dTileRect = tile.rect().geometry(dScaledWidth, dScaledHeight).translated(-dScaledCrop.topLeft()); + QRectF limitsInTile = QRectF(limits) & tileRect; QRect dLimitsInTile = dLimits & dTileRect; if (!limitsInTile.isEmpty()) { QPixmap *tilePixmap = tile.pixmap(); if (tilePixmap->width() == dTileRect.width() && tilePixmap->height() == dTileRect.height()) { - p.drawPixmap(limitsInTile.translated(-limits.topLeft()).topLeft(), *tilePixmap, dLimitsInTile.translated(-dTileRect.topLeft())); + p.drawPixmap(limitsInTile.translated(-limits.topLeft()), *tilePixmap, dLimitsInTile.translated(-dTileRect.topLeft())); } else { double xScale = tilePixmap->width() / (double)dTileRect.width(); double yScale = tilePixmap->height() / (double)dTileRect.height();