[PATCH] Added DrawIcon alpha blending support
Joel Holdsworth
joel at airwebreathe.org.uk
Sun May 31 11:00:17 CDT 2009
---
dlls/user32/cursoricon.c | 131 ++++++++++++++++++++++++++++++++++++----
dlls/user32/tests/cursoricon.c | 20 +++----
2 files changed, 128 insertions(+), 23 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 707d2bb..7f56648 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -1598,6 +1598,74 @@ BOOL WINAPI DestroyCursor( HCURSOR hCursor )
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.@)
@@ -1606,28 +1674,69 @@ BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
{
CURSORICONINFO *ptr;
HDC hMemDC;
- HBITMAP hXorBits, hAndBits;
+ HBITMAP hXorBits = NULL, hAndBits = NULL, hBitTemp = NULL;
COLORREF oldFg, oldBg;
+ unsigned char *xorBitmapBits;
+ unsigned int dibLength;
TRACE("%p, (%d,%d), %p\n", hdc, x, y, hIcon);
if (!(ptr = GlobalLock16(HICON_16(hIcon)))) 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,
- ptr->bBitsPerPixel, (char *)(ptr + 1)
- + ptr->nHeight * get_bitmap_width_bytes(ptr->nWidth,1) );
+
+ dibLength = ptr->nHeight * get_bitmap_width_bytes(
+ ptr->nWidth, ptr->bBitsPerPixel);
+
+ xorBitmapBits = (unsigned char *)(ptr + 1) + ptr->nHeight *
+ get_bitmap_width_bytes(ptr->nWidth, 1);
+
oldFg = SetTextColor( hdc, RGB(0,0,0) );
oldBg = SetBkColor( hdc, RGB(255,255,255) );
- if (hXorBits && hAndBits)
+ if(bitmap_has_alpha_channel(ptr->bBitsPerPixel, xorBitmapBits, dibLength))
+ {
+ BITMAPINFOHEADER bmih;
+ unsigned char *dibBits;
+
+ memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
+ 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
{
- HBITMAP 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 );
+ 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 );
if (hXorBits) DeleteObject( hXorBits );
if (hAndBits) DeleteObject( hAndBits );
diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index b15acc2..cfe2449 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -1090,26 +1090,22 @@ static void test_DrawIcon(void)
/* Test alpha blending */
/* 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, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
- todo_wine
- {
- check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__);
+ check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__);
+ check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __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, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __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__);
- }
+ 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 */
/* If a single pixel's alpha channel is non-zero, the icon
will be alpha blended, otherwise it will be draw with
and + xor blts. */
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__);
SelectObject(hdcDst, bmpOld);
DeleteObject(bmpDst);
--
1.6.0.4
--=-PQdgjbJhcxmvUU/Nr5v1--
More information about the wine-patches
mailing list