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.
This commit is contained in:
Max Mueggler 2022-11-24 13:02:26 -05:00 committed by Oliver Sander
parent 521ea660ee
commit 8c61b6a2b4
3 changed files with 22 additions and 10 deletions

View file

@ -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);

View file

@ -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.

View file

@ -247,18 +247,18 @@ void PagePainter::paintCroppedPageOnPainter(QPainter *destPainter,
QList<Okular::Tile>::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<Okular::Tile>::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();