diff --git a/src/widget/paintable.cpp b/src/widget/paintable.cpp index 781c7e8f512..ee6e27b6371 100644 --- a/src/widget/paintable.cpp +++ b/src/widget/paintable.cpp @@ -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(©_buffer); - pSvg->render(&painter); - WPixmapStore::correctImageColors(©_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); } } @@ -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(); } @@ -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(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( + 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() @@ -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; } } @@ -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); + } +} diff --git a/src/widget/paintable.h b/src/widget/paintable.h index 0e61390cd9e..c2779a0a7f4 100644 --- a/src/widget/paintable.h +++ b/src/widget/paintable.h @@ -53,8 +53,10 @@ class Paintable { private: void drawInternal(const QRectF& targetRect, QPainter* pPainter, const QRectF& sourceRect); + void mayCorrectColors(); std::unique_ptr m_pPixmap; std::unique_ptr m_pSvg; DrawMode m_drawMode; + QRectF m_lastSourceRect; };