TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
blobd2b3de23a6923fbcf40e945c674b89f6e3704a22
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 )
163 void *ptr;
164 DWORD err;
165 BOOL top_down = dst_info->bmiHeader.biHeight < 0;
167 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
168 dst_info->bmiHeader.biHeight = src->visrect.bottom - src->visrect.top;
169 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
170 if (top_down) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
172 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
173 return ERROR_OUTOFMEMORY;
175 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
176 if (bits->free) bits->free( bits );
177 bits->ptr = ptr;
178 bits->is_copy = TRUE;
179 bits->free = free_heap_bits;
180 return err;
183 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
184 BITMAPINFO *dst_info, struct bitblt_coords *dst,
185 struct gdi_image_bits *bits, int mode )
187 void *ptr;
188 DWORD err;
190 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
191 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
192 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
194 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
195 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
196 return ERROR_OUTOFMEMORY;
198 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
199 if (bits->free) bits->free( bits );
200 bits->ptr = ptr;
201 bits->is_copy = TRUE;
202 bits->free = free_heap_bits;
203 return err;
206 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
207 struct bitblt_coords *src, BITMAPINFO *dst_info,
208 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
210 if (!dst_bits->is_copy)
212 int size = dst_info->bmiHeader.biSizeImage;
213 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
214 if (!ptr) return ERROR_OUTOFMEMORY;
215 memcpy( ptr, dst_bits->ptr, size );
216 if (dst_bits->free) dst_bits->free( dst_bits );
217 dst_bits->ptr = ptr;
218 dst_bits->is_copy = TRUE;
219 dst_bits->free = free_heap_bits;
221 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
224 /* helper to retrieve either both colors or only the background color for monochrome blits */
225 static void get_mono_dc_colors( HDC hdc, BITMAPINFO *info, int count )
227 RGBQUAD *colors = info->bmiColors;
228 COLORREF color = GetBkColor( hdc );
230 colors[count - 1].rgbRed = GetRValue( color );
231 colors[count - 1].rgbGreen = GetGValue( color );
232 colors[count - 1].rgbBlue = GetBValue( color );
233 colors[count - 1].rgbReserved = 0;
235 if (count > 1)
237 color = GetTextColor( hdc );
238 colors[0].rgbRed = GetRValue( color );
239 colors[0].rgbGreen = GetGValue( color );
240 colors[0].rgbBlue = GetBValue( color );
241 colors[0].rgbReserved = 0;
243 info->bmiHeader.biClrUsed = count;
246 /***********************************************************************
247 * null driver fallback implementations
250 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
251 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
253 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
254 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
255 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
256 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
257 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
258 DWORD err;
259 struct gdi_image_bits bits;
261 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
262 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
263 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
265 release_dc_ptr( dc_src );
266 return FALSE;
269 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
270 copy_bitmapinfo( dst_info, src_info );
271 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
272 if (err == ERROR_BAD_FORMAT)
274 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
276 /* 1-bpp source without a color table uses the destination DC colors */
277 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
278 get_mono_dc_colors( dst_dev->hdc, src_info, 2 );
280 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
282 /* 1-bpp destination without a color table requires a fake 1-entry table
283 * that contains only the background color; except with a 1-bpp source,
284 * in which case it uses the source colors */
285 if (src_info->bmiHeader.biBitCount > 1)
286 get_mono_dc_colors( src_dev->hdc, dst_info, 1 );
287 else
288 get_mono_dc_colors( src_dev->hdc, dst_info, 2 );
291 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
293 /* get rid of the fake destination table */
294 dst_info->bmiHeader.biClrUsed = dst_colors;
295 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
299 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
300 ((src->width != dst->width) || (src->height != dst->height)))
302 copy_bitmapinfo( src_info, dst_info );
303 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
304 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
307 if (bits.free) bits.free( &bits );
308 release_dc_ptr( dc_src );
309 return !err;
313 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
314 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
316 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
317 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
318 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
319 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
320 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
321 DWORD err;
322 struct gdi_image_bits bits;
324 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
325 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
326 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
327 if (err) goto done;
329 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
330 copy_bitmapinfo( dst_info, src_info );
331 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
332 if (err == ERROR_BAD_FORMAT)
334 err = convert_bits( src_info, src, dst_info, &bits );
335 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
338 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
339 ((src->width != dst->width) || (src->height != dst->height)))
341 copy_bitmapinfo( src_info, dst_info );
342 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
343 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
346 if (bits.free) bits.free( &bits );
347 done:
348 release_dc_ptr( dc_src );
349 if (err) SetLastError( err );
350 return !err;
354 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
355 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
357 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
358 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
359 struct gdi_image_bits dst_bits;
360 struct bitblt_coords orig_dst;
361 DWORD *masks = (DWORD *)info->bmiColors;
362 DC *dc = get_nulldrv_dc( dev );
363 DWORD err;
365 if (info->bmiHeader.biPlanes != 1) goto update_format;
366 if (info->bmiHeader.biBitCount != 32) goto update_format;
367 if (info->bmiHeader.biCompression == BI_BITFIELDS)
369 if (blend.AlphaFormat & AC_SRC_ALPHA) return ERROR_INVALID_PARAMETER;
370 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
371 goto update_format;
374 if (!bits) return ERROR_SUCCESS;
375 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
377 dev = GET_DC_PHYSDEV( dc, pGetImage );
378 orig_dst = *dst;
379 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
380 if (err) return err;
382 dev = GET_DC_PHYSDEV( dc, pPutImage );
383 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
384 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
386 if (dst_bits.free) dst_bits.free( &dst_bits );
387 return err;
389 update_format:
390 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
391 return ERROR_INVALID_PARAMETER;
393 info->bmiHeader.biPlanes = 1;
394 info->bmiHeader.biBitCount = 32;
395 info->bmiHeader.biCompression = BI_BITFIELDS;
396 info->bmiHeader.biClrUsed = 0;
397 masks[0] = 0xff0000;
398 masks[1] = 0x00ff00;
399 masks[2] = 0x0000ff;
400 return ERROR_BAD_FORMAT;
403 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
404 void * grad_array, ULONG ngrad, ULONG mode )
406 DC *dc = get_nulldrv_dc( dev );
407 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
408 BITMAPINFO *info = (BITMAPINFO *)buffer;
409 struct bitblt_coords src, dst;
410 struct gdi_image_bits bits;
411 unsigned int i;
412 POINT *pts;
413 BOOL ret = FALSE;
414 DWORD err;
415 HRGN rgn;
417 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
418 for (i = 0; i < nvert; i++)
420 pts[i].x = vert_array[i].x;
421 pts[i].y = vert_array[i].y;
423 LPtoDP( dev->hdc, pts, nvert );
425 /* compute bounding rect of all the rectangles/triangles */
426 reset_bounds( &dst.visrect );
427 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
429 ULONG v = ((ULONG *)grad_array)[i];
430 dst.visrect.left = min( dst.visrect.left, pts[v].x );
431 dst.visrect.top = min( dst.visrect.top, pts[v].y );
432 dst.visrect.right = max( dst.visrect.right, pts[v].x );
433 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
436 dst.x = dst.visrect.left;
437 dst.y = dst.visrect.top;
438 dst.width = dst.visrect.right - dst.visrect.left;
439 dst.height = dst.visrect.bottom - dst.visrect.top;
440 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
442 /* query the bitmap format */
443 info->bmiHeader.biSize = sizeof(info->bmiHeader);
444 info->bmiHeader.biPlanes = 1;
445 info->bmiHeader.biBitCount = 0;
446 info->bmiHeader.biCompression = BI_RGB;
447 info->bmiHeader.biXPelsPerMeter = 0;
448 info->bmiHeader.biYPelsPerMeter = 0;
449 info->bmiHeader.biClrUsed = 0;
450 info->bmiHeader.biClrImportant = 0;
451 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
452 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
453 info->bmiHeader.biSizeImage = 0;
454 dev = GET_DC_PHYSDEV( dc, pPutImage );
455 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
456 if (err && err != ERROR_BAD_FORMAT) goto done;
458 info->bmiHeader.biSizeImage = get_dib_image_size( info );
459 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
460 goto done;
461 bits.is_copy = TRUE;
462 bits.free = free_heap_bits;
464 /* make src and points relative to the bitmap */
465 src = dst;
466 src.x -= dst.visrect.left;
467 src.y -= dst.visrect.top;
468 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
469 for (i = 0; i < nvert; i++)
471 pts[i].x -= dst.visrect.left;
472 pts[i].y -= dst.visrect.top;
475 rgn = CreateRectRgn( 0, 0, 0, 0 );
476 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
477 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
478 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
480 if (bits.free) bits.free( &bits );
481 DeleteObject( rgn );
483 done:
484 HeapFree( GetProcessHeap(), 0, pts );
485 return ret;
488 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
490 DC *dc = get_nulldrv_dc( dev );
491 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
492 BITMAPINFO *info = (BITMAPINFO *)buffer;
493 struct bitblt_coords src;
494 struct gdi_image_bits bits;
495 COLORREF ret;
497 src.visrect.left = x;
498 src.visrect.top = y;
499 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
500 src.visrect.right = src.visrect.left + 1;
501 src.visrect.bottom = src.visrect.top + 1;
502 src.x = src.visrect.left;
503 src.y = src.visrect.top;
504 src.width = src.height = 1;
506 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
508 dev = GET_DC_PHYSDEV( dc, pGetImage );
509 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
511 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
512 if (bits.free) bits.free( &bits );
513 return ret;
517 /***********************************************************************
518 * PatBlt (GDI32.@)
520 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
522 DC * dc;
523 BOOL ret = FALSE;
525 if (rop_uses_src( rop )) return FALSE;
526 if ((dc = get_dc_ptr( hdc )))
528 struct bitblt_coords dst;
530 update_dc( dc );
532 dst.log_x = left;
533 dst.log_y = top;
534 dst.log_width = width;
535 dst.log_height = height;
536 dst.layout = dc->layout;
537 if (rop & NOMIRRORBITMAP)
539 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
540 rop &= ~NOMIRRORBITMAP;
542 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
544 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
545 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
546 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
548 if (!ret)
550 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
551 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
553 release_dc_ptr( dc );
555 return ret;
559 /***********************************************************************
560 * BitBlt (GDI32.@)
562 BOOL WINAPI DECLSPEC_HOTPATCH BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
563 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
565 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
566 else return StretchBlt( hdcDst, xDst, yDst, width, height,
567 hdcSrc, xSrc, ySrc, width, height, rop );
571 /***********************************************************************
572 * StretchBlt (GDI32.@)
574 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
575 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
577 BOOL ret = FALSE;
578 DC *dcDst, *dcSrc;
580 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
582 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
584 if ((dcSrc = get_dc_ptr( hdcSrc )))
586 struct bitblt_coords src, dst;
588 update_dc( dcSrc );
589 update_dc( dcDst );
591 src.log_x = xSrc;
592 src.log_y = ySrc;
593 src.log_width = widthSrc;
594 src.log_height = heightSrc;
595 src.layout = dcSrc->layout;
596 dst.log_x = xDst;
597 dst.log_y = yDst;
598 dst.log_width = widthDst;
599 dst.log_height = heightDst;
600 dst.layout = dcDst->layout;
601 if (rop & NOMIRRORBITMAP)
603 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
604 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
605 rop &= ~NOMIRRORBITMAP;
607 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
609 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",
610 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
611 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
612 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
613 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
615 if (!ret)
617 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
618 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
619 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
621 release_dc_ptr( dcSrc );
623 release_dc_ptr( dcDst );
624 return ret;
627 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
628 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
630 /***********************************************************************
631 * MaskBlt [GDI32.@]
633 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
634 INT nWidth, INT nHeight, HDC hdcSrc,
635 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
636 INT xMask, INT yMask, DWORD dwRop)
638 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
639 HDC hDC1, hDC2;
640 HBRUSH hbrMask, hbrDst, hbrTmp;
642 static const DWORD ROP3Table[256] =
644 0x00000042, 0x00010289,
645 0x00020C89, 0x000300AA,
646 0x00040C88, 0x000500A9,
647 0x00060865, 0x000702C5,
648 0x00080F08, 0x00090245,
649 0x000A0329, 0x000B0B2A,
650 0x000C0324, 0x000D0B25,
651 0x000E08A5, 0x000F0001,
652 0x00100C85, 0x001100A6,
653 0x00120868, 0x001302C8,
654 0x00140869, 0x001502C9,
655 0x00165CCA, 0x00171D54,
656 0x00180D59, 0x00191CC8,
657 0x001A06C5, 0x001B0768,
658 0x001C06CA, 0x001D0766,
659 0x001E01A5, 0x001F0385,
660 0x00200F09, 0x00210248,
661 0x00220326, 0x00230B24,
662 0x00240D55, 0x00251CC5,
663 0x002606C8, 0x00271868,
664 0x00280369, 0x002916CA,
665 0x002A0CC9, 0x002B1D58,
666 0x002C0784, 0x002D060A,
667 0x002E064A, 0x002F0E2A,
668 0x0030032A, 0x00310B28,
669 0x00320688, 0x00330008,
670 0x003406C4, 0x00351864,
671 0x003601A8, 0x00370388,
672 0x0038078A, 0x00390604,
673 0x003A0644, 0x003B0E24,
674 0x003C004A, 0x003D18A4,
675 0x003E1B24, 0x003F00EA,
676 0x00400F0A, 0x00410249,
677 0x00420D5D, 0x00431CC4,
678 0x00440328, 0x00450B29,
679 0x004606C6, 0x0047076A,
680 0x00480368, 0x004916C5,
681 0x004A0789, 0x004B0605,
682 0x004C0CC8, 0x004D1954,
683 0x004E0645, 0x004F0E25,
684 0x00500325, 0x00510B26,
685 0x005206C9, 0x00530764,
686 0x005408A9, 0x00550009,
687 0x005601A9, 0x00570389,
688 0x00580785, 0x00590609,
689 0x005A0049, 0x005B18A9,
690 0x005C0649, 0x005D0E29,
691 0x005E1B29, 0x005F00E9,
692 0x00600365, 0x006116C6,
693 0x00620786, 0x00630608,
694 0x00640788, 0x00650606,
695 0x00660046, 0x006718A8,
696 0x006858A6, 0x00690145,
697 0x006A01E9, 0x006B178A,
698 0x006C01E8, 0x006D1785,
699 0x006E1E28, 0x006F0C65,
700 0x00700CC5, 0x00711D5C,
701 0x00720648, 0x00730E28,
702 0x00740646, 0x00750E26,
703 0x00761B28, 0x007700E6,
704 0x007801E5, 0x00791786,
705 0x007A1E29, 0x007B0C68,
706 0x007C1E24, 0x007D0C69,
707 0x007E0955, 0x007F03C9,
708 0x008003E9, 0x00810975,
709 0x00820C49, 0x00831E04,
710 0x00840C48, 0x00851E05,
711 0x008617A6, 0x008701C5,
712 0x008800C6, 0x00891B08,
713 0x008A0E06, 0x008B0666,
714 0x008C0E08, 0x008D0668,
715 0x008E1D7C, 0x008F0CE5,
716 0x00900C45, 0x00911E08,
717 0x009217A9, 0x009301C4,
718 0x009417AA, 0x009501C9,
719 0x00960169, 0x0097588A,
720 0x00981888, 0x00990066,
721 0x009A0709, 0x009B07A8,
722 0x009C0704, 0x009D07A6,
723 0x009E16E6, 0x009F0345,
724 0x00A000C9, 0x00A11B05,
725 0x00A20E09, 0x00A30669,
726 0x00A41885, 0x00A50065,
727 0x00A60706, 0x00A707A5,
728 0x00A803A9, 0x00A90189,
729 0x00AA0029, 0x00AB0889,
730 0x00AC0744, 0x00AD06E9,
731 0x00AE0B06, 0x00AF0229,
732 0x00B00E05, 0x00B10665,
733 0x00B21974, 0x00B30CE8,
734 0x00B4070A, 0x00B507A9,
735 0x00B616E9, 0x00B70348,
736 0x00B8074A, 0x00B906E6,
737 0x00BA0B09, 0x00BB0226,
738 0x00BC1CE4, 0x00BD0D7D,
739 0x00BE0269, 0x00BF08C9,
740 0x00C000CA, 0x00C11B04,
741 0x00C21884, 0x00C3006A,
742 0x00C40E04, 0x00C50664,
743 0x00C60708, 0x00C707AA,
744 0x00C803A8, 0x00C90184,
745 0x00CA0749, 0x00CB06E4,
746 0x00CC0020, 0x00CD0888,
747 0x00CE0B08, 0x00CF0224,
748 0x00D00E0A, 0x00D1066A,
749 0x00D20705, 0x00D307A4,
750 0x00D41D78, 0x00D50CE9,
751 0x00D616EA, 0x00D70349,
752 0x00D80745, 0x00D906E8,
753 0x00DA1CE9, 0x00DB0D75,
754 0x00DC0B04, 0x00DD0228,
755 0x00DE0268, 0x00DF08C8,
756 0x00E003A5, 0x00E10185,
757 0x00E20746, 0x00E306EA,
758 0x00E40748, 0x00E506E5,
759 0x00E61CE8, 0x00E70D79,
760 0x00E81D74, 0x00E95CE6,
761 0x00EA02E9, 0x00EB0849,
762 0x00EC02E8, 0x00ED0848,
763 0x00EE0086, 0x00EF0A08,
764 0x00F00021, 0x00F10885,
765 0x00F20B05, 0x00F3022A,
766 0x00F40B0A, 0x00F50225,
767 0x00F60265, 0x00F708C5,
768 0x00F802E5, 0x00F90845,
769 0x00FA0089, 0x00FB0A09,
770 0x00FC008A, 0x00FD0A0A,
771 0x00FE02A9, 0x00FF0062,
774 if (!hbmMask)
775 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
777 hbrMask = CreatePatternBrush(hbmMask);
778 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
780 /* make bitmap */
781 hDC1 = CreateCompatibleDC(hdcDest);
782 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
783 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
785 /* draw using bkgnd rop */
786 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
787 hbrTmp = SelectObject(hDC1, hbrDst);
788 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
789 SelectObject(hDC1, hbrTmp);
791 /* make bitmap */
792 hDC2 = CreateCompatibleDC(hdcDest);
793 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
794 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
796 /* draw using foregnd rop */
797 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
798 hbrTmp = SelectObject(hDC2, hbrDst);
799 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
801 /* combine both using the mask as a pattern brush */
802 SelectObject(hDC2, hbrMask);
803 SetBrushOrgEx(hDC2, -xMask, -yMask, NULL);
804 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
805 SelectObject(hDC2, hbrTmp);
807 /* blit to dst */
808 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
810 /* restore all objects */
811 SelectObject(hdcDest, hbrDst);
812 SelectObject(hDC1, hOldBitmap1);
813 SelectObject(hDC2, hOldBitmap2);
815 /* delete all temp objects */
816 DeleteObject(hBitmap1);
817 DeleteObject(hBitmap2);
818 DeleteObject(hbrMask);
820 DeleteDC(hDC1);
821 DeleteDC(hDC2);
823 return TRUE;
826 /******************************************************************************
827 * GdiTransparentBlt [GDI32.@]
829 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
830 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
831 UINT crTransparent )
833 BOOL ret = FALSE;
834 HDC hdcWork;
835 HBITMAP bmpWork;
836 HGDIOBJ oldWork;
837 HDC hdcMask = NULL;
838 HBITMAP bmpMask = NULL;
839 HBITMAP oldMask = NULL;
840 COLORREF oldBackground;
841 COLORREF oldForeground;
842 int oldStretchMode;
844 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
845 TRACE("Cannot mirror\n");
846 return FALSE;
849 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
850 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
852 /* Stretch bitmap */
853 oldStretchMode = GetStretchBltMode(hdcSrc);
854 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
855 SetStretchBltMode(hdcSrc, COLORONCOLOR);
856 hdcWork = CreateCompatibleDC(hdcDest);
857 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
858 oldWork = SelectObject(hdcWork, bmpWork);
859 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
860 TRACE("Failed to stretch\n");
861 goto error;
863 SetBkColor(hdcWork, crTransparent);
865 /* Create mask */
866 hdcMask = CreateCompatibleDC(hdcDest);
867 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
868 oldMask = SelectObject(hdcMask, bmpMask);
869 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
870 TRACE("Failed to create mask\n");
871 goto error;
874 /* Replace transparent color with black */
875 SetBkColor(hdcWork, RGB(0,0,0));
876 SetTextColor(hdcWork, RGB(255,255,255));
877 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
878 TRACE("Failed to mask out background\n");
879 goto error;
882 /* Replace non-transparent area on destination with black */
883 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
884 TRACE("Failed to clear destination area\n");
885 goto error;
888 /* Draw the image */
889 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
890 TRACE("Failed to paint image\n");
891 goto error;
894 ret = TRUE;
895 error:
896 SetStretchBltMode(hdcSrc, oldStretchMode);
897 SetBkColor(hdcDest, oldBackground);
898 SetTextColor(hdcDest, oldForeground);
899 if(hdcWork) {
900 SelectObject(hdcWork, oldWork);
901 DeleteDC(hdcWork);
903 if(bmpWork) DeleteObject(bmpWork);
904 if(hdcMask) {
905 SelectObject(hdcMask, oldMask);
906 DeleteDC(hdcMask);
908 if(bmpMask) DeleteObject(bmpMask);
909 return ret;
912 /******************************************************************************
913 * GdiAlphaBlend [GDI32.@]
915 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
916 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
917 BLENDFUNCTION blendFunction)
919 BOOL ret = FALSE;
920 DC *dcDst, *dcSrc;
922 dcSrc = get_dc_ptr( hdcSrc );
923 if (!dcSrc) return FALSE;
925 if ((dcDst = get_dc_ptr( hdcDst )))
927 struct bitblt_coords src, dst;
929 update_dc( dcSrc );
930 update_dc( dcDst );
932 src.log_x = xSrc;
933 src.log_y = ySrc;
934 src.log_width = widthSrc;
935 src.log_height = heightSrc;
936 src.layout = GetLayout( hdcSrc );
937 dst.log_x = xDst;
938 dst.log_y = yDst;
939 dst.log_width = widthDst;
940 dst.log_height = heightDst;
941 dst.layout = GetLayout( hdcDst );
942 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
944 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",
945 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
946 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
947 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
948 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
949 blendFunction.BlendOp, blendFunction.BlendFlags,
950 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
952 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
953 src.log_width < 0 || src.log_height < 0 ||
954 (!is_rect_empty( &dcSrc->device_rect ) &&
955 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
956 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
958 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
959 SetLastError( ERROR_INVALID_PARAMETER );
960 ret = FALSE;
962 else if (dst.log_width < 0 || dst.log_height < 0)
964 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
965 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
966 SetLastError( ERROR_INVALID_PARAMETER );
967 ret = FALSE;
969 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
970 src.y + src.height > dst.y && src.y < dst.y + dst.height)
972 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
973 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
974 SetLastError( ERROR_INVALID_PARAMETER );
975 ret = FALSE;
977 else if (!ret)
979 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
980 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
981 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
983 release_dc_ptr( dcDst );
985 release_dc_ptr( dcSrc );
986 return ret;
989 /*********************************************************************
990 * PlgBlt [GDI32.@]
993 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
994 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
995 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
997 int oldgMode;
998 /* parallelogram coords */
999 POINT plg[3];
1000 /* rect coords */
1001 POINT rect[3];
1002 XFORM xf;
1003 XFORM SrcXf;
1004 XFORM oldDestXf;
1005 double det;
1007 /* save actual mode, set GM_ADVANCED */
1008 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1009 if (oldgMode == 0)
1010 return FALSE;
1012 memcpy(plg,lpPoint,sizeof(POINT)*3);
1013 rect[0].x = nXSrc;
1014 rect[0].y = nYSrc;
1015 rect[1].x = nXSrc + nWidth;
1016 rect[1].y = nYSrc;
1017 rect[2].x = nXSrc;
1018 rect[2].y = nYSrc + nHeight;
1019 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1020 /* determinant */
1021 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);
1023 if (fabs(det) < 1e-5)
1025 SetGraphicsMode(hdcDest,oldgMode);
1026 return FALSE;
1029 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1030 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1032 /* X components */
1033 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;
1034 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;
1035 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1036 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1037 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1038 ) / det;
1040 /* Y components */
1041 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;
1042 xf.eM22 = (rect[1].x*(plg[2].y - plg[0].y) - rect[2].x*(plg[1].y - plg[0].y) - rect[0].x*(plg[2].y - plg[1].y)) / det;
1043 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1044 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1045 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1046 ) / det;
1048 GetWorldTransform(hdcSrc,&SrcXf);
1049 CombineTransform(&xf,&xf,&SrcXf);
1051 /* save actual dest transform */
1052 GetWorldTransform(hdcDest,&oldDestXf);
1054 SetWorldTransform(hdcDest,&xf);
1055 /* now destination and source DCs use same coords */
1056 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1057 hdcSrc, nXSrc,nYSrc,
1058 hbmMask,xMask,yMask,
1059 SRCCOPY);
1060 /* restore dest DC */
1061 SetWorldTransform(hdcDest,&oldDestXf);
1062 SetGraphicsMode(hdcDest,oldgMode);
1064 return TRUE;