- rewrite UserDrawIconEx, taken from yarotows, with same small modifications.
Fixes a whole bunch of user32:cursoricon tests


svn path=/trunk/; revision=48123
This commit is contained in:
Jérôme Gardou 2010-07-19 22:41:35 +00:00
parent 76d0b0da01
commit de85efc5ed

View file

@ -1181,6 +1181,7 @@ NtUserSetSystemCursor(
return FALSE; return FALSE;
} }
/* Mostly inspired from wine code */
BOOL BOOL
UserDrawIconEx( UserDrawIconEx(
HDC hDc, HDC hDc,
@ -1195,19 +1196,16 @@ UserDrawIconEx(
{ {
BOOL Ret = FALSE; BOOL Ret = FALSE;
HBITMAP hbmMask, hbmColor; HBITMAP hbmMask, hbmColor;
BITMAP bmpMask, bmpColor; BITMAP bmpColor, bm;
BOOL DoFlickerFree; BOOL DoFlickerFree;
SIZE IconSize; INT iOldBkColor = 0, iOldTxtColor = 0;
HDC hdcOff; HDC hMemDC, hDestDC = hDc;
HGDIOBJ hOldOffBrush = 0; HGDIOBJ hOldOffBrush = 0;
HGDIOBJ hOldOffBmp = 0; HGDIOBJ hOldOffBmp = 0;
HBITMAP hbmOff = 0; HBITMAP hTmpBmp = 0, hOffBmp = 0;
HDC hdcMask = 0;
HGDIOBJ hOldMask = NULL;
HDC hdcImage = 0;
HGDIOBJ hOldImage = NULL;
BOOL bAlpha = FALSE; BOOL bAlpha = FALSE;
INT x=xLeft, y=yTop;
hbmMask = pIcon->IconInfo.hbmMask; hbmMask = pIcon->IconInfo.hbmMask;
hbmColor = pIcon->IconInfo.hbmColor; hbmColor = pIcon->IconInfo.hbmColor;
@ -1215,7 +1213,7 @@ UserDrawIconEx(
if (istepIfAniCur) if (istepIfAniCur)
DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n"); DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask)) if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bm))
{ {
return FALSE; return FALSE;
} }
@ -1225,38 +1223,34 @@ UserDrawIconEx(
return FALSE; return FALSE;
} }
if (hbmColor) if(!(hMemDC = NtGdiCreateCompatibleDC(hDc)))
{ {
IconSize.cx = bmpColor.bmWidth; DPRINT1("NtGdiCreateCompatibleDC failed!\n");
IconSize.cy = bmpColor.bmHeight; return FALSE;
}
else
{
IconSize.cx = bmpMask.bmWidth;
IconSize.cy = bmpMask.bmHeight / 2;
} }
/* NtGdiCreateCompatibleBitmap will create a monochrome bitmap /* Check for alpha */
when cxWidth or cyHeight is 0 */ if (hbmColor
if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0)) && (bmpColor.bmBitsPixel == 32)
&& (diFlags & DI_IMAGE))
{ {
SURFACE *psurfOff = NULL; SURFACE *psurfOff = NULL;
PFN_DIB_GetPixel fnSource_GetPixel = NULL; PFN_DIB_GetPixel fnSource_GetPixel = NULL;
INT x, y; INT i, j;
/* In order to correctly display 32 bit icons Windows first scans the image, /* In order to correctly display 32 bit icons Windows first scans the image,
because information about transparency is not stored in any image's headers */ because information about transparency is not stored in any image's headers */
psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask); psurfOff = SURFACE_LockSurface(hbmColor);
if (psurfOff) if (psurfOff)
{ {
fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel; fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
if (fnSource_GetPixel) if (fnSource_GetPixel)
{ {
for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++) for (i = 0; i < psurfOff->SurfObj.sizlBitmap.cx; i++)
{ {
for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++) for (j = 0; j < psurfOff->SurfObj.sizlBitmap.cy; j++)
{ {
bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff); bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, i, j) >> 24) & 0xff);
if (bAlpha) if (bAlpha)
break; break;
} }
@ -1268,172 +1262,86 @@ UserDrawIconEx(
} }
} }
if (!diFlags)
diFlags = DI_NORMAL;
if (!cxWidth) if (!cxWidth)
cxWidth = ((diFlags & DI_DEFAULTSIZE) ? cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
UserGetSystemMetrics(SM_CXICON) : IconSize.cx); UserGetSystemMetrics(SM_CXICON) : pIcon->Size.cx);
if (!cyHeight) if (!cyHeight)
cyHeight = ((diFlags & DI_DEFAULTSIZE) ? cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
UserGetSystemMetrics(SM_CYICON) : IconSize.cy); UserGetSystemMetrics(SM_CYICON) : pIcon->Size.cy);
DoFlickerFree = (hbrFlickerFreeDraw && DoFlickerFree = (hbrFlickerFreeDraw &&
(GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH)); (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
if (DoFlickerFree || bAlpha) if (DoFlickerFree)
{ {
RECTL r; hDestDC = NtGdiCreateCompatibleDC(hDc);
BITMAP bm; if(!hDestDC)
SURFACE *psurfOff = NULL;
r.right = cxWidth;
r.bottom = cyHeight;
hdcOff = NtGdiCreateCompatibleDC(hDc);
if (!hdcOff)
{ {
DPRINT1("NtGdiCreateCompatibleDC() failed!\n"); DPRINT1("NtGdiCreateCompatibleDC failed!\n");
return FALSE; Ret = FALSE;
goto Cleanup ;
} }
hOffBmp = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight); if(!hOffBmp)
if (!hbmOff)
{ {
DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n"); DPRINT1("NtGdiCreateCompatibleBitmap failed!\n");
goto cleanup; goto Cleanup ;
}
/* make sure we have a 32 bit offscreen bitmap
otherwise we can't do alpha blending */
psurfOff = SURFACE_LockSurface(hbmOff);
if (psurfOff == NULL)
{
DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
goto cleanup;
}
BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
if (bm.bmBitsPixel != 32)
bAlpha = FALSE;
SURFACE_UnlockSurface(psurfOff);
hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
if (!hOldOffBmp)
{
DPRINT1("NtGdiSelectBitmap() failed!\n");
goto cleanup;
}
if (DoFlickerFree)
{
hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
if (!hOldOffBrush)
{
DPRINT1("NtGdiSelectBrush() failed!\n");
goto cleanup;
}
NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
}
}
else
hdcOff = hDc;
if (diFlags & DI_IMAGE)
{
hdcImage = NtGdiCreateCompatibleDC(hDc);
if (!hdcImage)
{
DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
goto cleanup;
}
hOldImage = NtGdiSelectBitmap(hdcImage, (hbmColor ? hbmColor : hbmMask));
if (!hOldImage)
{
DPRINT("NtGdiSelectBitmap() failed!\n");
goto cleanup;
} }
hOldOffBmp = NtGdiSelectBitmap(hDestDC, hOffBmp);
hOldOffBrush = NtGdiSelectBrush(hDestDC, hbrFlickerFreeDraw);
NtGdiPatBlt(hDestDC, 0, 0, cxWidth, cyHeight, PATCOPY);
NtGdiSelectBrush(hDestDC, hOldOffBrush);
x=y=0;
} }
/* If DI_IMAGE flag is specified and hbmMask exists, then always use mask for drawing */ /* Set Background/foreground colors */
if (diFlags & DI_MASK || (diFlags & DI_IMAGE && hbmMask)) iOldTxtColor = IntGdiSetTextColor(hDc, 0); //black
{ iOldBkColor = IntGdiSetBkColor(hDc, 0x00FFFFFF); //white
hdcMask = NtGdiCreateCompatibleDC(hDc);
if (!hdcMask)
{
DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
goto cleanup;
}
hOldMask = NtGdiSelectBitmap(hdcMask, hbmMask); if(bAlpha && (diFlags & DI_IMAGE))
if (!hOldMask) {
{ BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
DPRINT("NtGdiSelectBitmap() failed!\n");
goto cleanup;
}
}
if (hdcMask || hdcImage)
{
GreStretchBltMask(hdcOff,
(DoFlickerFree || bAlpha) ? 0 : xLeft,
(DoFlickerFree || bAlpha) ? 0 : yTop,
cxWidth,
cyHeight,
hdcImage ? hdcImage : hdcMask,
0,
0,
IconSize.cx,
IconSize.cy,
SRCCOPY,
0,
hdcMask,
0,
hdcImage ? 0 : IconSize.cy);
}
if (hOldMask) NtGdiSelectBitmap(hdcMask, hOldMask);
if (hOldImage) NtGdiSelectBitmap(hdcImage, hOldImage);
if (hdcImage) NtGdiDeleteObjectApp(hdcImage);
if (hdcMask) NtGdiDeleteObjectApp(hdcMask);
if (bAlpha)
{
BITMAP bm;
SURFACE *psurfOff = NULL;
PBYTE pBits = NULL;
BLENDFUNCTION BlendFunc;
DWORD Pixel; DWORD Pixel;
BYTE Red, Green, Blue, Alpha; BYTE Red, Green, Blue, Alpha;
DWORD Count = 0; DWORD Count = 0;
INT i, j; INT i, j;
PSURFACE psurf;
PBYTE pBits ;
HBITMAP hMemBmp = NULL;
psurfOff = SURFACE_LockSurface(hbmOff); pBits = ExAllocatePoolWithTag(PagedPool,
if (psurfOff == NULL) bmpColor.bmWidthBytes * abs(bmpColor.bmHeight),
{ TAG_BITMAP);
DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
goto cleanup;
}
BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
if (pBits == NULL) if (pBits == NULL)
{ {
DPRINT1("ExAllocatePoolWithTag() failed!\n"); Ret = FALSE;
SURFACE_UnlockSurface(psurfOff); goto CleanupAlpha;
goto cleanup;
} }
/* get icon bits */ hMemBmp = BITMAP_CopyBitmap(hbmColor);
IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits); if(!hMemBmp)
{
DPRINT1("BITMAP_CopyBitmap failed!");
goto CleanupAlpha;
}
psurf = SURFACE_LockSurface(hMemBmp);
if(!psurf)
{
DPRINT1("SURFACE_LockSurface failed!\n");
goto CleanupAlpha;
}
/* get color bits */
IntGetBitmapBits(psurf,
bmpColor.bmWidthBytes * abs(bmpColor.bmHeight),
pBits);
/* premultiply with the alpha channel value */ /* premultiply with the alpha channel value */
for (i = 0; i < cyHeight; i++) for (i = 0; i < abs(bmpColor.bmHeight); i++)
{ {
for (j = 0; j < cxWidth; j++) Count = i*bmpColor.bmWidthBytes;
for (j = 0; j < bmpColor.bmWidth; j++)
{ {
Pixel = *(DWORD *)(pBits + Count); Pixel = *(DWORD *)(pBits + Count);
@ -1449,35 +1357,112 @@ UserDrawIconEx(
} }
} }
/* set icon bits */ /* set mem bits */
IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits); IntSetBitmapBits(psurf,
ExFreePoolWithTag(pBits, TAG_BITMAP); bmpColor.bmWidthBytes * abs(bmpColor.bmHeight),
pBits);
SURFACE_UnlockSurface(psurf);
SURFACE_UnlockSurface(psurfOff); hTmpBmp = NtGdiSelectBitmap(hMemDC, hMemBmp);
BlendFunc.BlendOp = AC_SRC_OVER; Ret = NtGdiAlphaBlend(hDestDC,
BlendFunc.BlendFlags = 0; x,
BlendFunc.SourceConstantAlpha = 255; y,
BlendFunc.AlphaFormat = AC_SRC_ALPHA; cxWidth,
cyHeight,
NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight, hMemDC,
hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0); 0,
} 0,
else if (DoFlickerFree) pIcon->Size.cx,
{ pIcon->Size.cy,
NtGdiBitBlt(hDc, xLeft, yTop, cxWidth, pixelblend,
cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0); NULL);
NtGdiSelectBitmap(hMemDC, hTmpBmp);
CleanupAlpha:
if(pBits) ExFreePoolWithTag(pBits, TAG_BITMAP);
if(hMemBmp) NtGdiDeleteObjectApp(hMemBmp);
if(Ret) goto done;
} }
Ret = TRUE;
cleanup: if (diFlags & DI_MASK)
if (DoFlickerFree || bAlpha)
{ {
if (hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp); hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
if (hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush); NtGdiStretchBlt(hDestDC,
if (hbmOff) GreDeleteObject(hbmOff); x,
if (hdcOff) NtGdiDeleteObjectApp(hdcOff); y,
cxWidth,
cyHeight,
hMemDC,
0,
0,
pIcon->Size.cx,
pIcon->Size.cy,
SRCAND,
0);
NtGdiSelectBitmap(hMemDC, hTmpBmp);
}
if(diFlags & DI_IMAGE)
{
if (hbmColor)
{
DWORD rop = (diFlags & DI_MASK) ? SRCINVERT : SRCCOPY ;
hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmColor);
NtGdiStretchBlt(hDestDC,
x,
y,
cxWidth,
cyHeight,
hMemDC,
0,
0,
pIcon->Size.cx,
pIcon->Size.cy,
rop,
0);
NtGdiSelectBitmap(hMemDC, hTmpBmp);
}
else
{
/* Mask bitmap holds the information in its second half */
DWORD rop = (diFlags & DI_MASK) ? SRCINVERT : SRCCOPY ;
hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
NtGdiStretchBlt(hDestDC,
x,
y,
cxWidth,
cyHeight,
hMemDC,
0,
pIcon->Size.cy,
pIcon->Size.cx,
pIcon->Size.cy,
rop,
0);
NtGdiSelectBitmap(hMemDC, hTmpBmp);
}
}
done:
if(hDestDC != hDc)
{
NtGdiBitBlt(hDc, xLeft, yTop, cxWidth, cyHeight, hDestDC, 0, 0, SRCCOPY, 0, 0);
}
/* Restore foreground and background colors */
IntGdiSetBkColor(hDc, iOldBkColor);
IntGdiSetTextColor(hDc, iOldTxtColor);
Ret = TRUE ;
Cleanup:
NtGdiDeleteObjectApp(hMemDC);
if(hDestDC != hDc)
{
if(hOldOffBmp) NtGdiSelectBitmap(hDestDC, hOldOffBmp);
NtGdiDeleteObjectApp(hDestDC);
if(hOffBmp) NtGdiDeleteObjectApp(hOffBmp);
} }
return Ret; return Ret;