Sync with trunk (r48545)
[reactos.git] / subsystems / win32 / win32k / ntuser / cursoricon.c
index ea60488..4b0fa99 100644 (file)
@@ -38,7 +38,7 @@
 
 #include <win32k.h>
 
-#define NDEBUG
+//#define NDEBUG
 #include <debug.h>
 
 static PAGED_LOOKASIDE_LIST gProcessLookasideList;
@@ -46,7 +46,7 @@ static LIST_ENTRY gCurIconList;
 
 SYSTEM_CURSORINFO gSysCursorInfo;
 
-BOOL FASTCALL
+BOOL
 InitCursorImpl()
 {
     ExInitializePagedLookasideList(&gProcessLookasideList,
@@ -70,7 +70,7 @@ InitCursorImpl()
     return TRUE;
 }
 
-PSYSTEM_CURSORINFO FASTCALL
+PSYSTEM_CURSORINFO
 IntGetSysCursorInfo()
 {
     return &gSysCursorInfo;
@@ -110,7 +110,7 @@ UserSetCursor(
     HCURSOR hOldCursor = (HCURSOR)0;
     HDC hdcScreen;
     BOOL bResult;
-       
+
        CurInfo = IntGetSysCursorInfo();
 
     OldCursor = CurInfo->CurrentCursorObject;
@@ -175,7 +175,7 @@ UserSetCursor(
     return hOldCursor;
 }
 
-BOOL UserSetCursorPos( INT x, INT y)
+BOOL UserSetCursorPos( INT x, INT y, BOOL SendMouseMoveMsg)
 {
     PWINDOW_OBJECT DesktopWindow;
     PSYSTEM_CURSORINFO CurInfo;
@@ -224,6 +224,9 @@ BOOL UserSetCursorPos( INT x, INT y)
     //Move the mouse pointer
     GreMovePointer(hDC, x, y);
 
+    if (!SendMouseMoveMsg)
+       return TRUE;
+
     //Generate a mouse move message
     Msg.message = WM_MOUSEMOVE;
     Msg.wParam = CurInfo->ButtonsDown;
@@ -342,7 +345,7 @@ IntFindExistingCurIconObject(HMODULE hModule,
     return NULL;
 }
 
-PCURICON_OBJECT FASTCALL
+PCURICON_OBJECT
 IntCreateCurIconHandle()
 {
     PCURICON_OBJECT CurIcon;
@@ -488,84 +491,6 @@ IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
 
 }
 
-/*
- * @implemented
- */
-HANDLE
-APIENTRY
-NtUserCreateCursorIconHandle(PICONINFO IconInfo OPTIONAL, BOOL Indirect)
-{
-    PCURICON_OBJECT CurIcon;
-    PSURFACE psurfBmp;
-    NTSTATUS Status;
-    HANDLE Ret;
-    DECLARE_RETURN(HANDLE);
-
-    DPRINT("Enter NtUserCreateCursorIconHandle\n");
-    UserEnterExclusive();
-
-    if (!(CurIcon = IntCreateCurIconHandle()))
-    {
-        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-        RETURN((HANDLE)0);
-    }
-
-    Ret = CurIcon->Self;
-
-    if (IconInfo)
-    {
-        Status = MmCopyFromCaller(&CurIcon->IconInfo, IconInfo, sizeof(ICONINFO));
-        if (NT_SUCCESS(Status))
-        {
-            /* Copy bitmaps and size info */
-            if (Indirect)
-            {
-                // FIXME: WTF?
-                CurIcon->IconInfo.hbmMask = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmMask);
-                CurIcon->IconInfo.hbmColor = BITMAP_CopyBitmap(CurIcon->IconInfo.hbmColor);
-            }
-            if (CurIcon->IconInfo.hbmColor &&
-                    (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmColor)))
-            {
-                CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-                CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy;
-                SURFACE_UnlockSurface(psurfBmp);
-                GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
-            }
-            if (CurIcon->IconInfo.hbmMask &&
-                    (psurfBmp = SURFACE_LockSurface(CurIcon->IconInfo.hbmMask)))
-            {
-                if (CurIcon->IconInfo.hbmColor == NULL)
-                {
-                    CurIcon->Size.cx = psurfBmp->SurfObj.sizlBitmap.cx;
-                    CurIcon->Size.cy = psurfBmp->SurfObj.sizlBitmap.cy >> 1;
-                }
-                SURFACE_UnlockSurface(psurfBmp);
-                GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
-            }
-
-            /* Calculate icon hotspot */
-            if (CurIcon->IconInfo.fIcon == TRUE)
-            {
-                CurIcon->IconInfo.xHotspot = CurIcon->Size.cx >> 1;
-                CurIcon->IconInfo.yHotspot = CurIcon->Size.cy >> 1;
-            }
-        }
-        else
-        {
-            SetLastNtError(Status);
-            /* FIXME - Don't exit here */
-        }
-    }
-
-    UserDereferenceObject(CurIcon);
-    RETURN(Ret);
-
-CLEANUP:
-    DPRINT("Leave NtUserCreateCursorIconHandle, ret=%i\n",_ret_);
-    UserLeave();
-    END_CLEANUP;
-}
 
 /*
  * @implemented
@@ -789,8 +714,8 @@ UserClipCursor(
 
     DesktopWindow = UserGetDesktopWindow();
 
-    if (prcl != NULL && 
-       (prcl->right > prcl->left) && 
+    if (prcl != NULL &&
+       (prcl->right > prcl->left) &&
        (prcl->bottom > prcl->top) &&
         DesktopWindow != NULL)
     {
@@ -800,7 +725,7 @@ UserClipCursor(
         CurInfo->CursorClipInfo.Right = min(prcl->right, DesktopWindow->Wnd->rcWindow.right);
         CurInfo->CursorClipInfo.Bottom = min(prcl->bottom, DesktopWindow->Wnd->rcWindow.bottom);
 
-        UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y);
+        UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, FALSE);
     }
     else
     {
@@ -1049,11 +974,13 @@ NtUserSetCursorContents(
     }
 
     /* Delete old bitmaps */
-    if (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor)
+    if ((CurIcon->IconInfo.hbmColor)
+                       && (CurIcon->IconInfo.hbmColor != IconInfo.hbmColor))
     {
         GreDeleteObject(CurIcon->IconInfo.hbmColor);
     }
-    if (CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
+    if ((CurIcon->IconInfo.hbmMask)
+                       && CurIcon->IconInfo.hbmMask != IconInfo.hbmMask)
     {
         GreDeleteObject(CurIcon->IconInfo.hbmMask);
     }
@@ -1245,6 +1172,15 @@ NtUserSetCursorIconData(
     }
 
 done:
+       if(Ret)
+       {
+               /* This icon is shared now */
+               GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmMask, NULL);
+               if(CurIcon->IconInfo.hbmColor)
+               {
+                       GDIOBJ_SetOwnership(CurIcon->IconInfo.hbmColor, NULL);
+               }
+       }
     UserDereferenceObject(CurIcon);
     RETURN(Ret);
 
@@ -1268,6 +1204,7 @@ NtUserSetSystemCursor(
     return FALSE;
 }
 
+/* Mostly inspired from wine code */
 BOOL
 UserDrawIconEx(
     HDC hDc,
@@ -1280,294 +1217,325 @@ UserDrawIconEx(
     HBRUSH hbrFlickerFreeDraw,
     UINT diFlags)
 {
-    BOOL Ret = FALSE;
-    HBITMAP hbmMask, hbmColor;
-    BITMAP bmpMask, bmpColor;
+    PSURFACE psurfColor = NULL, psurfMask, psurfDst = NULL;
+    HGDIOBJ hObjs[3];
+    PGDIOBJ pObjs[3];
     BOOL DoFlickerFree;
-    SIZE IconSize;
-
-    HDC hdcOff;
-    HGDIOBJ hOldOffBrush = 0;
-    HGDIOBJ hOldOffBmp = 0;
-    HBITMAP hbmOff = 0;
-    HDC hdcMask = 0;
-    HGDIOBJ hOldMask = NULL;
-    HDC hdcImage = 0;
-    HGDIOBJ hOldImage = NULL;
-    BOOL bAlpha = FALSE;
-
-    hbmMask = pIcon->IconInfo.hbmMask;
-    hbmColor = pIcon->IconInfo.hbmColor;
+    PDC pdc;
+    HSURF hsurfDst = NULL;
+    RECTL rcSrc, rcDst;
+    CLIPOBJ clo, *pclo;
+    EXLATEOBJ exlo;
+    BOOL bAlpha = FALSE, Ret = FALSE, bStretch;
 
     if (istepIfAniCur)
         DPRINT1("NtUserDrawIconEx: istepIfAniCur is not supported!\n");
 
-    if (!hbmMask || !IntGdiGetObject(hbmMask, sizeof(BITMAP), (PVOID)&bmpMask))
+    DPRINT("Flags : 0x%08x\n", diFlags);
+
+    hObjs[0] = pIcon->IconInfo.hbmMask;
+    hObjs[1] = pIcon->IconInfo.hbmColor;
+    hObjs[2] = hDc;
+    GDIOBJ_LockMultipleObjs(3, hObjs, pObjs);
+    psurfMask = pObjs[0];
+    psurfColor = pObjs[1];
+    pdc = pObjs[2];
+
+    if (!pIcon->IconInfo.hbmMask
+         || !psurfMask)
     {
+        DPRINT1("No hbmMask?!\n");
+        if(pdc) DC_UnlockDc(pdc);
+        if(psurfColor) SURFACE_UnlockSurface(psurfColor);
         return FALSE;
     }
 
-    if (hbmColor && !IntGdiGetObject(hbmColor, sizeof(BITMAP), (PVOID)&bmpColor))
+    if (pIcon->IconInfo.hbmColor
+         && !psurfColor)
     {
+        DPRINT1("Unable to lock the color Bitmap?!\n");
+        SURFACE_UnlockSurface(psurfMask);
+        if(pdc) DC_UnlockDc(pdc);
         return FALSE;
     }
 
-    if (hbmColor)
+    if(!psurfColor)
     {
-        IconSize.cx = bmpColor.bmWidth;
-        IconSize.cy = bmpColor.bmHeight;
+        DPRINT("Monochrome Icon\n");
+        psurfColor = psurfMask;
+        RECTL_vSetRect(&rcSrc, 0, pIcon->Size.cy, pIcon->Size.cx, 2*pIcon->Size.cy);
     }
     else
     {
-        IconSize.cx = bmpMask.bmWidth;
-        IconSize.cy = bmpMask.bmHeight / 2;
+        DPRINT("Color Icon\n");
+        RECTL_vSetRect(&rcSrc, 0, 0, pIcon->Size.cx, pIcon->Size.cy);
+    }
+
+    if(!pdc)
+    {
+        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+        SURFACE_UnlockSurface(psurfMask);
+        if(psurfColor != psurfMask) SURFACE_UnlockSurface(psurfColor);
+        DPRINT1("Invalid DC!\n");
+        return FALSE;
     }
 
-    /* NtGdiCreateCompatibleBitmap will create a monochrome bitmap
-       when cxWidth or cyHeight is 0 */
-    if ((bmpColor.bmBitsPixel == 32) && (cxWidth != 0) && (cyHeight != 0))
+    /* Check for alpha */
+    if ((BitsPerFormat(psurfColor->SurfObj.iBitmapFormat) == 32)
+            && (diFlags & DI_IMAGE))
     {
-        SURFACE *psurfOff = 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,
            because information about transparency is not stored in any image's headers */
-        psurfOff = SURFACE_LockSurface(hbmColor ? hbmColor : hbmMask);
-        if (psurfOff)
+        fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfColor->SurfObj.iBitmapFormat].DIB_GetPixel;
+        if (fnSource_GetPixel)
         {
-            fnSource_GetPixel = DibFunctionsForBitmapFormat[psurfOff->SurfObj.iBitmapFormat].DIB_GetPixel;
-            if (fnSource_GetPixel)
+            for (i = 0; i < psurfColor->SurfObj.sizlBitmap.cx; i++)
             {
-                for (x = 0; x < psurfOff->SurfObj.sizlBitmap.cx; x++)
+                for (j = 0; j < psurfColor->SurfObj.sizlBitmap.cy; j++)
                 {
-                    for (y = 0; y < psurfOff->SurfObj.sizlBitmap.cy; y++)
-                    {
-                        bAlpha = ((BYTE)(fnSource_GetPixel(&psurfOff->SurfObj, x, y) >> 24) & 0xff);
-                        if (bAlpha)
-                            break;
-                    }
+                    bAlpha = ((BYTE)(fnSource_GetPixel(&psurfColor->SurfObj, i, j) >> 24) & 0xff);
                     if (bAlpha)
                         break;
                 }
+                if (bAlpha)
+                    break;
             }
-            SURFACE_UnlockSurface(psurfOff);
         }
     }
 
-    if (!diFlags)
-        diFlags = DI_NORMAL;
-
     if (!cxWidth)
         cxWidth = ((diFlags & DI_DEFAULTSIZE) ?
-                   UserGetSystemMetrics(SM_CXICON) : IconSize.cx);
+                   UserGetSystemMetrics(SM_CXICON) : pIcon->Size.cx);
 
     if (!cyHeight)
         cyHeight = ((diFlags & DI_DEFAULTSIZE) ?
-                    UserGetSystemMetrics(SM_CYICON) : IconSize.cy);
+                    UserGetSystemMetrics(SM_CYICON) : pIcon->Size.cy);
+
+    /* Check stretching */
+    bStretch = (pIcon->Size.cx != cxWidth) || (pIcon->Size.cy != cyHeight);
 
     DoFlickerFree = (hbrFlickerFreeDraw &&
                      (GDI_HANDLE_GET_TYPE(hbrFlickerFreeDraw) == GDI_OBJECT_TYPE_BRUSH));
 
-    if (DoFlickerFree || bAlpha)
+    if (DoFlickerFree)
     {
-        RECTL r;
-        BITMAP bm;
-        SURFACE *psurfOff = NULL;
-
-        r.right = cxWidth;
-        r.bottom = cyHeight;
+        EBRUSHOBJ ebo;
+        PBRUSH pBrush ;
+        POINTL ptBrushOrig;
 
-        hdcOff = NtGdiCreateCompatibleDC(hDc);
-        if (!hdcOff)
+        pBrush = BRUSH_LockBrush(hbrFlickerFreeDraw);
+        if(!pBrush)
         {
-            DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
-            return FALSE;
+            SetLastWin32Error(ERROR_INVALID_PARAMETER);
+            DPRINT1("Invalid brush!\n");
+            goto cleanup;
         }
 
-        hbmOff = NtGdiCreateCompatibleBitmap(hDc, cxWidth, cyHeight);
-        if (!hbmOff)
+        hsurfDst = IntCreateCompatibleBitmap(pdc, cxWidth, cyHeight);
+        if(!hsurfDst)
         {
-            DPRINT1("NtGdiCreateCompatibleBitmap() failed!\n");
+            DPRINT1("Error : Failed to allocate the offscreen surface\n");
             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)
+        psurfDst = SURFACE_LockSurface(hsurfDst);
+        if(!psurfDst)
         {
-            DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
+            DPRINT1("Error : Failed to lock the offScreen bitmap\n");
             goto cleanup;
         }
-        BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
+        RECTL_vSetRect(&rcDst, 0, 0, cxWidth, cyHeight);
 
-        if (bm.bmBitsPixel != 32)
-            bAlpha = FALSE;
+        ptBrushOrig.x = pBrush->ptOrigin.x;
+        ptBrushOrig.y = pBrush->ptOrigin.y;
 
-        SURFACE_UnlockSurface(psurfOff);
+        EBRUSHOBJ_vInit(&ebo, pBrush, pdc);
 
-        hOldOffBmp = NtGdiSelectBitmap(hdcOff, hbmOff);
-        if (!hOldOffBmp)
-        {
-            DPRINT1("NtGdiSelectBitmap() failed!\n");
-            goto cleanup;
-        }
+        clo.iDComplexity =  DC_TRIVIAL;
+        pclo = &clo;
 
-        if (DoFlickerFree)
-        {
-            hOldOffBrush = NtGdiSelectBrush(hdcOff, hbrFlickerFreeDraw);
-            if (!hOldOffBrush)
-            {
-                DPRINT1("NtGdiSelectBrush() failed!\n");
-                goto cleanup;
-            }
+        IntEngBitBlt(&psurfDst->SurfObj, NULL, NULL, pclo, NULL, &rcDst, NULL,
+                     NULL, &ebo.BrushObject, &ptBrushOrig, ROP3_TO_ROP4(PATCOPY));
 
-            NtGdiPatBlt(hdcOff, 0, 0, r.right, r.bottom, PATCOPY);
-        }
+        EBRUSHOBJ_vCleanup(&ebo);
+        BRUSH_UnlockBrush(pBrush);
     }
     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;
-        }
-    }
+        RECT rcBmp;
+        RECTL_vSetRect(&rcDst, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
+        IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
+        RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
 
-    /* If DI_IMAGE flag is specified and hbmMask exists, then always use mask for drawing */
-    if (diFlags & DI_MASK || (diFlags & DI_IMAGE && hbmMask))
-    {
-        hdcMask = NtGdiCreateCompatibleDC(hDc);
-        if (!hdcMask)
-        {
-            DPRINT1("NtGdiCreateCompatibleDC() failed!\n");
-            goto cleanup;
-        }
+        DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcDst );
 
-        hOldMask = NtGdiSelectBitmap(hdcMask, hbmMask);
-        if (!hOldMask)
+        if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+            DC_vUpdateFillBrush(pdc);
+
+        psurfDst = pdc->dclevel.pSurface;
+        pclo = pdc->rosdc.CombinedClip;
+        RECTL_vSetRect(&rcBmp, 0, 0, psurfDst->SurfObj.sizlBitmap.cx, psurfDst->SurfObj.sizlBitmap.cy);
+        if(!RECTL_bIntersectRect(&rcDst, &rcDst, &rcBmp))
         {
-            DPRINT("NtGdiSelectBitmap() failed!\n");
-            goto cleanup;
+            Ret = FALSE;
+            goto done;
         }
     }
 
