From 954bd930d0af4335faebae68c77570d25ebd1020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Gardou?= Date: Fri, 24 Oct 2014 17:31:50 +0000 Subject: [PATCH] [USER32] - Use CreateDIBitmap with the CDM_CREATEDIB undocumented flag to create alpha bitmaps. This permits to create display compatible yet 32bpp DDBs. CORE-8695 #comment PLease retest, should be OK now. svn path=/trunk/; revision=64967 --- .../user/user32/windows/cursoricon_new.c | 192 +++++++++++------- 1 file changed, 123 insertions(+), 69 deletions(-) diff --git a/reactos/win32ss/user/user32/windows/cursoricon_new.c b/reactos/win32ss/user/user32/windows/cursoricon_new.c index e79c8dc831f..6e024620edf 100644 --- a/reactos/win32ss/user/user32/windows/cursoricon_new.c +++ b/reactos/win32ss/user/user32/windows/cursoricon_new.c @@ -241,56 +241,41 @@ static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits ) * * Create the alpha bitmap for a 32-bpp icon that has an alpha channel. */ -static HBITMAP create_alpha_bitmap( - _In_ HBITMAP color, - _In_opt_ const BITMAPINFO *src_info, - _In_opt_ const void *color_bits ) +static +HBITMAP +create_alpha_bitmap( + _In_opt_ HBITMAP color, + _In_opt_ BITMAPINFO *src_info, + _In_opt_ const void *color_bits, + _In_ LONG width, + _In_ LONG height) { HBITMAP alpha = NULL, hbmpOld; - BITMAPINFO *info = NULL; HDC hdc = NULL, hdcScreen; - void *bits = NULL; unsigned char *ptr; + void *bits = NULL; int i; - LONG width, height; - BITMAP bm; - - if (!GetObjectW( color, sizeof(bm), &bm )) - return NULL; - if (bm.bmBitsPixel != 32) - return NULL; hdcScreen = CreateDCW(DISPLAYW, NULL, NULL, NULL); - if(!hdcScreen) + if (!hdcScreen) return NULL; - if(GetDeviceCaps(hdcScreen, BITSPIXEL) != 32) - goto done; hdc = CreateCompatibleDC(hdcScreen); - if(!hdc) - goto done; - - if(src_info) + if (!hdc) { - WORD bpp; - DWORD compr; - int size; - - if(!bmi_has_alpha(src_info, color_bits)) - goto done; - - if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &width, &height, &bpp, &compr)) - goto done; - if(bpp != 32) - goto done; - - size = get_dib_image_size(width, height, bpp); - bits = HeapAlloc(GetProcessHeap(), 0, size); - if(!bits) - goto done; - CopyMemory(bits, color_bits, size); + DeleteDC(hdcScreen); + return NULL; } - else + + if (color) { + BITMAP bm; + BITMAPINFO *info = NULL; + + if (!GetObjectW( color, sizeof(bm), &bm )) + goto done; + if (bm.bmBitsPixel != 32) + goto done; + info = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256])); if(!info) goto done; @@ -308,46 +293,116 @@ static HBITMAP create_alpha_bitmap( bits = HeapAlloc(GetProcessHeap(), 0, info->bmiHeader.biSizeImage); if(!bits) + { + HeapFree(GetProcessHeap(), 0, info); goto done; + } if(!GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS )) + { + HeapFree(GetProcessHeap(), 0, info); goto done; + } if (!bmi_has_alpha( info, bits )) + { + HeapFree(GetProcessHeap(), 0, info); goto done; - width = bm.bmWidth; - height = bm.bmHeight; - } + } - /* pre-multiply by alpha */ - for (i = 0, ptr = bits; i < width * height; i++, ptr += 4) - { - unsigned int alpha = ptr[3]; - ptr[0] = ptr[0] * alpha / 255; - ptr[1] = ptr[1] * alpha / 255; - ptr[2] = ptr[2] * alpha / 255; + /* pre-multiply by alpha */ + for (i = 0, ptr = bits; i < width * height; i++, ptr += 4) + { + unsigned int alpha = ptr[3]; + ptr[0] = (ptr[0] * alpha) / 255; + ptr[1] = (ptr[1] * alpha) / 255; + ptr[2] = (ptr[2] * alpha) / 255; + } + + /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */ + alpha = CreateDIBitmap(hdc, NULL, CBM_INIT | 2, bits, info, DIB_RGB_COLORS); + + HeapFree(GetProcessHeap(), 0, info); + HeapFree(GetProcessHeap(), 0, bits); } - - /* Create the bitmap */ - alpha = CreateCompatibleBitmap(hdcScreen, bm.bmWidth, bm.bmHeight); - if(!alpha) - goto done; - hbmpOld = SelectObject(hdc, alpha); - if(!hbmpOld) - goto done; - if(!StretchDIBits( hdc, 0, 0, bm.bmWidth, bm.bmHeight, - 0, 0, width, height, - bits, src_info ? src_info : info, DIB_RGB_COLORS, SRCCOPY )) + else { - SelectObject(hdc, hbmpOld); - hbmpOld = NULL; - DeleteObject(alpha); - alpha = NULL; + WORD bpp; + DWORD compr; + int size; + LONG orig_width, orig_height; + + if(!bmi_has_alpha(src_info, color_bits)) + goto done; + + if(!DIB_GetBitmapInfo(&src_info->bmiHeader, &orig_width, &orig_height, &bpp, &compr)) + goto done; + if(bpp != 32) + goto done; + + size = get_dib_image_size(orig_width, orig_height, bpp); + bits = HeapAlloc(GetProcessHeap(), 0, size); + if(!bits) + goto done; + CopyMemory(bits, color_bits, size); + /* pre-multiply by alpha */ + for (i = 0, ptr = bits; i < width * height; i++, ptr += 4) + { + unsigned int alpha = ptr[3]; + ptr[0] = (ptr[0] * alpha) / 255; + ptr[1] = (ptr[1] * alpha) / 255; + ptr[2] = (ptr[2] * alpha) / 255; + } + + /* Create the bitmap. Set the bitmap info to have the right width and height */ + if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = width; + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = height; + } + else + { + src_info->bmiHeader.biWidth = width; + src_info->bmiHeader.biHeight = height; + } + /* Directly create a 32-bits DDB (thanks to undocumented CreateDIBitmap flag). */ + alpha = CreateDIBitmap(hdcScreen, NULL, 2, NULL, src_info, DIB_RGB_COLORS); + /* Restore values */ + if(src_info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcWidth = orig_width; + ((BITMAPCOREHEADER*)&src_info->bmiHeader)->bcHeight = orig_height; + } + else + { + src_info->bmiHeader.biWidth = orig_width; + src_info->bmiHeader.biHeight = orig_height; + } + if(!alpha) + goto done; + hbmpOld = SelectObject(hdc, alpha); + if(!hbmpOld) + { + DeleteObject(alpha); + alpha = NULL; + goto done; + } + if(!StretchDIBits( hdc, 0, 0, width, height, + 0, 0, orig_width, orig_height, + bits, src_info, DIB_RGB_COLORS, SRCCOPY )) + { + SelectObject(hdc, hbmpOld); + hbmpOld = NULL; + DeleteObject(alpha); + alpha = NULL; + } + else + { + SelectObject(hdc, hbmpOld); + } } - SelectObject(hdc, hbmpOld); done: DeleteDC(hdcScreen); - if(hdc) DeleteDC( hdc ); - if(info) HeapFree( GetProcessHeap(), 0, info ); + DeleteDC( hdc ); if(bits) HeapFree(GetProcessHeap(), 0, bits); TRACE("Returning 0x%08x.\n", alpha); @@ -571,8 +626,7 @@ static BOOL CURSORICON_GetCursorDataFromBMI( pvColor, pbmiCopy, DIB_RGB_COLORS, SRCCOPY)) goto done; pdata->bpp = GetDeviceCaps(hdcScreen, BITSPIXEL); - if(pdata->bpp == 32) - pdata->hbmAlpha = create_alpha_bitmap(pdata->hbmColor, pbmiCopy, pvColor); + pdata->hbmAlpha = create_alpha_bitmap(NULL, pbmiCopy, pvColor, pdata->cx, pdata->cy); /* Now convert the info to monochrome for the mask bits */ if (pbmiCopy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) @@ -673,7 +727,7 @@ static BOOL CURSORICON_GetCursorDataFromIconInfo( pCursorData->cx = bm.bmWidth; pCursorData->cy = bm.bmHeight; if(pCursorData->bpp == 32) - pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL); + pCursorData->hbmAlpha = create_alpha_bitmap(pCursorData->hbmColor, NULL, NULL, 0, 0); } else {