Don't paint a partial pixmap over a fully rendered pixmap, even if dirty

This preserves fully rendered areas when zooming in or out instead of
replacing them with partially rendered pixmaps.
This commit is contained in:
Max Mueggler 2022-11-23 19:56:58 -05:00 committed by Oliver Sander
parent aa0386dccd
commit a1cf3f9e5e
2 changed files with 24 additions and 2 deletions

View File

@ -226,6 +226,10 @@ void TilesManager::Private::setPixmap(const QPixmap *pixmap, const NormalizedRec
if (!tile.rect.intersects(rect)) {
return;
}
// Avoid painting partial pixmaps over tiles that already have a fully rendered pixmap, even if dirty
if (isPartialPixmap && tile.pixmap != nullptr && !tile.partial) {
return;
}
// if the tile is not entirely within the viewport (the tile intersects an
// edged of the viewport), attempt to set the pixmap in the children tiles
@ -239,13 +243,17 @@ void TilesManager::Private::setPixmap(const QPixmap *pixmap, const NormalizedRec
delete tile.pixmap;
tile.pixmap = nullptr;
}
// We could paint the pixmap over part of the tile here, but
// there is little reason to as it will usually be offscreen
// and it will be overwritten later if more tiles enter the screen,
// as we only track the dirty state of whole tiles, not rects.
return;
}
// the tile lies entirely within the viewport
if (tile.nTiles == 0) {
tile.dirty = isPartialPixmap;
tile.partial = isPartialPixmap;
// check whether the tile size is big and split it if necessary
if (!splitBigTiles(tile, rect)) {
@ -276,8 +284,11 @@ void TilesManager::Private::setPixmap(const QPixmap *pixmap, const NormalizedRec
QRect tileRect = tile.rect.geometry(width, height);
// sets the pixmap of the children tiles. if the tile's size is too
// small, discards the children tiles and use the current one
if (tileRect.width() * tileRect.height() >= TILES_MAXSIZE) {
// Never join small tiles during a partial update in order to
// not lose existing image data
if (tileRect.width() * tileRect.height() >= TILES_MAXSIZE || isPartialPixmap) {
tile.dirty = isPartialPixmap;
tile.partial = isPartialPixmap;
if (tile.pixmap) {
totalPixels -= tile.pixmap->width() * tile.pixmap->height();
delete tile.pixmap;
@ -312,6 +323,7 @@ void TilesManager::Private::setPixmap(const QPixmap *pixmap, const NormalizedRec
tile.pixmap = nullptr;
}
tile.dirty = isPartialPixmap;
tile.partial = isPartialPixmap;
}
}
}
@ -471,6 +483,8 @@ void TilesManager::cleanupPixmapMemory(qulonglong numberOfBytes, const Normalize
delete tile->pixmap;
tile->pixmap = nullptr;
tile->partial = true;
d->markParentDirty(*tile);
}
}
@ -625,6 +639,7 @@ TileNode::TileNode()
: pixmap(nullptr)
, rotation(Rotation0)
, dirty(true)
, partial(true)
, distance(-1)
, tiles(nullptr)
, nTiles(0)

View File

@ -66,6 +66,13 @@ public:
*/
bool dirty;
/**
Whether the tile contains a partially rendered pixmap.
Some backends, such as PDF, can send partial updates that contain
only some of the page's elements (e.g. only a background image) drawn.
*/
bool partial;
/**
* Distance between the tile and the viewport.
* This is used by the evicting algorithm.