dix: Work around non-premultiplied ARGB cursor data harder

Turns out some apps (e.g. the Civilization VI game) use
non-premultiplied cursor data which doesn't have any pixels with 0 alpha
but non-0 non-alpha, but can still result in visual artifacts.

This uses the method suggested by Kamil in
https://bugs.freedesktop.org/92309#c19: check for pixels where any
colour component value is larger than the alpha value, which isn't
possible with premultiplied alpha.

There can still be non-premultiplied data which won't be caught by this,
but that should result in slightly incorrect colours and/or blending at
the worst, not wildly incorrect colours such as shown in the bug report
below.

Bugzilla: https://bugs.freedesktop.org/108355
Suggested-by: Kamil Paral <kamil.paral@gmail.com>
This commit is contained in:
Michel Dänzer 2018-10-25 10:50:03 +02:00 committed by Adam Jackson
parent 248d164eae
commit b45c74f0f2

View File

@ -293,12 +293,13 @@ AllocARGBCursor(unsigned char *psrcbits, unsigned char *pmaskbits,
size_t i, size = bits->width * bits->height;
for (i = 0; i < size; i++) {
if ((argb[i] & 0xff000000) == 0 && (argb[i] & 0xffffff) != 0) {
CARD32 a = argb[i] >> 24;
if (argb[i] > (a << 24 | a << 16 | a << 8 | a)) {
/* ARGB data doesn't seem pre-multiplied, fix it */
for (i = 0; i < size; i++) {
CARD32 a, ar, ag, ab;
CARD32 ar, ag, ab;
a = argb[i] >> 24;
ar = a * ((argb[i] >> 16) & 0xff) / 0xff;
ag = a * ((argb[i] >> 8) & 0xff) / 0xff;
ab = a * (argb[i] & 0xff) / 0xff;