[PATCH] Fix for monochrome device independent bitmaps with inverted colors

Oldřich Jedlička <[email protected]> Mon, 15 Aug 2005 10:56:12 +0000
Newsgroups gmane.comp.emulators.winex.devel
Organization CorteNico
Message-ID <[email protected]>
Hi,

I found a problem in translating XImage into DIB created by CreateDIBSection. 
All problems are in graphics/x11drv/dib.c only.

A) When the DIB palette is inverted (color[0]=0xFFFFFF, color[1]=0x000000), 
colors in DIB are not correct.

1. When there is descr.palentry == NULL, which is normal for updating 
BMP->DIB, function X11DRV_DIB_GetImageBits_1 falls back into "notsupported" 
branch and one-to-one mapping is applied. The palette of DIB is completely 
ignored in this case. There is a simple fix for this - check if the colors 
are inverted and invert image in translation BMP->DIB. Direction DIB->BMP is 
not affected as it uses current DIB palette.

2. Used XImage (bmpImage parameter) has RGB mask corresponding to current 
visual, so they are not zero. But zero is checked in condition

if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 
&& srccolors)

which is then not true. Fixed in new static inline X11DRV_DIB_CheckMask 
function.

B) Another small thing is that on line 6174 of dib.c there is 
X11DRV_DIB_CreateXImage using directly bpp, not DEPTH_FROM_BPP(bpp), while 
all other functions uses the conversion macro. This is also changed in the 
patch.

This was found out in game Neighbours from Hell which uses inverted palette 
monochrome bitmaps for outputting the text. The testcase for exactly this 
problem is very simple: create bitmap with CreateDIBSection with inverted RGB 
colors (color[0]=0xFFFFFF, color[1]=0x000000), create some font, select 
bitmap and font into device context and call TextOut. You can see then the 
result in bits of DIB (correct with the patch, inverted without patch).

Please find the attached patch.

Best regards,

  Oldrich Jedlicka.
dib.c.patch (text/x-diff, 7.4 KB)
Index: graphics/x11drv/dib.c
===================================================================
RCS file: /cvsroot/winex/graphics/x11drv/dib.c,v
retrieving revision 1.90
diff -u -r1.90 graphics/x11drv/dib.c
--- graphics/x11drv/dib.c	21 Jan 2005 22:05:40 -0000	1.90
+++ graphics/x11drv/dib.c	15 Aug 2005 06:59:10 -0000
@@ -1725,6 +1725,17 @@
 }
 
 /***********************************************************************
+ *           X11DRV_DIB_CheckMask
+ *
+ * Check RGB mask if it is either 0 or matches visual's mask.
+ */
+static inline int X11DRV_DIB_CheckMask( int red_mask, int green_mask, int blue_mask ) {
+    return ( red_mask == 0 && green_mask == 0 && blue_mask == 0 ) ||
+           ( red_mask == visual->red_mask && green_mask == visual->green_mask &&
+             blue_mask == visual->blue_mask );
+}
+
+/***********************************************************************
  *           X11DRV_DIB_SetImageBits_1
  *
  * SetDIBits for a 1-bit deep DIB.
@@ -1810,7 +1821,8 @@
     {
     case 1:
     case 4:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 1 or 4 bmp -> pal 1 dib ==== */
             BYTE* dstbyte;
 
@@ -1842,7 +1854,8 @@
         break;
 
     case 8:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask, bmpImage->green_mask, bmpImage->blue_mask )
