winex11: Create contexts at initialization time to avoid the need for locks.
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
blob238e3752cea35c9cc94a6471f07f5edc6348f13e
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
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 #include "config.h"
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <math.h>
26 #ifdef HAVE_FLOAT_H
27 #include <float.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "gdi_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
38 static inline BOOL rop_uses_src( DWORD rop )
40 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
43 static inline void swap_ints( int *i, int *j )
45 int tmp = *i;
46 *i = *j;
47 *j = tmp;
50 BOOL intersect_vis_rectangles( struct bitblt_coords *dst, struct bitblt_coords *src )
52 RECT rect;
54 /* intersect the rectangles */
56 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
58 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
59 if (!intersect_rect( &rect, &src->visrect, &dst->visrect )) return FALSE;
60 src->visrect = dst->visrect = rect;
61 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
63 else /* stretching */
65 /* map source rectangle into destination coordinates */
66 rect = src->visrect;
67 offset_rect( &rect, -min( src->x, src->x + src->width + 1),
68 -min( src->y, src->y + src->height + 1) );
69 rect.left = dst->x + rect.left * dst->width / abs(src->width);
70 rect.top = dst->y + rect.top * dst->height / abs(src->height);
71 rect.right = dst->x + rect.right * dst->width / abs(src->width);
72 rect.bottom = dst->y + rect.bottom * dst->height / abs(src->height);
73 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
74 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
76 /* avoid rounding errors */
77 rect.left--;
78 rect.top--;
79 rect.right++;
80 rect.bottom++;
81 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
83 /* map destination rectangle back to source coordinates */
84 rect = dst->visrect;
85 offset_rect( &rect, -min( dst->x, dst->x + dst->width + 1),
86 -min( dst->y, dst->y + dst->height + 1) );
87 rect.left = src->x + rect.left * src->width / abs(dst->width);
88 rect.top = src->y + rect.top * src->height / abs(dst->height);
89 rect.right = src->x + rect.right * src->width / abs(dst->width);
90 rect.bottom = src->y + rect.bottom * src->height / abs(dst->height);
91 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
92 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
94 /* avoid rounding errors */
95 rect.left--;
96 rect.top--;
97 rect.right++;
98 rect.bottom++;
99 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
101 return TRUE;
104 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
105 DC *dc_src, struct bitblt_coords *src )
107 RECT rect;
109 /* get the destination visible rectangle */
111 rect.left = dst->log_x;
112 rect.top = dst->log_y;
113 rect.right = dst->log_x + dst->log_width;
114 rect.bottom = dst->log_y + dst->log_height;
115 LPtoDP( dc_dst->hSelf, (POINT *)&rect, 2 );
116 dst->x = rect.left;
117 dst->y = rect.top;
118 dst->width = rect.right - rect.left;
119 dst->height = rect.bottom - rect.top;
120 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
122 dst->x += dst->width;
123 dst->width = -dst->width;
125 get_bounding_rect( &rect, dst->x, dst->y, dst->width, dst->height );
127 clip_visrect( dc_dst, &dst->visrect, &rect );
129 /* get the source visible rectangle */
131 if (!src) return !is_rect_empty( &dst->visrect );
133 rect.left = src->log_x;
134 rect.top = src->log_y;
135 rect.right = src->log_x + src->log_width;
136 rect.bottom = src->log_y + src->log_height;
137 LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
138 src->x = rect.left;
139 src->y = rect.top;
140 src->width = rect.right - rect.left;
141 src->height = rect.bottom - rect.top;
142 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
144 src->x += src->width;
145 src->width = -src->width;
147 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
149 if (!clip_device_rect( dc_src, &src->visrect, &rect )) return FALSE;
150 if (is_rect_empty( &dst->visrect )) return FALSE;
152 return intersect_vis_rectangles( dst, src );
155 void free_heap_bits( struct gdi_image_bits *bits )
157 HeapFree( GetProcessHeap(), 0, bits->ptr );
160 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
161 BITMAPINFO *dst_info, struct gdi_image_bits *bits, BOOL add_alpha )
163 void *ptr;
164 DWORD err;
166 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
167 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
169 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
170 return ERROR_OUTOFMEMORY;
172 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
173 if (bits->free) bits->free( bits );
174 bits->ptr = ptr;
175 bits->is_copy = TRUE;
176 bits->free = free_heap_bits;
177 return err;
180 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
181 BITMAPINFO *dst_info, struct bitblt_coords *dst,
182 struct gdi_image_bits *bits, int mode )
184 void *ptr;
185 DWORD err;
187 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
188 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
189 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
191 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
192 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
193 return ERROR_OUTOFMEMORY;
195 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
196 if (bits->free) bits->free( bits );
197 bits->ptr = ptr;
198 bits->is_copy = TRUE;
199 bits->free = free_heap_bits;
200 return err;
203 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
204 struct bitblt_coords *src, BITMAPINFO *dst_info,
205 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
207 if (!dst_bits->is_copy)
209 int size = dst_info->bmiHeader.biSizeImage;
210 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
211 if (!ptr) return ERROR_OUTOFMEMORY;
212 memcpy( ptr, dst_bits->ptr, size );
213 if (dst_bits->free) dst_bits->free( dst_bits );
214 dst_bits->ptr = ptr;
215 dst_bits->is_copy = TRUE;
216 dst_bits->free = free_heap_bits;
218 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
221 /* helper to retrieve either both colors or only the background color for monochrome blits */
222 static void get_mono_dc_colors( HDC hdc, BITMAPINFO *info, int count )
224 COLORREF color = GetBkColor( hdc );
226 info->bmiColors[count - 1].rgbRed = GetRValue( color );
227 info->bmiColors[count - 1].rgbGreen = GetGValue( color );
228 info->bmiColors[count - 1].rgbBlue = GetBValue( color );
229 info->bmiColors[count - 1].rgbReserved = 0;
231 if (count > 1)
233 color = GetTextColor( hdc );
234 info->bmiColors[0].rgbRed = GetRValue( color );
235 info->bmiColors[0].rgbGreen = GetGValue( color );
236 info->bmiColors[0].rgbBlue = GetBValue( color );
237 info->bmiColors[0].rgbReserved = 0;
239 info->bmiHeader.biClrUsed = count;
242 /***********************************************************************
243 * null driver fallback implementations
246 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
247 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
249 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
250 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
251 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
252 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
253 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
254 DWORD err;
255 struct gdi_image_bits bits;
257 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
258 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
259 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
261 release_dc_ptr( dc_src );
262 return FALSE;
265 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
266 copy_bitmapinfo( dst_info, src_info );
267 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
268 if (err == ERROR_BAD_FORMAT)
270 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
272 /* 1-bpp source without a color table uses the destination DC colors */
273 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
274 get_mono_dc_colors( dst_dev->hdc, src_info, 2 );
276 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
278 /* 1-bpp destination without a color table requires a fake 1-entry table
279 * that contains only the background color; except with a 1-bpp source,
280 * in which case it uses the source colors */
281 if (src_info->bmiHeader.biBitCount > 1)
282 get_mono_dc_colors( src_dev->hdc, dst_info, 1 );
283 else
284 get_mono_dc_colors( src_dev->hdc, dst_info, 2 );
287 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
289 /* get rid of the fake destination table */
290 dst_info->bmiHeader.biClrUsed = dst_colors;
291 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
295 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
296 ((src->width != dst->width) || (src->height != dst->height)))
298 copy_bitmapinfo( src_info, dst_info );
299 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
300 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
303 if (bits.free) bits.free( &bits );
304 release_dc_ptr( dc_src );
305 return !err;
309 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
310 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
312 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
313 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
314 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
315 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
316 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
317 DWORD err;
318 struct gdi_image_bits bits;
320 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
321 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
322 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
323 if (err) goto done;
325 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
326 copy_bitmapinfo( dst_info, src_info );
327 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
328 if (err == ERROR_BAD_FORMAT)
330 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
331 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
334 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
335 ((src->width != dst->width) || (src->height != dst->height)))
337 copy_bitmapinfo( src_info, dst_info );
338 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
339 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
342 if (bits.free) bits.free( &bits );
343 done:
344 release_dc_ptr( dc_src );
345 if (err) SetLastError( err );
346 return !err;
350 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
351 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
353 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
354 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
355 struct gdi_image_bits dst_bits;
356 struct bitblt_coords orig_dst;
357 DC *dc = get_nulldrv_dc( dev );
358 DWORD err;
360 if (info->bmiHeader.biPlanes != 1) goto update_format;
361 if (info->bmiHeader.biBitCount != 32) goto update_format;
362 if (info->bmiHeader.biCompression == BI_BITFIELDS)
364 DWORD *masks = (DWORD *)info->bmiColors;
365 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
366 goto update_format;
369 if (!bits) return ERROR_SUCCESS;
370 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
372 dev = GET_DC_PHYSDEV( dc, pGetImage );
373 orig_dst = *dst;
374 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
375 if (err) return err;
377 dev = GET_DC_PHYSDEV( dc, pPutImage );
378 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
379 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
381 if (dst_bits.free) dst_bits.free( &dst_bits );
382 return err;
384 update_format:
385 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
386 return ERROR_INVALID_PARAMETER;
388 info->bmiHeader.biPlanes = 1;
389 info->bmiHeader.biBitCount = 32;
390 info->bmiHeader.biCompression = BI_RGB;
391 info->bmiHeader.biClrUsed = 0;
392 return ERROR_BAD_FORMAT;
395 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
396 void * grad_array, ULONG ngrad, ULONG mode )
398 DC *dc = get_nulldrv_dc( dev );
399 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
400 BITMAPINFO *info = (BITMAPINFO *)buffer;
401 struct bitblt_coords src, dst;
402 struct gdi_image_bits bits;
403 unsigned int i;
404 POINT *pts;
405 BOOL ret = FALSE;
406 DWORD err;
407 HRGN rgn;
409 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
410 for (i = 0; i < nvert; i++)
412 pts[i].x = vert_array[i].x;
413 pts[i].y = vert_array[i].y;
415 LPtoDP( dev->hdc, pts, nvert );
417 /* compute bounding rect of all the rectangles/triangles */
418 reset_bounds( &dst.visrect );
419 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
421 ULONG v = ((ULONG *)grad_array)[i];
422 dst.visrect.left = min( dst.visrect.left, pts[v].x );
423 dst.visrect.top = min( dst.visrect.top, pts[v].y );
424 dst.visrect.right = max( dst.visrect.right, pts[v].x );
425 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
428 dst.x = dst.visrect.left;
429 dst.y = dst.visrect.top;
430 dst.width = dst.visrect.right - dst.visrect.left;
431 dst.height = dst.visrect.bottom - dst.visrect.top;
432 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
434 /* query the bitmap format */
435 info->bmiHeader.biSize = sizeof(info->bmiHeader);
436 info->bmiHeader.biPlanes = 1;
437 info->bmiHeader.biBitCount = 0;
438 info->bmiHeader.biCompression = BI_RGB;
439 info->bmiHeader.biXPelsPerMeter = 0;
440 info->bmiHeader.biYPelsPerMeter = 0;
441 info->bmiHeader.biClrUsed = 0;
442 info->bmiHeader.biClrImportant = 0;
443 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
444 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
445 info->bmiHeader.biSizeImage = 0;
446 dev = GET_DC_PHYSDEV( dc, pPutImage );
447 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
448 if (err && err != ERROR_BAD_FORMAT) goto done;
450 info->bmiHeader.biSizeImage = get_dib_image_size( info );
451 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
452 goto done;
453 bits.is_copy = TRUE;
454 bits.free = free_heap_bits;
456 /* make src and points relative to the bitmap */
457 src = dst;
458 src.x -= dst.visrect.left;
459 src.y -= dst.visrect.top;
460 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
461 for (i = 0; i < nvert; i++)
463 pts[i].x -= dst.visrect.left;
464 pts[i].y -= dst.visrect.top;
467 rgn = CreateRectRgn( 0, 0, 0, 0 );
468 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
469 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
470 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
472 if (bits.free) bits.free( &bits );
473 DeleteObject( rgn );
475 done:
476 HeapFree( GetProcessHeap(), 0, pts );
477 return ret;
480 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
482 DC *dc = get_nulldrv_dc( dev );
483 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
484 BITMAPINFO *info = (BITMAPINFO *)buffer;
485 struct bitblt_coords src;
486 struct gdi_image_bits bits;
487 COLORREF ret;
489 src.visrect.left = x;
490 src.visrect.top = y;
491 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
492 src.visrect.right = src.visrect.left + 1;
493 src.visrect.bottom = src.visrect.top + 1;
494 src.x = src.visrect.left;
495 src.y = src.visrect.top;
496 src.width = src.height = 1;
498 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
500 dev = GET_DC_PHYSDEV( dc, pGetImage );
501 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
503 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
504 if (bits.free) bits.free( &bits );
505 return ret;
509 /***********************************************************************
510 * PatBlt (GDI32.@)
512 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
514 DC * dc;
515 BOOL ret = FALSE;
517 if (rop_uses_src( rop )) return FALSE;
518 if ((dc = get_dc_ptr( hdc )))
520 struct bitblt_coords dst;
521 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
523 update_dc( dc );
525 dst.log_x = left;
526 dst.log_y = top;
527 dst.log_width = width;
528 dst.log_height = height;
529 dst.layout = dc->layout;
530 if (rop & NOMIRRORBITMAP)
532 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
533 rop &= ~NOMIRRORBITMAP;
535 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
537 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
538 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
539 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
541 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
543 release_dc_ptr( dc );
545 return ret;
549 /***********************************************************************
550 * BitBlt (GDI32.@)
552 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
553 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
555 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
556 else return StretchBlt( hdcDst, xDst, yDst, width, height,
557 hdcSrc, xSrc, ySrc, width, height, rop );
561 /***********************************************************************
562 * StretchBlt (GDI32.@)
564 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
565 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
567 BOOL ret = FALSE;
568 DC *dcDst, *dcSrc;
570 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
572 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
574 if ((dcSrc = get_dc_ptr( hdcSrc )))
576 struct bitblt_coords src, dst;
577 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
578 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
580 update_dc( dcSrc );
581 update_dc( dcDst );
583 src.log_x = xSrc;
584 src.log_y = ySrc;
585 src.log_width = widthSrc;
586 src.log_height = heightSrc;
587 src.layout = dcSrc->layout;
588 dst.log_x = xDst;
589 dst.log_y = yDst;
590 dst.log_width = widthDst;
591 dst.log_height = heightDst;
592 dst.layout = dcDst->layout;
593 if (rop & NOMIRRORBITMAP)
595 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
596 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
597 rop &= ~NOMIRRORBITMAP;
599 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
601 TRACE("src %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
602 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
603 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
604 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
605 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
607 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
608 release_dc_ptr( dcSrc );
610 release_dc_ptr( dcDst );
611 return ret;
614 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
615 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
617 /***********************************************************************
618 * MaskBlt [GDI32.@]
620 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
621 INT nWidth, INT nHeight, HDC hdcSrc,
622 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
623 INT xMask, INT yMask, DWORD dwRop)
625 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
626 HDC hDC1, hDC2;
627 HBRUSH hbrMask, hbrDst, hbrTmp;
629 static const DWORD ROP3Table[256] =
631 0x00000042, 0x00010289,
632 0x00020C89, 0x000300AA,
633 0x00040C88, 0x000500A9,
634 0x00060865, 0x000702C5,
635 0x00080F08, 0x00090245,
636 0x000A0329, 0x000B0B2A,
637 0x000C0324, 0x000D0B25,
638 0x000E08A5, 0x000F0001,
639 0x00100C85, 0x001100A6,
640 0x00120868, 0x001302C8,
641 0x00140869, 0x001502C9,
642 0x00165CCA, 0x00171D54,
643 0x00180D59, 0x00191CC8,
644 0x001A06C5, 0x001B0768,
645 0x001C06CA, 0x001D0766,
646 0x001E01A5, 0x001F0385,
647 0x00200F09, 0x00210248,
648 0x00220326, 0x00230B24,
649 0x00240D55, 0x00251CC5,
650 0x002606C8, 0x00271868,
651 0x00280369, 0x002916CA,
652 0x002A0CC9, 0x002B1D58,
653 0x002C0784, 0x002D060A,
654 0x002E064A, 0x002F0E2A,
655 0x0030032A, 0x00310B28,
656 0x00320688, 0x00330008,
657 0x003406C4, 0x00351864,
658 0x003601A8, 0x00370388,
659 0x0038078A, 0x00390604,
660 0x003A0644, 0x003B0E24,
661 0x003C004A, 0x003D18A4,
662 0x003E1B24, 0x003F00EA,
663 0x00400F0A, 0x00410249,
664 0x00420D5D, 0x00431CC4,
665 0x00440328, 0x00450B29,
666 0x004606C6, 0x0047076A,
667 0x00480368, 0x004916C5,
668 0x004A0789, 0x004B0605,
669 0x004C0CC8, 0x004D1954,
670 0x004E0645, 0x004F0E25,
671 0x00500325, 0x00510B26,
672 0x005206C9, 0x00530764,
673 0x005408A9, 0x00550009,
674 0x005601A9, 0x00570389,
675 0x00580785, 0x00590609,
676 0x005A0049, 0x005B18A9,
677 0x005C0649, 0x005D0E29,
678 0x005E1B29, 0x005F00E9,
679 0x00600365, 0x006116C6,
680 0x00620786, 0x00630608,
681 0x00640788, 0x00650606,
682 0x00660046, 0x006718A8,
683 0x006858A6, 0x00690145,
684 0x006A01E9, 0x006B178A,
685 0x006C01E8, 0x006D1785,
686 0x006E1E28, 0x006F0C65,
687 0x00700CC5, 0x00711D5C,
688 0x00720648, 0x00730E28,
689 0x00740646, 0x00750E26,
690 0x00761B28, 0x007700E6,
691 0x007801E5, 0x00791786,
692 0x007A1E29, 0x007B0C68,
693 0x007C1E24, 0x007D0C69,
694 0x007E0955, 0x007F03C9,
695 0x008003E9, 0x00810975,
696 0x00820C49, 0x00831E04,
697 0x00840C48, 0x00851E05,
698 0x008617A6, 0x008701C5,
699 0x008800C6, 0x00891B08,
700 0x008A0E06, 0x008B0666,
701 0x008C0E08, 0x008D0668,
702 0x008E1D7C, 0x008F0CE5,
703 0x00900C45, 0x00911E08,
704 0x009217A9, 0x009301C4,
705 0x009417AA, 0x009501C9,
706 0x00960169, 0x0097588A,
707 0x00981888, 0x00990066,
708 0x009A0709, 0x009B07A8,
709 0x009C0704, 0x009D07A6,
710 0x009E16E6, 0x009F0345,
711 0x00A000C9, 0x00A11B05,
712 0x00A20E09, 0x00A30669,
713 0x00A41885, 0x00A50065,
714 0x00A60706, 0x00A707A5,
715 0x00A803A9, 0x00A90189,
716 0x00AA0029, 0x00AB0889,
717 0x00AC0744, 0x00AD06E9,
718 0x00AE0B06, 0x00AF0229,
719 0x00B00E05, 0x00B10665,
720 0x00B21974, 0x00B30CE8,
721 0x00B4070A, 0x00B507A9,
722 0x00B616E9, 0x00B70348,
723 0x00B8074A, 0x00B906E6,
724 0x00BA0B09, 0x00BB0226,
725 0x00BC1CE4, 0x00BD0D7D,
726 0x00BE0269, 0x00BF08C9,
727 0x00C000CA, 0x00C11B04,
728 0x00C21884, 0x00C3006A,
729 0x00C40E04, 0x00C50664,
730 0x00C60708, 0x00C707AA,
731 0x00C803A8, 0x00C90184,
732 0x00CA0749, 0x00CB06E4,
733 0x00CC0020, 0x00CD0888,
734 0x00CE0B08, 0x00CF0224,
735 0x00D00E0A, 0x00D1066A,
736 0x00D20705, 0x00D307A4,
737 0x00D41D78, 0x00D50CE9,
738 0x00D616EA, 0x00D70349,
739 0x00D80745, 0x00D906E8,
740 0x00DA1CE9, 0x00DB0D75,
741 0x00DC0B04, 0x00DD0228,
742 0x00DE0268, 0x00DF08C8,
743 0x00E003A5, 0x00E10185,
744 0x00E20746, 0x00E306EA,
745 0x00E40748, 0x00E506E5,
746 0x00E61CE8, 0x00E70D79,
747 0x00E81D74, 0x00E95CE6,
748 0x00EA02E9, 0x00EB0849,
749 0x00EC02E8, 0x00ED0848,
750 0x00EE0086, 0x00EF0A08,
751 0x00F00021, 0x00F10885,
752 0x00F20B05, 0x00F3022A,
753 0x00F40B0A, 0x00F50225,
754 0x00F60265, 0x00F708C5,
755 0x00F802E5, 0x00F90845,
756 0x00FA0089, 0x00FB0A09,
757 0x00FC008A, 0x00FD0A0A,
758 0x00FE02A9, 0x00FF0062,
761 if (!hbmMask)
762 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
764 hbrMask = CreatePatternBrush(hbmMask);
765 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
767 /* make bitmap */
768 hDC1 = CreateCompatibleDC(hdcDest);
769 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
770 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
772 /* draw using bkgnd rop */
773 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
774 hbrTmp = SelectObject(hDC1, hbrDst);
775 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
776 SelectObject(hDC1, hbrTmp);
778 /* make bitmap */
779 hDC2 = CreateCompatibleDC(hdcDest);
780 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
781 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
783 /* draw using foregnd rop */
784 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
785 hbrTmp = SelectObject(hDC2, hbrDst);
786 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
788 /* combine both using the mask as a pattern brush */
789 SelectObject(hDC2, hbrMask);
790 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
791 SelectObject(hDC2, hbrTmp);
793 /* blit to dst */
794 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
796 /* restore all objects */
797 SelectObject(hdcDest, hbrDst);
798 SelectObject(hDC1, hOldBitmap1);
799 SelectObject(hDC2, hOldBitmap2);
801 /* delete all temp objects */
802 DeleteObject(hBitmap1);
803 DeleteObject(hBitmap2);
804 DeleteObject(hbrMask);
806 DeleteDC(hDC1);
807 DeleteDC(hDC2);
809 return TRUE;
812 /******************************************************************************
813 * GdiTransparentBlt [GDI32.@]
815 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
816 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
817 UINT crTransparent )
819 BOOL ret = FALSE;
820 HDC hdcWork;
821 HBITMAP bmpWork;
822 HGDIOBJ oldWork;
823 HDC hdcMask = NULL;
824 HBITMAP bmpMask = NULL;
825 HBITMAP oldMask = NULL;
826 COLORREF oldBackground;
827 COLORREF oldForeground;
828 int oldStretchMode;
830 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
831 TRACE("Cannot mirror\n");
832 return FALSE;
835 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
836 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
838 /* Stretch bitmap */
839 oldStretchMode = GetStretchBltMode(hdcSrc);
840 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
841 SetStretchBltMode(hdcSrc, COLORONCOLOR);
842 hdcWork = CreateCompatibleDC(hdcDest);
843 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
844 oldWork = SelectObject(hdcWork, bmpWork);
845 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
846 TRACE("Failed to stretch\n");
847 goto error;
849 SetBkColor(hdcWork, crTransparent);
851 /* Create mask */
852 hdcMask = CreateCompatibleDC(hdcDest);
853 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
854 oldMask = SelectObject(hdcMask, bmpMask);
855 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
856 TRACE("Failed to create mask\n");
857 goto error;
860 /* Replace transparent color with black */
861 SetBkColor(hdcWork, RGB(0,0,0));
862 SetTextColor(hdcWork, RGB(255,255,255));
863 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
864 TRACE("Failed to mask out background\n");
865 goto error;
868 /* Replace non-transparent area on destination with black */
869 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
870 TRACE("Failed to clear destination area\n");
871 goto error;
874 /* Draw the image */
875 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
876 TRACE("Failed to paint image\n");
877 goto error;
880 ret = TRUE;
881 error:
882 SetStretchBltMode(hdcSrc, oldStretchMode);
883 SetBkColor(hdcDest, oldBackground);
884 SetTextColor(hdcDest, oldForeground);
885 if(hdcWork) {
886 SelectObject(hdcWork, oldWork);
887 DeleteDC(hdcWork);
889 if(bmpWork) DeleteObject(bmpWork);
890 if(hdcMask) {
891 SelectObject(hdcMask, oldMask);
892 DeleteDC(hdcMask);
894 if(bmpMask) DeleteObject(bmpMask);
895 return ret;
898 /******************************************************************************
899 * GdiAlphaBlend [GDI32.@]
901 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
902 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
903 BLENDFUNCTION blendFunction)
905 BOOL ret = FALSE;
906 DC *dcDst, *dcSrc;
908 dcSrc = get_dc_ptr( hdcSrc );
909 if (!dcSrc) return FALSE;
911 if ((dcDst = get_dc_ptr( hdcDst )))
913 struct bitblt_coords src, dst;
914 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
915 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
917 update_dc( dcSrc );
918 update_dc( dcDst );
920 src.log_x = xSrc;
921 src.log_y = ySrc;
922 src.log_width = widthSrc;
923 src.log_height = heightSrc;
924 src.layout = GetLayout( src_dev->hdc );
925 dst.log_x = xDst;
926 dst.log_y = yDst;
927 dst.log_width = widthDst;
928 dst.log_height = heightDst;
929 dst.layout = GetLayout( dst_dev->hdc );
930 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
932 TRACE("src %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s blend=%02x/%02x/%02x/%02x\n",
933 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
934 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
935 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
936 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
937 blendFunction.BlendOp, blendFunction.BlendFlags,
938 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
940 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
941 src.log_width < 0 || src.log_height < 0 ||
942 (!is_rect_empty( &dcSrc->device_rect ) &&
943 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
944 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
946 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
947 SetLastError( ERROR_INVALID_PARAMETER );
948 ret = FALSE;
950 else if (dst.log_width < 0 || dst.log_height < 0)
952 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
953 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
954 SetLastError( ERROR_INVALID_PARAMETER );
955 ret = FALSE;
957 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
958 src.y + src.height > dst.y && src.y < dst.y + dst.height)
960 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
961 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
962 SetLastError( ERROR_INVALID_PARAMETER );
963 ret = FALSE;
965 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
967 release_dc_ptr( dcDst );
969 release_dc_ptr( dcSrc );
970 return ret;
973 /*********************************************************************
974 * PlgBlt [GDI32.@]
977 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
978 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
979 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
981 int oldgMode;
982 /* parallelogram coords */
983 POINT plg[3];
984 /* rect coords */
985 POINT rect[3];
986 XFORM xf;
987 XFORM SrcXf;
988 XFORM oldDestXf;
989 double det;
991 /* save actual mode, set GM_ADVANCED */
992 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
993 if (oldgMode == 0)
994 return FALSE;
996 memcpy(plg,lpPoint,sizeof(POINT)*3);
997 rect[0].x = nXSrc;
998 rect[0].y = nYSrc;
999 rect[1].x = nXSrc + nWidth;
1000 rect[1].y = nYSrc;
1001 rect[2].x = nXSrc;
1002 rect[2].y = nYSrc + nHeight;
1003 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1004 /* determinant */
1005 det = rect[1].x*(rect[2].y - rect[0].y) - rect[2].x*(rect[1].y - rect[0].y) - rect[0].x*(rect[2].y - rect[1].y);
1007 if (fabs(det) < 1e-5)
1009 SetGraphicsMode(hdcDest,oldgMode);
1010 return FALSE;
1013 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1014 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1016 /* X components */
1017 xf.eM11 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;
1018 xf.eM21 = (rect[1].x*(plg[2].x - plg[0].x) - rect[2].x*(plg[1].x - plg[0].x) - rect[0].x*(plg[2].x - plg[1].x)) / det;
1019 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1020 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1021 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1022 ) / det;
1024 /* Y components */
1025 xf.eM12 = (plg[1].y*(rect[2].y - rect[0].y) - plg[2].y*(rect[1].y - rect[0].y) - plg[0].y*(rect[2].y - rect[1].y)) / det;
1026 xf.eM22 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;
1027 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1028 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1029 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1030 ) / det;
1032 GetWorldTransform(hdcSrc,&SrcXf);
1033 CombineTransform(&xf,&xf,&SrcXf);
1035 /* save actual dest transform */
1036 GetWorldTransform(hdcDest,&oldDestXf);
1038 SetWorldTransform(hdcDest,&xf);
1039 /* now destination and source DCs use same coords */
1040 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1041 hdcSrc, nXSrc,nYSrc,
1042 hbmMask,xMask,yMask,
1043 SRCCOPY);
1044 /* restore dest DC */
1045 SetWorldTransform(hdcDest,&oldDestXf);
1046 SetGraphicsMode(hdcDest,oldgMode);
1048 return TRUE;