d2d1: Implement ID2D1DeviceContext::CreateImageBrush().
[wine.git] / dlls / winemac.drv / surface.c
blob6b0abb1078047e740a7fede623906368d1aafe47
1 /*
2 * Mac driver window surface implementation
4 * Copyright 1993, 1994, 2011 Alexandre Julliard
5 * Copyright 2006 Damjan Jovanovic
6 * Copyright 2012, 2013 Ken Thomases for CodeWeavers, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
25 #include "macdrv.h"
26 #include "winuser.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(macdrv);
31 /* only for use on sanitized BITMAPINFO structures */
32 static inline int get_dib_info_size(const BITMAPINFO *info, UINT coloruse)
34 if (info->bmiHeader.biCompression == BI_BITFIELDS)
35 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
36 if (coloruse == DIB_PAL_COLORS)
37 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
38 return FIELD_OFFSET(BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed]);
41 static inline int get_dib_stride(int width, int bpp)
43 return ((width * bpp + 31) >> 3) & ~3;
46 static inline int get_dib_image_size(const BITMAPINFO *info)
48 return get_dib_stride(info->bmiHeader.biWidth, info->bmiHeader.biBitCount)
49 * abs(info->bmiHeader.biHeight);
52 static inline void reset_bounds(RECT *bounds)
54 bounds->left = bounds->top = INT_MAX;
55 bounds->right = bounds->bottom = INT_MIN;
59 struct macdrv_window_surface
61 struct window_surface header;
62 macdrv_window window;
63 RECT bounds;
64 HRGN region;
65 HRGN drawn;
66 BOOL use_alpha;
67 RGNDATA *blit_data;
68 BYTE *bits;
69 pthread_mutex_t mutex;
70 BITMAPINFO info; /* variable size, must be last */
73 static struct macdrv_window_surface *get_mac_surface(struct window_surface *surface);
75 /***********************************************************************
76 * update_blit_data
78 static void update_blit_data(struct macdrv_window_surface *surface)
80 HeapFree(GetProcessHeap(), 0, surface->blit_data);
81 surface->blit_data = NULL;
83 if (surface->drawn)
85 HRGN blit = CreateRectRgn(0, 0, 0, 0);
87 if (CombineRgn(blit, surface->drawn, 0, RGN_COPY) > NULLREGION &&
88 (!surface->region || CombineRgn(blit, blit, surface->region, RGN_AND) > NULLREGION) &&
89 OffsetRgn(blit, surface->header.rect.left, surface->header.rect.top) > NULLREGION)
90 surface->blit_data = get_region_data(blit, 0);
92 DeleteObject(blit);
96 /***********************************************************************
97 * macdrv_surface_lock
99 static void macdrv_surface_lock(struct window_surface *window_surface)
101 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
103 pthread_mutex_lock(&surface->mutex);
106 /***********************************************************************
107 * macdrv_surface_unlock
109 static void macdrv_surface_unlock(struct window_surface *window_surface)
111 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
113 pthread_mutex_unlock(&surface->mutex);
116 /***********************************************************************
117 * macdrv_surface_get_bitmap_info
119 static void *macdrv_surface_get_bitmap_info(struct window_surface *window_surface,
120 BITMAPINFO *info)
122 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
124 memcpy(info, &surface->info, get_dib_info_size(&surface->info, DIB_RGB_COLORS));
125 return surface->bits;
128 /***********************************************************************
129 * macdrv_surface_get_bounds
131 static RECT *macdrv_surface_get_bounds(struct window_surface *window_surface)
133 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
135 return &surface->bounds;
138 /***********************************************************************
139 * macdrv_surface_set_region
141 static void macdrv_surface_set_region(struct window_surface *window_surface, HRGN region)
143 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
145 TRACE("updating surface %p with %p\n", surface, region);
147 window_surface->funcs->lock(window_surface);
149 if (region)
151 if (!surface->region) surface->region = CreateRectRgn(0, 0, 0, 0);
152 CombineRgn(surface->region, region, 0, RGN_COPY);
154 else
156 if (surface->region) DeleteObject(surface->region);
157 surface->region = 0;
159 update_blit_data(surface);
161 window_surface->funcs->unlock(window_surface);
164 /***********************************************************************
165 * macdrv_surface_flush
167 static void macdrv_surface_flush(struct window_surface *window_surface)
169 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
170 CGRect rect;
171 HRGN region;
173 window_surface->funcs->lock(window_surface);
175 TRACE("flushing %p %s bounds %s bits %p\n", surface, wine_dbgstr_rect(&surface->header.rect),
176 wine_dbgstr_rect(&surface->bounds), surface->bits);
178 rect = cgrect_from_rect(surface->bounds);
179 rect = CGRectOffset(rect, surface->header.rect.left, surface->header.rect.top);
181 if (!IsRectEmpty(&surface->bounds) && (region = CreateRectRgnIndirect(&surface->bounds)))
183 if (surface->drawn)
185 CombineRgn(surface->drawn, surface->drawn, region, RGN_OR);
186 DeleteObject(region);
188 else
189 surface->drawn = region;
191 update_blit_data(surface);
192 reset_bounds(&surface->bounds);
194 window_surface->funcs->unlock(window_surface);
196 if (!CGRectIsEmpty(rect))
197 macdrv_window_needs_display(surface->window, rect);
200 /***********************************************************************
201 * macdrv_surface_destroy
203 static void macdrv_surface_destroy(struct window_surface *window_surface)
205 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
207 TRACE("freeing %p bits %p\n", surface, surface->bits);
208 if (surface->region) DeleteObject(surface->region);
209 if (surface->drawn) DeleteObject(surface->drawn);
210 HeapFree(GetProcessHeap(), 0, surface->blit_data);
211 HeapFree(GetProcessHeap(), 0, surface->bits);
212 pthread_mutex_destroy(&surface->mutex);
213 HeapFree(GetProcessHeap(), 0, surface);
216 static const struct window_surface_funcs macdrv_surface_funcs =
218 macdrv_surface_lock,
219 macdrv_surface_unlock,
220 macdrv_surface_get_bitmap_info,
221 macdrv_surface_get_bounds,
222 macdrv_surface_set_region,
223 macdrv_surface_flush,
224 macdrv_surface_destroy,
227 static struct macdrv_window_surface *get_mac_surface(struct window_surface *surface)
229 if (!surface || surface->funcs != &macdrv_surface_funcs) return NULL;
230 return (struct macdrv_window_surface *)surface;
233 /***********************************************************************
234 * create_surface
236 struct window_surface *create_surface(macdrv_window window, const RECT *rect,
237 struct window_surface *old_surface, BOOL use_alpha)
239 struct macdrv_window_surface *surface;
240 struct macdrv_window_surface *old_mac_surface = get_mac_surface(old_surface);
241 int width = rect->right - rect->left, height = rect->bottom - rect->top;
242 DWORD *colors;
243 pthread_mutexattr_t attr;
244 int err;
245 DWORD window_background;
247 surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
248 FIELD_OFFSET(struct macdrv_window_surface, info.bmiColors[3]));
249 if (!surface) return NULL;
251 err = pthread_mutexattr_init(&attr);
252 if (!err)
254 err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
255 if (!err)
256 err = pthread_mutex_init(&surface->mutex, &attr);
257 pthread_mutexattr_destroy(&attr);
259 if (err)
261 HeapFree(GetProcessHeap(), 0, surface);
262 return NULL;
265 surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
266 surface->info.bmiHeader.biWidth = width;
267 surface->info.bmiHeader.biHeight = -height; /* top-down */
268 surface->info.bmiHeader.biPlanes = 1;
269 surface->info.bmiHeader.biBitCount = 32;
270 surface->info.bmiHeader.biSizeImage = get_dib_image_size(&surface->info);
271 surface->info.bmiHeader.biCompression = BI_RGB;
272 surface->info.bmiHeader.biClrUsed = 0;
274 colors = (DWORD *)((char *)&surface->info + surface->info.bmiHeader.biSize);
275 colors[0] = 0x00ff0000;
276 colors[1] = 0x0000ff00;
277 colors[2] = 0x000000ff;
279 surface->header.funcs = &macdrv_surface_funcs;
280 surface->header.rect = *rect;
281 surface->header.ref = 1;
282 surface->window = window;
283 reset_bounds(&surface->bounds);
284 if (old_mac_surface && old_mac_surface->drawn)
286 surface->drawn = CreateRectRgnIndirect(rect);
287 OffsetRgn(surface->drawn, -rect->left, -rect->top);
288 if (CombineRgn(surface->drawn, surface->drawn, old_mac_surface->drawn, RGN_AND) <= NULLREGION)
290 DeleteObject(surface->drawn);
291 surface->drawn = 0;
294 update_blit_data(surface);
295 surface->use_alpha = use_alpha;
296 surface->bits = HeapAlloc(GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage);
297 if (!surface->bits) goto failed;
298 window_background = macdrv_window_background_color();
299 memset_pattern4(surface->bits, &window_background, surface->info.bmiHeader.biSizeImage);
301 TRACE("created %p for %p %s bits %p-%p\n", surface, window, wine_dbgstr_rect(rect),
302 surface->bits, surface->bits + surface->info.bmiHeader.biSizeImage);
304 return &surface->header;
306 failed:
307 macdrv_surface_destroy(&surface->header);
308 return NULL;
311 /***********************************************************************
312 * set_surface_use_alpha
314 void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha)
316 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
317 if (surface) surface->use_alpha = use_alpha;
320 /***********************************************************************
321 * set_window_surface
323 void set_window_surface(macdrv_window window, struct window_surface *window_surface)
325 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
326 macdrv_set_window_surface(window, window_surface, surface ? &surface->mutex : NULL);
329 /***********************************************************************
330 * get_surface_blit_rects
332 * Caller must hold the surface lock. Indirectly returns the surface
333 * blit region rects. Returns zero if the surface has nothing to blit;
334 * returns non-zero if the surface does have rects to blit (drawn area
335 * which isn't clipped away by a surface region).
337 * IMPORTANT: This function is called from non-Wine threads, so it
338 * must not use Win32 or Wine functions, including debug
339 * logging.
341 int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count)
343 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
345 if (rects && count)
347 if (surface->blit_data)
349 *rects = (const CGRect*)surface->blit_data->Buffer;
350 *count = surface->blit_data->rdh.nCount;
352 else
354 *rects = NULL;
355 *count = 0;
359 return (surface->blit_data != NULL && surface->blit_data->rdh.nCount > 0);
362 /***********************************************************************
363 * create_surface_image
365 * Caller must hold the surface lock. On input, *rect is the requested
366 * image rect, relative to the window whole_rect, a.k.a. visible_rect.
367 * On output, it's been intersected with that part backed by the surface
368 * and is the actual size of the returned image. copy_data indicates if
369 * the caller will keep the returned image beyond the point where the
370 * surface bits can be guaranteed to remain valid and unchanged. If so,
371 * the bits are copied instead of merely referenced by the image.
373 * IMPORTANT: This function is called from non-Wine threads, so it
374 * must not use Win32 or Wine functions, including debug
375 * logging.
377 CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data, int color_keyed,
378 CGFloat key_red, CGFloat key_green, CGFloat key_blue)
380 CGImageRef cgimage = NULL;
381 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
382 int width, height;
384 width = surface->header.rect.right - surface->header.rect.left;
385 height = surface->header.rect.bottom - surface->header.rect.top;
386 *rect = CGRectIntersection(cgrect_from_rect(surface->header.rect), *rect);
387 if (!CGRectIsEmpty(*rect))
389 CGRect visrect;
390 CGColorSpaceRef colorspace;
391 CGDataProviderRef provider;
392 int bytes_per_row, offset, size;
393 CGImageAlphaInfo alphaInfo;
395 visrect = CGRectOffset(*rect, -surface->header.rect.left, -surface->header.rect.top);
397 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
398 bytes_per_row = get_dib_stride(width, 32);
399 offset = CGRectGetMinX(visrect) * 4 + CGRectGetMinY(visrect) * bytes_per_row;
400 size = min(CGRectGetHeight(visrect) * bytes_per_row,
401 surface->info.bmiHeader.biSizeImage - offset);
403 if (copy_data)
405 CFDataRef data = CFDataCreate(NULL, (UInt8*)surface->bits + offset, size);
406 provider = CGDataProviderCreateWithCFData(data);
407 CFRelease(data);
409 else
410 provider = CGDataProviderCreateWithData(NULL, surface->bits + offset, size, NULL);
412 alphaInfo = surface->use_alpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
413 cgimage = CGImageCreate(CGRectGetWidth(visrect), CGRectGetHeight(visrect),
414 8, 32, bytes_per_row, colorspace,
415 alphaInfo | kCGBitmapByteOrder32Little,
416 provider, NULL, retina_on, kCGRenderingIntentDefault);
417 CGDataProviderRelease(provider);
418 CGColorSpaceRelease(colorspace);
420 if (color_keyed)
422 CGImageRef maskedImage;
423 CGFloat components[] = { key_red - 0.5, key_red + 0.5,
424 key_green - 0.5, key_green + 0.5,
425 key_blue - 0.5, key_blue + 0.5 };
426 maskedImage = CGImageCreateWithMaskingColors(cgimage, components);
427 if (maskedImage)
429 CGImageRelease(cgimage);
430 cgimage = maskedImage;
435 return cgimage;
438 /***********************************************************************
439 * surface_clip_to_visible_rect
441 * Intersect the accumulated drawn region with a new visible rect,
442 * effectively discarding stale drawing in the surface slack area.
444 void surface_clip_to_visible_rect(struct window_surface *window_surface, const RECT *visible_rect)
446 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
448 if (!surface) return;
449 window_surface->funcs->lock(window_surface);
451 if (surface->drawn)
453 RECT rect;
454 HRGN region;
456 rect = *visible_rect;
457 OffsetRect(&rect, -rect.left, -rect.top);
459 if ((region = CreateRectRgnIndirect(&rect)))
461 CombineRgn(surface->drawn, surface->drawn, region, RGN_AND);
462 DeleteObject(region);
464 update_blit_data(surface);
468 window_surface->funcs->unlock(window_surface);