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
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;
67 pthread_mutex_t mutex;
68 BITMAPINFO info; /* variable size, must be last */
71 static struct macdrv_window_surface *get_mac_surface(struct window_surface *surface)
73 return (struct macdrv_window_surface *)surface;
76 /***********************************************************************
79 static void macdrv_surface_lock(struct window_surface *window_surface)
81 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
83 pthread_mutex_lock(&surface->mutex);
86 /***********************************************************************
87 * macdrv_surface_unlock
89 static void macdrv_surface_unlock(struct window_surface *window_surface)
91 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
93 pthread_mutex_unlock(&surface->mutex);
96 /***********************************************************************
97 * macdrv_surface_get_bitmap_info
99 static void *macdrv_surface_get_bitmap_info(struct window_surface *window_surface,
102 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
104 memcpy(info, &surface->info, get_dib_info_size(&surface->info, DIB_RGB_COLORS));
105 return surface->bits;
108 /***********************************************************************
109 * macdrv_surface_get_bounds
111 static RECT *macdrv_surface_get_bounds(struct window_surface *window_surface)
113 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
115 return &surface->bounds;
118 /***********************************************************************
119 * macdrv_surface_set_region
121 static void macdrv_surface_set_region(struct window_surface *window_surface, HRGN region)
123 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
125 TRACE("updating surface %p with %p\n", surface, region);
127 HeapFree(GetProcessHeap(), 0, surface->region_data);
128 surface->region_data = NULL;
132 int rc = OffsetRgn(region, surface->header.rect.left, surface->header.rect.top);
134 surface->region_data = get_region_data(region, 0);
138 /***********************************************************************
139 * macdrv_surface_flush
141 static void macdrv_surface_flush(struct window_surface *window_surface)
143 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
146 window_surface->funcs->lock(window_surface);
148 TRACE("flushing %p %s bounds %s bits %p\n", surface, wine_dbgstr_rect(&surface->header.rect),
149 wine_dbgstr_rect(&surface->bounds), surface->bits);
151 rect = cgrect_from_rect(surface->bounds);
152 rect = CGRectOffset(rect, surface->header.rect.left, surface->header.rect.top);
153 reset_bounds(&surface->bounds);
155 window_surface->funcs->unlock(window_surface);
157 if (!CGRectIsEmpty(rect))
158 macdrv_window_needs_display(surface->window, rect);
161 /***********************************************************************
162 * macdrv_surface_destroy
164 static void macdrv_surface_destroy(struct window_surface *window_surface)
166 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
168 TRACE("freeing %p bits %p\n", surface, surface->bits);
169 HeapFree(GetProcessHeap(), 0, surface->bits);
170 pthread_mutex_destroy(&surface->mutex);
171 HeapFree(GetProcessHeap(), 0, surface);
174 static const struct window_surface_funcs macdrv_surface_funcs =
177 macdrv_surface_unlock,
178 macdrv_surface_get_bitmap_info,
179 macdrv_surface_get_bounds,
180 macdrv_surface_set_region,
181 macdrv_surface_flush,
182 macdrv_surface_destroy,
185 /***********************************************************************
188 struct window_surface *create_surface(macdrv_window window, const RECT *rect, BOOL use_alpha)
190 struct macdrv_window_surface *surface;
191 int width = rect->right - rect->left, height = rect->bottom - rect->top;
193 pthread_mutexattr_t attr;
196 surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
197 FIELD_OFFSET(struct macdrv_window_surface, info.bmiColors[3]));
198 if (!surface) return NULL;
200 err = pthread_mutexattr_init(&attr);
203 err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
205 err = pthread_mutex_init(&surface->mutex, &attr);
206 pthread_mutexattr_destroy(&attr);
210 HeapFree(GetProcessHeap(), 0, surface);
214 surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
215 surface->info.bmiHeader.biWidth = width;
216 surface->info.bmiHeader.biHeight = height; /* bottom-up */
217 surface->info.bmiHeader.biPlanes = 1;
218 surface->info.bmiHeader.biBitCount = 32;
219 surface->info.bmiHeader.biSizeImage = get_dib_image_size(&surface->info);
220 surface->info.bmiHeader.biCompression = BI_RGB;
221 surface->info.bmiHeader.biClrUsed = 0;
223 colors = (DWORD *)((char *)&surface->info + surface->info.bmiHeader.biSize);
224 colors[0] = 0x00ff0000;
225 colors[1] = 0x0000ff00;
226 colors[2] = 0x000000ff;
228 surface->header.funcs = &macdrv_surface_funcs;
229 surface->header.rect = *rect;
230 surface->header.ref = 1;
231 surface->window = window;
232 reset_bounds(&surface->bounds);
233 surface->use_alpha = use_alpha;
234 surface->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, surface->info.bmiHeader.biSizeImage);
235 if (!surface->bits) goto failed;
237 TRACE("created %p for %p %s bits %p-%p\n", surface, window, wine_dbgstr_rect(rect),
238 surface->bits, surface->bits + surface->info.bmiHeader.biSizeImage);
240 return &surface->header;
243 macdrv_surface_destroy(&surface->header);
247 /***********************************************************************
248 * set_surface_use_alpha
250 void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha)
252 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
253 surface->use_alpha = use_alpha;
256 /***********************************************************************
259 void set_window_surface(macdrv_window window, struct window_surface *window_surface)
261 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
262 macdrv_set_window_surface(window, window_surface, surface ? &surface->mutex : NULL);
265 /***********************************************************************
266 * get_surface_region_rects
268 * Caller must hold the surface lock. Indirectly returns the surface
269 * region rects. Returns zero if the surface has no region set (it is
270 * unclipped); returns non-zero if the surface does have a region set.
272 * IMPORTANT: This function is called from non-Wine threads, so it
273 * must not use Win32 or Wine functions, including debug
276 int get_surface_region_rects(void *window_surface, const CGRect **rects, int *count)
278 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
280 if (surface->region_data)
282 *rects = (const CGRect*)surface->region_data->Buffer;
283 *count = surface->region_data->rdh.nCount;
291 return (surface->region_data != NULL);
294 /***********************************************************************
295 * create_surface_image
297 * Caller must hold the surface lock. On input, *rect is the requested
298 * image rect, relative to the window whole_rect, a.k.a. visible_rect.
299 * On output, it's been intersected with that part backed by the surface
300 * and is the actual size of the returned image. copy_data indicates if
301 * the caller will keep the returned image beyond the point where the
302 * surface bits can be guaranteed to remain valid and unchanged. If so,
303 * the bits are copied instead of merely referenced by the image.
305 * IMPORTANT: This function is called from non-Wine threads, so it
306 * must not use Win32 or Wine functions, including debug
309 CGImageRef create_surface_image(void *window_surface, CGRect *rect, int copy_data)
311 CGImageRef cgimage = NULL;
312 struct macdrv_window_surface *surface = get_mac_surface(window_surface);
315 width = surface->header.rect.right - surface->header.rect.left;
316 height = surface->header.rect.bottom - surface->header.rect.top;
317 *rect = CGRectIntersection(cgrect_from_rect(surface->header.rect), *rect);
318 if (!CGRectIsEmpty(*rect))
321 CGColorSpaceRef colorspace;
322 CGDataProviderRef provider;
323 int bytes_per_row, offset, size;
324 CGImageAlphaInfo alphaInfo;
326 visrect = CGRectOffset(*rect, -surface->header.rect.left, -surface->header.rect.top);
328 colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
329 bytes_per_row = get_dib_stride(width, 32);
330 offset = CGRectGetMinX(visrect) * 4 + (height - CGRectGetMaxY(visrect)) * bytes_per_row;
331 size = min(CGRectGetHeight(visrect) * bytes_per_row,
332 surface->info.bmiHeader.biSizeImage - offset);
336 CFDataRef data = CFDataCreate(NULL, (UInt8*)surface->bits + offset, size);
337 provider = CGDataProviderCreateWithCFData(data);
341 provider = CGDataProviderCreateWithData(NULL, surface->bits + offset, size, NULL);
343 alphaInfo = surface->use_alpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
344 cgimage = CGImageCreate(CGRectGetWidth(visrect), CGRectGetHeight(visrect),
345 8, 32, bytes_per_row, colorspace,
346 alphaInfo | kCGBitmapByteOrder32Little,
347 provider, NULL, FALSE, kCGRenderingIntentDefault);
348 CGDataProviderRelease(provider);
349 CGColorSpaceRelease(colorspace);