+            && srccolors) {
             /* ==== pal 8 bmp -> pal 1 dib ==== */
             const void* srcbits;
             const BYTE* srcpixel;
@@ -2090,19 +2103,30 @@
     notsupported:
         {
             BYTE* dstbyte;
+            BYTE neg = 0;
             unsigned long white = (1 << bmpImage->bits_per_pixel) - 1;
 
             /* ==== any bmp format -> pal 1 dib ==== */
-            WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 1 bit DIB\n",
-                  bmpImage->bits_per_pixel, bmpImage->red_mask,
-                  bmpImage->green_mask, bmpImage->blue_mask );
+            if ( (unsigned)colors[0].rgbRed+colors[0].rgbGreen+
+            	 	   colors[0].rgbBlue >= 
+            	 (unsigned)colors[1].rgbRed+colors[1].rgbGreen+
+            	 	   colors[1].rgbBlue ) {
+            	neg = 1;
+            }
 
+            WARN("from unknown %d bit bitmap (%lx,%lx,%lx) to 1 bit DIB, "
+            	 "%s color mapping\n",
+                  bmpImage->bits_per_pixel, bmpImage->red_mask,
+                  bmpImage->green_mask, bmpImage->blue_mask,
+                  neg?"negative":"direct" );
+                  
             for (h=lines-1; h>=0; h--) {
                 BYTE dstval;
                 dstbyte=dstbits;
                 dstval=0;
                 for (x=0; x<dstwidth; x++) {
-                    dstval|=(XGetPixel( bmpImage, x, h) >= white) << (7 - (x&7));
+                    dstval|=((XGetPixel(bmpImage, x, h) >= white) ^ neg) << 
+                            (7 - (x&7));
                     if ((x&7)==7) {
                         *dstbyte++=dstval;
                         dstval=0;
@@ -2185,7 +2209,8 @@
     switch (bmpImage->depth) {
     case 1:
     case 4:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 1 or 4 bmp -> pal 4 dib ==== */
             BYTE* dstbyte;
 
@@ -2217,7 +2242,8 @@
         break;
 
     case 8:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 8 bmp -> pal 4 dib ==== */
             const void* srcbits;
             const BYTE *srcpixel;
@@ -2770,7 +2796,8 @@
     switch (bmpImage->depth) {
     case 1:
     case 4:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
 
             /* ==== pal 1 bmp -> pal 8 dib ==== */
             /* ==== pal 4 bmp -> pal 8 dib ==== */
@@ -2792,7 +2819,8 @@
         break;
 
     case 8:
-       if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+       if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+           && srccolors) {
             /* ==== pal 8 bmp -> pal 8 dib ==== */
            const void* srcbits;
            const BYTE* srcpixel;
@@ -3464,7 +3492,8 @@
 
     case 1:
     case 4:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 1 or 4 bmp -> rgb or bgr 555 or 565 dib ==== */
             int rShift,gShift,bShift;
             WORD* dstpixel;
@@ -3502,7 +3531,8 @@
         break;
 
     case 8:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 8 bmp -> rgb or bgr 555 or 565 dib ==== */
             int rShift,gShift,bShift;
             const BYTE* srcbits;
@@ -3888,7 +3918,8 @@
 
     case 1:
     case 4:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 1 or 4 bmp -> rgb 888 dib ==== */
             BYTE* dstbyte;
 
@@ -3911,7 +3942,8 @@
         break;
 
     case 8:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask == 0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 8 bmp -> rgb 888 dib ==== */
             const void* srcbits;
             const BYTE* srcpixel;
@@ -4462,7 +4494,8 @@
 
     case 1:
     case 4:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 1 or 4 bmp -> any 0888 dib ==== */
             int rShift,gShift,bShift;
             DWORD* dstpixel;
@@ -4487,7 +4520,8 @@
         break;
 
     case 8:
-        if (bmpImage->red_mask==0 && bmpImage->green_mask==0 && bmpImage->blue_mask==0 && srccolors) {
+        if (X11DRV_DIB_CheckMask(bmpImage->red_mask,bmpImage->green_mask,bmpImage->blue_mask)
+            && srccolors) {
             /* ==== pal 8 bmp -> any 0888 dib ==== */
             int rShift,gShift,bShift;
             const void* srcbits;
@@ -6171,7 +6205,7 @@
 	{
 	    ; /* Created Image */
 	} else {
-	   dib->image = X11DRV_DIB_CreateXImage( aligned_width, height, bpp );
+	   dib->image = X11DRV_DIB_CreateXImage( aligned_width, height, DEPTH_FROM_BPP(bpp) );
 	   dib->shminfo.shmid = -1;
 	}
 #else