user32: Add support for PNG icons.
Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
f80b1f45ff
commit
728255cf2c
|
@ -2,6 +2,7 @@ EXTRADEFS = -D_USER32_ -D_WINABLE_
|
||||||
MODULE = user32.dll
|
MODULE = user32.dll
|
||||||
IMPORTLIB = user32
|
IMPORTLIB = user32
|
||||||
IMPORTS = gdi32 version advapi32
|
IMPORTS = gdi32 version advapi32
|
||||||
|
EXTRAINCL = $(PNG_CFLAGS)
|
||||||
DELAYIMPORTS = imm32 usp10
|
DELAYIMPORTS = imm32 usp10
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
* Cursor and icon support
|
* Cursor and icon support
|
||||||
*
|
*
|
||||||
* Copyright 1995 Alexandre Julliard
|
* Copyright 1995 Alexandre Julliard
|
||||||
* 1996 Martin Von Loewis
|
* Copyright 1996 Martin Von Loewis
|
||||||
* 1997 Alex Korobka
|
* Copyright 1997 Alex Korobka
|
||||||
* 1998 Turchanov Sergey
|
* Copyright 1998 Turchanov Sergey
|
||||||
* 2007 Henri Verbeet
|
* Copyright 2007 Henri Verbeet
|
||||||
|
* Copyright 2009 Vincent Povirk for CodeWeavers
|
||||||
|
* Copyright 2016 Dmitry Timoshkov
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -29,6 +31,9 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#ifdef HAVE_PNG_H
|
||||||
|
#include <png.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
|
@ -43,11 +48,17 @@
|
||||||
#include "wine/list.h"
|
#include "wine/list.h"
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/library.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
|
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
|
||||||
WINE_DECLARE_DEBUG_CHANNEL(icon);
|
WINE_DECLARE_DEBUG_CHANNEL(icon);
|
||||||
WINE_DECLARE_DEBUG_CHANNEL(resource);
|
WINE_DECLARE_DEBUG_CHANNEL(resource);
|
||||||
|
|
||||||
|
#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 struct list icon_cache = LIST_INIT( icon_cache );
|
static struct list icon_cache = LIST_INIT( icon_cache );
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
@ -108,6 +119,303 @@ static int get_display_bpp(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
const char *buffer;
|
||||||
|
size_t 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_ptr, "failed to read PNG data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned be_uint(unsigned val)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
unsigned val;
|
||||||
|
unsigned char c[4];
|
||||||
|
} u;
|
||||||
|
|
||||||
|
u.val = val;
|
||||||
|
return (u.c[0] << 24) | (u.c[1] << 16) | (u.c[2] << 8) | u.c[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
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 };
|
||||||
|
static const char png_IHDR[8] = { 0,0,0,0x0d,'I','H','D','R' };
|
||||||
|
const struct
|
||||||
|
{
|
||||||
|
char png_sig[8];
|
||||||
|
char ihdr_sig[8];
|
||||||
|
unsigned width, height;
|
||||||
|
char bit_depth, color_type, compression, filter, interlace;
|
||||||
|
} *png = png_data;
|
||||||
|
|
||||||
|
if (size < sizeof(*png)) return FALSE;
|
||||||
|
if (memcmp(png->png_sig, png_sig, sizeof(png_sig)) != 0) return FALSE;
|
||||||
|
if (memcmp(png->ihdr_sig, png_IHDR, sizeof(png_IHDR)) != 0) return FALSE;
|
||||||
|
|
||||||
|
*bpp = (png->color_type == PNG_COLOR_TYPE_RGB_ALPHA) ? 32 : 24;
|
||||||
|
*width = be_uint(png->width);
|
||||||
|
*height = be_uint(png->height);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BITMAPINFO *load_png(const char *png_data, DWORD *size)
|
||||||
|
{
|
||||||
|
struct png_wrapper png;
|
||||||
|
png_structp png_ptr;
|
||||||
|
png_infop info_ptr;
|
||||||
|
png_bytep *row_pointers = NULL;
|
||||||
|
jmp_buf jmpbuf;
|
||||||
|
int color_type, bit_depth, bpp, width, height;
|
||||||
|
int rowbytes, image_size, mask_size = 0, i;
|
||||||
|
BITMAPINFO *info = NULL;
|
||||||
|
unsigned char *image_data;
|
||||||
|
|
||||||
|
if (!get_png_info(png_data, *size, &width, &height, &bpp))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!load_libpng()) return NULL;
|
||||||
|
|
||||||
|
png.buffer = png_data;
|
||||||
|
png.size = *size;
|
||||||
|
png.pos = 0;
|
||||||
|
|
||||||
|
/* initialize libpng */
|
||||||
|
png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (!png_ptr) return NULL;
|
||||||
|
|
||||||
|
info_ptr = ppng_create_info_struct(png_ptr);
|
||||||
|
if (!info_ptr)
|
||||||
|
{
|
||||||
|
ppng_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up setjmp/longjmp error handling */
|
||||||
|
if (setjmp(jmpbuf))
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, row_pointers);
|
||||||
|
HeapFree(GetProcessHeap(), 0, info);
|
||||||
|
ppng_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppng_set_error_fn(png_ptr, jmpbuf, user_error_fn, user_warning_fn);
|
||||||
|
ppng_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
|
||||||
|
|
||||||
|
/* set up custom i/o handling */
|
||||||
|
ppng_set_read_fn(png_ptr, &png, user_read_data);
|
||||||
|
|
||||||
|
/* read the header */
|
||||||
|
ppng_read_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
color_type = ppng_get_color_type(png_ptr, info_ptr);
|
||||||
|
bit_depth = ppng_get_bit_depth(png_ptr, 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_ptr);
|
||||||
|
|
||||||
|
/* expand palette image data to rgb */
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE || bit_depth < 8)
|
||||||
|
ppng_set_expand(png_ptr);
|
||||||
|
|
||||||
|
/* update color type information */
|
||||||
|
ppng_read_update_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
color_type = ppng_get_color_type(png_ptr, info_ptr);
|
||||||
|
bit_depth = ppng_get_bit_depth(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
bpp = 0;
|
||||||
|
|
||||||
|
switch (color_type)
|
||||||
|
{
|
||||||
|
case PNG_COLOR_TYPE_RGB:
|
||||||
|
if (bit_depth == 8)
|
||||||
|
bpp = 24;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||||
|
if (bit_depth == 8)
|
||||||
|
{
|
||||||
|
ppng_set_bgr(png_ptr);
|
||||||
|
bpp = 32;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bpp)
|
||||||
|
{
|
||||||
|
FIXME("unsupported PNG color format %d, %d bpp\n", color_type, bit_depth);
|
||||||
|
ppng_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
width = ppng_get_image_width(png_ptr, info_ptr);
|
||||||
|
height = ppng_get_image_height(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
rowbytes = (width * bpp + 7) / 8;
|
||||||
|
image_size = height * rowbytes;
|
||||||
|
if (bpp != 32) /* add a mask if there is no alpha */
|
||||||
|
mask_size = (width + 7) / 8 * height;
|
||||||
|
|
||||||
|
info = HeapAlloc(GetProcessHeap(), 0, sizeof(BITMAPINFOHEADER) + image_size + mask_size);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
ppng_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
image_data = (unsigned char *)info + sizeof(BITMAPINFOHEADER);
|
||||||
|
memset(image_data + image_size, 0, mask_size);
|
||||||
|
|
||||||
|
row_pointers = HeapAlloc(GetProcessHeap(), 0, height * sizeof(png_bytep));
|
||||||
|
if (!row_pointers)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, info);
|
||||||
|
ppng_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* upside down */
|
||||||
|
for (i = 0; i < height; i++)
|
||||||
|
row_pointers[i] = image_data + (height - i - 1) * rowbytes;
|
||||||
|
|
||||||
|
ppng_read_image(png_ptr, row_pointers);
|
||||||
|
HeapFree(GetProcessHeap(), 0, row_pointers);
|
||||||
|
ppng_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
|
||||||
|
info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
info->bmiHeader.biWidth = width;
|
||||||
|
info->bmiHeader.biHeight = height * 2;
|
||||||
|
info->bmiHeader.biPlanes = 1;
|
||||||
|
info->bmiHeader.biBitCount = 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;
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* SONAME_LIBPNG */
|
||||||
|
|
||||||
|
static BOOL get_png_info(const void *png_data, DWORD size, int *width, int *height, int *bpp)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BITMAPINFO *load_png( const char *png, DWORD *max_size )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static HICON alloc_icon_handle( BOOL is_ani, UINT num_steps )
|
static HICON alloc_icon_handle( BOOL is_ani, UINT num_steps )
|
||||||
{
|
{
|
||||||
struct cursoricon_object *obj;
|
struct cursoricon_object *obj;
|
||||||
|
@ -523,6 +831,8 @@ static int CURSORICON_FindBestIcon( LPCVOID dir, DWORD size, fnGetCIEntry get_en
|
||||||
/* Find Best Colors for Best Fit */
|
/* Find Best Colors for Best Fit */
|
||||||
for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ )
|
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)
|
if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
|
||||||
{
|
{
|
||||||
iTempColorDiff = abs(depth - bits);
|
iTempColorDiff = abs(depth - bits);
|
||||||
|
@ -680,6 +990,10 @@ static BOOL CURSORICON_GetFileEntry( LPCVOID dir, DWORD size, int n,
|
||||||
entry = &filedir->idEntries[n];
|
entry = &filedir->idEntries[n];
|
||||||
if (entry->dwDIBOffset > size - sizeof(info->biSize)) return FALSE;
|
if (entry->dwDIBOffset > size - sizeof(info->biSize)) return FALSE;
|
||||||
info = (const BITMAPINFOHEADER *)((const char *)dir + entry->dwDIBOffset);
|
info = (const BITMAPINFOHEADER *)((const char *)dir + entry->dwDIBOffset);
|
||||||
|
|
||||||
|
if (info->biSize == PNG_SIGN)
|
||||||
|
return get_png_info(info, size, width, height, bits);
|
||||||
|
|
||||||
if (info->biSize != sizeof(BITMAPCOREHEADER))
|
if (info->biSize != sizeof(BITMAPCOREHEADER))
|
||||||
{
|
{
|
||||||
if ((const char *)(info + 1) - (const char *)dir > size) return FALSE;
|
if ((const char *)(info + 1) - (const char *)dir > size) return FALSE;
|
||||||
|
@ -824,6 +1138,21 @@ static HICON create_icon_from_bmi( const BITMAPINFO *bmi, DWORD maxsize, HMODULE
|
||||||
|
|
||||||
/* Check bitmap header */
|
/* 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))
|
if (maxsize < sizeof(BITMAPCOREHEADER))
|
||||||
{
|
{
|
||||||
WARN( "invalid size %u\n", maxsize );
|
WARN( "invalid size %u\n", maxsize );
|
||||||
|
@ -1001,10 +1330,6 @@ done:
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* .ANI cursor support
|
* .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_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
|
||||||
#define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
|
#define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
|
||||||
#define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
|
#define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
|
||||||
|
|
Loading…
Reference in New Issue