Fix icon alpha blending in QTableView

Some widgets such as QTableView do not call QIconEngine::pixmap(), but do
the drawing immediately through QIconEngine::paint(). This breaks alpha
blending for recolouring, since the underlying image canvas is not
necessarily transparent and also not anchored at (0, 0). This results in
a black box of the size of the icon bounding box.

Icon recolouring is now always done on a temporary QImage with
transparent background and only the finished end result is composed onto
the original canvas.

Fixes #6006
This commit is contained in:
Janek Bevendorff 2021-01-31 14:45:14 +01:00
parent c7323accf2
commit b55f419386

View File

@ -117,23 +117,34 @@ AdaptiveIconEngine::AdaptiveIconEngine(QIcon baseIcon)
void AdaptiveIconEngine::paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state) void AdaptiveIconEngine::paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state)
{ {
painter->save(); // Temporary image canvas to ensure that the background is transparent and alpha blending works.
m_baseIcon.paint(painter, rect, Qt::AlignCenter, mode, state); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
auto scale = painter->device()->devicePixelRatioF();
#else
auto scale = painter->device()->devicePixelRatio();
#endif
QImage img(rect.size() * scale, QImage::Format_ARGB32_Premultiplied);
img.fill(0);
QPainter p(&img);
m_baseIcon.paint(&p, img.rect(), Qt::AlignCenter, mode, state);
if (getMainWindow()) { if (getMainWindow()) {
QPalette palette = getMainWindow()->palette(); QPalette palette = getMainWindow()->palette();
painter->setCompositionMode(QPainter::CompositionMode_SourceAtop); p.setCompositionMode(QPainter::CompositionMode_SourceIn);
if (mode == QIcon::Active) { if (mode == QIcon::Active) {
painter->fillRect(rect, palette.color(QPalette::Active, QPalette::ButtonText)); p.fillRect(img.rect(), palette.color(QPalette::Active, QPalette::ButtonText));
} else if (mode == QIcon::Selected) { } else if (mode == QIcon::Selected) {
painter->fillRect(rect, palette.color(QPalette::Active, QPalette::HighlightedText)); p.fillRect(img.rect(), palette.color(QPalette::Active, QPalette::HighlightedText));
} else if (mode == QIcon::Disabled) { } else if (mode == QIcon::Disabled) {
painter->fillRect(rect, palette.color(QPalette::Disabled, QPalette::WindowText)); p.fillRect(img.rect(), palette.color(QPalette::Disabled, QPalette::WindowText));
} else { } else {
painter->fillRect(rect, palette.color(QPalette::Normal, QPalette::WindowText)); p.fillRect(img.rect(), palette.color(QPalette::Normal, QPalette::WindowText));
} }
} }
painter->restore();
painter->drawImage(rect, img);
} }
QPixmap AdaptiveIconEngine::pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state) QPixmap AdaptiveIconEngine::pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state)
@ -142,7 +153,7 @@ QPixmap AdaptiveIconEngine::pixmap(const QSize& size, QIcon::Mode mode, QIcon::S
img.fill(0); img.fill(0);
QPainter painter(&img); QPainter painter(&img);
paint(&painter, QRect(0, 0, size.width(), size.height()), mode, state); paint(&painter, QRect(0, 0, size.width(), size.height()), mode, state);
return QPixmap::fromImage(img, Qt::NoFormatConversion); return QPixmap::fromImage(img, Qt::ImageConversionFlag::NoFormatConversion);
} }
QIconEngine* AdaptiveIconEngine::clone() const QIconEngine* AdaptiveIconEngine::clone() const