mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
Added patch to implement support for loading PNG icon files.
This commit is contained in:
parent
38db26b6d9
commit
b4a404a22a
@ -327,6 +327,7 @@ patch_enable_all ()
|
||||
enable_user32_ListBox_Size="$1"
|
||||
enable_user32_MessageBox_WS_EX_TOPMOST="$1"
|
||||
enable_user32_Mouse_Message_Hwnd="$1"
|
||||
enable_user32_PNG_Support="$1"
|
||||
enable_user32_Refresh_MDI_Menus="$1"
|
||||
enable_user32_ScrollWindowEx="$1"
|
||||
enable_user32_SetCoalescableTimer="$1"
|
||||
@ -1152,6 +1153,9 @@ patch_enable ()
|
||||
user32-Mouse_Message_Hwnd)
|
||||
enable_user32_Mouse_Message_Hwnd="$2"
|
||||
;;
|
||||
user32-PNG_Support)
|
||||
enable_user32_PNG_Support="$2"
|
||||
;;
|
||||
user32-Refresh_MDI_Menus)
|
||||
enable_user32_Refresh_MDI_Menus="$2"
|
||||
;;
|
||||
@ -6736,6 +6740,21 @@ if test "$enable_user32_Mouse_Message_Hwnd" -eq 1; then
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset user32-PNG_Support
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
# | * [#38959] Add support for loading PNG icon files
|
||||
# |
|
||||
# | Modified files:
|
||||
# | * dlls/user32/cursoricon.c
|
||||
# |
|
||||
if test "$enable_user32_PNG_Support" -eq 1; then
|
||||
patch_apply user32-PNG_Support/0001-user32-Add-support-for-PNG-icons.-v4.patch
|
||||
(
|
||||
echo '+ { "Dmitry Timoshkov", "user32: Add support for PNG icons.", 5 },';
|
||||
) >> "$patchlist"
|
||||
fi
|
||||
|
||||
# Patchset user32-Refresh_MDI_Menus
|
||||
# |
|
||||
# | This patchset fixes the following Wine bugs:
|
||||
|
@ -0,0 +1,418 @@
|
||||
From 58d0e4f6ca6beaa0e0e470fb288780c0001d58b3 Mon Sep 17 00:00:00 2001
|
||||
From: Dmitry Timoshkov <dmitry@baikal.ru>
|
||||
Date: Thu, 7 Apr 2016 21:18:44 +0800
|
||||
Subject: user32: Add support for PNG icons. (v5)
|
||||
|
||||
---
|
||||
dlls/user32/cursoricon.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 334 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dlls/user32/cursoricon.c b/dlls/user32/cursoricon.c
|
||||
index 4de6b28..a8cd135 100644
|
||||
--- a/dlls/user32/cursoricon.c
|
||||
+++ b/dlls/user32/cursoricon.c
|
||||
@@ -6,6 +6,8 @@
|
||||
* 1997 Alex Korobka
|
||||
* 1998 Turchanov Sergey
|
||||
* 2007 Henri Verbeet
|
||||
+ * Copyright 2009 Vincent Povirk for CodeWeavers
|
||||
+ * Copyright 2016 Dmitry Timoshkov
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -29,6 +31,9 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
+#ifdef HAVE_PNG_H
|
||||
+#include <png.h>
|
||||
+#endif
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
@@ -43,6 +48,7 @@
|
||||
#include "wine/list.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/debug.h"
|
||||
+#include "wine/library.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(icon);
|
||||
@@ -71,6 +77,11 @@ typedef struct
|
||||
|
||||
#include "poppack.h"
|
||||
|
||||
+#define RIFF_FOURCC( c0, c1, c2, c3 ) \
|
||||
+ ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
|
||||
+ ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
|
||||
+#define PNG_SIGN RIFF_FOURCC(0x89,'P','N','G')
|
||||
+
|
||||
static HDC screen_dc;
|
||||
|
||||
static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
|
||||
@@ -119,6 +130,307 @@ struct animated_cursoricon_object
|
||||
HICON frames[1]; /* list of animated cursor frames */
|
||||
};
|
||||
|
||||
+#ifdef SONAME_LIBPNG
|
||||
+
|
||||
+static void *libpng_handle;
|
||||
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f
|
||||
+MAKE_FUNCPTR(png_create_read_struct);
|
||||
+MAKE_FUNCPTR(png_create_info_struct);
|
||||
+MAKE_FUNCPTR(png_destroy_read_struct);
|
||||
+MAKE_FUNCPTR(png_error);
|
||||
+MAKE_FUNCPTR(png_get_bit_depth);
|
||||
+MAKE_FUNCPTR(png_get_color_type);
|
||||
+MAKE_FUNCPTR(png_get_error_ptr);
|
||||
+MAKE_FUNCPTR(png_get_image_height);
|
||||
+MAKE_FUNCPTR(png_get_image_width);
|
||||
+MAKE_FUNCPTR(png_get_io_ptr);
|
||||
+MAKE_FUNCPTR(png_read_image);
|
||||
+MAKE_FUNCPTR(png_read_info);
|
||||
+MAKE_FUNCPTR(png_read_update_info);
|
||||
+MAKE_FUNCPTR(png_set_bgr);
|
||||
+MAKE_FUNCPTR(png_set_crc_action);
|
||||
+MAKE_FUNCPTR(png_set_error_fn);
|
||||
+MAKE_FUNCPTR(png_set_expand);
|
||||
+MAKE_FUNCPTR(png_set_gray_to_rgb);
|
||||
+MAKE_FUNCPTR(png_set_read_fn);
|
||||
+#undef MAKE_FUNCPTR
|
||||
+
|
||||
+static BOOL load_libpng(void)
|
||||
+{
|
||||
+ USER_Lock();
|
||||
+
|
||||
+ if (!libpng_handle && (libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL)
|
||||
+ {
|
||||
+#define LOAD_FUNCPTR(f) \
|
||||
+ if ((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) \
|
||||
+ { \
|
||||
+ libpng_handle = NULL; \
|
||||
+ USER_Unlock(); \
|
||||
+ return FALSE; \
|
||||
+ }
|
||||
+ LOAD_FUNCPTR(png_create_read_struct);
|
||||
+ LOAD_FUNCPTR(png_create_info_struct);
|
||||
+ LOAD_FUNCPTR(png_destroy_read_struct);
|
||||
+ LOAD_FUNCPTR(png_error);
|
||||
+ LOAD_FUNCPTR(png_get_bit_depth);
|
||||
+ LOAD_FUNCPTR(png_get_color_type);
|
||||
+ LOAD_FUNCPTR(png_get_error_ptr);
|
||||
+ LOAD_FUNCPTR(png_get_image_height);
|
||||
+ LOAD_FUNCPTR(png_get_image_width);
|
||||
+ LOAD_FUNCPTR(png_get_io_ptr);
|
||||
+ LOAD_FUNCPTR(png_read_image);
|
||||
+ LOAD_FUNCPTR(png_read_info);
|
||||
+ LOAD_FUNCPTR(png_read_update_info);
|
||||
+ LOAD_FUNCPTR(png_set_bgr);
|
||||
+ LOAD_FUNCPTR(png_set_crc_action);
|
||||
+ LOAD_FUNCPTR(png_set_error_fn);
|
||||
+ LOAD_FUNCPTR(png_set_expand);
|
||||
+ LOAD_FUNCPTR(png_set_gray_to_rgb);
|
||||
+ LOAD_FUNCPTR(png_set_read_fn);
|
||||
+#undef LOAD_FUNCPTR
|
||||
+ }
|
||||
+
|
||||
+ USER_Unlock();
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void user_error_fn(png_structp png_ptr, png_const_charp error_message)
|
||||
+{
|
||||
+ jmp_buf *pjmpbuf;
|
||||
+
|
||||
+ /* This uses setjmp/longjmp just like the default. We can't use the
|
||||
+ * default because there's no way to access the jmp buffer in the png_struct
|
||||
+ * that works in 1.2 and 1.4 and allows us to dynamically load libpng. */
|
||||
+ WARN("PNG error: %s\n", debugstr_a(error_message));
|
||||
+ pjmpbuf = ppng_get_error_ptr(png_ptr);
|
||||
+ longjmp(*pjmpbuf, 1);
|
||||
+}
|
||||
+
|
||||
+static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message)
|
||||
+{
|
||||
+ WARN("PNG warning: %s\n", debugstr_a(warning_message));
|
||||
+}
|
||||
+
|
||||
+struct png_wrapper
|
||||
+{
|
||||
+ png_structp png_ptr;
|
||||
+ png_infop info_ptr;
|
||||
+ int width, height, bpp;
|
||||
+ const char *buffer;
|
||||
+ int size, pos;
|
||||
+};
|
||||
+
|
||||
+static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
+{
|
||||
+ struct png_wrapper *png = ppng_get_io_ptr(png_ptr);
|
||||
+
|
||||
+ if (png->size - png->pos >= length)
|
||||
+ {
|
||||
+ memcpy(data, png->buffer + png->pos, length);
|
||||
+ png->pos += length;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ ppng_error(png->png_ptr, "failed to read PNG data");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static BOOL create_png_decoder(struct png_wrapper *png)
|
||||
+{
|
||||
+ jmp_buf jmpbuf;
|
||||
+ int color_type, bit_depth;
|
||||
+
|
||||
+ if (!load_libpng()) return FALSE;
|
||||
+
|
||||
+ /* initialize libpng */
|
||||
+ png->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
+ if (!png->png_ptr) return FALSE;
|
||||
+
|
||||
+ png->info_ptr = ppng_create_info_struct(png->png_ptr);
|
||||
+ if (!png->info_ptr)
|
||||
+ {
|
||||
+ ppng_destroy_read_struct(&png->png_ptr, NULL, NULL);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ /* set up setjmp/longjmp error handling */
|
||||
+ if (setjmp(jmpbuf))
|
||||
+ {
|
||||
+ ppng_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ ppng_set_error_fn(png->png_ptr, jmpbuf, user_error_fn, user_warning_fn);
|
||||
+ ppng_set_crc_action(png->png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
|
||||
+
|
||||
+ /* set up custom i/o handling */
|
||||
+ ppng_set_read_fn(png->png_ptr, png, user_read_data);
|
||||
+
|
||||
+ /* read the header */
|
||||
+ ppng_read_info(png->png_ptr, png->info_ptr);
|
||||
+
|
||||
+ color_type = ppng_get_color_type(png->png_ptr, png->info_ptr);
|
||||
+ bit_depth = ppng_get_bit_depth(png->png_ptr, png->info_ptr);
|
||||
+
|
||||
+ /* expand grayscale image data to rgb */
|
||||
+ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
+ ppng_set_gray_to_rgb(png->png_ptr);
|
||||
+
|
||||
+ /* expand palette image data to rgb */
|
||||
+ if (color_type == PNG_COLOR_TYPE_PALETTE || bit_depth < 8)
|
||||
+ ppng_set_expand(png->png_ptr);
|
||||
+
|
||||
+ /* update color type information */
|
||||
+ ppng_read_update_info(png->png_ptr, png->info_ptr);
|
||||
+
|
||||
+ color_type = ppng_get_color_type(png->png_ptr, png->info_ptr);
|
||||
+ bit_depth = ppng_get_bit_depth(png->png_ptr, png->info_ptr);
|
||||
+
|
||||
+ png->bpp = 0;
|
||||
+
|
||||
+ switch (color_type)
|
||||
+ {
|
||||
+ case PNG_COLOR_TYPE_RGB:
|
||||
+ if (bit_depth == 8)
|
||||
+ png->bpp = 24;
|
||||
+ break;
|
||||
+
|
||||
+ case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
+ if (bit_depth == 8)
|
||||
+ {
|
||||
+ ppng_set_bgr(png->png_ptr);
|
||||
+ png->bpp = 32;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (!png->bpp)
|
||||
+ {
|
||||
+ FIXME("unsupported PNG color format %d, %d bpp\n", color_type, bit_depth);
|
||||
+ ppng_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ png->width = ppng_get_image_width(png->png_ptr, png->info_ptr);
|
||||
+ png->height = ppng_get_image_height(png->png_ptr, png->info_ptr);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void destroy_png_decoder(struct png_wrapper *png)
|
||||
+{
|
||||
+ ppng_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
|
||||
+}
|
||||
+
|
||||
+static BOOL get_png_info(const void *png_data, DWORD size, int *width, int *height, int *bpp)
|
||||
+{
|
||||
+ static const char png_sig[8] = { 0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a };
|
||||
+ struct png_wrapper png;
|
||||
+
|
||||
+ if (size < sizeof(png_sig) || memcmp(png_data, png_sig, sizeof(png_sig)) != 0)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ png.buffer = png_data;
|
||||
+ png.size = size;
|
||||
+ png.pos = 0;
|
||||
+
|
||||
+ if (!create_png_decoder(&png)) return FALSE;
|
||||
+
|
||||
+ *width = png.width;
|
||||
+ *height = png.height;
|
||||
+ *bpp = png.bpp;
|
||||
+
|
||||
+ destroy_png_decoder(&png);
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static BITMAPINFO *load_png(const char *png_data, DWORD *size)
|
||||
+{
|
||||
+ static const char png_sig[8] = { 0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a };
|
||||
+ struct png_wrapper png;
|
||||
+ png_bytep *row_pointers;
|
||||
+ int rowbytes, image_size, mask_size = 0, i;
|
||||
+ BITMAPINFO *info;
|
||||
+ unsigned char *image_data;
|
||||
+
|
||||
+ if (*size < sizeof(png_sig) || memcmp(png_data, png_sig, sizeof(png_sig)) != 0)
|
||||
+ return NULL;
|
||||
+
|
||||
+ png.buffer = png_data;
|
||||
+ png.size = *size;
|
||||
+ png.pos = 0;
|
||||
+
|
||||
+ if (!create_png_decoder(&png)) return NULL;
|
||||
+
|
||||
+ rowbytes = (png.width * png.bpp + 7) / 8;
|
||||
+ image_size = png.height * rowbytes;
|
||||
+ if (png.bpp != 32) /* add a mask if there is no alpha */
|
||||
+ mask_size = (png.width + 7) / 8 * png.height;
|
||||
+
|
||||
+ info = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) + image_size + mask_size);
|
||||
+ if (!info)
|
||||
+ {
|
||||
+ destroy_png_decoder(&png);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ image_data = (unsigned char *)info + sizeof(BITMAPINFOHEADER);
|
||||
+ memset(image_data + image_size, 0, mask_size);
|
||||
+
|
||||
+ row_pointers = HeapAlloc(GetProcessHeap(), 0, png.height * sizeof(png_bytep));
|
||||
+ if (!row_pointers)
|
||||
+ {
|
||||
+ HeapFree(GetProcessHeap(), 0, info);
|
||||
+ destroy_png_decoder(&png);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* upside down */
|
||||
+ for (i = 0; i < png.height; i++)
|
||||
+ row_pointers[i] = image_data + (png.height - i - 1) * rowbytes;
|
||||
+
|
||||
+ ppng_read_image(png.png_ptr, row_pointers);
|
||||
+
|
||||
+ HeapFree(GetProcessHeap(), 0, row_pointers);
|
||||
+
|
||||
+ info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
+ info->bmiHeader.biWidth = png.width;
|
||||
+ info->bmiHeader.biHeight = png.height * 2;
|
||||
+ info->bmiHeader.biPlanes = 1;
|
||||
+ info->bmiHeader.biBitCount = png.bpp;
|
||||
+ info->bmiHeader.biCompression = BI_RGB;
|
||||
+ info->bmiHeader.biSizeImage = image_size;
|
||||
+ info->bmiHeader.biXPelsPerMeter = 0;
|
||||
+ info->bmiHeader.biYPelsPerMeter = 0;
|
||||
+ info->bmiHeader.biClrUsed = 0;
|
||||
+ info->bmiHeader.biClrImportant = 0;
|
||||
+
|
||||
+ *size = sizeof(BITMAPINFOHEADER) + image_size + mask_size;
|
||||
+
|
||||
+ destroy_png_decoder(&png);
|
||||
+
|
||||
+ return info;
|
||||
+}
|
||||
+
|
||||
+#else /* SONAME_LIBPNG */
|
||||
+
|
||||
+static BOOL get_png_info(const void *png_data, DWORD size, int *width, int *height, int *bpp)
|
||||
+{
|
||||
+ ERR("Trying to load PNG icon, but PNG support is not compiled in.\n");
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static BITMAPINFO *load_png( const char *png, DWORD *max_size )
|
||||
+{
|
||||
+ ERR("Trying to load PNG icon, but PNG support is not compiled in.\n");
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
static HICON alloc_icon_handle( BOOL is_ani, UINT num_steps )
|
||||
{
|
||||
struct cursoricon_object *obj;
|
||||
@@ -534,6 +846,8 @@ static int CURSORICON_FindBestIcon( LPCVOID dir, DWORD size, fnGetCIEntry get_en
|
||||
/* Find Best Colors for Best Fit */
|
||||
for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ )
|
||||
{
|
||||
+ TRACE("entry %d: %d x %d, %d bpp\n", i, cx, cy, bits);
|
||||
+
|
||||
if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
|
||||
{
|
||||
iTempColorDiff = abs(depth - bits);
|
||||
@@ -678,7 +992,11 @@ static BOOL CURSORICON_GetFileEntry( LPCVOID dir, DWORD size, int n,
|
||||
return FALSE;
|
||||
entry = &filedir->idEntries[n];
|
||||
info = (const BITMAPINFOHEADER *)((const char *)dir + entry->dwDIBOffset);
|
||||
- if (info->biSize != sizeof(BITMAPCOREHEADER))
|
||||
+ if (info->biSize == PNG_SIGN)
|
||||
+ {
|
||||
+ return get_png_info(info, size, width, height, bits);
|
||||
+ }
|
||||
+ else if (info->biSize != sizeof(BITMAPCOREHEADER))
|
||||
{
|
||||
if ((const char *)(info + 1) - (const char *)dir > size) return FALSE;
|
||||
*bits = info->biBitCount;
|
||||
@@ -822,6 +1140,21 @@ static HICON create_icon_from_bmi( const BITMAPINFO *bmi, DWORD maxsize, HMODULE
|
||||
|
||||
/* Check bitmap header */
|
||||
|
||||
+ if (bmi->bmiHeader.biSize == PNG_SIGN)
|
||||
+ {
|
||||
+ BITMAPINFO *bmi_png;
|
||||
+
|
||||
+ bmi_png = load_png( (const char *)bmi, &maxsize );
|
||||
+ if (bmi_png)
|
||||
+ {
|
||||
+ hObj = create_icon_from_bmi( bmi_png, maxsize, module, resname,
|
||||
+ rsrc, hotspot, bIcon, width, height, cFlag );
|
||||
+ HeapFree( GetProcessHeap(), 0, bmi_png );
|
||||
+ return hObj;
|
||||
+ }
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
if (maxsize < sizeof(BITMAPCOREHEADER))
|
||||
{
|
||||
WARN( "invalid size %u\n", maxsize );
|
||||
@@ -1003,10 +1336,6 @@ done:
|
||||
/**********************************************************************
|
||||
* .ANI cursor support
|
||||
*/
|
||||
-#define RIFF_FOURCC( c0, c1, c2, c3 ) \
|
||||
- ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
|
||||
- ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
|
||||
-
|
||||
#define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
|
||||
#define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
|
||||
#define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
|
||||
--
|
||||
2.7.1
|
||||
|
1
patches/user32-PNG_Support/definition
Normal file
1
patches/user32-PNG_Support/definition
Normal file
@ -0,0 +1 @@
|
||||
Fixes: [38959] Add support for loading PNG icon files
|
Loading…
Reference in New Issue
Block a user