Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
728255cf
Commit
728255cf
authored
Apr 03, 2018
by
Dmitry Timoshkov
Committed by
Alexandre Julliard
Apr 03, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
user32: Add support for PNG icons.
Signed-off-by:
Dmitry Timoshkov
<
dmitry@baikal.ru
>
Signed-off-by:
Alexandre Julliard
<
julliard@winehq.org
>
parent
f80b1f45
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
334 additions
and
8 deletions
+334
-8
Makefile.in
dlls/user32/Makefile.in
+1
-0
cursoricon.c
dlls/user32/cursoricon.c
+333
-8
No files found.
dlls/user32/Makefile.in
View file @
728255cf
...
...
@@ -2,6 +2,7 @@ EXTRADEFS = -D_USER32_ -D_WINABLE_
MODULE
=
user32.dll
IMPORTLIB
=
user32
IMPORTS
=
gdi32 version advapi32
EXTRAINCL
=
$(PNG_CFLAGS)
DELAYIMPORTS
=
imm32 usp10
C_SRCS
=
\
...
...
dlls/user32/cursoricon.c
View file @
728255cf
...
...
@@ -2,10 +2,12 @@
* Cursor and icon support
*
* Copyright 1995 Alexandre Julliard
* 1996 Martin Von Loewis
* 1997 Alex Korobka
* 1998 Turchanov Sergey
* 2007 Henri Verbeet
* Copyright 1996 Martin Von Loewis
* Copyright 1997 Alex Korobka
* Copyright 1998 Turchanov Sergey
* 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
* 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,11 +48,17 @@
#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
);
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
);
/**********************************************************************
...
...
@@ -108,6 +119,303 @@ static int get_display_bpp(void)
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
)
{
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 */
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
);
...
...
@@ -680,6 +990,10 @@ static BOOL CURSORICON_GetFileEntry( LPCVOID dir, DWORD size, int n,
entry
=
&
filedir
->
idEntries
[
n
];
if
(
entry
->
dwDIBOffset
>
size
-
sizeof
(
info
->
biSize
))
return
FALSE
;
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
((
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 */
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
);
...
...
@@ -1001,10 +1330,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')
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment