Skip to content

Commit

Permalink
Merge pull request #13679 from daschuer/scaled_svg_cache
Browse files Browse the repository at this point in the history
Scaled svg cache
  • Loading branch information
JoergAtGithub authored Oct 19, 2024
2 parents ac33b83 + 606fd3e commit 6c97ded
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 48 deletions.
116 changes: 68 additions & 48 deletions src/widget/paintable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,29 +69,7 @@ Paintable::Paintable(const PixmapSource& source, DrawMode mode, double scaleFact
} else {
return;
}
#ifdef __APPLE__
// Apple does Retina scaling behind the scenes, so we also pass a
// Paintable::FIXED image. On the other targets, it is better to
// cache the pixmap. We do not do this for TILE and color schemas.
// which can result in a correct but possibly blurry picture at a
// Retina display. This can be fixed when switching to QT5
if (mode == TILE || WPixmapStore::willCorrectColors()) {
#else
if (mode == TILE || mode == Paintable::FIXED || WPixmapStore::willCorrectColors()) {
#endif
// The SVG renderer doesn't directly support tiling, so we render
// it to a pixmap which will then get tiled.
QImage copy_buffer(pSvg->defaultSize() * scaleFactor, QImage::Format_ARGB32);
copy_buffer.fill(0x00000000); // Transparent black.
QPainter painter(&copy_buffer);
pSvg->render(&painter);
WPixmapStore::correctImageColors(&copy_buffer);

m_pPixmap.reset(new QPixmap(copy_buffer.size()));
m_pPixmap->convertFromImage(copy_buffer);
} else {
m_pSvg = std::move(pSvg);
}
m_pSvg = std::move(pSvg);
}
}

Expand All @@ -100,39 +78,43 @@ bool Paintable::isNull() const {
}

QSize Paintable::size() const {
if (m_pSvg) {
return m_pSvg->defaultSize();
}
if (m_pPixmap) {
return m_pPixmap->size();
} else if (m_pSvg) {
return m_pSvg->defaultSize();
}
return QSize();
}

int Paintable::width() const {
if (m_pPixmap) {
return m_pPixmap->width();
} else if (m_pSvg) {
if (m_pSvg) {
QSize size = m_pSvg->defaultSize();
return size.width();
}
if (m_pPixmap) {
return m_pPixmap->width();
}
return 0;
}

int Paintable::height() const {
if (m_pPixmap) {
return m_pPixmap->height();
} else if (m_pSvg) {
if (m_pSvg) {
QSize size = m_pSvg->defaultSize();
return size.height();
}
if (m_pPixmap) {
return m_pPixmap->height();
}
return 0;
}

QRectF Paintable::rect() const {
if (m_pSvg) {
return QRectF(QPointF(0, 0), m_pSvg->defaultSize());
}
if (m_pPixmap) {
return m_pPixmap->rect();
} else if (m_pSvg) {
return QRectF(QPointF(0, 0), m_pSvg->defaultSize());
}
return QRectF();
}
Expand Down Expand Up @@ -247,6 +229,50 @@ void Paintable::drawInternal(const QRectF& targetRect, QPainter* pPainter,
const QRectF& sourceRect) {
// qDebug() << "Paintable::drawInternal" << DrawModeToString(m_drawMode)
// << targetRect << sourceRect;
if (m_pSvg) {
if (m_drawMode == TILE) {
if (!m_pPixmap) {
// qDebug() << "Paintable cache miss";
qreal devicePixelRatio = pPainter->device()->devicePixelRatio();
m_pPixmap = std::make_unique<QPixmap>(m_pSvg->defaultSize() * devicePixelRatio);
m_pPixmap->setDevicePixelRatio(devicePixelRatio);
m_pPixmap->fill(Qt::transparent);
{ // QPainter Scope
auto pixmapPainter = QPainter(m_pPixmap.get());
m_pSvg->render(&pixmapPainter);
}
mayCorrectColors();
}
// The SVG renderer doesn't directly support tiling, so we render
// it to a pixmap which will then get tiled.
pPainter->drawTiledPixmap(targetRect, *m_pPixmap);
} else {
if (!m_pPixmap ||
m_pPixmap->size() != targetRect.size().toSize() ||
m_lastSourceRect != sourceRect) {
// qDebug() << "Paintable cache miss";
qreal devicePixelRatio = pPainter->device()->devicePixelRatio();
m_pPixmap = std::make_unique<QPixmap>(
targetRect.size().toSize() * devicePixelRatio);
m_pPixmap->setDevicePixelRatio(devicePixelRatio);
m_pPixmap->fill(Qt::transparent);
{ // QPainter Scope
auto pixmapPainter = QPainter(m_pPixmap.get());
QRectF deviceSourceRect = QRectF(
sourceRect.x() * devicePixelRatio,
sourceRect.y() * devicePixelRatio,
sourceRect.width() * devicePixelRatio,
sourceRect.height() * devicePixelRatio);
m_pSvg->setViewBox(deviceSourceRect);
m_pSvg->render(&pixmapPainter);
}
mayCorrectColors();
m_lastSourceRect = sourceRect;
}
pPainter->drawPixmap(targetRect.topLeft(), *m_pPixmap);
}
return;
}
if (m_pPixmap) {
// Note: Qt rounds the target rect to device pixels internally
// using roundInDeviceCoordinates()
Expand All @@ -263,21 +289,7 @@ void Paintable::drawInternal(const QRectF& targetRect, QPainter* pPainter,
pPainter->drawPixmap(targetRect, *m_pPixmap, sourceRect);
}
}
} else if (m_pSvg) {
if (m_drawMode == TILE) {
qWarning() << "Tiled SVG should have been rendered to pixmap!";
} else {
// NOTE(rryan): QSvgRenderer render does not clip for us -- it
// applies a world transformation using viewBox and renders the
// entire SVG to the painter. We save/restore the QPainter in case
// there is an existing clip region (I don't know of any Mixxx code
// that uses one but we may in the future).
PainterScope PainterScope(pPainter);
pPainter->setClipping(true);
pPainter->setClipRect(targetRect);
m_pSvg->setViewBox(sourceRect);
m_pSvg->render(pPainter, targetRect);
}
return;
}
}

Expand All @@ -298,3 +310,11 @@ QString Paintable::getAltFileName(const QString& fileName) {
return fileName;
}
}

void Paintable::mayCorrectColors() {
if (WPixmapStore::willCorrectColors()) {
QImage image = m_pPixmap->toImage();
WPixmapStore::correctImageColors(&image);
m_pPixmap->convertFromImage(image);
}
}
2 changes: 2 additions & 0 deletions src/widget/paintable.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ class Paintable {
private:
void drawInternal(const QRectF& targetRect, QPainter* pPainter,
const QRectF& sourceRect);
void mayCorrectColors();

std::unique_ptr<QPixmap> m_pPixmap;
std::unique_ptr<QSvgRenderer> m_pSvg;
DrawMode m_drawMode;
QRectF m_lastSourceRect;
};

0 comments on commit 6c97ded

Please sign in to comment.