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