Author: jgardou
Date: Thu Oct 18 18:27:44 2012
New Revision: 57573
URL:
http://svn.reactos.org/svn/reactos?rev=57573&view=rev
Log:
[WIN32K]
- Use low level functions (IntEng*) to draw an icon.
Now mode settings change (eg. 16->32bpp) is not so ugly.
Modified:
trunk/reactos/win32ss/user/ntuser/cursoricon.c
Modified: trunk/reactos/win32ss/user/ntuser/cursoricon.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/win32ss/user/ntuser/cursor…
==============================================================================
--- trunk/reactos/win32ss/user/ntuser/cursoricon.c [iso-8859-1] (original)
+++ trunk/reactos/win32ss/user/ntuser/cursoricon.c [iso-8859-1] Thu Oct 18 18:27:44 2012
@@ -1042,7 +1042,14 @@
}
#endif
-/* Mostly inspired from wine code */
+/* Mostly inspired from wine code.
+ * We use low level functions because:
+ * - at this point, the icon bitmap could have a different bit depth than the DC,
+ * making it thus impossible to use NtCreateCompatibleDC and selecting the bitmap.
+ * This happens after a mode setting change.
+ * - it avoids massive GDI objects locking when only the destination surface needs it.
+ * - It makes (small) performance gains.
+ */
BOOL
UserDrawIconEx(
HDC hDc,
@@ -1055,128 +1062,220 @@
HBRUSH hbrFlickerFreeDraw,
UINT diFlags)
{
+ PSURFACE psurfDest, psurfMask, psurfColor, psurfOffScreen;
+ PDC pdc = NULL;
BOOL Ret = FALSE;
HBITMAP hbmMask, hbmColor;
- BITMAP bmpColor, bm;
- BOOL DoFlickerFree;
- INT iOldBkColor = 0, iOldTxtColor = 0;
-
- HDC hMemDC, hDestDC = hDc;
- HGDIOBJ hOldOffBrush = 0;
- HGDIOBJ hOldOffBmp = 0;
- HBITMAP hTmpBmp = 0, hOffBmp = 0;
- BOOL bAlpha = FALSE;
- INT x=xLeft, y=yTop;
+ BOOL bOffScreen, bAlpha = FALSE;
+ RECTL rcDest, rcSrc;
+ CLIPOBJ* pdcClipObj = NULL;
+ EXLATEOBJ exlo;
+
+ /* Stupid case */
+ if((diFlags & DI_NORMAL) == 0)
+ {
+ ERR("DrawIconEx called without mask or color bitmap to draw.\n");
+ return FALSE;
+ }
hbmMask = pIcon->IconInfo.hbmMask;
hbmColor = pIcon->IconInfo.hbmColor;
-
+
if (istepIfAniCur)
ERR("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
-
- if (!hbmMask || !GreGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bm))
- {
+
+ /*
+ * Get our objects.
+ * Shared locks are enough, we are only reading those bitmaps
+ */
+ psurfMask = SURFACE_ShareLockSurface(hbmMask);
+ if(psurfMask == NULL)
+ {
+ ERR("Unable to lock the mask surface.\n");
return FALSE;
}
-
- if (hbmColor && !GreGetObject(hbmColor, sizeof(BITMAP),
(PVOID)&bmpColor))
- {
+
+ /* Color bitmap is not mandatory */
+ if(hbmColor == NULL)
+ {
+ /* But then the mask bitmap must have the information in it's bottom half */
+ ASSERT(psurfMask->SurfObj.sizlBitmap.cy == 2*pIcon->Size.cy);
+ psurfColor = NULL;
+ }
+ else if ((psurfColor = SURFACE_ShareLockSurface(hbmColor)) == NULL)
+ {
+ ERR("Unable to lock the color bitmap.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
return FALSE;
}
-
- if(!(hMemDC = NtGdiCreateCompatibleDC(hDc)))
- {
- ERR("NtGdiCreateCompatibleDC failed!\n");
- return FALSE;
- }
+
+ /* Set source rect */
+ RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
/* Check for alpha */
- if (hbmColor
- && (bmpColor.bmBitsPixel == 32)
- && (diFlags & DI_IMAGE))
- {
- SURFACE *psurfOff = NULL;
+ if (psurfColor &&
+ (psurfColor->SurfObj.iBitmapFormat == BMF_32BPP) &&
+ (diFlags & DI_IMAGE))
+ {
PFN_DIB_GetPixel fnSource_GetPixel = NULL;
INT i, j;
/* 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 */
- psurfOff = SURFACE_ShareLockSurface(hbmColor);
- if (psurfOff)
- {
- fnSource_GetPixel =
DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
- if (fnSource_GetPixel)
+ fnSource_GetPixel = DibFunctionsForBitmapFormat[BMF_32BPP].DIB_GetPixel;
+ for (i = 0; i < psurfColor->SurfObj.sizlBitmap.cx; i++)
+ {
+ for (j = 0; j < psurfColor->SurfObj.sizlBitmap.cy; j++)
{
- for (i = 0; i < psurfOff->SurfObj.sizlBitmap.cx; i++)
- {
- for (j = 0; j < psurfOff->SurfObj.sizlBitmap.cy; j++)
- {
- bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, i,
j) >> 24) & 0xff);
- if (bAlpha)
- break;
- }
- if (bAlpha)
- break;
- }
+ bAlpha = ((BYTE)(fnSource_GetPixel(&psurfColor->SurfObj, i, j)
>> 24) & 0xff);
+ if (bAlpha)
+ break;
}
- SURFACE_ShareUnlockSurface(psurfOff);
- }
- }
-
+ if (bAlpha)
+ break;
+ }
+ }
+
+ /* Fix width parameter, if needed */
if (!cxWidth)
- cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
- UserGetSystemMetrics(SM_CXICON) : pIcon->Size.cx);
-
+ {
+ if(diFlags & DI_DEFAULTSIZE)
+ cxWidth = pIcon->IconInfo.fIcon ?
+ UserGetSystemMetrics(SM_CXICON) : UserGetSystemMetrics(SM_CXCURSOR);
+ else
+ cxWidth = pIcon->Size.cx;
+ }
+
+ /* Fix height parameter, if needed */
if (!cyHeight)
- cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
- UserGetSystemMetrics(SM_CYICON) : pIcon->Size.cy);
-
- DoFlickerFree = (hbrFlickerFreeDraw &&
- (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) ==
GDI_OBJECT_TYPE_BRUSH));
-
- if (DoFlickerFree)
- {
- hDestDC = NtGdiCreateCompatibleDC(hDc);
- if(!hDestDC)
- {
- ERR("NtGdiCreateCompatibleDC failed!\n");
- Ret = FALSE;
- goto Cleanup ;
- }
- hOffBmp = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
- if(!hOffBmp)
- {
- ERR("NtGdiCreateCompatibleBitmap 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;
- }
-
- /* Set Background/foreground colors */
- iOldTxtColor = IntGdiSetTextColor(hDc, 0); // Black
- iOldBkColor = IntGdiSetBkColor(hDc, 0x00FFFFFF); // White
-
+ {
+ if(diFlags & DI_DEFAULTSIZE)
+ cyHeight = pIcon->IconInfo.fIcon ?
+ UserGetSystemMetrics(SM_CYICON) : UserGetSystemMetrics(SM_CYCURSOR);
+ else
+ cyHeight = pIcon->Size.cy;
+ }
+
+ /* Should we render off-screen? */
+ bOffScreen = hbrFlickerFreeDraw && (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw)
== GDI_OBJECT_TYPE_BRUSH);
+
+ if (bOffScreen)
+ {
+ /* Yes: Allocate and paint the offscreen surface */
+ EBRUSHOBJ eboFill;
+ PBRUSH pbrush = BRUSH_ShareLockBrush(hbrFlickerFreeDraw);
+
+ TRACE("Performing off-screen rendering.\n");
+
+ if(!pbrush)
+ {
+ ERR("Failed to get brush object.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+
+ psurfOffScreen = SURFACE_AllocSurface(STYPE_BITMAP,
+ cxWidth, cyHeight, psurfColor->SurfObj.iBitmapFormat,
+ 0, 0, NULL);
+ if(!psurfOffScreen)
+ {
+ ERR("Failed to allocate the off-screen surface.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ BRUSH_ShareUnlockBrush(pbrush);
+ return FALSE;
+ }
+
+ /* Paint the brush */
+ EBRUSHOBJ_vInit(&eboFill, pbrush, psurfOffScreen, 0x00FFFFFF, 0, NULL);
+ RECTL_vSetRect(&rcDest, 0, 0, cxWidth, cyHeight);
+
+ Ret = IntEngBitBlt(&psurfOffScreen->SurfObj,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &rcDest,
+ NULL,
+ NULL,
+ &eboFill.BrushObject,
+ &pbrush->ptOrigin,
+ ROP4_PATCOPY);
+
+ /* Clean up everything */
+ EBRUSHOBJ_vCleanup(&eboFill);
+ BRUSH_ShareUnlockBrush(pbrush);
+
+ if(!Ret)
+ {
+ ERR("Failed to paint the off-screen surface.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
+ return FALSE;
+ }
+
+ /* We now have our destination surface */
+ psurfDest = psurfOffScreen;
+ }
+ else
+ {
+ /* We directly draw to the DC */
+ TRACE("Performing on screen rendering.\n");
+
+ psurfOffScreen = NULL;
+ pdc = DC_LockDc(hDc);
+ if(!pdc)
+ {
+ ERR("Could not lock the destination DC.\n");
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+ /* Calculate destination rectangle */
+ RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
+ IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
+ RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+
+ /* Prepare the underlying surface */
+ DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
+
+ /* Get the clip object */
+ pdcClipObj = pdc->rosdc.CombinedClip;
+
+ /* We now have our destination surface and rectangle */
+ psurfDest = pdc->dclevel.pSurface;
+
+ if(psurfDest == NULL)
+ {
+ /* Empty DC */
+ DC_vFinishBlit(pdc, NULL);
+ DC_UnlockDc(pdc);
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
+ return FALSE;
+ }
+ }
+
+ /* Now do the rendering */
if(bAlpha && (diFlags & DI_IMAGE))
{
- BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ BLENDOBJ blendobj = { {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA } };
BYTE Alpha;
INT i, j;
- PSURFACE psurf;
+ PSURFACE psurf = NULL;
PBYTE ptr ;
- HBITMAP hMemBmp = NULL;
-
- hMemBmp = BITMAP_CopyBitmap(hbmColor);
- if(!hMemBmp)
+ HBITMAP hsurfCopy = NULL;
+
+ hsurfCopy = BITMAP_CopyBitmap(hbmColor);
+ if(!hsurfCopy)
{
ERR("BITMAP_CopyBitmap failed!");
goto CleanupAlpha;
}
- psurf = SURFACE_ShareLockSurface(hMemBmp);
+ psurf = SURFACE_ShareLockSurface(hsurfCopy);
if(!psurf)
{
ERR("SURFACE_LockSurface failed!\n");
@@ -1197,109 +1296,181 @@
ptr += 4;
}
}
-
- SURFACE_ShareUnlockSurface(psurf);
-
- hTmpBmp = NtGdiSelectBitmap(hMemDC, hMemBmp);
-
- Ret = NtGdiAlphaBlend(hDestDC,
- x,
- y,
- cxWidth,
- cyHeight,
- hMemDC,
- 0,
- 0,
- pIcon->Size.cx,
- pIcon->Size.cy,
- pixelblend,
- NULL);
- NtGdiSelectBitmap(hMemDC, hTmpBmp);
+
+ /* Initialize color translation object */
+ EXLATEOBJ_vInitialize(&exlo, psurf->ppal, psurfDest->ppal, 0xFFFFFFFF,
0xFFFFFFFF, 0);
+
+ /* Now do it */
+ Ret = IntEngAlphaBlend(&psurfDest->SurfObj,
+ &psurf->SurfObj,
+ pdcClipObj,
+ &exlo.xlo,
+ &rcDest,
+ &rcSrc,
+ &blendobj);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
CleanupAlpha:
- if(hMemBmp) NtGdiDeleteObjectApp(hMemBmp);
+ if(psurf) SURFACE_ShareUnlockSurface(psurf);
+ if(hsurfCopy) NtGdiDeleteObjectApp(hsurfCopy);
if(Ret) goto done;
+ ERR("NtGdiAlphaBlend failed!\n");
}
if (diFlags & DI_MASK)
{
- DWORD rop = (diFlags & DI_IMAGE) ? SRCAND : SRCCOPY;
- hTmpBmp = NtGdiSelectBitmap(hMemDC, hbmMask);
- NtGdiStretchBlt(hDestDC,
- x,
- y,
- cxWidth,
- cyHeight,
- hMemDC,
- 0,
- 0,
- pIcon->Size.cx,
- pIcon->Size.cy,
- rop,
- 0);
- NtGdiSelectBitmap(hMemDC, hTmpBmp);
+ DWORD rop4 = (diFlags & DI_IMAGE) ? ROP4_SRCAND : ROP4_SRCCOPY;
+
+ EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
+
+ Ret = IntEngStretchBlt(&psurfDest->SurfObj,
+ &psurfMask->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ NULL,
+ &rcDest,
+ &rcSrc,
+ NULL,
+ NULL,
+ NULL,
+ rop4);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+ if(!Ret)
+ {
+ ERR("Failed to mask the bitmap data.\n");
+ goto Cleanup;
+ }
}
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);
+ if (psurfColor)
+ {
+ DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY ;
+
+ EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, psurfDest->ppal,
0x00FFFFFF, 0x00FFFFFF, 0);
+
+ Ret = IntEngStretchBlt(&psurfDest->SurfObj,
+ &psurfColor->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ NULL,
+ &rcDest,
+ &rcSrc,
+ NULL,
+ NULL,
+ NULL,
+ rop4);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+ if(!Ret)
+ {
+ ERR("Failed to render the icon bitmap.\n");
+ goto Cleanup;
+ }
}
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);
+ /* Mask bitmap holds the information in its bottom half */
+ DWORD rop4 = (diFlags & DI_MASK) ? ROP4_SRCINVERT : ROP4_SRCCOPY;
+ RECTL_vOffsetRect(&rcSrc, 0, pIcon->Size.cy);
+
+ EXLATEOBJ_vInitSrcMonoXlate(&exlo, psurfDest->ppal, 0x00FFFFFF, 0);
+
+ Ret = IntEngStretchBlt(&psurfDest->SurfObj,
+ &psurfMask->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ NULL,
+ &rcDest,
+ &rcSrc,
+ NULL,
+ NULL,
+ NULL,
+ rop4);
+
+ EXLATEOBJ_vCleanup(&exlo);
+
+ if(!Ret)
+ {
+ ERR("Failed to render the icon bitmap.\n");
+ goto Cleanup;
+ }
}
}
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 ;
-
+ /* We're done. Was it a double buffered draw ? */
+ if(bOffScreen)
+ {
+ /* Yes. Draw it back to our DC */
+ POINTL ptSrc = {0, 0};
+ pdc = DC_LockDc(hDc);
+ if(!pdc)
+ {
+ ERR("Could not lock the destination DC.\n");
+ return FALSE;
+ }
+ /* Calculate destination rectangle */
+ RECTL_vSetRect(&rcDest, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
+ IntLPtoDP(pdc, (LPPOINT)&rcDest, 2);
+ RECTL_vOffsetRect(&rcDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+
+ /* Prepare the underlying surface */
+ DC_vPrepareDCsForBlit(pdc, rcDest, NULL, rcDest);
+
+ /* Get the clip object */
+ pdcClipObj = pdc->rosdc.CombinedClip;
+
+ /* We now have our destination surface and rectangle */
+ psurfDest = pdc->dclevel.pSurface;
+ if(!psurfDest)
+ {
+ /* So, you did all of this for an empty DC. */
+ DC_UnlockDc(pdc);
+ goto Cleanup2;
+ }
+
+ /* Color translation */
+ EXLATEOBJ_vInitialize(&exlo, psurfOffScreen->ppal, psurfDest->ppal,
0x00FFFFFF, 0x00FFFFFF, 0);
+
+ /* Blt it! */
+ Ret = IntEngBitBlt(&psurfDest->SurfObj,
+ &psurfOffScreen->SurfObj,
+ NULL,
+ pdcClipObj,
+ &exlo.xlo,
+ &rcDest,
+ &ptSrc,
+ NULL,
+ NULL,
+ NULL,
+ ROP4_SRCCOPY);
+
+ EXLATEOBJ_vCleanup(&exlo);
+ }
Cleanup:
- NtGdiDeleteObjectApp(hMemDC);
- if(hDestDC != hDc)
- {
- if(hOldOffBmp) NtGdiSelectBitmap(hDestDC, hOldOffBmp);
- NtGdiDeleteObjectApp(hDestDC);
- if(hOffBmp) NtGdiDeleteObjectApp(hOffBmp);
- }
+ if(pdc)
+ {
+ DC_vFinishBlit(pdc, NULL);
+ DC_UnlockDc(pdc);
+ }
+
+Cleanup2:
+ /* Delete off screen rendering surface */
+ if(psurfOffScreen)
+ GDIOBJ_vDeleteObject(&psurfOffScreen->BaseObject);
+
+ /* Unlock other surfaces */
+ SURFACE_ShareUnlockSurface(psurfMask);
+ if(psurfColor) SURFACE_ShareUnlockSurface(psurfColor);
return Ret;
}