user32: Added DrawIcon alpha blending support.
This commit is contained in:
parent
8d833ee2e7
commit
a0232508b3
|
@ -1598,6 +1598,74 @@ BOOL WINAPI DestroyCursor( HCURSOR hCursor )
|
||||||
return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
|
return DestroyIcon32(HCURSOR_16(hCursor), CID_WIN32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* bitmap_has_alpha_channel
|
||||||
|
*
|
||||||
|
* Analyses bits bitmap to determine if alpha data is present.
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* bpp [I] The bits-per-pixel of the bitmap
|
||||||
|
* bitmapBits [I] A pointer to the bitmap data
|
||||||
|
* bitmapLength [I] The length of the bitmap in bytes
|
||||||
|
*
|
||||||
|
* RETURNS
|
||||||
|
* TRUE if an alpha channel is discovered, FALSE
|
||||||
|
*
|
||||||
|
* NOTE
|
||||||
|
* Windows' behaviour is that if the icon bitmap is 32-bit and at
|
||||||
|
* least one pixel has a non-zero alpha, then the bitmap is a
|
||||||
|
* treated as having an alpha channel transparentcy. Otherwise,
|
||||||
|
* it's treated as being completely opaque.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static BOOL bitmap_has_alpha_channel( int bpp, unsigned char *bitmapBits,
|
||||||
|
unsigned int bitmapLength )
|
||||||
|
{
|
||||||
|
/* Detect an alpha channel by looking for non-zero alpha pixels */
|
||||||
|
if(bpp == 32)
|
||||||
|
{
|
||||||
|
unsigned int offset;
|
||||||
|
for(offset = 3; offset < bitmapLength; offset += 4)
|
||||||
|
{
|
||||||
|
if(bitmapBits[offset] != 0)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* premultiply_alpha_channel
|
||||||
|
*
|
||||||
|
* Premultiplies the color channels of a 32-bit bitmap by the alpha
|
||||||
|
* channel. This is a necessary step that must be carried out on
|
||||||
|
* the image before it is passed to GdiAlphaBlend
|
||||||
|
*
|
||||||
|
* PARAMS
|
||||||
|
* destBitmap [I] The destination bitmap buffer
|
||||||
|
* srcBitmap [I] The source bitmap buffer
|
||||||
|
* bitmapLength [I] The length of the bitmap in bytes
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void premultiply_alpha_channel( unsigned char *destBitmap,
|
||||||
|
unsigned char *srcBitmap,
|
||||||
|
unsigned int bitmapLength )
|
||||||
|
{
|
||||||
|
unsigned char *destPixel = destBitmap;
|
||||||
|
unsigned char *srcPixel = srcBitmap;
|
||||||
|
|
||||||
|
while(destPixel < destBitmap + bitmapLength)
|
||||||
|
{
|
||||||
|
unsigned char alpha = srcPixel[3];
|
||||||
|
*(destPixel++) = *(srcPixel++) * alpha / 255;
|
||||||
|
*(destPixel++) = *(srcPixel++) * alpha / 255;
|
||||||
|
*(destPixel++) = *(srcPixel++) * alpha / 255;
|
||||||
|
*(destPixel++) = *(srcPixel++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* DrawIcon (USER32.@)
|
* DrawIcon (USER32.@)
|
||||||
|
@ -1606,28 +1674,69 @@ BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
|
||||||
{
|
{
|
||||||
CURSORICONINFO *ptr;
|
CURSORICONINFO *ptr;
|
||||||
HDC hMemDC;
|
HDC hMemDC;
|
||||||
HBITMAP hXorBits, hAndBits;
|
HBITMAP hXorBits = NULL, hAndBits = NULL, hBitTemp = NULL;
|
||||||
COLORREF oldFg, oldBg;
|
COLORREF oldFg, oldBg;
|
||||||
|
unsigned char *xorBitmapBits;
|
||||||
|
unsigned int dibLength;
|
||||||
|
|
||||||
TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
|
TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
|
||||||
|
|
||||||
if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
|
if (!(ptr = GlobalLock16(HICON_16(hIcon)))) return FALSE;
|
||||||
if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
|
if (!(hMemDC = CreateCompatibleDC( hdc ))) return FALSE;
|
||||||
hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
|
|
||||||
hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
|
dibLength = ptr->nHeight * get_bitmap_width_bytes(
|
||||||
ptr->bBitsPerPixel, (char *)(ptr + 1)
|
ptr->nWidth, ptr->bBitsPerPixel);
|
||||||
+ ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
|
|
||||||
|
xorBitmapBits = (unsigned char *)(ptr + 1) + ptr->nHeight *
|
||||||
|
get_bitmap_width_bytes(ptr->nWidth, 1);
|
||||||
|
|
||||||
oldFg = SetTextColor( hdc, RGB(0,0,0) );
|
oldFg = SetTextColor( hdc, RGB(0,0,0) );
|
||||||
oldBg = SetBkColor( hdc, RGB(255,255,255) );
|
oldBg = SetBkColor( hdc, RGB(255,255,255) );
|
||||||
|
|
||||||
if (hXorBits && hAndBits)
|
if(bitmap_has_alpha_channel(ptr->bBitsPerPixel, xorBitmapBits, dibLength))
|
||||||
{
|
{
|
||||||
HBITMAP hBitTemp = SelectObject( hMemDC, hAndBits );
|
BITMAPINFOHEADER bmih;
|
||||||
BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
|
unsigned char *dibBits;
|
||||||
SelectObject( hMemDC, hXorBits );
|
|
||||||
BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
|
memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
|
||||||
SelectObject( hMemDC, hBitTemp );
|
bmih.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
bmih.biWidth = ptr->nWidth;
|
||||||
|
bmih.biHeight = -ptr->nHeight;
|
||||||
|
bmih.biPlanes = ptr->bPlanes;
|
||||||
|
bmih.biBitCount = 32;
|
||||||
|
bmih.biCompression = BI_RGB;
|
||||||
|
|
||||||
|
hXorBits = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS,
|
||||||
|
(void*)&dibBits, NULL, 0);
|
||||||
|
|
||||||
|
if (hXorBits && dibBits)
|
||||||
|
{
|
||||||
|
BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
||||||
|
|
||||||
|
/* Do the alpha blending render */
|
||||||
|
premultiply_alpha_channel(dibBits, xorBitmapBits, dibLength);
|
||||||
|
hBitTemp = SelectObject( hMemDC, hXorBits );
|
||||||
|
GdiAlphaBlend(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC,
|
||||||
|
0, 0, ptr->nWidth, ptr->nHeight, pixelblend);
|
||||||
|
SelectObject( hMemDC, hBitTemp );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hAndBits = CreateBitmap( ptr->nWidth, ptr->nHeight, 1, 1, ptr + 1 );
|
||||||
|
hXorBits = CreateBitmap( ptr->nWidth, ptr->nHeight, ptr->bPlanes,
|
||||||
|
ptr->bBitsPerPixel, xorBitmapBits);
|
||||||
|
|
||||||
|
if (hXorBits && hAndBits)
|
||||||
|
{
|
||||||
|
hBitTemp = SelectObject( hMemDC, hAndBits );
|
||||||
|
BitBlt( hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0, SRCAND );
|
||||||
|
SelectObject( hMemDC, hXorBits );
|
||||||
|
BitBlt(hdc, x, y, ptr->nWidth, ptr->nHeight, hMemDC, 0, 0,SRCINVERT);
|
||||||
|
SelectObject( hMemDC, hBitTemp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DeleteDC( hMemDC );
|
DeleteDC( hMemDC );
|
||||||
if (hXorBits) DeleteObject( hXorBits );
|
if (hXorBits) DeleteObject( hXorBits );
|
||||||
if (hAndBits) DeleteObject( hAndBits );
|
if (hAndBits) DeleteObject( hAndBits );
|
||||||
|
|
|
@ -1090,26 +1090,22 @@ static void test_DrawIcon(void)
|
||||||
/* Test alpha blending */
|
/* Test alpha blending */
|
||||||
/* Windows 2000 and up will alpha blend, earlier Windows versions will not */
|
/* Windows 2000 and up will alpha blend, earlier Windows versions will not */
|
||||||
check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
|
check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__);
|
||||||
|
check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
|
||||||
|
|
||||||
todo_wine
|
check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
|
||||||
{
|
check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
|
||||||
check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
|
check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
|
||||||
|
check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
|
||||||
|
|
||||||
check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
|
check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
|
||||||
check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
|
check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
|
||||||
check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__);
|
|
||||||
check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__);
|
|
||||||
|
|
||||||
check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
|
|
||||||
check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test detecting of alpha channel */
|
/* Test detecting of alpha channel */
|
||||||
/* If a single pixel's alpha channel is non-zero, the icon
|
/* If a single pixel's alpha channel is non-zero, the icon
|
||||||
will be alpha blended, otherwise it will be draw with
|
will be alpha blended, otherwise it will be draw with
|
||||||
and + xor blts. */
|
and + xor blts. */
|
||||||
check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__);
|
check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__);
|
||||||
todo_wine check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__);
|
check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if(bmpOld)
|
if(bmpOld)
|
||||||
|
|
Loading…
Reference in New Issue