user32: Use the stored color and mask bitmaps instead of the raw bits in DrawIconEx.

This commit is contained in:
Alexandre Julliard 2010-05-20 14:26:58 +02:00
parent bb33cebe3f
commit 072d0b3483
1 changed files with 56 additions and 184 deletions

View File

@ -1807,74 +1807,6 @@ BOOL WINAPI DestroyCursor( HCURSOR hCursor )
return DestroyIcon( hCursor );
}
/***********************************************************************
* 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;
}
}
}
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.@)
*/
@ -2357,12 +2289,11 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
HBRUSH hbr, UINT flags )
{
struct cursoricon_object *ptr;
HDC hDC_off = 0, hMemDC;
HDC hdc_dest, hMemDC;
BOOL result = FALSE, DoOffscreen;
HBITMAP hB_off = 0, hOld = 0;
unsigned char *xorBitmapBits;
unsigned int xorLength;
BOOL has_alpha = FALSE;
HBITMAP hB_off = 0;
COLORREF oldFg, oldBg;
INT x, y, nStretchMode;
TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
@ -2379,15 +2310,6 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
if (flags & DI_NOMIRROR)
FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
xorLength = ptr->data.nHeight * get_bitmap_width_bytes(
ptr->data.nWidth, ptr->data.bBitsPerPixel);
xorBitmapBits = (unsigned char *)(ptr + 1) + ptr->data.nHeight *
get_bitmap_width_bytes(ptr->data.nWidth, 1);
if (flags & DI_IMAGE)
has_alpha = bitmap_has_alpha_channel(
ptr->data.bBitsPerPixel, xorBitmapBits, xorLength);
/* Calculate the size of the destination image. */
if (cxWidth == 0)
{
@ -2414,121 +2336,71 @@ BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
r.right = cxWidth;
r.bottom = cxWidth;
hDC_off = CreateCompatibleDC(hdc);
hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth);
if (hDC_off && hB_off) {
hOld = SelectObject(hDC_off, hB_off);
FillRect(hDC_off, &r, hbr);
}
}
if (hMemDC && (!DoOffscreen || (hDC_off && hB_off)))
if (!(hdc_dest = CreateCompatibleDC(hdc))) goto done;
if (!(hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth)))
{
HBITMAP hBitTemp;
HBITMAP hXorBits = NULL, hAndBits = NULL;
COLORREF oldFg, oldBg;
INT nStretchMode;
DeleteDC( hdc_dest );
goto done;
}
SelectObject(hdc_dest, hB_off);
FillRect(hdc_dest, &r, hbr);
x = y = 0;
}
else
{
hdc_dest = hdc;
x = x0;
y = y0;
}
nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
oldFg = SetTextColor( hdc, RGB(0,0,0) );
oldBg = SetBkColor( hdc, RGB(255,255,255) );
if ((flags & DI_MASK) && !has_alpha)
if ((flags & DI_MASK) && (!ptr->alpha || !(flags & DI_IMAGE)))
{
hAndBits = CreateBitmap ( ptr->data.nWidth, ptr->data.nHeight, 1, 1, ptr + 1 );
if (hAndBits)
{
hBitTemp = SelectObject( hMemDC, hAndBits );
if (DoOffscreen)
StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, SRCAND);
else
StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, SRCAND);
SelectObject( hMemDC, hBitTemp );
}
SelectObject( hMemDC, ptr->mask );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, SRCAND );
}
if (flags & DI_IMAGE)
{
if (ptr->data.bPlanes * ptr->data.bBitsPerPixel == 1)
{
hXorBits = CreateBitmap( ptr->data.nWidth, ptr->data.nHeight, 1, 1, xorBitmapBits );
}
else
{
unsigned char *dibBits;
BITMAPINFO *bmi = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi->bmiHeader.biWidth = ptr->data.nWidth;
bmi->bmiHeader.biHeight = -ptr->data.nHeight;
bmi->bmiHeader.biPlanes = ptr->data.bPlanes;
bmi->bmiHeader.biBitCount = ptr->data.bBitsPerPixel;
bmi->bmiHeader.biCompression = BI_RGB;
/* FIXME: color table */
hXorBits = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, (void*)&dibBits, NULL, 0);
if (hXorBits)
{
if(has_alpha)
premultiply_alpha_channel(dibBits, xorBitmapBits, xorLength);
else
memcpy(dibBits, xorBitmapBits, xorLength);
}
}
if (hXorBits)
{
if(has_alpha)
if (ptr->alpha)
{
BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
/* Do the alpha blending render */
hBitTemp = SelectObject( hMemDC, hXorBits );
if (DoOffscreen)
GdiAlphaBlend(hDC_off, 0, 0, cxWidth, cyWidth, hMemDC,
0, 0, ptr->data.nWidth, ptr->data.nHeight, pixelblend);
else
GdiAlphaBlend(hdc, x0, y0, cxWidth, cyWidth, hMemDC,
0, 0, ptr->data.nWidth, ptr->data.nHeight, pixelblend);
SelectObject( hMemDC, hBitTemp );
SelectObject( hMemDC, ptr->alpha );
GdiAlphaBlend( hdc_dest, x, y, cxWidth, cyWidth, hMemDC,
0, 0, ptr->data.nWidth, ptr->data.nHeight, pixelblend );
}
else if (ptr->color)
{
DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
SelectObject( hMemDC, ptr->color );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, rop );
}
else
{
DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
hBitTemp = SelectObject( hMemDC, hXorBits );
if (DoOffscreen)
StretchBlt (hDC_off, 0, 0, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, rop);
else
StretchBlt (hdc, x0, y0, cxWidth, cyWidth,
hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, rop);
SelectObject( hMemDC, hBitTemp );
}
DeleteObject( hXorBits );
SelectObject( hMemDC, ptr->mask );
StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
hMemDC, 0, ptr->data.nHeight, ptr->data.nWidth, ptr->data.nHeight, rop );
}
}
result = TRUE;
if (DoOffscreen) BitBlt( hdc, x0, y0, cxWidth, cyWidth, hdc_dest, 0, 0, SRCCOPY );
SetTextColor( hdc, oldFg );
SetBkColor( hdc, oldBg );
if (hAndBits) DeleteObject( hAndBits );
SetStretchBltMode (hdc, nStretchMode);
if (DoOffscreen) {
BitBlt(hdc, x0, y0, cxWidth, cyWidth, hDC_off, 0, 0, SRCCOPY);
SelectObject(hDC_off, hOld);
}
}
if (hMemDC) DeleteDC( hMemDC );
if (hDC_off) DeleteDC(hDC_off);
result = TRUE;
if (hdc_dest != hdc) DeleteDC( hdc_dest );
if (hB_off) DeleteObject(hB_off);
done:
DeleteDC( hMemDC );
release_icon_ptr( hIcon, ptr );
return result;
}