Hi all,
I need some help in fixing a bug in CreateDIBitmap. I've attached a patch, but unfortunately it introduces new bugs.
The function CreateDIBitmap creates a monochrome device-dependent bitmap if it's possible. But that's very bad, because BitBlt and StretchBlt handle monochrome bitmaps in a different way than color bitmaps (copied from MSDN):
"If *StretchBlt* must convert a monochrome bitmap to a color bitmap, it sets white bits (1) to the background color and black bits (0) to the foreground color. The foreground and background colors of the device context with color are used."
So SetTextColor and SetBkColor can change the colors of the (formerly device independent) bitmap, and that's not what we want. The attached patch fixes this bug (don't create monochrome bitmaps anymore), but it seems that other code in WINE depends on the old behavior. The mouse cursor is now completely garbage. Can anybody help me finding the remaining bugs?
Test Program (DIB-Testcase.zip): ---------------------------------
I've created a test program that shows the problem. It also shows a bug in Windows! It displays two bitmaps, both should be black and white. WINE displays them red on green (I've set these colors with SetTextColor/SetBkColor).
The images differ only in a single byte. I've used the program bmpdump ( http://david.tribble.com/programs.html ) to analyze them. In the color table of the bitmaps, the rgbReserved member of a RGBQUAD structure is 0x00 for the left bitmap and 0xFF for the right bitmap. This shouldn't make a difference. But Windows creates a monochrome bitmap for the left one, and a color bitmap for the right one! Does anyone understand this behavior?
Regards
Michael
Index: dlls/gdi/dib.c =================================================================== RCS file: /home/wine/wine/dlls/gdi/dib.c,v retrieving revision 1.3 diff -u -r1.3 dib.c --- dlls/gdi/dib.c 12 Aug 2004 20:02:39 -0000 1.3 +++ dlls/gdi/dib.c 23 Aug 2004 14:45:03 -0000 @@ -779,7 +779,6 @@ UINT coloruse ) { HBITMAP handle; - BOOL fColor; DWORD width; int height; WORD bpp; @@ -789,79 +788,10 @@ if (DIB_GetBitmapInfo( header, &width, &height, &bpp, &compr ) == -1) return 0; if (height < 0) height = -height;
- /* Check if we should create a monochrome or color bitmap. */ - /* We create a monochrome bitmap only if it has exactly 2 */ - /* colors, which are black followed by white, nothing else. */ - /* In all other cases, we create a color bitmap. */ - - if (bpp != 1) fColor = TRUE; - else if ((coloruse != DIB_RGB_COLORS) || !data) fColor = FALSE; - else - { - if (data->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)) - { - RGBQUAD *rgb = data->bmiColors; - DWORD col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue ); - - /* Check if the first color of the colormap is black */ - if ((col == RGB(0,0,0))) - { - rgb++; - col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue ); - /* If the second color is white, create a monochrome bitmap */ - fColor = (col != RGB(0xff,0xff,0xff)); - } - /* Note : If the first color of the colormap is white - followed by black, we have to create a color bitmap. - If we don't the white will be displayed in black later on!*/ - else fColor = TRUE; - } - else if (data->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - RGBTRIPLE *rgb = ((BITMAPCOREINFO *)data)->bmciColors; - DWORD col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue ); - if ((col == RGB(0,0,0))) - { - rgb++; - col = RGB( rgb->rgbtRed, rgb->rgbtGreen, rgb->rgbtBlue ); - fColor = (col != RGB(0xff,0xff,0xff)); - } - else fColor = TRUE; - } - else if (data->bmiHeader.biSize == sizeof(BITMAPV4HEADER)) - { /* FIXME: correct ? */ - RGBQUAD *rgb = data->bmiColors; - DWORD col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue ); - - /* Check if the first color of the colormap is black */ - if ((col == RGB(0,0,0))) - { - rgb++; - col = RGB( rgb->rgbRed, rgb->rgbGreen, rgb->rgbBlue ); - /* If the second color is white, create a monochrome bitmap */ - fColor = (col != RGB(0xff,0xff,0xff)); - } - /* Note : If the first color of the colormap is white - followed by black, we have to create a color bitmap. - If we don't the white will be displayed in black later on!*/ - else fColor = TRUE; - } - else - { - ERR("(%ld): wrong/unknown size for data\n", - data->bmiHeader.biSize ); - return 0; - } - } - - /* Now create the bitmap */ - if (!(dc = DC_GetDCPtr( hdc ))) return 0;
- if (fColor) - handle = CreateBitmap( width, height, GetDeviceCaps( hdc, PLANES ), + handle = CreateBitmap( width, height, GetDeviceCaps( hdc, PLANES ), GetDeviceCaps( hdc, BITSPIXEL ), NULL ); - else handle = CreateBitmap( width, height, 1, 1, NULL );
if (handle) {
Hi all,
I finally managed to create a patch that fixes the bug in CreateDIBitmap and also changes all the WINE code that was relying on the wrong behavior. I'll send the patch to wine-patches in a couple of minutes. So if you intended to help, it's too late ;-)
Test Program (DIB-Testcase.zip):
I've created a test program that shows the problem. It also shows a bug in Windows! It displays two bitmaps, both should be black and white. WINE displays them red on green (I've set these colors with SetTextColor/SetBkColor).
The images differ only in a single byte. I've used the program bmpdump ( http://david.tribble.com/programs.html ) to analyze them. In the color table of the bitmaps, the rgbReserved member of a RGBQUAD structure is 0x00 for the left bitmap and 0xFF for the right bitmap. This shouldn't make a difference. But Windows creates a monochrome bitmap for the left one, and a color bitmap for the right one! Does anyone understand this behavior?
Now I do. CreateDIBitmap() doesn't provoke this, it's LoadImage(). This function creates a device-dependent bitmap. If it's possible, it creates a monochrome bitmap. Windows looks at the color tables to check if the two colors are really black and white. For the right bitmap, this is not the case, and so Windows creates a color bitmap.
WINE will do the same with my patch applied.
Regards
Michael
On Thu, 26 Aug 2004, Michael Kaufmann wrote: [...]
Test Program (DIB-Testcase.zip):
I've created a test program that shows the problem. It also shows a bug in Windows! It displays two bitmaps, both should be black and white. WINE displays them red on green (I've set these colors with SetTextColor/SetBkColor).
[...]
Now I do. CreateDIBitmap() doesn't provoke this, it's LoadImage(). This function creates a device-dependent bitmap. If it's possible, it creates a monochrome bitmap. Windows looks at the color tables to check if the two colors are really black and white. For the right bitmap, this is not the case, and so Windows creates a color bitmap.
WINE will do the same with my patch applied.
Could you integrate the DIB-Testcase program with the conformance framework? It seems like it would be a valuable addition and a good complement to your patch.
Hi!
Could you integrate the DIB-Testcase program with the conformance framework? It seems like it would be a valuable addition and a good complement to your patch.
Currently I don't have the time to do this, but I'll try it eventually.
By the way: I've found some more incompatibilities:
- CreateCompatibleBitmap: If a DIB is selected into the device context, CreateCompatibleBitmap should create a copy of this DIB. I don't know how to implement this (how do we detect whether a DIB is selected?). I found code to copy a DIB in dlls/gdi/brush.c
- CreatePatternBrush: The specification of this function has been changed! Look at the function description ( http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/brushes... ). Microsoft replaced "cannot be a DIB" with "can be a DIB"!
Maybe the specification of many more API functions has been changed. It would be a good thing to check this systematically.
Regards
Michael