mfplat/sample: Optimize copying to 2d buffer.
[wine.git] / dlls / winemac.drv / image.c
blob6e2fcf1eaa2a4002f4263067fb0a61afe2ee64cd
1 /*
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
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include "macdrv.h"
28 #include "winuser.h"
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)
41 int i;
42 BOOL has_alpha = FALSE;
43 DWORD *ptr;
44 CGBitmapInfo alpha_format;
45 CGColorSpaceRef colorspace;
46 CFDataRef data;
47 CGDataProviderRef provider;
48 CGImageRef cgimage;
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);
56 return NULL;
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;
63 if (has_alpha)
64 alpha_format = kCGImageAlphaFirst;
65 else
66 alpha_format = kCGImageAlphaNoneSkipFirst;
68 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
69 if (!colorspace)
71 WARN("failed to create colorspace\n");
72 return NULL;
75 data = CFDataCreate(NULL, (UInt8*)color_bits, color_size);
76 if (!data)
78 WARN("failed to create data\n");
79 CGColorSpaceRelease(colorspace);
80 return NULL;
83 provider = CGDataProviderCreateWithCFData(data);
84 CFRelease(data);
85 if (!provider)
87 WARN("failed to create data provider\n");
88 CGColorSpaceRelease(colorspace);
89 return NULL;
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);
97 if (!cgimage)
99 WARN("failed to create image\n");
100 return NULL;
103 /* if no alpha channel was drawn then generate it from the mask */
104 if (!has_alpha)
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);
116 return NULL;
119 data = CFDataCreate(NULL, (UInt8*)mask_bits, mask_size);
120 if (!data)
122 WARN("failed to create data\n");
123 CGImageRelease(cgimage);
124 return NULL;
127 provider = CGDataProviderCreateWithCFData(data);
128 CFRelease(data);
129 if (!provider)
131 WARN("failed to create data provider\n");
132 CGImageRelease(cgimage);
133 return NULL;
136 cgmask = CGImageMaskCreate(width, height, 1, 1, width_bytes, provider, NULL, FALSE);
137 CGDataProviderRelease(provider);
138 if (!cgmask)
140 WARN("failed to create mask\n");
141 CGImageRelease(cgimage);
142 return NULL;
145 temp = CGImageCreateWithMask(cgimage, cgmask);
146 CGImageRelease(cgmask);
147 CGImageRelease(cgimage);
148 if (!temp)
150 WARN("failed to create masked image\n");
151 return NULL;
153 cgimage = temp;
156 return cgimage;
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;
168 HDC hdc;
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)
179 ICONINFO info;
180 BITMAP bm;
182 if (!NtUserGetIconInfo(icon, &info, NULL, NULL, NULL, 0))
183 return NULL;
185 NtGdiExtGetObjectW(info.hbmMask, sizeof(bm), &bm);
186 if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
187 width = bm.bmWidth;
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);
211 if (!hbmColor)
213 WARN("failed to create DIB section for cursor color data\n");
214 goto cleanup;
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);
230 if (!hbmMask)
232 WARN("failed to create DIB section for cursor mask data\n");
233 goto cleanup;
236 ret = create_cgimage_from_icon_bitmaps(hdc, icon, hbmColor, color_bits, color_size, hbmMask,
237 mask_bits, mask_size, width, height, 0);
239 cleanup:
240 if (hbmColor) NtGdiDeleteObjectApp(hbmColor);
241 if (hbmMask) NtGdiDeleteObjectApp(hbmMask);
242 NtGdiDeleteObjectApp(hdc);
243 return ret;
247 /***********************************************************************
248 * create_app_icon_images
250 CFArrayRef create_app_icon_images(void)
252 CFMutableArrayRef images = NULL;
253 struct app_icon_entry *entries;
254 ULONG ret_len;
255 unsigned count;
256 int i;
258 TRACE("()\n");
260 if (KeUserModeCallback(client_func_app_icon, NULL, 0, (void**)&entries, &ret_len) ||
261 (ret_len % sizeof(*entries)))
263 WARN("incorrect callback result\n");
264 return NULL;
266 count = ret_len / sizeof(*entries);
267 if (!count || !entries) return NULL;
269 images = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
270 if (!images)
272 WARN("failed to create images array\n");
273 return NULL;
276 for (i = 0; i < count; i++)
278 struct app_icon_entry *icon = &entries[i];
279 CGImageRef cgimage = NULL;
281 if (icon->png)
283 CFDataRef data = CFDataCreate(NULL, param_ptr(icon->png), icon->size);
284 if (data)
286 CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
287 CFRelease(data);
288 if (provider)
290 cgimage = CGImageCreateWithPNGDataProvider(provider, NULL, FALSE,
291 kCGRenderingIntentDefault);
292 CGDataProviderRelease(provider);
296 else
298 HICON handle = UlongToHandle(icon->icon);
299 cgimage = create_cgimage_from_icon(handle, icon->width, icon->height);
300 NtUserDestroyCursor(handle, 0);
303 if (cgimage)
305 CFArrayAppendValue(images, cgimage);
306 CGImageRelease(cgimage);
310 if (images && !CFArrayGetCount(images))
312 CFRelease(images);
313 images = NULL;
316 return images;