[PATCH] Fixed CURSORICON_CreateIconFromBMI to preserve the alpha channel
Joel Holdsworth
joel at airwebreathe.org.uk
Tue Jun 2 16:05:14 CDT 2009
---
dlls/user32/cursoricon.c | 159 ++++++++++++++++++++++++++++++++--------------
1 files changed, 112 insertions(+), 47 deletions(-)
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
index 92446e1..0c847b5 100644
--- a/dlls/user32/cursoricon.c
+++ b/dlls/user32/cursoricon.c
@@ -659,6 +659,39 @@ static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *d
return &dir->idEntries[n];
}
+/***********************************************************************
+ * stretch_blt_icon
+ *
+ * A helper function that stretches a bitmap buffer into an HBITMAP.
+ *
+ * PARAMS
+ * hDest [I] The handle of the destination bitmap.
+ * pDestInfo [I] The BITMAPINFO of the destination bitmap.
+ * pSrcInfo [I] The BITMAPINFO of the source bitmap.
+ * pSrcBits [I] A pointer to the source bitmap buffer.
+ **/
+static BOOL stretch_blt_icon(HBITMAP hDest, BITMAPINFO *pDestInfo, BITMAPINFO *pSrcInfo, char *pSrcBits)
+{
+ HBITMAP hOld;
+ BOOL res = FALSE;
+ static HDC hdcMem = NULL;
+
+ if (!hdcMem)
+ hdcMem = CreateCompatibleDC(screen_dc);
+
+ if (hdcMem)
+ {
+ hOld = SelectObject(hdcMem, hDest);
+ res = StretchDIBits(hdcMem,
+ 0, 0, pDestInfo->bmiHeader.biWidth, pDestInfo->bmiHeader.biHeight,
+ 0, 0, pSrcInfo->bmiHeader.biWidth, pSrcInfo->bmiHeader.biHeight,
+ pSrcBits, pSrcInfo, DIB_RGB_COLORS, SRCCOPY);
+ SelectObject(hdcMem, hOld);
+ }
+
+ return res;
+}
+
static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
POINT16 hotspot, BOOL bIcon,
DWORD dwVersion,
@@ -666,7 +699,6 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
UINT cFlag )
{
HGLOBAL16 hObj;
- static HDC hdcMem;
int sizeAnd, sizeXor;
HBITMAP hAndBits = 0, hXorBits = 0; /* error condition for later */
BITMAP bmpXor, bmpAnd;
@@ -706,7 +738,7 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
if (screen_dc)
{
- BITMAPINFO* pInfo;
+ BITMAPINFO *pSrcInfo, *pDestInfo;
/* Make sure we have room for the monochrome bitmap later on.
* Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
@@ -719,40 +751,78 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
* BYTE icAND[] // DIB bits for AND mask
*/
- if ((pInfo = HeapAlloc( GetProcessHeap(), 0,
- max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)))))
+ pSrcInfo = HeapAlloc( GetProcessHeap(), 0,
+ max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
+ pDestInfo = HeapAlloc( GetProcessHeap(), 0,
+ max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
+ if (pSrcInfo && pDestInfo)
{
- memcpy( pInfo, bmi, size );
- pInfo->bmiHeader.biHeight /= 2;
+ memcpy( pSrcInfo, bmi, size );
+ pSrcInfo->bmiHeader.biHeight /= 2;
+ memcpy( pDestInfo, bmi, size );
+
+ pDestInfo->bmiHeader.biWidth = width;
+ pDestInfo->bmiHeader.biHeight = height;
+ pDestInfo->bmiHeader.biSizeImage = 0;
/* Create the XOR bitmap */
+ if(pSrcInfo->bmiHeader.biBitCount == 32)
+ {
+ UINT32 *dibBuffer = NULL;
+
+ pDestInfo->bmiHeader.biSizeImage = get_dib_width_bytes( pDestInfo->bmiHeader.biWidth,
+ pDestInfo->bmiHeader.biBitCount ) * abs( pDestInfo->bmiHeader.biHeight );
+
+ /* If this is a 32-bpp bitmap, we need to use a dib section
+ so that the alpha channel is preserved */
+ hXorBits = CreateDIBSection(screen_dc, pDestInfo, DIB_RGB_COLORS, (void**)&dibBuffer, NULL, 0);
- if (DoStretch) {
- hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
if(hXorBits)
{
- HBITMAP hOld;
- BOOL res = FALSE;
-
- if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
- if (hdcMem) {
- hOld = SelectObject(hdcMem, hXorBits);
- res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
- bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight/2,
- (char*)bmi + size, pInfo, DIB_RGB_COLORS, SRCCOPY);
- SelectObject(hdcMem, hOld);
+ if(DoStretch)
+ {
+ if(pSrcInfo->bmiHeader.biBitCount == 32)
+ {
+ /* FIXME: StretchDIBits currently draws via X11, which does
+ * not preserve the alpha channel.
+ */
+ FIXME("StretchDIBits will not preserve the alpha channel.\n");
+ }
+
+ if (!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
+ {
+ DeleteObject(hXorBits);
+ hXorBits = 0;
+ }
+ }
+ else
+ {
+ if(dibBuffer)
+ memcpy(dibBuffer, (char*)bmi + size, pDestInfo->bmiHeader.biSizeImage);
+ else
+ {
+ DeleteObject(hXorBits);
+ hXorBits = 0;
+ ERR("dibBuffer should not have been NULL");
+ }
+ }
}
- if (!res) { DeleteObject(hXorBits); hXorBits = 0; }
- }
- } else {
- if (is_dib_monochrome(bmi)) {
- hXorBits = CreateBitmap(width, height, 1, 1, NULL);
- SetDIBits(screen_dc, hXorBits, 0, height,
- (char*)bmi + size, pInfo, DIB_RGB_COLORS);
- }
- else
- hXorBits = CreateDIBitmap(screen_dc, &pInfo->bmiHeader,
- CBM_INIT, (char*)bmi + size, pInfo, DIB_RGB_COLORS);
+ }
+ else
+ {
+ if(DoStretch)
+ {
+ hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
+
+ if (!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
+ {
+ DeleteObject(hXorBits);
+ hXorBits = 0;
+ }
+ }
+ else
+ hXorBits = CreateDIBitmap(screen_dc, &pSrcInfo->bmiHeader,
+ CBM_INIT, (char*)bmi + size, pSrcInfo, DIB_RGB_COLORS);
}
if( hXorBits )
@@ -761,19 +831,19 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
get_dib_width_bytes( bmi->bmiHeader.biWidth,
bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
- pInfo->bmiHeader.biBitCount = 1;
- if (pInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
+ pSrcInfo->bmiHeader.biBitCount = 1;
+ if (pSrcInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
{
- RGBQUAD *rgb = pInfo->bmiColors;
+ RGBQUAD *rgb = pSrcInfo->bmiColors;
- pInfo->bmiHeader.biClrUsed = pInfo->bmiHeader.biClrImportant = 2;
+ pSrcInfo->bmiHeader.biClrUsed = pSrcInfo->bmiHeader.biClrImportant = 2;
rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
}
else
{
- RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pInfo) + 1);
+ RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pSrcInfo) + 1);
rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
@@ -783,29 +853,24 @@ static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
if (DoStretch) {
if ((hAndBits = CreateBitmap(width, height, 1, 1, NULL))) {
- HBITMAP hOld;
- BOOL res = FALSE;
-
- if (!hdcMem) hdcMem = CreateCompatibleDC(screen_dc);
- if (hdcMem) {
- hOld = SelectObject(hdcMem, hAndBits);
- res = StretchDIBits(hdcMem, 0, 0, width, height, 0, 0,
- pInfo->bmiHeader.biWidth, pInfo->bmiHeader.biHeight,
- xbits, pInfo, DIB_RGB_COLORS, SRCCOPY);
- SelectObject(hdcMem, hOld);
+ if (!stretch_blt_icon(hAndBits, pDestInfo, pSrcInfo, xbits))
+ {
+ DeleteObject(hAndBits);
+ hAndBits = 0;
}
- if (!res) { DeleteObject(hAndBits); hAndBits = 0; }
}
} else {
hAndBits = CreateBitmap(width, height, 1, 1, NULL);
if (hAndBits) SetDIBits(screen_dc, hAndBits, 0, height,
- xbits, pInfo, DIB_RGB_COLORS);
+ xbits, pSrcInfo, DIB_RGB_COLORS);
}
if( !hAndBits ) DeleteObject( hXorBits );
}
- HeapFree( GetProcessHeap(), 0, pInfo );
+
+ HeapFree( GetProcessHeap(), 0, pSrcInfo );
+ HeapFree( GetProcessHeap(), 0, pDestInfo );
}
}
--
1.6.0.4
--=-Zb7gDoDE7W/3Atnx1zNj--
More information about the wine-patches
mailing list