Fix a regression when painting CMYK over ARGB32_Premultiplied

With the introduction of CMYK32 the old logic of assuming depth
meant compatible alpha version no longer works. So change the logic
to more explicitly return compatible opaque or alpha versions and
remove the now invalid qt_maybeAlphaVersionWithSameDepth.

Change-Id: Ib1f7b76b0ce0eae7d49a0dfe369918a746bbe2b4
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
bb10
Allan Sandfeld Jensen 2024-04-04 10:08:55 +02:00
parent 7f72a93e87
commit a07cb53c23
5 changed files with 116 additions and 15 deletions

View File

@ -322,6 +322,63 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
return QImage::Format_ARGB32_Premultiplied;
}
// Returns an opaque version that is compatible with format
inline QImage::Format qt_maybeDataCompatibleOpaqueVersion(QImage::Format format)
{
switch (format) {
case QImage::Format_ARGB6666_Premultiplied:
return QImage::Format_RGB666;
case QImage::Format_ARGB4444_Premultiplied:
return QImage::Format_RGB444;
case QImage::Format_RGBA8888:
case QImage::Format_RGBA8888_Premultiplied:
return QImage::Format_RGBX8888;
case QImage::Format_A2BGR30_Premultiplied:
return QImage::Format_BGR30;
case QImage::Format_A2RGB30_Premultiplied:
return QImage::Format_RGB30;
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
return QImage::Format_RGBX64;
case QImage::Format_RGBA16FPx4:
case QImage::Format_RGBA16FPx4_Premultiplied:
return QImage::Format_RGBX16FPx4;
case QImage::Format_RGBA32FPx4:
case QImage::Format_RGBA32FPx4_Premultiplied:
return QImage::Format_RGBX32FPx4;
case QImage::Format_ARGB32_Premultiplied:
case QImage::Format_ARGB32:
return QImage::Format_RGB32;
case QImage::Format_RGB16:
case QImage::Format_RGB32:
case QImage::Format_RGB444:
case QImage::Format_RGB555:
case QImage::Format_RGB666:
case QImage::Format_RGB888:
case QImage::Format_BGR888:
case QImage::Format_RGBX8888:
case QImage::Format_BGR30:
case QImage::Format_RGB30:
case QImage::Format_RGBX64:
case QImage::Format_RGBX16FPx4:
case QImage::Format_RGBX32FPx4:
case QImage::Format_Grayscale8:
case QImage::Format_Grayscale16:
case QImage::Format_CMYK32:
return format; // Already opaque
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
case QImage::Format_Indexed8:
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_ARGB8555_Premultiplied:
case QImage::Format_Alpha8:
case QImage::Format_Invalid:
case QImage::NImageFormats:
break;
}
return format; // No compatible opaque versions
}
constexpr QImage::Format qt_toUnpremultipliedFormat(QImage::Format format)
{
// Assumes input is already a premultiplied format with an unpremultiplied counterpart
@ -380,10 +437,60 @@ inline bool qt_fpColorPrecision(QImage::Format format)
return false;
}
inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
inline QImage::Format qt_maybeDataCompatibleAlphaVersion(QImage::Format format)
{
const QImage::Format toFormat = qt_alphaVersion(format);
return qt_depthForFormat(format) == qt_depthForFormat(toFormat) ? toFormat : format;
switch (format) {
case QImage::Format_RGB32:
return QImage::Format_ARGB32_Premultiplied;
case QImage::Format_RGB666:
return QImage::Format_ARGB6666_Premultiplied;
case QImage::Format_RGB444:
return QImage::Format_ARGB4444_Premultiplied;
case QImage::Format_RGBX8888:
return QImage::Format_RGBA8888_Premultiplied;
case QImage::Format_BGR30:
return QImage::Format_A2BGR30_Premultiplied;
case QImage::Format_RGB30:
return QImage::Format_A2RGB30_Premultiplied;
case QImage::Format_RGBX64:
return QImage::Format_RGBA64_Premultiplied;
case QImage::Format_RGBX16FPx4:
return QImage::Format_RGBA16FPx4_Premultiplied;
case QImage::Format_RGBX32FPx4:
return QImage::Format_RGBA32FPx4_Premultiplied;
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_ARGB8555_Premultiplied:
case QImage::Format_ARGB6666_Premultiplied:
case QImage::Format_ARGB4444_Premultiplied:
case QImage::Format_RGBA8888:
case QImage::Format_RGBA8888_Premultiplied:
case QImage::Format_A2BGR30_Premultiplied:
case QImage::Format_A2RGB30_Premultiplied:
case QImage::Format_Alpha8:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
case QImage::Format_RGBA16FPx4:
case QImage::Format_RGBA16FPx4_Premultiplied:
case QImage::Format_RGBA32FPx4:
case QImage::Format_RGBA32FPx4_Premultiplied:
return format; // Already alpha versions
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
case QImage::Format_Indexed8:
case QImage::Format_RGB16:
case QImage::Format_RGB555:
case QImage::Format_RGB888:
case QImage::Format_BGR888:
case QImage::Format_Grayscale8:
case QImage::Format_Grayscale16:
case QImage::Format_CMYK32:
case QImage::Format_Invalid:
case QImage::NImageFormats:
break;
}
return format; // No data-compatible alpha version
}
inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)

View File

@ -3713,15 +3713,9 @@ bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mo
QImage::Format dFormat = rasterBuffer->format;
QImage::Format sFormat = image.format();
// Formats must match or source format must be a subset of destination format
if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) {
if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32)
|| (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888)
|| (sFormat == QImage::Format_RGBX64 && dFormat == QImage::Format_RGBA64))
sFormat = dFormat;
else
sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats
}
// Formats must match or source format must be an opaque version of destination format
if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha)
dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat);
return (dFormat == sFormat);
}

View File

@ -60,7 +60,7 @@ QImage::Format QRhiBackingStore::format() const
// image must have an alpha channel. Hence upgrading the format. Matches
// what other platforms (Windows, xcb) do.
if (QImage::toPixelFormat(fmt).alphaUsage() != QPixelFormat::UsesAlpha)
fmt = qt_maybeAlphaVersionWithSameDepth(fmt);
fmt = qt_maybeDataCompatibleAlphaVersion(fmt);
return fmt;
}

View File

@ -117,7 +117,7 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha)
m_alphaNeedsFill = true;
else // upgrade but here we know app painting does not rely on alpha hence no need to fill
format = qt_maybeAlphaVersionWithSameDepth(format);
format = qt_maybeDataCompatibleAlphaVersion(format);
QWindowsNativeImage *oldwni = m_image.data();
auto *newwni = new QWindowsNativeImage(size.width(), size.height(), format);

View File

@ -173,7 +173,7 @@ void QXcbBackingStoreImage::init(const QSize &size, uint depth, QImage::Format f
m_qimage_format = format;
m_hasAlpha = QImage::toPixelFormat(m_qimage_format).alphaUsage() == QPixelFormat::UsesAlpha;
if (!m_hasAlpha)
m_qimage_format = qt_maybeAlphaVersionWithSameDepth(m_qimage_format);
m_qimage_format = qt_maybeDataCompatibleAlphaVersion(m_qimage_format);
memset(&m_shm_info, 0, sizeof m_shm_info);