Reactos

[USER32][LIBPNG] Support PNG/Vista icons (Retry) (#7709)

CORE-18385
Retry of PR #7704

In USER32 change CMakeLists.txt to include libpng.
Improve libpng.spec to include additional needed defines.
Add code into mostly cursoricon.c to support PNG icons.

Co-authored-by: Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>

authored by

Doug Lyons
Katayama Hirofumi MZ
and committed by
GitHub
13657fdb 190782c3

+353 -62
+13
dll/3rdparty/libpng/libpng.spec
··· 7 7 @ cdecl png_destroy_read_struct(ptr ptr ptr) 8 8 @ cdecl png_destroy_write_struct(ptr ptr) 9 9 @ cdecl png_error(ptr ptr) 10 + @ cdecl png_free(ptr ptr) 10 11 @ cdecl png_get_bit_depth(ptr ptr) 12 + @ cdecl png_get_channels(ptr ptr) 11 13 @ cdecl png_get_color_type(ptr ptr) 12 14 @ cdecl png_get_error_ptr(ptr) 13 15 @ cdecl png_get_iCCP(ptr ptr ptr ptr ptr ptr) 16 + @ cdecl png_get_IHDR(ptr ptr ptr ptr ptr ptr ptr ptr ptr) 14 17 @ cdecl png_get_image_height(ptr ptr) 15 18 @ cdecl png_get_image_width(ptr ptr) 16 19 @ cdecl png_get_io_ptr(ptr) 17 20 @ cdecl png_get_pHYs(ptr ptr ptr ptr) 18 21 @ cdecl png_get_PLTE(ptr ptr ptr ptr) 22 + @ cdecl png_get_rowbytes(ptr ptr) 23 + @ cdecl png_get_rows(ptr ptr) 19 24 @ cdecl png_get_tRNS(ptr ptr ptr ptr ptr) 25 + @ cdecl png_malloc(ptr long) 26 + @ cdecl png_read_end(ptr ptr) 20 27 @ cdecl png_read_image(ptr ptr) 21 28 @ cdecl png_read_info(ptr ptr) 29 + @ cdecl png_read_update_info(ptr ptr) 22 30 @ cdecl png_set_bgr(ptr) 23 31 @ cdecl png_set_crc_action(ptr long long) 24 32 @ cdecl png_set_filter(ptr long long) ··· 27 35 @ cdecl png_set_gray_to_rgb(ptr) 28 36 @ cdecl png_set_IHDR(ptr ptr long long long long long long long) 29 37 @ cdecl png_set_interlace_handling(ptr) 38 + @ cdecl png_set_palette_to_rgb(ptr) 30 39 @ cdecl png_set_pHYs(ptr ptr ptr long long long) 31 40 @ cdecl png_set_PLTE(ptr ptr ptr long) 32 41 @ cdecl png_set_read_fn(ptr ptr ptr) 42 + @ cdecl png_set_rows(ptr ptr ptr) 43 + @ cdecl png_set_scale_16(ptr) 44 + @ cdecl png_set_sig_bytes(ptr long) 33 45 @ cdecl png_set_swap(ptr) 34 46 @ cdecl png_set_tRNS(ptr ptr ptr long ptr) 35 47 @ cdecl png_set_tRNS_to_alpha(ptr) 36 48 @ cdecl png_set_write_fn(ptr ptr ptr ptr) 37 49 @ cdecl png_set_chunk_malloc_max(ptr long) 50 + @ cdecl png_sig_cmp(ptr long long) 38 51 @ cdecl png_write_end(ptr) 39 52 @ cdecl png_write_info(ptr ptr) 40 53 @ cdecl png_write_rows(ptr ptr long)
+3 -2
win32ss/user/user32/CMakeLists.txt
··· 5 5 ${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys 6 6 include 7 7 ${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine 8 - ${REACTOS_SOURCE_DIR}/win32ss/include) 8 + ${REACTOS_SOURCE_DIR}/win32ss/include 9 + ${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/libpng) 9 10 10 11 list(APPEND SOURCE 11 12 controls/appswitch.c ··· 88 89 target_sources(user32 PRIVATE $<TARGET_OBJECTS:ftol2_sse>) 89 90 endif() 90 91 91 - add_delay_importlibs(user32 usp10) 92 + add_delay_importlibs(user32 usp10 libpng) 92 93 add_importlibs(user32 gdi32 advapi32 kernel32 ntdll) 93 94 add_pch(user32 include/user32.h SOURCE) 94 95 add_cd_file(TARGET user32 DESTINATION reactos/system32 FOR all)
+337 -60
win32ss/user/user32/windows/cursoricon.c
··· 1 1 /* 2 - * PROJECT: ReactOS user32.dll 3 - * COPYRIGHT: GPL - See COPYING in the top level directory 4 - * FILE: win32ss/user/user32/windows/cursoricon.c 5 - * PURPOSE: cursor and icons implementation 6 - * PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org) 2 + * PROJECT: ReactOS user32.dll 3 + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 + * PURPOSE: cursor and icons implementation 5 + * COPYRIGHT: Copyright Jérôme Gardou <jerome.gardou@reactos.org> 6 + * Copyright 2022-2025 Doug Lyons <douglyons@douglyons.com> 7 + * Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 7 8 */ 8 9 9 10 #include <user32.h> 11 + #include "png.h" 10 12 11 13 WINE_DEFAULT_DEBUG_CHANNEL(cursor); 12 14 WINE_DECLARE_DEBUG_CHANNEL(icon); 13 15 //WINE_DECLARE_DEBUG_CHANNEL(resource); 14 16 17 + #include <pshpack1.h> 18 + typedef struct _CURSORICONFILEDIRENTRY 19 + { 20 + BYTE bWidth; 21 + BYTE bHeight; 22 + BYTE bColorCount; 23 + BYTE bReserved; 24 + union 25 + { 26 + WORD wPlanes; /* For icons */ 27 + WORD xHotspot; /* For cursors */ 28 + }; 29 + union 30 + { 31 + WORD wBitCount; /* For icons */ 32 + WORD yHotspot; /* For cursors */ 33 + }; 34 + DWORD dwDIBSize; 35 + DWORD dwDIBOffset; 36 + } CURSORICONFILEDIRENTRY; 37 + 38 + typedef struct _CURSORICONFILEDIR 39 + { 40 + WORD idReserved; 41 + WORD idType; 42 + WORD idCount; 43 + CURSORICONFILEDIRENTRY idEntries[1]; 44 + } CURSORICONFILEDIR; 45 + #include <poppack.h> 46 + 47 + #define PNG_CHECK_SIG_SIZE 8 /* Check signature size */ 48 + 49 + /* libpng helpers */ 50 + typedef struct _PNG_READER_STATE 51 + { 52 + png_bytep buffer; 53 + size_t bufSize; 54 + size_t currentPos; 55 + } PNG_READER_STATE; 56 + 57 + /* This function is used for reading png data from memory */ 58 + static VOID 59 + ReadMemoryPng( 60 + _Inout_ png_structp png_ptr, 61 + _Out_ png_bytep data, 62 + _In_ size_t length) 63 + { 64 + PNG_READER_STATE *state = png_get_io_ptr(png_ptr); 65 + if ((state->currentPos + length) > state->bufSize) 66 + { 67 + ERR("png read error\n"); 68 + png_error(png_ptr, "read error in ReadMemoryPng"); 69 + return; 70 + } 71 + RtlCopyMemory(data, state->buffer + state->currentPos, length); 72 + state->currentPos += length; 73 + } 74 + 75 + /* libpng.dll is delay-loaded. If no libpng.dll exists, we have to avoid exception */ 76 + static BOOL 77 + LibPngExists(VOID) 78 + { 79 + static BOOL bLibPngFound = -1; 80 + if (bLibPngFound == -1) 81 + { 82 + HINSTANCE hLibPng = LoadLibraryExW(L"libpng.dll", NULL, LOAD_LIBRARY_AS_DATAFILE); 83 + bLibPngFound = !!hLibPng; 84 + FreeLibrary(hLibPng); 85 + } 86 + return bLibPngFound; 87 + } 88 + 89 + static int get_dib_image_size(int width, int height, int depth); 90 + 91 + /* Convert PNG raw data to BMP icon data */ 92 + static PBYTE 93 + CURSORICON_ConvertPngToBmpIcon( 94 + _In_ PBYTE pngBits, 95 + _In_ DWORD fileSize, 96 + _Out_ PDWORD pBmpIconSize) 97 + { 98 + TRACE("pngBits %p fileSize %d\n", pngBits, fileSize); 99 + 100 + if (!LibPngExists()) 101 + { 102 + ERR("No libpng.dll\n"); 103 + return NULL; 104 + } 105 + 106 + if (!pngBits || fileSize < PNG_CHECK_SIG_SIZE || !png_check_sig(pngBits, PNG_CHECK_SIG_SIZE)) 107 + return NULL; 108 + 109 + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 110 + if (!png_ptr) 111 + { 112 + ERR("png_create_read_struct error\n"); 113 + return NULL; 114 + } 115 + 116 + png_infop info_ptr = png_create_info_struct(png_ptr); 117 + if (!info_ptr) 118 + { 119 + ERR("png_create_info_struct error\n"); 120 + png_destroy_read_struct(&png_ptr, NULL, NULL); 121 + return NULL; 122 + } 123 + 124 + /* Set our own read_function */ 125 + PNG_READER_STATE readerState = { pngBits, fileSize, PNG_CHECK_SIG_SIZE }; 126 + png_set_read_fn(png_ptr, &readerState, ReadMemoryPng); 127 + png_set_sig_bytes(png_ptr, PNG_CHECK_SIG_SIZE); 128 + 129 + /* Read png info */ 130 + png_read_info(png_ptr, info_ptr); 131 + 132 + /* Add translation of some PNG formats and update info */ 133 + int colorType = png_get_color_type(png_ptr, info_ptr); 134 + if (colorType == PNG_COLOR_TYPE_PALETTE) 135 + png_set_palette_to_rgb(png_ptr); 136 + else if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) 137 + png_set_gray_to_rgb(png_ptr); 138 + png_set_scale_16(png_ptr); /* Convert 16-bit channels to 8-bit */ 139 + png_read_update_info(png_ptr, info_ptr); 140 + 141 + /* Get updated png info */ 142 + png_uint_32 width, height; 143 + int bitDepth; 144 + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL); 145 + TRACE("width %d, height %d, bitDepth %d, colorType %d\n", 146 + width, height, bitDepth, colorType); 147 + 148 + int channels = png_get_channels(png_ptr, info_ptr); 149 + int rowbytes = png_get_rowbytes(png_ptr, info_ptr); 150 + int imageSize = height * rowbytes; 151 + TRACE("rowbytes %d, channels %d, imageSize %d\n", rowbytes, channels, imageSize); 152 + 153 + /* Allocate rows data */ 154 + png_bytepp rows = png_malloc(png_ptr, sizeof(png_bytep) * height); 155 + if (!rows) 156 + { 157 + ERR("png_malloc failed\n"); 158 + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 159 + return NULL; 160 + } 161 + 162 + for (int i = 0; i < (int)height; i++) 163 + { 164 + rows[i] = png_malloc(png_ptr, rowbytes); 165 + if (!rows[i]) 166 + { 167 + ERR("png_malloc failed\n"); 168 + 169 + /* Clean up */ 170 + while (--i >= 0) 171 + png_free(png_ptr, rows[i]); 172 + png_free(png_ptr, rows); 173 + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 174 + 175 + return NULL; 176 + } 177 + } 178 + 179 + /* Read png image data */ 180 + png_set_rows(png_ptr, info_ptr, rows); 181 + png_read_image(png_ptr, rows); 182 + png_read_end(png_ptr, info_ptr); 183 + 184 + /* After reading the image, you can deal with row pointers */ 185 + PBYTE imageBytes = HeapAlloc(GetProcessHeap(), 0, imageSize); 186 + if (imageBytes) 187 + { 188 + PBYTE pb = imageBytes; 189 + for (int i = height - 1; i >= 0; i--) 190 + { 191 + png_bytep row = rows[i]; 192 + for (int j = 0; j < channels * width; j += channels) 193 + { 194 + *pb++ = row[j + 2]; /* Red */ 195 + *pb++ = row[j + 1]; /* Green */ 196 + *pb++ = row[j + 0]; /* Blue */ 197 + if (channels == 4) 198 + *pb++ = row[j + 3]; /* Alpha */ 199 + } 200 + pb += (channels * width) % 4; 201 + } 202 + } 203 + 204 + /* Clean up */ 205 + for (int i = 0; i < (int)height; i++) 206 + png_free(png_ptr, rows[i]); 207 + png_free(png_ptr, rows); 208 + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 209 + 210 + if (!imageBytes) 211 + { 212 + ERR("HeapAlloc failed\n"); 213 + return NULL; 214 + } 215 + 216 + /* BPP (Bits Per Pixel) */ 217 + WORD bpp = (WORD)(bitDepth * channels); 218 + 219 + /* The byte size of mask bits */ 220 + DWORD maskSize = get_dib_image_size(width, height, 1); 221 + 222 + /* Build BITMAPINFOHEADER */ 223 + BITMAPINFOHEADER info = { sizeof(info) }; 224 + info.biWidth = width; 225 + info.biHeight = 2 * height; 226 + info.biPlanes = 1; 227 + info.biBitCount = bpp; 228 + info.biCompression = BI_RGB; 229 + 230 + /* Build CURSORICONFILEDIR */ 231 + CURSORICONFILEDIR cifd = { 0, 1, 1 }; 232 + cifd.idEntries[0].bWidth = (BYTE)width; 233 + cifd.idEntries[0].bHeight = (BYTE)height; 234 + cifd.idEntries[0].bColorCount = 0; /* No color palette */ 235 + cifd.idEntries[0].wPlanes = 1; /* Must be 1 */ 236 + cifd.idEntries[0].wBitCount = bpp; 237 + cifd.idEntries[0].dwDIBSize = (DWORD)(sizeof(info) + imageSize + maskSize); 238 + cifd.idEntries[0].dwDIBOffset = (DWORD)sizeof(cifd); 239 + 240 + /* Allocate BMP icon data */ 241 + *pBmpIconSize = (DWORD)(sizeof(cifd) + sizeof(info) + imageSize + maskSize); 242 + PBYTE pbBmpIcon = HeapAlloc(GetProcessHeap(), 0, *pBmpIconSize); 243 + if (!pbBmpIcon) 244 + { 245 + ERR("HeapAlloc failed\n"); 246 + HeapFree(GetProcessHeap(), 0, imageBytes); 247 + return NULL; 248 + } 249 + 250 + /* Store data to pbBmpIcon */ 251 + PBYTE pb = pbBmpIcon; 252 + RtlCopyMemory(pb, &cifd, sizeof(cifd)); 253 + pb += sizeof(cifd); 254 + RtlCopyMemory(pb, &info, sizeof(info)); 255 + pb += sizeof(info); 256 + RtlCopyMemory(pb, imageBytes, imageSize); 257 + pb += imageSize; 258 + RtlFillMemory(pb, maskSize, 0xFF); /* Mask bits for AND operation */ 259 + 260 + HeapFree(GetProcessHeap(), 0, imageBytes); 261 + return pbBmpIcon; 262 + } 263 + 15 264 /* We only use Wide string functions */ 16 265 #undef MAKEINTRESOURCE 17 266 #define MAKEINTRESOURCE MAKEINTRESOURCEW ··· 221 470 } 222 471 if (memcmp(&header->biSize, png_sig_pattern, sizeof(png_sig_pattern)) == 0) 223 472 { 224 - ERR("Cannot yet display PNG icons\n"); 473 + TRACE("We have a PNG icon\n"); 225 474 /* for PNG format details see https://en.wikipedia.org/wiki/PNG */ 226 475 } 227 476 else ··· 469 718 return alpha; 470 719 } 471 720 472 - #include "pshpack1.h" 473 - 474 - typedef struct { 475 - BYTE bWidth; 476 - BYTE bHeight; 477 - BYTE bColorCount; 478 - BYTE bReserved; 479 - WORD xHotspot; 480 - WORD yHotspot; 481 - DWORD dwDIBSize; 482 - DWORD dwDIBOffset; 483 - } CURSORICONFILEDIRENTRY; 484 - 485 - typedef struct 486 - { 487 - WORD idReserved; 488 - WORD idType; 489 - WORD idCount; 490 - CURSORICONFILEDIRENTRY idEntries[1]; 491 - } CURSORICONFILEDIR; 492 - 493 - #include "poppack.h" 494 - 495 721 const CURSORICONFILEDIRENTRY* 496 722 get_best_icon_file_entry( 497 723 _In_ const CURSORICONFILEDIR* dir, ··· 1155 1381 ResSize = SizeofResource(hinst, hrsrc); 1156 1382 } 1157 1383 1384 + if (pbmi->bmiHeader.biCompression == BI_BITFIELDS && pbmi->bmiHeader.biBitCount == 32) 1385 + { 1386 + SIZE_T totalSize = pbmi->bmiHeader.biSize + (3 * sizeof(DWORD)) + 1387 + pbmi->bmiHeader.biSizeImage; 1388 + if (pbmi->bmiHeader.biSizeImage != 0 && totalSize != ResSize) 1389 + WARN("Possibly bad resource size provided\n"); 1390 + } 1391 + 1158 1392 /* Fix up values */ 1159 1393 if(DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr) == -1) 1160 1394 goto end; ··· 1385 1619 { 1386 1620 const CURSORICONFILEDIRENTRY *entry; 1387 1621 const CURSORICONFILEDIR *dir; 1388 - DWORD filesize = 0; 1389 - LPBYTE bits; 1622 + DWORD filesize = 0, BmpIconSize; 1623 + PBYTE bits, pbBmpIcon = NULL; 1390 1624 HANDLE hCurIcon = NULL; 1391 1625 CURSORDATA cursorData; 1392 1626 ··· 1418 1652 cursorData.xHotspot = entry->xHotspot; 1419 1653 cursorData.yHotspot = entry->yHotspot; 1420 1654 } 1421 - cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR)); 1655 + cursorData.rt = LOWORD(bIcon ? RT_ICON : RT_CURSOR); 1422 1656 1423 - /* Do the dance */ 1424 - if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)(&bits[entry->dwDIBOffset]))) 1657 + /* Try to load BMP icon */ 1658 + if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (PBITMAPINFO)(&bits[entry->dwDIBOffset]))) 1659 + { 1660 + /* Convert PNG raw data to BMP icon if the icon was PNG icon */ 1661 + PBYTE pngBits = &bits[entry->dwDIBOffset]; 1662 + pbBmpIcon = CURSORICON_ConvertPngToBmpIcon(pngBits, filesize, &BmpIconSize); 1663 + if (!pbBmpIcon) 1664 + goto end; /* Not PNG icon or failed */ 1665 + 1666 + /* Find icon entry from BMP icon */ 1667 + dir = (CURSORICONFILEDIR *)pbBmpIcon; 1668 + entry = &dir->idEntries[0]; /* Only one entry */ 1669 + 1670 + /* A bit of preparation */ 1671 + ZeroMemory(&cursorData, sizeof(cursorData)); 1672 + cursorData.rt = LOWORD(bIcon ? RT_ICON : RT_CURSOR); 1673 + 1674 + /* Can we load this BMP icon? */ 1675 + if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (PBITMAPINFO)(&pbBmpIcon[entry->dwDIBOffset]))) 1425 1676 { 1426 - ERR("Failing File is \n '%S'.\n", lpszName); 1677 + ERR("Failing file: '%S'.\n", lpszName); 1427 1678 goto end; 1428 1679 } 1429 1680 1681 + TRACE("Processing PNG/Vista icon: '%S'\n", lpszName); 1682 + } 1683 + 1430 1684 hCurIcon = NtUserxCreateEmptyCurObject(FALSE); 1431 1685 if(!hCurIcon) 1432 1686 goto end; ··· 1435 1689 if(!NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData)) 1436 1690 { 1437 1691 NtUserDestroyCursor(hCurIcon, TRUE); 1438 - goto end_error; 1692 + hCurIcon = NULL; 1439 1693 } 1440 1694 1441 1695 end: 1696 + if (!hCurIcon) 1697 + { 1698 + if (cursorData.hbmMask) DeleteObject(cursorData.hbmMask); 1699 + if (cursorData.hbmColor) DeleteObject(cursorData.hbmColor); 1700 + if (cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); 1701 + } 1702 + HeapFree(GetProcessHeap(), 0, pbBmpIcon); 1442 1703 UnmapViewOfFile(bits); 1443 1704 return hCurIcon; 1444 - 1445 - /* Clean up */ 1446 - end_error: 1447 - DeleteObject(cursorData.hbmMask); 1448 - if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); 1449 - if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); 1450 - UnmapViewOfFile(bits); 1451 - 1452 - return NULL; 1453 1705 } 1454 1706 1455 1707 static ··· 1514 1766 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1515 1767 return NULL; 1516 1768 } 1517 - ustrModule.Length = wsprintfW(ustrModule.Buffer, fakeNameFmt, hinst) * sizeof(WCHAR); 1769 + ustrModule.Length = (USHORT)wsprintfW(ustrModule.Buffer, fakeNameFmt, hinst) * sizeof(WCHAR); 1518 1770 } 1519 1771 else if(hinst) 1520 1772 { ··· 1545 1797 } 1546 1798 1547 1799 ustrModule.Buffer[ret] = UNICODE_NULL; 1548 - ustrModule.Length = ret * sizeof(WCHAR); 1549 - ustrModule.MaximumLength = size * sizeof(WCHAR); 1800 + ustrModule.Length = (USHORT)(ret * sizeof(WCHAR)); 1801 + ustrModule.MaximumLength = (USHORT)(size * sizeof(WCHAR)); 1550 1802 break; 1551 1803 } 1552 1804 } ··· 2539 2791 CURSORDATA cursorData; 2540 2792 HICON hIcon; 2541 2793 BOOL isAnimated; 2794 + PBYTE pbBmpIcon = NULL; 2795 + DWORD BmpIconSize; 2542 2796 2543 2797 TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags); 2544 2798 2799 + if (!pbIconBits || cbIconBits < 2 * sizeof(DWORD)) 2800 + { 2801 + ERR("Invalid IconBits array\n"); 2802 + return NULL; 2803 + } 2804 + 2545 2805 if(uFlags & LR_DEFAULTSIZE) 2546 2806 { 2547 2807 if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR); ··· 2551 2811 ZeroMemory(&cursorData, sizeof(cursorData)); 2552 2812 cursorData.cx = cxDesired; 2553 2813 cursorData.cy = cyDesired; 2554 - cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR)); 2814 + cursorData.rt = LOWORD(fIcon ? RT_ICON : RT_CURSOR); 2555 2815 2556 2816 /* Convert to win32k-ready data */ 2557 2817 if(!memcmp(pbIconBits, "RIFF", 4)) ··· 2622 2882 pbIconBits = (PBYTE)pt; 2623 2883 } 2624 2884 2625 - if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits)) 2885 + isAnimated = FALSE; 2886 + 2887 + /* Try to load BMP icon */ 2888 + if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (PBITMAPINFO)pbIconBits)) 2626 2889 { 2627 - ERR("Couldn't fill the CURSORDATA structure.\n"); 2628 - if (ResHandle) 2629 - FreeResource(ResHandle); 2630 - return NULL; 2890 + /* Convert PNG raw data to BMP icon if the icon was PNG icon */ 2891 + pbBmpIcon = CURSORICON_ConvertPngToBmpIcon(pbIconBits, cbIconBits, &BmpIconSize); 2892 + if (!pbBmpIcon) 2893 + return NULL; /* Not PNG icon or failed */ 2894 + 2895 + /* Find icon entry from BMP icon */ 2896 + CURSORICONFILEDIR *dir = (CURSORICONFILEDIR *)pbBmpIcon; 2897 + CURSORICONFILEDIRENTRY *entry = &dir->idEntries[0]; /* Only one entry */ 2898 + 2899 + /* A bit of preparation */ 2900 + RtlZeroMemory(&cursorData, sizeof(cursorData)); 2901 + cursorData.rt = LOWORD(fIcon ? RT_ICON : RT_CURSOR); 2902 + 2903 + /* Can we load this BMP icon? */ 2904 + if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (PBITMAPINFO)&pbBmpIcon[entry->dwDIBOffset])) 2905 + { 2906 + ERR("Couldn't get cursor/icon data\n"); 2907 + goto end_error; 2908 + } 2631 2909 } 2632 - if (ResHandle) 2633 - FreeResource(ResHandle); 2634 - isAnimated = FALSE; 2635 2910 } 2636 2911 2637 2912 if (uFlags & LR_SHARED) ··· 2651 2926 if(isAnimated) 2652 2927 HeapFree(GetProcessHeap(), 0, cursorData.aspcur); 2653 2928 2929 + HeapFree(GetProcessHeap(), 0, pbBmpIcon); 2654 2930 return hIcon; 2655 2931 2656 2932 /* Clean up */ 2657 2933 end_error: 2934 + HeapFree(GetProcessHeap(), 0, pbBmpIcon); 2658 2935 if(isAnimated) 2659 2936 HeapFree(GetProcessHeap(), 0, cursorData.aspcur); 2660 - DeleteObject(cursorData.hbmMask); 2661 - if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor); 2662 - if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); 2937 + if (cursorData.hbmMask) DeleteObject(cursorData.hbmMask); 2938 + if (cursorData.hbmColor) DeleteObject(cursorData.hbmColor); 2939 + if (cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha); 2663 2940 2664 2941 return NULL; 2665 2942 }