comctl32: Correctly set the colour table for ILC_COLOR4 and ILC_COLOR8 imagelists.

Huw Davies huw at codeweavers.com
Mon Jan 30 10:33:05 CST 2017


Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/comctl32/imagelist.c       |  42 +++++++--
 dlls/comctl32/tests/imagelist.c | 199 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 235 insertions(+), 6 deletions(-)

diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c
index 9811da3..157344c 100644
--- a/dlls/comctl32/imagelist.c
+++ b/dlls/comctl32/imagelist.c
@@ -85,6 +85,7 @@ struct _IMAGELIST
     INT     cInitial;
     UINT    uBitsPixel;
     char   *has_alpha;
+    BOOL    color_table_set;
 
     LONG        ref;                       /* reference count */
 };
@@ -311,6 +312,9 @@ done:
     return ret;
 }
 
+UINT WINAPI
+ImageList_SetColorTable(HIMAGELIST himl, UINT uStartIndex, UINT cEntries, const RGBQUAD *prgb);
+
 /*************************************************************************
  * IMAGELIST_InternalExpandBitmaps [Internal]
  *
@@ -433,7 +437,8 @@ ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
 
     nImageCount = bmp.bmWidth / himl->cx;
 
-    TRACE("%p has %d images (%d x %d)\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight);
+    TRACE("%p has %d images (%d x %d) bpp %d\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight,
+          bmp.bmBitsPixel);
 
     IMAGELIST_InternalExpandBitmaps(himl, nImageCount);
 
@@ -451,6 +456,14 @@ ImageList_Add (HIMAGELIST himl,	HBITMAP hbmImage, HBITMAP hbmMask)
         SelectObject(hdcTemp, hbmMask);
     }
 
+    if (himl->uBitsPixel <= 8 && bmp.bmBitsPixel <= 8 &&
+        !himl->color_table_set && himl->cCurImage == 0)
+    {
+        RGBQUAD colors[256];
+        UINT num = GetDIBColorTable( hdcBitmap, 0, 1 << bmp.bmBitsPixel, colors );
+        if (num) ImageList_SetColorTable( himl, 0, num, colors );
+    }
+
     for (i=0; i<nImageCount; i++)
     {
         imagelist_point_from_index( himl, himl->cCurImage + i, &pt );
@@ -800,6 +813,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
     himl->cGrow     = cGrow;
     himl->clrFg     = CLR_DEFAULT;
     himl->clrBk     = CLR_NONE;
+    himl->color_table_set = FALSE;
 
     /* initialize overlay mask indices */
     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
@@ -3132,11 +3146,25 @@ static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
 
 	if (himl->uBitsPixel <= ILC_COLOR8)
 	{
-            /* retrieve the default color map */
-            HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
-            GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
-            DeleteObject( tmp );
-	}
+            if (!himl->color_table_set)
+            {
+                /* retrieve the default color map */
+                HBITMAP tmp = CreateBitmap( 1, 1, 1, 1, NULL );
+                GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
+                DeleteObject( tmp );
+                if (ilc == ILC_COLOR4)
+                {
+                    RGBQUAD tmp;
+                    tmp = bmi->bmiColors[7];
+                    bmi->bmiColors[7] = bmi->bmiColors[8];
+                    bmi->bmiColors[8] = tmp;
+                }
+            }
+            else
+            {
+                GetDIBColorTable(himl->hdcImage, 0, 1 << himl->uBitsPixel, bmi->bmiColors);
+            }
+        }
 	hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, 0, 0);
     }
     else /*if (ilc == ILC_COLORDDB)*/
@@ -3171,6 +3199,8 @@ static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
 UINT WINAPI
 ImageList_SetColorTable(HIMAGELIST himl, UINT uStartIndex, UINT cEntries, const RGBQUAD *prgb)
 {
+    TRACE("(%p, %d, %d, %p)\n", himl, uStartIndex, cEntries, prgb);
+    himl->color_table_set = TRUE;
     return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb);
 }
 
diff --git a/dlls/comctl32/tests/imagelist.c b/dlls/comctl32/tests/imagelist.c
index 7e029e0..9009f18 100644
--- a/dlls/comctl32/tests/imagelist.c
+++ b/dlls/comctl32/tests/imagelist.c
@@ -66,6 +66,7 @@ static BOOL (WINAPI *pImageList_SetImageCount)(HIMAGELIST,UINT);
 static HRESULT (WINAPI *pImageList_CoCreateInstance)(REFCLSID,const IUnknown *,
     REFIID,void **);
 static HRESULT (WINAPI *pHIMAGELIST_QueryInterface)(HIMAGELIST,REFIID,void **);
+static int (WINAPI *pImageList_SetColorTable)(HIMAGELIST,int,int,RGBQUAD*);
 
 static HINSTANCE hinst;
 
@@ -2030,6 +2031,201 @@ static void test_create_destroy(void)
     ok(himl == NULL, "got %p\n", himl);
 }
 