-    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;
-        BYTE Red, Green, Blue, Alpha;
-        DWORD Count = 0;
+    /* Optimization : use directly the palette of the DC,
+     * so we XLATE only once, and then we directly copy bits */
+    EXLATEOBJ_vInitialize(&exlo, psurfColor->ppal, pdc->dclevel.pSurface->ppal, 0, 0, 0xFFFFFFFF);
+
+       if(bAlpha && (diFlags & DI_IMAGE))
+       {
+               BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+        BYTE Alpha;
         INT i, j;
+        PSURFACE psurf = NULL;
+        PBYTE ptr ;
+        HBITMAP hMemBmp = NULL;
 
-        psurfOff = SURFACE_LockSurface(hbmOff);
-        if (psurfOff == NULL)
+        hMemBmp = BITMAP_CopyBitmap(pIcon->IconInfo.hbmColor);
+        if(!hMemBmp)
         {
-            DPRINT1("BITMAPOBJ_LockBitmap() failed!\n");
-            goto cleanup;
+            DPRINT1("BITMAP_CopyBitmap failed!");
+            goto CleanupAlpha;
         }
-        BITMAP_GetObject(psurfOff, sizeof(BITMAP), (PVOID)&bm);
 
-        pBits = ExAllocatePoolWithTag(PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
-        if (pBits == NULL)
+        psurf = SURFACE_LockSurface(hMemBmp);
+        if(!psurf)
         {
-            DPRINT1("ExAllocatePoolWithTag() failed!\n");
-            SURFACE_UnlockSurface(psurfOff);
-            goto cleanup;
+            DPRINT1("SURFACE_LockSurface failed!\n");
+            goto CleanupAlpha;
         }
 
-        /* get icon bits */
-        IntGetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
-
         /* premultiply with the alpha channel value */
-        for (i = 0; i < cyHeight; i++)
+        for (i = 0; i < psurf->SurfObj.sizlBitmap.cy; i++)
         {
-            for (j = 0; j < cxWidth; j++)
+                       ptr = (PBYTE)psurf->SurfObj.pvScan0 + i*psurf->SurfObj.lDelta;
+            for (j = 0; j < psurf->SurfObj.sizlBitmap.cx; j++)
             {
-                Pixel = *(DWORD *)(pBits + Count);
+                Alpha = ptr[3];
+                ptr[0] = (ptr[0] * Alpha) / 0xff;
+                ptr[1] = (ptr[1] * Alpha) / 0xff;
+                ptr[2] = (ptr[2] * Alpha) / 0xff;
 
-                Alpha = ((BYTE)(Pixel >> 24) & 0xff);
+                               ptr += 4;
+            }
+        }
 
-                Red   = (((BYTE)(Pixel >>  0)) * Alpha) / 0xff;
-                Green = (((BYTE)(Pixel >>  8)) * Alpha) / 0xff;
-                Blue  = (((BYTE)(Pixel >> 16)) * Alpha) / 0xff;
+        DPRINT("Performing alpha blending\n");
+        Ret = IntEngAlphaBlend(&psurfDst->SurfObj,
+                               &psurf->SurfObj,
+                               pclo,
+                               &exlo.xlo,
+                               &rcDst,
+                               &rcSrc,
+                               (BLENDOBJ*)&pixelblend);
 
-                *(DWORD *)(pBits + Count) = (DWORD)(Red | (Green << 8) | (Blue << 16) | (Alpha << 24));
+    CleanupAlpha:
+        if(psurf) SURFACE_UnlockSurface(psurf);
+        if(hMemBmp) NtGdiDeleteObjectApp(hMemBmp);
+               if(Ret) goto done;
+        else DPRINT1("IntEngAlphaBlend failed!\n");
+    }
 
-                Count += sizeof(DWORD);
-            }
+    if (diFlags & DI_IMAGE)
+    {
+        POINTL ptMaskOrig = {0,0};
+        if(bStretch)
+        {
+            DPRINT("Stretching\n");
+            Ret = IntEngStretchBlt(&psurfDst->SurfObj,
+                                   &psurfColor->SurfObj,
+                                   (diFlags & DI_MASK) ? &psurfMask->SurfObj : NULL,
+                                   pclo,
+                                   &exlo.xlo,
+                                   &rcDst,
+                                   &rcSrc,
+                                   (diFlags & DI_MASK) ? &ptMaskOrig : NULL,
+                                   NULL,
+                                   NULL,
+                                   (diFlags & DI_MASK) ? R4_MASK : ROP3_TO_ROP4(SRCCOPY));
+            if(!Ret) DPRINT1("IntEngStretchBlt Failed\n");
         }
+        else
+        {
+            DPRINT("Blting\n");
+            Ret = IntEngBitBlt(&psurfDst->SurfObj,
+                               &psurfColor->SurfObj,
+                               (diFlags & DI_MASK) ? &psurfMask->SurfObj : NULL,
+                               pclo,
+                               &exlo.xlo,
+                               &rcDst,
+                               (PPOINTL)&rcSrc,
+                               (diFlags & DI_MASK) ? &ptMaskOrig : NULL,
+                               NULL,
+                               NULL,
+                               (diFlags & DI_MASK) ? R4_MASK : ROP3_TO_ROP4(SRCCOPY));
+            if(!Ret) DPRINT1("IntEngBitBlt Failed\n");
+        }
+    }
+    else
+    {
+        DPRINT1("Uh? Calling DrawIcon without anything to draw? diFlags %d\n", diFlags);
+    }
+
+done:
+    if(DoFlickerFree && Ret)
+    {
+        POINTL ptSrc = {0,0};
+        RECTL rcBmp;
 
-        /* set icon bits */
-        IntSetBitmapBits(psurfOff, bm.bmWidthBytes * abs(bm.bmHeight), pBits);
-        ExFreePoolWithTag(pBits, TAG_BITMAP);
+        RECTL_vSetRect(&rcDst, xLeft, yTop, xLeft + cxWidth, yTop + cyHeight);
 
-        SURFACE_UnlockSurface(psurfOff);
+        IntLPtoDP(pdc, (LPPOINT)&rcDst, 2);
 
-        BlendFunc.BlendOp = AC_SRC_OVER;
-        BlendFunc.BlendFlags = 0;
-        BlendFunc.SourceConstantAlpha = 255;
-        BlendFunc.AlphaFormat = AC_SRC_ALPHA;
+        RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
+        DC_vPrepareDCsForBlit(pdc, rcDst, NULL, rcDst );
 
-        NtGdiAlphaBlend(hDc, xLeft, yTop, cxWidth, cyHeight,
-                        hdcOff, 0, 0, cxWidth, cyHeight, BlendFunc, 0);
-    }
-    else if (DoFlickerFree)
-    {
-        NtGdiBitBlt(hDc, xLeft, yTop, cxWidth,
-                    cyHeight, hdcOff, 0, 0, SRCCOPY, 0, 0);
+        if (pdc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+            DC_vUpdateFillBrush(pdc);
+
+        RECTL_vSetRect(&rcBmp, 0, 0,
+                       pdc->dclevel.pSurface->SurfObj.sizlBitmap.cx,
+                       pdc->dclevel.pSurface->SurfObj.sizlBitmap.cy);
+
+        if(RECTL_bIntersectRect(&rcDst, &rcDst, &rcBmp))
+        {
+            /* Copy everything */
+            DPRINT("Copying bits from offscreen buffer\n");
+            Ret = IntEngCopyBits(&pdc->dclevel.pSurface->SurfObj,
+                                 &psurfDst->SurfObj,
+                                 pdc->rosdc.CombinedClip,
+                                 gpxloTrivial,
+                                 &rcDst,
+                                 &ptSrc);
+            if(!Ret) DPRINT1("IntEngCopyBits Failed\n");
+        }
+
+        DC_vFinishBlit(pdc, NULL);
     }
 
-    Ret = TRUE;
+    if(!DoFlickerFree) DC_vFinishBlit(pdc, NULL);
+    EXLATEOBJ_vCleanup(&exlo);
 
 cleanup:
-    if (DoFlickerFree || bAlpha)
+    if(psurfColor != psurfMask)
+        SURFACE_UnlockSurface(psurfColor);
+    SURFACE_UnlockSurface(psurfMask);
+    if(hsurfDst)
     {
-        if (hOldOffBmp) NtGdiSelectBitmap(hdcOff, hOldOffBmp);
-        if (hOldOffBrush) NtGdiSelectBrush(hdcOff, hOldOffBrush);
-        if (hbmOff) GreDeleteObject(hbmOff);
-        if (hdcOff) NtGdiDeleteObjectApp(hdcOff);
+        if(psurfDst) SURFACE_UnlockSurface(psurfDst);
+        GreDeleteObject(hsurfDst);
     }
+    DC_UnlockDc(pdc);
 
-    return Ret;
+    DPRINT("return %s\n", Ret ? "TRUE" : "FALSE") ;
+
+    return Ret ;
 }
 
 /*