Revert "[USER32][LIBPNG] Support PNG/Vista icons (#7704)"

This reverts commit 7f4708479d.

- PR was still in review;
- Doug has commit access himself.
This commit is contained in:
Hermès Bélusca-Maïto 2025-02-07 15:20:05 +01:00
parent 7f4708479d
commit 468a9787d1
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
4 changed files with 60 additions and 565 deletions

View file

@ -5,8 +5,7 @@ include_directories(
${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys
include
${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine
${REACTOS_SOURCE_DIR}/win32ss/include
${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/libpng)
${REACTOS_SOURCE_DIR}/win32ss/include)
list(APPEND SOURCE
controls/appswitch.c
@ -89,7 +88,7 @@ if(MSVC AND (ARCH STREQUAL "i386"))
target_sources(user32 PRIVATE $<TARGET_OBJECTS:ftol2_sse>)
endif()
add_delay_importlibs(user32 usp10 libpng)
add_importlibs(user32 gdi32 advapi32 msvcrt kernel32 ntdll)
add_delay_importlibs(user32 usp10)
add_importlibs(user32 gdi32 advapi32 kernel32 ntdll)
add_pch(user32 include/user32.h SOURCE)
add_cd_file(TARGET user32 DESTINATION reactos/system32 FOR all)

View file

@ -1,244 +1,17 @@
/*
* PROJECT: ReactOS user32.dll
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: cursor and icons implementation
* COPYRIGHT: Copyright Jérôme Gardou (jerome.gardou@reactos.org)
* Copyright 2022-2025 Doug Lyons (douglyons@douglyons.com)
* Copyright 2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
* PROJECT: ReactOS user32.dll
* COPYRIGHT: GPL - See COPYING in the top level directory
* FILE: win32ss/user/user32/windows/cursoricon.c
* PURPOSE: cursor and icons implementation
* PROGRAMMER: Jérôme Gardou (jerome.gardou@reactos.org)
*/
#include <user32.h>
#include "png.h"
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
WINE_DECLARE_DEBUG_CHANNEL(icon);
//WINE_DECLARE_DEBUG_CHANNEL(resource);
#include <pshpack1.h>
typedef struct {
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
union
{
WORD wPlanes; /* For icons */
WORD xHotspot; /* For cursors */
};
union
{
WORD wBitCount; /* For icons */
WORD yHotspot; /* For cursors */
};
DWORD dwDIBSize;
DWORD dwDIBOffset;
} CURSORICONFILEDIRENTRY;
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
CURSORICONFILEDIRENTRY idEntries[1];
} CURSORICONFILEDIR;
#include <poppack.h>
#define PNG_CHECK_SIG_SIZE 8 /* Check signature size */
/* libpng helpers */
typedef struct {
png_bytep buffer;
size_t bufSize;
size_t currentPos;
} PNG_READER_STATE;
/* This function will be used for reading png data from memory */
static VOID
ReadMemoryPng(
_Inout_ png_structp png_ptr,
_Out_ png_bytep data,
_In_ size_t length)
{
PNG_READER_STATE *state = png_get_io_ptr(png_ptr);
if ((state->currentPos + length) > state->bufSize)
{
ERR("png read error\n");
png_error(png_ptr, "read error in ReadMemoryPng");
return;
}
RtlCopyMemory(data, state->buffer + state->currentPos, length);
state->currentPos += length;
}
static int get_dib_image_size(int width, int height, int depth);
/* Convert PNG raw data to BMP icon data */
static LPBYTE
CURSORICON_ConvertPngToBmpIcon(
_In_ LPBYTE pngBits,
_In_ DWORD fileSize,
_Out_ PDWORD pBmpIconSize)
{
if (!pngBits || fileSize < PNG_CHECK_SIG_SIZE || !png_check_sig(pngBits, PNG_CHECK_SIG_SIZE))
return NULL;
TRACE("pngBits %p fileSize %d\n", pngBits, fileSize);
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
ERR("png_create_read_struct error\n");
return NULL;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
ERR("png_create_info_struct error\n");
png_destroy_read_struct(&png_ptr, NULL, NULL);
return NULL;
}
/* Set our own read_function */
PNG_READER_STATE readerState = { pngBits, fileSize, PNG_CHECK_SIG_SIZE };
png_set_read_fn(png_ptr, &readerState, ReadMemoryPng);
png_set_sig_bytes(png_ptr, PNG_CHECK_SIG_SIZE);
/* Read png info */
png_read_info(png_ptr, info_ptr);
/* Add translation of some PNG formats and update info */
int colorType = png_get_color_type(png_ptr, info_ptr);
if (colorType == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png_ptr);
else if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
png_set_scale_16(png_ptr); /* Convert 16-bit channels to 8-bit */
png_read_update_info(png_ptr, info_ptr);
/* Get updated png info */
png_uint_32 width, height;
int bitDepth;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, NULL, NULL, NULL);
TRACE("width %d, height %d, bitDepth %d, colorType %d\n",
width, height, bitDepth, colorType);
int channels = png_get_channels(png_ptr, info_ptr);
int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
int imageSize = height * rowbytes;
TRACE("rowbytes %d, channels %d, imageSize %d\n", rowbytes, channels, imageSize);
/* Allocate rows data */
png_bytepp rows = png_malloc(png_ptr, sizeof(png_bytep) * height);
if (!rows)
{
ERR("png_malloc failed\n");
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
for (int i = 0; i < (int)height; i++)
{
rows[i] = png_malloc(png_ptr, rowbytes);
if (!rows[i])
{
ERR("png_malloc failed\n");
/* Clean up */
while (--i >= 0)
png_free(png_ptr, rows[i]);
png_free(png_ptr, rows);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return NULL;
}
}
/* Read png image data */
png_set_rows(png_ptr, info_ptr, rows);
png_read_image(png_ptr, rows);
png_read_end(png_ptr, info_ptr);
/* After reading the image, you can deal with row pointers */
LPBYTE imageBytes = HeapAlloc(GetProcessHeap(), 0, imageSize);
if (imageBytes)
{
LPBYTE pb = imageBytes;
for (int i = height - 1; i >= 0; i--)
{
png_bytep row = rows[i];
for (int j = 0; j < channels * width; j += channels)
{
*pb++ = row[j + 2]; /* Red */
*pb++ = row[j + 1]; /* Green */
*pb++ = row[j + 0]; /* Blue */
if (channels == 4)
*pb++ = row[j + 3]; /* Alpha */
}
pb += (channels * width) % 4;
}
}
/* Clean up */
for (int i = 0; i < (int)height; i++)
png_free(png_ptr, rows[i]);
png_free(png_ptr, rows);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
if (!imageBytes)
{
ERR("HeapAlloc failed\n");
return NULL;
}
/* BPP (Bits Per Pixel) */
WORD bpp = (WORD)(bitDepth * channels);
/* The byte size of mask bits */
DWORD maskSize = get_dib_image_size(width, height, 1);
/* Build BITMAPINFOHEADER */
BITMAPINFOHEADER info = { sizeof(info) };
info.biWidth = width;
info.biHeight = 2 * height;
info.biPlanes = 1;
info.biBitCount = bpp;
info.biCompression = BI_RGB;
/* Build CURSORICONFILEDIR */
CURSORICONFILEDIR cifd = { 0, 1, 1 };
cifd.idEntries[0].bWidth = (BYTE)width;
cifd.idEntries[0].bHeight = (BYTE)height;
cifd.idEntries[0].bColorCount = 0; /* No color pallete */
cifd.idEntries[0].wPlanes = 1; /* Must be 1 */
cifd.idEntries[0].wBitCount = bpp;
cifd.idEntries[0].dwDIBSize = (DWORD)(sizeof(info) + imageSize + maskSize);
cifd.idEntries[0].dwDIBOffset = (DWORD)sizeof(cifd);
/* Allocate BMP icon data */
*pBmpIconSize = (DWORD)(sizeof(cifd) + sizeof(info) + imageSize + maskSize);
LPBYTE pbBmpIcon = HeapAlloc(GetProcessHeap(), 0, *pBmpIconSize);
if (!pbBmpIcon)
{
ERR("HeapAlloc failed\n");
HeapFree(GetProcessHeap(), 0, imageBytes);
return NULL;
}
/* Store data to pbBmpIcon */
LPBYTE pb = pbBmpIcon;
RtlCopyMemory(pb, &cifd, sizeof(cifd));
pb += sizeof(cifd);
RtlCopyMemory(pb, &info, sizeof(info));
pb += sizeof(info);
RtlCopyMemory(pb, imageBytes, imageSize);
pb += imageSize;
RtlFillMemory(pb, maskSize, 0xFF); /* Mask bits for AND operation */
HeapFree(GetProcessHeap(), 0, imageBytes);
return pbBmpIcon;
}
/* We only use Wide string functions */
#undef MAKEINTRESOURCE
#define MAKEINTRESOURCE MAKEINTRESOURCEW
@ -448,7 +221,7 @@ static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
}
if (memcmp(&header->biSize, png_sig_pattern, sizeof(png_sig_pattern)) == 0)
{
TRACE("We have a PNG icon\n");
ERR("Cannot yet display PNG icons\n");
/* for PNG format details see https://en.wikipedia.org/wiki/PNG */
}
else
@ -696,6 +469,29 @@ done:
return alpha;
}
#include "pshpack1.h"
typedef struct {
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD xHotspot;
WORD yHotspot;
DWORD dwDIBSize;
DWORD dwDIBOffset;
} CURSORICONFILEDIRENTRY;
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
CURSORICONFILEDIRENTRY idEntries[1];
} CURSORICONFILEDIR;
#include "poppack.h"
const CURSORICONFILEDIRENTRY*
get_best_icon_file_entry(
_In_ const CURSORICONFILEDIR* dir,
@ -1359,14 +1155,6 @@ BITMAP_LoadImageW(
ResSize = SizeofResource(hinst, hrsrc);
}
if (pbmi->bmiHeader.biCompression == BI_BITFIELDS && pbmi->bmiHeader.biBitCount == 32)
{
SIZE_T totalSize = pbmi->bmiHeader.biSize + (3 * sizeof(DWORD)) +
pbmi->bmiHeader.biSizeImage;
if (pbmi->bmiHeader.biSizeImage != 0 && totalSize != ResSize)
WARN("Possibly bad resource size provided\n");
}
/* Fix up values */
if(DIB_GetBitmapInfo(&pbmi->bmiHeader, &width, &height, &bpp, &compr) == -1)
goto end;
@ -1597,8 +1385,8 @@ CURSORICON_LoadFromFileW(
{
const CURSORICONFILEDIRENTRY *entry;
const CURSORICONFILEDIR *dir;
DWORD filesize = 0, BmpIconSize;
LPBYTE bits, pbBmpIcon = NULL;
DWORD filesize = 0;
LPBYTE bits;
HANDLE hCurIcon = NULL;
CURSORDATA cursorData;
@ -1630,37 +1418,15 @@ CURSORICON_LoadFromFileW(
cursorData.xHotspot = entry->xHotspot;
cursorData.yHotspot = entry->yHotspot;
}
cursorData.rt = LOWORD(bIcon ? RT_ICON : RT_CURSOR);
cursorData.rt = (USHORT)((ULONG_PTR)(bIcon ? RT_ICON : RT_CURSOR));
/* Try to load BMP icon */
DWORD dwOffset = entry->dwDIBOffset;
if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO *)(&bits[dwOffset])))
{
/* Convert PNG raw data to BMP icon if the icon was PNG icon */
LPBYTE pngBits = &bits[entry->dwDIBOffset];
pbBmpIcon = CURSORICON_ConvertPngToBmpIcon(pngBits, filesize, &BmpIconSize);
if (!pbBmpIcon)
goto end; /* Not PNG icon or failed */
/* Find icon entry from BMP icon */
dir = (CURSORICONFILEDIR *)pbBmpIcon;
entry = &dir->idEntries[0]; /* Only one entry */
/* A bit of preparation */
RtlZeroMemory(&cursorData, sizeof(cursorData));
cursorData.rt = LOWORD(bIcon ? RT_ICON : RT_CURSOR);
/* Can we load this BMP icon? */
dwOffset = entry->dwDIBOffset;
if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO *)(&pbBmpIcon[dwOffset])))
/* Do the dance */
if(!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)(&bits[entry->dwDIBOffset])))
{
ERR("Failing file: '%S'.\n", lpszName);
ERR("Failing File is \n '%S'.\n", lpszName);
goto end;
}
TRACE("Processing PNG/Vista icon: '%S'\n", lpszName);
}
hCurIcon = NtUserxCreateEmptyCurObject(FALSE);
if(!hCurIcon)
goto end;
@ -1669,16 +1435,21 @@ CURSORICON_LoadFromFileW(
if(!NtUserSetCursorIconData(hCurIcon, NULL, NULL, &cursorData))
{
NtUserDestroyCursor(hCurIcon, TRUE);
hCurIcon = NULL;
if (cursorData.hbmMask) DeleteObject(cursorData.hbmMask);
if (cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
if (cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
goto end_error;
}
end:
UnmapViewOfFile(bits);
HeapFree(GetProcessHeap(), 0, pbBmpIcon);
return hCurIcon;
/* Clean up */
end_error:
DeleteObject(cursorData.hbmMask);
if(cursorData.hbmColor) DeleteObject(cursorData.hbmColor);
if(cursorData.hbmAlpha) DeleteObject(cursorData.hbmAlpha);
UnmapViewOfFile(bits);
return NULL;
}
static
@ -1743,7 +1514,7 @@ CURSORICON_LoadImageW(
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
ustrModule.Length = (USHORT)wsprintfW(ustrModule.Buffer, fakeNameFmt, hinst) * sizeof(WCHAR);
ustrModule.Length = wsprintfW(ustrModule.Buffer, fakeNameFmt, hinst) * sizeof(WCHAR);
}
else if(hinst)
{
@ -1774,8 +1545,8 @@ CURSORICON_LoadImageW(
}
ustrModule.Buffer[ret] = UNICODE_NULL;
ustrModule.Length = (USHORT)(ret * sizeof(WCHAR));
ustrModule.MaximumLength = (USHORT)(size * sizeof(WCHAR));
ustrModule.Length = ret * sizeof(WCHAR);
ustrModule.MaximumLength = size * sizeof(WCHAR);
break;
}
}
@ -2768,17 +2539,9 @@ HICON WINAPI CreateIconFromResourceEx(
CURSORDATA cursorData;
HICON hIcon;
BOOL isAnimated;
LPBYTE pbBmpIcon = NULL;
DWORD BmpIconSize;
TRACE("%p, %lu, %lu, %lu, %i, %i, %lu.\n", pbIconBits, cbIconBits, fIcon, dwVersion, cxDesired, cyDesired, uFlags);
if (!pbIconBits || cbIconBits < 2 * sizeof(DWORD))
{
ERR("Sanity check failed\n");
return NULL;
}
if(uFlags & LR_DEFAULTSIZE)
{
if(!cxDesired) cxDesired = GetSystemMetrics(fIcon ? SM_CXICON : SM_CXCURSOR);
@ -2788,7 +2551,7 @@ HICON WINAPI CreateIconFromResourceEx(
ZeroMemory(&cursorData, sizeof(cursorData));
cursorData.cx = cxDesired;
cursorData.cy = cyDesired;
cursorData.rt = LOWORD(fIcon ? RT_ICON : RT_CURSOR);
cursorData.rt = (USHORT)((ULONG_PTR)(fIcon ? RT_ICON : RT_CURSOR));
/* Convert to win32k-ready data */
if(!memcmp(pbIconBits, "RIFF", 4))
@ -2859,30 +2622,15 @@ HICON WINAPI CreateIconFromResourceEx(
pbIconBits = (PBYTE)pt;
}
/* Try to load BMP icon */
if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO *)pbIconBits))
if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO*)pbIconBits))
{
/* Convert PNG raw data to BMP icon if the icon was PNG icon */
pbBmpIcon = CURSORICON_ConvertPngToBmpIcon(pbIconBits, cbIconBits, &BmpIconSize);
if (!pbBmpIcon)
goto end; /* Not PNG icon or failed */
/* Find icon entry from BMP icon */
CURSORICONFILEDIR *dir = (CURSORICONFILEDIR *)pbBmpIcon;
CURSORICONFILEDIRENTRY *entry = &dir->idEntries[0]; /* Only one entry */
/* A bit of preparation */
RtlZeroMemory(&cursorData, sizeof(cursorData));
cursorData.rt = LOWORD(fIcon ? RT_ICON : RT_CURSOR);
/* Can we load this BMP icon? */
DWORD dwOffset = entry->dwDIBOffset;
if (!CURSORICON_GetCursorDataFromBMI(&cursorData, (BITMAPINFO *)&pbBmpIcon[dwOffset]))
{
ERR("Couldn't get cursor/icon data\n");
goto end;
}
ERR("Couldn't fill the CURSORDATA structure.\n");
if (ResHandle)
FreeResource(ResHandle);
return NULL;
}
if (ResHandle)
FreeResource(ResHandle);
isAnimated = FALSE;
}
@ -2903,13 +2651,10 @@ HICON WINAPI CreateIconFromResourceEx(
if(isAnimated)
HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
end:
HeapFree(GetProcessHeap(), 0, pbBmpIcon);
return hIcon;
/* Clean up */
end_error:
HeapFree(GetProcessHeap(), 0, pbBmpIcon);
if(isAnimated)
HeapFree(GetProcessHeap(), 0, cursorData.aspcur);
DeleteObject(cursorData.hbmMask);