From a7c8dad0bc76a335a9a9de6123a2a46c0b77cb23 Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Tue, 16 Jun 2009 14:59:58 +0100 Subject: [PATCH] user32/tests: Added tests for DrawIcon and DrawIconEx. --- dlls/user32/tests/cursoricon.c | 278 +++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c index 947553498ef..26c533b160b 100644 --- a/dlls/user32/tests/cursoricon.c +++ b/dlls/user32/tests/cursoricon.c @@ -956,6 +956,282 @@ static void test_CreateIconFromResource(void) HeapFree(GetProcessHeap(), 0, hotspot); } +static HICON create_test_icon(HDC hdc, int width, int height, int bpp, + BOOL maskvalue, UINT32 *color, int colorSize) +{ + ICONINFO iconInfo; + BITMAPINFO bitmapInfo; + UINT32 *buffer = NULL; + UINT32 mask = maskvalue ? 0xFFFFFFFF : 0x00000000; + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = width; + bitmapInfo.bmiHeader.biHeight = height; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biBitCount = bpp; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = colorSize; + + iconInfo.fIcon = TRUE; + iconInfo.xHotspot = 0; + iconInfo.yHotspot = 0; + + iconInfo.hbmMask = CreateBitmap( width, height, 1, 1, &mask ); + if(!iconInfo.hbmMask) return NULL; + + iconInfo.hbmColor = CreateDIBSection(hdc, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, NULL, 0); + if(!iconInfo.hbmColor || !buffer) + { + DeleteObject(iconInfo.hbmMask); + return NULL; + } + + memcpy(buffer, color, colorSize); + + return CreateIconIndirect(&iconInfo); +} + +static BOOL color_match(COLORREF a, COLORREF b) +{ + /* 5-bit accuracy is a sufficient test. This will match, so long as + * colors are never truncated to less that 3x5-bit accuracy i.e. + * paletized. */ + return (a & 0x00F8F8F8) == (b & 0x00F8F8F8); +} + +static void check_alpha_draw(HDC hdc, BOOL drawiconex, BOOL alpha, int bpp, int line) +{ + HICON hicon; + UINT32 mask; + UINT32 color[2]; + COLORREF modern_expected, legacy_expected, result; + + mask = 0x00000000; + color[0] = 0x00A0B0C0; + color[1] = alpha ? 0xFF000000 : 0x00000000; + modern_expected = alpha ? 0x00FFFFFF : 0x00C0B0A0; + legacy_expected = 0x00C0B0A0; + + hicon = create_test_icon(hdc, 2, 1, bpp, 0, color, sizeof(color)); + if (!hicon) return; + + SetPixelV(hdc, 0, 0, 0x00FFFFFF); + + if(drawiconex) + DrawIconEx(hdc, 0, 0, hicon, 2, 1, 0, NULL, DI_NORMAL); + else + DrawIcon(hdc, 0, 0, hicon); + + result = GetPixel(hdc, 0, 0); + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "%s. Expected a close match to %06X (modern) or %06X (legacy) with %s. " + "Got %06X from line %d\n", + alpha ? "Alpha blending" : "Not alpha blending", modern_expected, legacy_expected, + drawiconex ? "DrawIconEx" : "DrawIcon", result, line); +} + +static void check_DrawIcon(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, COLORREF background, + COLORREF modern_expected, COLORREF legacy_expected, int line) +{ + COLORREF result; + HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color)); + if (!hicon) return; + SetPixelV(hdc, 0, 0, background); + DrawIcon(hdc, 0, 0, hicon); + result = GetPixel(hdc, 0, 0); + + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "Overlaying Mask %d on Color %06X with DrawIcon. " + "Expected a close match to %06X (modern), or %06X (legacy). Got %06X from line %d\n", + maskvalue, color, modern_expected, legacy_expected, result, line); +} + +static void test_DrawIcon(void) +{ + BITMAPINFO bitmapInfo; + HDC hdcDst = NULL; + HBITMAP bmpDst = NULL; + HBITMAP bmpOld = NULL; + UINT32 *bits = 0; + + hdcDst = CreateCompatibleDC(0); + ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n"); + if (!hdcDst) + return; + + if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8) + { + skip("Windows will distort DrawIcon colors at 8-bpp and less due to palletizing.\n"); + goto cleanup; + } + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 1; + bitmapInfo.bmiHeader.biHeight = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32); + + bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n"); + if (!bmpDst || !bits) + goto cleanup; + bmpOld = SelectObject(hdcDst, bmpDst); + + /* Mask is only heeded if alpha channel is always zero */ + check_DrawIcon(hdcDst, FALSE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x00A0B0C0, 32, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__); + + /* Test alpha blending */ + /* Windows 2000 and up will alpha blend, earlier Windows versions will not */ + check_DrawIcon(hdcDst, FALSE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + + todo_wine + { + check_DrawIcon(hdcDst, TRUE, 0xFFA0B0C0, 32, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__); + + check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, FALSE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x80A0B0C0, 32, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__); + + check_DrawIcon(hdcDst, FALSE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + check_DrawIcon(hdcDst, TRUE, 0x01FFFFFF, 32, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + } + + /* Test detecting of alpha channel */ + /* If a single pixel's alpha channel is non-zero, the icon + will be alpha blended, otherwise it will be draw with + and + xor blts. */ + check_alpha_draw(hdcDst, FALSE, FALSE, 32, __LINE__); + todo_wine check_alpha_draw(hdcDst, FALSE, TRUE, 32, __LINE__); + + SelectObject(hdcDst, bmpOld); + DeleteObject(bmpDst); + bmpOld = NULL; + bmpDst = NULL; + +cleanup: + if(bmpOld) + SelectObject(hdcDst, bmpOld); + if(bmpDst) + DeleteObject(bmpDst); + if(hdcDst) + DeleteDC(hdcDst); +} + +static void check_DrawIconEx(HDC hdc, BOOL maskvalue, UINT32 color, int bpp, UINT flags, COLORREF background, + COLORREF modern_expected, COLORREF legacy_expected, int line) +{ + COLORREF result; + HICON hicon = create_test_icon(hdc, 1, 1, bpp, maskvalue, &color, sizeof(color)); + if (!hicon) return; + SetPixelV(hdc, 0, 0, background); + DrawIconEx(hdc, 0, 0, hicon, 1, 1, 0, NULL, flags); + result = GetPixel(hdc, 0, 0); + + ok (color_match(result, modern_expected) || /* Windows 2000 and up */ + broken(color_match(result, legacy_expected)), /* Windows NT 4.0, 9X and below */ + "Overlaying Mask %d on Color %06X with DrawIconEx flags %08X. " + "Expected a close match to %06X (modern) or %06X (legacy). Got %06X from line %d\n", + maskvalue, color, flags, modern_expected, legacy_expected, result, line); +} + +static void test_DrawIconEx(void) +{ + BITMAPINFO bitmapInfo; + HDC hdcDst = NULL; + HBITMAP bmpDst = NULL; + HBITMAP bmpOld = NULL; + UINT32 bits = 0; + + hdcDst = CreateCompatibleDC(0); + ok(hdcDst != 0, "CreateCompatibleDC(0) failed to return a valid DC\n"); + if (!hdcDst) + return; + + if(GetDeviceCaps(hdcDst, BITSPIXEL) <= 8) + { + skip("Windows will distort DrawIconEx colors at 8-bpp and less due to palletizing.\n"); + goto cleanup; + } + + memset(&bitmapInfo, 0, sizeof(bitmapInfo)); + bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bitmapInfo.bmiHeader.biWidth = 1; + bitmapInfo.bmiHeader.biHeight = 1; + bitmapInfo.bmiHeader.biBitCount = 32; + bitmapInfo.bmiHeader.biPlanes = 1; + bitmapInfo.bmiHeader.biCompression = BI_RGB; + bitmapInfo.bmiHeader.biSizeImage = sizeof(UINT32); + bmpDst = CreateDIBSection(hdcDst, &bitmapInfo, DIB_RGB_COLORS, (void**)&bits, NULL, 0); + ok (bmpDst && bits, "CreateDIBSection failed to return a valid bitmap and buffer\n"); + if (!bmpDst || !bits) + goto cleanup; + bmpOld = SelectObject(hdcDst, bmpDst); + + /* Test null, image only, and mask only drawing */ + todo_wine + { + check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, 0, 0x00102030, 0x00102030, 0x00102030, __LINE__); + } + + check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00000000, 0x00000000, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_MASK, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, __LINE__); + + todo_wine + { + check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_IMAGE, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + } + + /* Test normal drawing */ + check_DrawIconEx(hdcDst, FALSE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + todo_wine check_DrawIconEx(hdcDst, TRUE, 0x00A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x003F4F5F, 0x003F4F5F, __LINE__); + check_DrawIconEx(hdcDst, FALSE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x00C0B0A0, __LINE__); + + /* Test alpha blending */ + /* Windows 2000 and up will alpha blend, earlier Windows versions will not */ + todo_wine check_DrawIconEx(hdcDst, TRUE, 0xFFA0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00C0B0A0, 0x003F4F5F, __LINE__); + + todo_wine + { + check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00000000, 0x00605850, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, FALSE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x00C0B0A0, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x80A0B0C0, 32, DI_NORMAL, 0x00FFFFFF, 0x00DFD7CF, 0x003F4F5F, __LINE__); + + check_DrawIconEx(hdcDst, FALSE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + check_DrawIconEx(hdcDst, TRUE, 0x01FFFFFF, 32, DI_NORMAL, 0x00000000, 0x00010101, 0x00FFFFFF, __LINE__); + } + + /* Test detecting of alpha channel */ + /* If a single pixel's alpha channel is non-zero, the icon + will be alpha blended, otherwise it will be draw with + and + xor blts. */ + check_alpha_draw(hdcDst, TRUE, FALSE, 32, __LINE__); + todo_wine check_alpha_draw(hdcDst, TRUE, TRUE, 32, __LINE__); + + SelectObject(hdcDst, bmpOld); + DeleteObject(bmpDst); + bmpOld = NULL; + bmpDst = NULL; + +cleanup: + if(bmpOld) + SelectObject(hdcDst, bmpOld); + if(bmpDst) + DeleteObject(bmpDst); + if(hdcDst) + DeleteDC(hdcDst); +} + static void test_DestroyCursor(void) { static const BYTE bmp_bits[4096]; @@ -1063,6 +1339,8 @@ START_TEST(cursoricon) test_CreateIcon(); test_LoadImage(); test_CreateIconFromResource(); + test_DrawIcon(); + test_DrawIconEx(); test_DestroyCursor(); do_parent(); test_child_process();