+static void check_color_table(HDC hdc, HIMAGELIST himl, UINT ilc, RGBQUAD *expect, const char *name)
+{
+    IMAGEINFO info;
+    INT ret;
+    char bmi_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+    BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
+    int i, depth = ilc & 0xfe;
+
+    ret = ImageList_GetImageInfo(himl, 0, &info);
+    ok(ret, "got %d\n", ret);
+    ok(info.hbmImage != NULL, "got %p\n", info.hbmImage);
+
+    memset(bmi_buffer, 0, sizeof(bmi_buffer));
+    bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
+    ret = GetDIBits(hdc, info.hbmImage, 0, 0, NULL, bmi, DIB_RGB_COLORS);
+    ok(ret, "got %d\n", ret);
+    ok(bmi->bmiHeader.biBitCount == depth, "got %d\n", bmi->bmiHeader.biBitCount);
+
+    ret = GetDIBits(hdc, info.hbmImage, 0, 0, NULL, bmi, DIB_RGB_COLORS);
+    ok(ret, "got %d\n", ret);
+    ok(bmi->bmiHeader.biBitCount == depth, "got %d\n", bmi->bmiHeader.biBitCount);
+
+    for (i = 0; i < (1 << depth); i++)
+        ok(expect[i].rgbRed == bmi->bmiColors[i].rgbRed &&
+           expect[i].rgbGreen == bmi->bmiColors[i].rgbGreen &&
+           expect[i].rgbBlue == bmi->bmiColors[i].rgbBlue,
+           "%d: %s: got color[%d] %02x %02x %02x expect %02x %02x %02x\n", depth, name, i,
+           bmi->bmiColors[i].rgbRed, bmi->bmiColors[i].rgbGreen, bmi->bmiColors[i].rgbBlue,
+           expect[i].rgbRed, expect[i].rgbGreen, expect[i].rgbBlue);
+}
+
+static void get_default_color_table(HDC hdc, int bpp, RGBQUAD *table)
+{
+    char bmi_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+    BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
+    HBITMAP tmp;
+    int ret, i;
+    HPALETTE pal;
+    PALETTEENTRY entries[256];
+
+    switch (bpp)
+    {
+    case 4:
+        tmp = CreateBitmap( 1, 1, 1, 1, NULL );
+        memset(bmi_buffer, 0, sizeof(bmi_buffer));
+        bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
+        bmi->bmiHeader.biHeight = 1;
+        bmi->bmiHeader.biWidth = 1;
+        bmi->bmiHeader.biBitCount = bpp;
+        bmi->bmiHeader.biPlanes = 1;
+        bmi->bmiHeader.biCompression = BI_RGB;
+        ret = GetDIBits( hdc, tmp, 0, 0, NULL, bmi, DIB_RGB_COLORS );
+
+        memcpy(table, bmi->bmiColors, (1 << bpp) * sizeof(RGBQUAD));
+        table[7] = bmi->bmiColors[8];
+        table[8] = bmi->bmiColors[7];
+        DeleteObject( tmp );
+        break;
+
+    case 8:
+        pal = CreateHalftonePalette(hdc);
+        GetPaletteEntries(pal, 0, 256, entries);
+        for (i = 0; i < 256; i++)
+        {
+            table[i].rgbRed = entries[i].peRed;
+            table[i].rgbGreen = entries[i].peGreen;
+            table[i].rgbBlue = entries[i].peBlue;
+            table[i].rgbReserved = 0;
+        }
+        DeleteObject(pal);
+        break;
+
+    default:
+        ok(0, "unhandled depth %d\n", bpp);
+    }
+}
+
+static void test_color_table(UINT ilc)
+{
+    HIMAGELIST himl;
+    INT ret;
+    char bmi_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
+    BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
+    HDC hdc = CreateCompatibleDC(0);
+    HBITMAP dib4, dib8, dib32;
+    RGBQUAD rgb[256], default_table[256];
+
+    get_default_color_table(hdc, ilc & 0xfe, default_table);
+
+    himl = ImageList_Create(16, 16, ilc, 0, 3);
+    ok(himl != NULL, "got %p\n", himl);
+
+    memset(bmi_buffer, 0, sizeof(bmi_buffer));
+    bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
+    bmi->bmiHeader.biHeight = 16;
+    bmi->bmiHeader.biWidth = 16;
+    bmi->bmiHeader.biBitCount = 8;
+    bmi->bmiHeader.biPlanes = 1;
+    bmi->bmiHeader.biCompression = BI_RGB;
+    bmi->bmiColors[0].rgbRed = 0xff;
+    bmi->bmiColors[1].rgbGreen = 0xff;
+    bmi->bmiColors[2].rgbBlue = 0xff;
+
+    dib8 = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+    bmi->bmiHeader.biBitCount = 4;
+    bmi->bmiColors[0].rgbRed   = 0xff;
+    bmi->bmiColors[0].rgbGreen = 0x00;
+    bmi->bmiColors[0].rgbBlue  = 0xff;
+    bmi->bmiColors[1].rgbRed   = 0xff;
+    bmi->bmiColors[1].rgbGreen = 0xff;
+    bmi->bmiColors[1].rgbBlue  = 0x00;
+    bmi->bmiColors[2].rgbRed   = 0x00;
+    bmi->bmiColors[2].rgbGreen = 0xff;
+    bmi->bmiColors[2].rgbBlue  = 0xff;
+
+    dib4 = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+    bmi->bmiHeader.biBitCount = 32;
+
+    dib32 = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+    /* add 32 first then 8.  This won't set the color table */
+    ret = ImageList_Add(himl, dib32, NULL);
+    ok(ret == 0, "got %d\n", ret);
+    ret = ImageList_Add(himl, dib8, NULL);
+    ok(ret == 1, "got %d\n", ret);
+
+    check_color_table(hdc, himl, ilc, default_table, "add 32, 8");
+
+    /* since the previous _Adds didn't set the color table, this one will */
+    ret = ImageList_Remove(himl, -1);
+    ok(ret, "got %d\n", ret);
+    ret = ImageList_Add(himl, dib8, NULL);
+    ok(ret == 0, "got %d\n", ret);
+
+    memset(rgb, 0, sizeof(rgb));
+    rgb[0].rgbRed = 0xff;
+    rgb[1].rgbGreen = 0xff;
+    rgb[2].rgbBlue = 0xff;
+    check_color_table(hdc, himl, ilc, rgb, "remove all, add 8");
+
+    /* remove all, add 4. Color table remains the same since it's inplicitly
+       been set by the previous _Add */
+    ret = ImageList_Remove(himl, -1);
+    ok(ret, "got %d\n", ret);
+    ret = ImageList_Add(himl, dib4, NULL);
+    ok(ret == 0, "got %d\n", ret);
+    check_color_table(hdc, himl, ilc, rgb, "remove all, add 4");
+
+    ImageList_Destroy(himl);
+    himl = ImageList_Create(16, 16, ilc, 0, 3);
+    ok(himl != NULL, "got %p\n", himl);
+
+    /* add 4 */
+    ret = ImageList_Add(himl, dib4, NULL);
+    ok(ret == 0, "got %d\n", ret);
+
+    memset(rgb, 0, 16 * sizeof(rgb[0]));
+    rgb[0].rgbRed = 0xff;
+    rgb[0].rgbBlue = 0xff;
+    rgb[1].rgbRed = 0xff;
+    rgb[1].rgbGreen = 0xff;
+    rgb[2].rgbGreen = 0xff;
+    rgb[2].rgbBlue = 0xff;
+    memcpy(rgb + 16, default_table + 16, 240 * sizeof(rgb[0]));
+
+    check_color_table(hdc, himl, ilc, rgb, "add 4");
+
+    ImageList_Destroy(himl);
+    himl = ImageList_Create(16, 16, ilc, 0, 3);
+    ok(himl != NULL, "got %p\n", himl);
+
+    /* set color table, add 8 */
+    ret = ImageList_Remove(himl, -1);
+    ok(ret, "got %d\n", ret);
+    memset(rgb, 0, sizeof(rgb));
+    rgb[0].rgbRed = 0xcc;
+    rgb[1].rgbBlue = 0xcc;
+    ret = pImageList_SetColorTable(himl, 0, 2, rgb);
+    ok(ret == 2, "got %d\n", ret);
+    /* the table is set, so this doesn't change it */
+    ret = ImageList_Add(himl, dib8, NULL);
+    ok(ret == 0, "got %d\n", ret);
+
+    memcpy(rgb + 2, default_table + 2, 254 * sizeof(rgb[0]));
+    check_color_table(hdc, himl, ilc, rgb, "SetColorTable");
+
+    DeleteObject(dib32);
+    DeleteObject(dib8);
+    DeleteObject(dib4);
+    DeleteDC(hdc);
+    ImageList_Destroy(himl);
+}
+
 static void test_IImageList_Clone(void)
 {
     IImageList *imgl, *imgl2;
@@ -2162,6 +2358,7 @@ START_TEST(imagelist)
     pImageList_Add = NULL;
     pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
     pImageList_SetImageCount = (void*)GetProcAddress(hComCtl32, "ImageList_SetImageCount");
+    pImageList_SetColorTable = (void*)GetProcAddress(hComCtl32, (const char*)390);
 
     hinst = GetModuleHandleA(NULL);
 
@@ -2177,6 +2374,8 @@ START_TEST(imagelist)
     test_merge_colors();
     test_imagelist_storage();
     test_iconsize();
+    test_color_table(ILC_COLOR4);
+    test_color_table(ILC_COLOR8);
 
     FreeLibrary(hComCtl32);
 
-- 
2.10.2




More information about the wine-patches mailing list