2 * MACDRV image functions
4 * Copyright 2013 Ken Thomases for CodeWeavers Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 WINE_DEFAULT_DEBUG_CHANNEL(image
);
33 /***********************************************************************
34 * create_cgimage_from_icon_bitmaps
36 CGImageRef
create_cgimage_from_icon_bitmaps(HDC hdc
, HANDLE icon
, HBITMAP hbmColor
,
37 unsigned char *color_bits
, int color_size
, HBITMAP hbmMask
,
38 unsigned char *mask_bits
, int mask_size
, int width
,
39 int height
, int istep
)
42 BOOL has_alpha
= FALSE
;
44 CGBitmapInfo alpha_format
;
45 CGColorSpaceRef colorspace
;
47 CGDataProviderRef provider
;
50 /* draw the cursor frame to a temporary buffer then create a CGImage from that */
51 memset(color_bits
, 0x00, color_size
);
52 NtGdiSelectBitmap(hdc
, hbmColor
);
53 if (!NtUserDrawIconEx(hdc
, 0, 0, icon
, width
, height
, istep
, NULL
, DI_NORMAL
))
55 WARN("Could not draw frame %d (walk past end of frames).\n", istep
);
59 /* check if the cursor frame was drawn with an alpha channel */
60 for (i
= 0, ptr
= (DWORD
*)color_bits
; i
< width
* height
; i
++, ptr
++)
61 if ((has_alpha
= (*ptr
& 0xff000000) != 0)) break;
64 alpha_format
= kCGImageAlphaFirst
;
66 alpha_format
= kCGImageAlphaNoneSkipFirst
;
68 colorspace
= CGColorSpaceCreateWithName(kCGColorSpaceSRGB
);
71 WARN("failed to create colorspace\n");
75 data
= CFDataCreate(NULL
, (UInt8
*)color_bits
, color_size
);
78 WARN("failed to create data\n");
79 CGColorSpaceRelease(colorspace
);
83 provider
= CGDataProviderCreateWithCFData(data
);
87 WARN("failed to create data provider\n");
88 CGColorSpaceRelease(colorspace
);
92 cgimage
= CGImageCreate(width
, height
, 8, 32, width
* 4, colorspace
,
93 alpha_format
| kCGBitmapByteOrder32Little
,
94 provider
, NULL
, FALSE
, kCGRenderingIntentDefault
);
95 CGDataProviderRelease(provider
);
96 CGColorSpaceRelease(colorspace
);
99 WARN("failed to create image\n");
103 /* if no alpha channel was drawn then generate it from the mask */
106 unsigned int width_bytes
= (width
+ 31) / 32 * 4;
107 CGImageRef cgmask
, temp
;
109 /* draw the cursor mask to a temporary buffer */
110 memset(mask_bits
, 0xFF, mask_size
);
111 NtGdiSelectBitmap(hdc
, hbmMask
);
112 if (!NtUserDrawIconEx(hdc
, 0, 0, icon
, width
, height
, istep
, NULL
, DI_MASK
))
114 WARN("Failed to draw frame mask %d.\n", istep
);
115 CGImageRelease(cgimage
);
119 data
= CFDataCreate(NULL
, (UInt8
*)mask_bits
, mask_size
);
122 WARN("failed to create data\n");
123 CGImageRelease(cgimage
);
127 provider
= CGDataProviderCreateWithCFData(data
);
131 WARN("failed to create data provider\n");
132 CGImageRelease(cgimage
);
136 cgmask
= CGImageMaskCreate(width
, height
, 1, 1, width_bytes
, provider
, NULL
, FALSE
);
137 CGDataProviderRelease(provider
);
140 WARN("failed to create mask\n");
141 CGImageRelease(cgimage
);
145 temp
= CGImageCreateWithMask(cgimage
, cgmask
);
146 CGImageRelease(cgmask
);
147 CGImageRelease(cgimage
);
150 WARN("failed to create masked image\n");
160 /***********************************************************************
161 * create_cgimage_from_icon
163 * Create a CGImage from a Windows icon.
165 CGImageRef
create_cgimage_from_icon(HANDLE icon
, int width
, int height
)
167 CGImageRef ret
= NULL
;
169 char buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
170 BITMAPINFO
*bitmapinfo
= (BITMAPINFO
*)buffer
;
171 unsigned char *color_bits
, *mask_bits
;
172 HBITMAP hbmColor
= 0, hbmMask
= 0;
173 int color_size
, mask_size
;
175 TRACE("icon %p width %d height %d\n", icon
, width
, height
);
177 if (!width
&& !height
)
182 if (!NtUserGetIconInfo(icon
, &info
, NULL
, NULL
, NULL
, 0))
185 NtGdiExtGetObjectW(info
.hbmMask
, sizeof(bm
), &bm
);
186 if (!info
.hbmColor
) bm
.bmHeight
= max(1, bm
.bmHeight
/ 2);
188 height
= bm
.bmHeight
;
189 TRACE("new width %d height %d\n", width
, height
);
191 NtGdiDeleteObjectApp(info
.hbmColor
);
192 NtGdiDeleteObjectApp(info
.hbmMask
);
195 hdc
= NtGdiCreateCompatibleDC(0);
197 bitmapinfo
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
198 bitmapinfo
->bmiHeader
.biWidth
= width
;
199 bitmapinfo
->bmiHeader
.biHeight
= -height
;
200 bitmapinfo
->bmiHeader
.biPlanes
= 1;
201 bitmapinfo
->bmiHeader
.biCompression
= BI_RGB
;
202 bitmapinfo
->bmiHeader
.biXPelsPerMeter
= 0;
203 bitmapinfo
->bmiHeader
.biYPelsPerMeter
= 0;
204 bitmapinfo
->bmiHeader
.biClrUsed
= 0;
205 bitmapinfo
->bmiHeader
.biClrImportant
= 0;
206 bitmapinfo
->bmiHeader
.biBitCount
= 32;
207 color_size
= width
* height
* 4;
208 bitmapinfo
->bmiHeader
.biSizeImage
= color_size
;
209 hbmColor
= NtGdiCreateDIBSection(hdc
, NULL
, 0, bitmapinfo
, DIB_RGB_COLORS
,
210 0, 0, 0, (void **)&color_bits
);
213 WARN("failed to create DIB section for cursor color data\n");
217 bitmapinfo
->bmiHeader
.biBitCount
= 1;
218 bitmapinfo
->bmiColors
[0].rgbRed
= 0;
219 bitmapinfo
->bmiColors
[0].rgbGreen
= 0;
220 bitmapinfo
->bmiColors
[0].rgbBlue
= 0;
221 bitmapinfo
->bmiColors
[0].rgbReserved
= 0;
222 bitmapinfo
->bmiColors
[1].rgbRed
= 0xff;
223 bitmapinfo
->bmiColors
[1].rgbGreen
= 0xff;
224 bitmapinfo
->bmiColors
[1].rgbBlue
= 0xff;
225 bitmapinfo
->bmiColors
[1].rgbReserved
= 0;
226 mask_size
= ((width
+ 31) / 32 * 4) * height
;
227 bitmapinfo
->bmiHeader
.biSizeImage
= mask_size
;
228 hbmMask
= NtGdiCreateDIBSection(hdc
, NULL
, 0, bitmapinfo
, DIB_RGB_COLORS
,
229 0, 0, 0, (void **)&mask_bits
);
232 WARN("failed to create DIB section for cursor mask data\n");
236 ret
= create_cgimage_from_icon_bitmaps(hdc
, icon
, hbmColor
, color_bits
, color_size
, hbmMask
,
237 mask_bits
, mask_size
, width
, height
, 0);
240 if (hbmColor
) NtGdiDeleteObjectApp(hbmColor
);
241 if (hbmMask
) NtGdiDeleteObjectApp(hbmMask
);
242 NtGdiDeleteObjectApp(hdc
);
247 /***********************************************************************
248 * create_app_icon_images
250 CFArrayRef
create_app_icon_images(void)
252 CFMutableArrayRef images
= NULL
;
253 struct app_icon_entry
*entries
;
260 if (KeUserModeCallback(client_func_app_icon
, NULL
, 0, (void**)&entries
, &ret_len
) ||
261 (ret_len
% sizeof(*entries
)))
263 WARN("incorrect callback result\n");
266 count
= ret_len
/ sizeof(*entries
);
267 if (!count
|| !entries
) return NULL
;
269 images
= CFArrayCreateMutable(NULL
, count
, &kCFTypeArrayCallBacks
);
272 WARN("failed to create images array\n");
276 for (i
= 0; i
< count
; i
++)
278 struct app_icon_entry
*icon
= &entries
[i
];
279 CGImageRef cgimage
= NULL
;
283 CFDataRef data
= CFDataCreate(NULL
, param_ptr(icon
->png
), icon
->size
);
286 CGDataProviderRef provider
= CGDataProviderCreateWithCFData(data
);
290 cgimage
= CGImageCreateWithPNGDataProvider(provider
, NULL
, FALSE
,
291 kCGRenderingIntentDefault
);
292 CGDataProviderRelease(provider
);
298 HICON handle
= UlongToHandle(icon
->icon
);
299 cgimage
= create_cgimage_from_icon(handle
, icon
->width
, icon
->height
);
300 NtUserDestroyCursor(handle
, 0);
305 CFArrayAppendValue(images
, cgimage
);
306 CGImageRelease(cgimage
);
310 if (images
&& !CFArrayGetCount(images
))