comctl32: toolbar[1/4]: avoid using CopyImage as it doesn't work well when the DDBs are RGB565 (fixes bug #7905)

Mikołaj Zalewski mikolaj at zalewski.pl
Thu Apr 5 05:46:01 CDT 2007


If the DDB format is RGB565, CopyImage uses an RGB555 intermediate DIB 
that leads to data loses. This may change the COLOR_BTNFACE pixels 
slightly and they won't be recognized as transparent anymore. As this 
bug is also present under Windows, I haven't changed CopyImage but wrote 
a new function that I hope works correctly.
-------------- next part --------------
From f0fba499e6a5f7d919992e3472604717116b208c Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Miko=C5=82aj_Zalewski?= <mikolaj at zalewski.pl>
Date: Thu, 5 Apr 2007 09:11:19 +0200
Subject: [PATCH] comctl32: toolbar: avoid using CopyImage as it doesn't work well when the DDBs are RGB565 (fixes bug #7905)

---
 dlls/comctl32/comctl32.h |    1 +
 dlls/comctl32/commctrl.c |   64 ++++++++++++++++++++++++++++++++++++++++++++++
 dlls/comctl32/toolbar.c  |    5 +--
 3 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h
index e7a3598..1e9c5b3 100644
--- a/dlls/comctl32/comctl32.h
+++ b/dlls/comctl32/comctl32.h
@@ -147,6 +147,7 @@ HWND COMCTL32_CreateToolTip (HWND);
 VOID COMCTL32_RefreshSysColors(void);
 void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal);
 void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground);
+HBITMAP COMCTL32_CopyBitmap(HBITMAP hBitmap);
 INT  Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen);
 BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc);
 BOOL Str_SetPtrWtoA (LPSTR *lppDest, LPCWSTR lpSrc);
diff --git a/dlls/comctl32/commctrl.c b/dlls/comctl32/commctrl.c
index a5796f3..c5a1a64 100644
--- a/dlls/comctl32/commctrl.c
+++ b/dlls/comctl32/commctrl.c
@@ -1459,6 +1459,70 @@ void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight
 }
 
 /***********************************************************************
+ * COMCTL32_CopyBitmap [internal]
+ *
+ * Even on Windows Vista the user32 CopyImage doesn't work well when the DDBs
+ * are in the RGB565 format - it passes through RGB555 DIBs and this may change
+ * the key color. This function doesn't have this problem.
+ *
+ * PARAMS
+ *     hBitmap       [I]   Bitmap to copy. May be a DDB or DIB
+ *
+ * RETURNS
+ *     A copy of the bitmap as a DDB or NULL if failed.
+ */
+HBITMAP COMCTL32_CopyBitmap(HBITMAP hBitmap)
+{
+    DIBSECTION dib;
+    HBITMAP ret, hbmDstOld;
+    HDC hdcDev;
+    HDC hdcDst;
+    int size;
+    
+    size = GetObjectW(hBitmap, sizeof(dib), &dib);
+    if (!size)
+        return NULL;
+
+    hdcDev = GetDC(NULL);
+    /* dib.dsBm always valid. Other fields are valid only if a DIBSECTION */    
+    if (dib.dsBm.bmBitsPixel > 1)
+        ret = CreateCompatibleBitmap(hdcDev, dib.dsBm.bmWidth, dib.dsBm.bmHeight);
+    else
+        ret = CreateBitmap(dib.dsBm.bmWidth, dib.dsBm.bmHeight, 1, 1, NULL);
+
+    hdcDst = CreateCompatibleDC(hdcDev);
+    hbmDstOld = SelectObject(hdcDst, ret);
+    
+    if (size == sizeof(DIBSECTION))
+    {
+        BITMAPINFO *pInfo = Alloc(sizeof(BITMAPV4HEADER) + dib.dsBmih.biClrUsed * sizeof(RGBQUAD));
+    
+        /* copy the header and the color masks */
+        memcpy(&pInfo->bmiHeader, &dib.dsBmih, sizeof(dib.dsBmih) + 3 * sizeof(DWORD));
+        pInfo->bmiHeader.biSize = sizeof(BITMAPV4HEADER);
+        /* get the color table */
+        GetDIBits(hdcDst, hBitmap, 0, 0, NULL, pInfo, DIB_RGB_COLORS);
+        /* copy to the destination bitmap */
+        SetDIBits(hdcDst, ret, 0, dib.dsBm.bmHeight, dib.dsBm.bmBits, pInfo, DIB_RGB_COLORS);
+        Free(pInfo);
+    }
+    else
+    {
+        HDC hdcSrc = CreateCompatibleDC(hdcDev);
+        HBITMAP hbmSrcOld = SelectObject(hdcSrc, hBitmap);
+        BitBlt(hdcDst, 0, 0, dib.dsBm.bmWidth, dib.dsBm.bmHeight, hdcSrc, 0, 0, SRCCOPY);
+        SelectObject(hdcSrc, hbmSrcOld);
+        DeleteDC(hdcSrc);
+    }
+    
+    SelectObject(hdcDst, hbmDstOld);
+    DeleteDC(hdcDst);
+    ReleaseDC(NULL, hdcDev);
+    return ret;
+}
+
+
+/***********************************************************************
  * MirrorIcon [COMCTL32.414]
  *
  * Mirrors an icon so that it will appear correctly on a mirrored DC.
diff --git a/dlls/comctl32/toolbar.c b/dlls/comctl32/toolbar.c
index b8c76e5..da683ab 100644
--- a/dlls/comctl32/toolbar.c
+++ b/dlls/comctl32/toolbar.c
@@ -2668,7 +2668,7 @@ TOOLBAR_AddBitmapToImageList(TOOLBAR_INFO *infoPtr, HIMAGELIST himlDef, const TB
     TRACE("adding hInst=%p nID=%d nButtons=%d\n", bitmap->hInst, bitmap->nID, bitmap->nButtons);
     /* Add bitmaps to the default image list */
     if (bitmap->hInst == NULL)         /* a handle was passed */
-        hbmLoad = (HBITMAP)CopyImage((HBITMAP)bitmap->nID, IMAGE_BITMAP, 0, 0, 0);
+        hbmLoad = COMCTL32_CopyBitmap((HBITMAP)bitmap->nID);
     else
         hbmLoad = CreateMappedBitmap(bitmap->hInst, bitmap->nID, 0, NULL, 0);
 
@@ -2831,7 +2831,6 @@ TOOLBAR_AddBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
     if (!TOOLBAR_AddBitmapToImageList(infoPtr, himlDef, &info))
         return -1;
 
-    TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos);
     infoPtr->bitmaps = ReAlloc(infoPtr->bitmaps, (infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO));
     infoPtr->bitmaps[infoPtr->nNumBitmapInfos] = info;
     infoPtr->nNumBitmapInfos++;
@@ -4190,7 +4189,7 @@ TOOLBAR_ReplaceBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
     if (lpReplace->hInstNew)
         hBitmap = LoadBitmapW(lpReplace->hInstNew,(LPWSTR)lpReplace->nIDNew);
     else
-        hBitmap = CopyImage((HBITMAP)lpReplace->nIDNew, IMAGE_BITMAP, 0, 0, 0);
+        hBitmap = COMCTL32_CopyBitmap((HBITMAP)lpReplace->nIDNew);
 
     himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */
     nOldBitmaps = ImageList_GetImageCount(himlDef);
-- 
1.4.4.2


More information about the wine-patches mailing list