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
;
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 /***********************************************************************
78 static void update_blit_data(struct macdrv_window_surface
*surface
)
80 HeapFree(GetProcessHeap(), 0, surface
->blit_data
);
81 surface
->blit_data
= NULL
;
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);
96 /***********************************************************************
99 static void CDECL
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 CDECL
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 *CDECL
macdrv_surface_get_bitmap_info(struct window_surface
*window_surface
,
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
*CDECL
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 CDECL
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
);
151 if (!surface
->region
) surface
->region
= CreateRectRgn(0, 0, 0, 0);
152 CombineRgn(surface
->region
, region
, 0, RGN_COPY
);
156 if (surface
->region
) DeleteObject(surface
->region
);
159 update_blit_data(surface
);
161 window_surface
->funcs
->unlock(window_surface
);
164 /***********************************************************************
165 * macdrv_surface_flush
167 static void CDECL
macdrv_surface_flush(struct window_surface
*window_surface
)
169 struct macdrv_window_surface
*surface
= get_mac_surface(window_surface
);
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
)))
185 CombineRgn(surface
->drawn
, surface
->drawn
, region
, RGN_OR
);
186 DeleteObject(region
);
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 CDECL
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
=
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 /***********************************************************************
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
;
243 pthread_mutexattr_t attr
;
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
);
254 err
= pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
256 err
= pthread_mutex_init(&surface
->mutex
, &attr
);
257 pthread_mutexattr_destroy(&attr
);
261 HeapFree(GetProcessHeap(), 0, surface
);
265 surface
->info
.bmiHeader
.biSize
= sizeof(surface
->info
.bmiHeader
);
266 surface
->info
.bmiHeader
.biWidth
= width
;
267 surface
->info
.bmiHeader
.biHeight
= height
; /* bottom-up */
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
);
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
;
307 macdrv_surface_destroy(&surface
->header
);
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 /***********************************************************************
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
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 (surface
->blit_data
)
347 *rects
= (const CGRect
*)surface
->blit_data
->Buffer
;
348 *count
= surface
->blit_data
->rdh
.nCount
;
356 return (surface
->blit_data
!= NULL
);
359 /***********************************************************************
360 * create_surface_image
362 * Caller must hold the surface lock. On input, *rect is the requested
363 * image rect, relative to the window whole_rect, a.k.a. visible_rect.
364 * On output, it's been intersected with that part backed by the surface
365 * and is the actual size of the returned image. copy_data indicates if
366 * the caller will keep the returned image beyond the point where the
367 * surface bits can be guaranteed to remain valid and unchanged. If so,
368 * the bits are copied instead of merely referenced by the image.
370 * IMPORTANT: This function is called from non-Wine threads, so it
371 * must not use Win32 or Wine functions, including debug
374 CGImageRef
create_surface_image(void *window_surface
, CGRect
*rect
, int copy_data
)
376 CGImageRef cgimage
= NULL
;
377 struct macdrv_window_surface
*surface
= get_mac_surface(window_surface
);
380 width
= surface
->header
.rect
.right
- surface
->header
.rect
.left
;
381 height
= surface
->header
.rect
.bottom
- surface
->header
.rect
.top
;
382 *rect
= CGRectIntersection(cgrect_from_rect(surface
->header
.rect
), *rect
);
383 if (!CGRectIsEmpty(*rect
))
386 CGColorSpaceRef colorspace
;
387 CGDataProviderRef provider
;
388 int bytes_per_row
, offset
, size
;
389 CGImageAlphaInfo alphaInfo
;
391 visrect
= CGRectOffset(*rect
, -surface
->header
.rect
.left
, -surface
->header
.rect
.top
);
393 colorspace
= CGColorSpaceCreateWithName(kCGColorSpaceSRGB
);
394 bytes_per_row
= get_dib_stride(width
, 32);
395 offset
= CGRectGetMinX(visrect
) * 4 + (height
- CGRectGetMaxY(visrect
)) * bytes_per_row
;
396 size
= min(CGRectGetHeight(visrect
) * bytes_per_row
,
397 surface
->info
.bmiHeader
.biSizeImage
- offset
);
401 CFDataRef data
= CFDataCreate(NULL
, (UInt8
*)surface
->bits
+ offset
, size
);
402 provider
= CGDataProviderCreateWithCFData(data
);
406 provider
= CGDataProviderCreateWithData(NULL
, surface
->bits
+ offset
, size
, NULL
);
408 alphaInfo
= surface
->use_alpha
? kCGImageAlphaPremultipliedFirst
: kCGImageAlphaNoneSkipFirst
;
409 cgimage
= CGImageCreate(CGRectGetWidth(visrect
), CGRectGetHeight(visrect
),
410 8, 32, bytes_per_row
, colorspace
,
411 alphaInfo
| kCGBitmapByteOrder32Little
,
412 provider
, NULL
, retina_on
, kCGRenderingIntentDefault
);
413 CGDataProviderRelease(provider
);
414 CGColorSpaceRelease(colorspace
);
420 /***********************************************************************
421 * surface_clip_to_visible_rect
423 * Intersect the accumulated drawn region with a new visible rect,
424 * effectively discarding stale drawing in the surface slack area.
426 void surface_clip_to_visible_rect(struct window_surface
*window_surface
, const RECT
*visible_rect
)
428 struct macdrv_window_surface
*surface
= get_mac_surface(window_surface
);
430 if (!surface
) return;
431 window_surface
->funcs
->lock(window_surface
);
438 rect
= *visible_rect
;
439 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
441 if ((region
= CreateRectRgnIndirect(&rect
)))
443 CombineRgn(surface
->drawn
, surface
->drawn
, region
, RGN_AND
);
444 DeleteObject(region
);
446 update_blit_data(surface
);
450 window_surface
->funcs
->unlock(window_surface
);