gdi32: Add support for PS_ALTERNATE pens.
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
blob0d7ed3c1f968d3e44f103db81a7200a580503afa
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 /* source is not clipped */
150 if (dc_src->header.type == OBJ_MEMDC)
151 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
152 else
153 src->visrect = rect; /* FIXME: clip to device size */
155 if (is_rect_empty( &src->visrect )) return FALSE;
156 if (is_rect_empty( &dst->visrect )) return FALSE;
158 return intersect_vis_rectangles( dst, src );
161 void free_heap_bits( struct gdi_image_bits *bits )
163 HeapFree( GetProcessHeap(), 0, bits->ptr );
166 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
167 BITMAPINFO *dst_info, struct gdi_image_bits *bits, BOOL add_alpha )
169 void *ptr;
170 DWORD err;
172 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
173 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
175 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
176 return ERROR_OUTOFMEMORY;
178 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
179 if (bits->free) bits->free( bits );
180 bits->ptr = ptr;
181 bits->is_copy = TRUE;
182 bits->free = free_heap_bits;
183 return err;
186 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
187 BITMAPINFO *dst_info, struct bitblt_coords *dst,
188 struct gdi_image_bits *bits, int mode )
190 void *ptr;
191 DWORD err;
193 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
194 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
195 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
197 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
198 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
199 return ERROR_OUTOFMEMORY;
201 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
202 if (bits->free) bits->free( bits );
203 bits->ptr = ptr;
204 bits->is_copy = TRUE;
205 bits->free = free_heap_bits;
206 return err;
209 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
210 struct bitblt_coords *src, BITMAPINFO *dst_info,
211 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
213 if (!dst_bits->is_copy)
215 int size = dst_info->bmiHeader.biSizeImage;
216 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
217 if (!ptr) return ERROR_OUTOFMEMORY;
218 memcpy( ptr, dst_bits->ptr, size );
219 if (dst_bits->free) dst_bits->free( dst_bits );
220 dst_bits->ptr = ptr;
221 dst_bits->is_copy = TRUE;
222 dst_bits->free = free_heap_bits;
224 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
227 /***********************************************************************
228 * null driver fallback implementations
231 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
232 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
234 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
235 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
236 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
237 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
238 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
239 DWORD err;
240 struct gdi_image_bits bits;
242 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
243 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
244 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
245 release_dc_ptr( dc_src );
246 if (err) return FALSE;
248 /* 1-bpp source without a color table uses the destination DC colors */
249 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
251 COLORREF color = GetTextColor( dst_dev->hdc );
252 src_info->bmiColors[0].rgbRed = GetRValue( color );
253 src_info->bmiColors[0].rgbGreen = GetGValue( color );
254 src_info->bmiColors[0].rgbBlue = GetBValue( color );
255 src_info->bmiColors[0].rgbReserved = 0;
256 color = GetBkColor( dst_dev->hdc );
257 src_info->bmiColors[1].rgbRed = GetRValue( color );
258 src_info->bmiColors[1].rgbGreen = GetGValue( color );
259 src_info->bmiColors[1].rgbBlue = GetBValue( color );
260 src_info->bmiColors[1].rgbReserved = 0;
261 src_info->bmiHeader.biClrUsed = 2;
264 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
265 copy_bitmapinfo( dst_info, src_info );
266 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
267 if (err == ERROR_BAD_FORMAT)
269 /* 1-bpp destination without a color table requires a fake 1-entry table
270 * that contains only the background color */
271 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
273 COLORREF color = GetBkColor( src_dev->hdc );
274 dst_info->bmiColors[0].rgbRed = GetRValue( color );
275 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
276 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
277 dst_info->bmiColors[0].rgbReserved = 0;
278 dst_info->bmiHeader.biClrUsed = 1;
281 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
283 /* get rid of the fake 1-bpp table */
284 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
285 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
289 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
290 ((src->width != dst->width) || (src->height != dst->height)))
292 copy_bitmapinfo( src_info, dst_info );
293 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
294 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
297 if (bits.free) bits.free( &bits );
298 return !err;
302 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
303 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
305 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
306 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
307 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
308 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
309 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
310 DWORD err;
311 struct gdi_image_bits bits;
313 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
314 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
315 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
316 release_dc_ptr( dc_src );
317 if (err) goto done;
319 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
320 copy_bitmapinfo( dst_info, src_info );
321 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
322 if (err == ERROR_BAD_FORMAT)
324 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
325 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
328 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
329 ((src->width != dst->width) || (src->height != dst->height)))
331 copy_bitmapinfo( src_info, dst_info );
332 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
333 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
336 if (bits.free) bits.free( &bits );
337 done:
338 if (err) SetLastError( err );
339 return !err;
343 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
344 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
346 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
347 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
348 struct gdi_image_bits dst_bits;
349 struct bitblt_coords orig_dst;
350 DC *dc = get_nulldrv_dc( dev );
351 DWORD err;
353 if (info->bmiHeader.biPlanes != 1) goto update_format;
354 if (info->bmiHeader.biBitCount != 32) goto update_format;
355 if (info->bmiHeader.biCompression == BI_BITFIELDS)
357 DWORD *masks = (DWORD *)info->bmiColors;
358 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
359 goto update_format;
362 if (!bits) return ERROR_SUCCESS;
363 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
365 dev = GET_DC_PHYSDEV( dc, pGetImage );
366 orig_dst = *dst;
367 err = dev->funcs->pGetImage( dev, 0, dst_info, &dst_bits, dst );
368 if (err) return err;
370 dev = GET_DC_PHYSDEV( dc, pPutImage );
371 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
372 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
374 if (dst_bits.free) dst_bits.free( &dst_bits );
375 return err;
377 update_format:
378 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
379 return ERROR_INVALID_PARAMETER;
381 info->bmiHeader.biPlanes = 1;
382 info->bmiHeader.biBitCount = 32;
383 info->bmiHeader.biCompression = BI_RGB;
384 info->bmiHeader.biClrUsed = 0;
385 return ERROR_BAD_FORMAT;
388 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
389 void * grad_array, ULONG ngrad, ULONG mode )
391 DC *dc = get_nulldrv_dc( dev );
392 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
393 BITMAPINFO *info = (BITMAPINFO *)buffer;
394 struct bitblt_coords src, dst;
395 struct gdi_image_bits bits;
396 unsigned int i;
397 POINT *pts;
398 BOOL ret = TRUE;
399 DWORD err;
400 HRGN rgn;
402 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
403 for (i = 0; i < nvert; i++)
405 pts[i].x = vert_array[i].x;
406 pts[i].y = vert_array[i].y;
408 LPtoDP( dev->hdc, pts, nvert );
410 /* compute bounding rect of all the rectangles/triangles */
411 dst.visrect.left = dst.visrect.top = INT_MAX;
412 dst.visrect.right = dst.visrect.bottom = INT_MIN;
413 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
415 ULONG v = ((ULONG *)grad_array)[i];
416 dst.visrect.left = min( dst.visrect.left, pts[v].x );
417 dst.visrect.top = min( dst.visrect.top, pts[v].y );
418 dst.visrect.right = max( dst.visrect.right, pts[v].x );
419 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
422 dst.x = dst.visrect.left;
423 dst.y = dst.visrect.top;
424 dst.width = dst.visrect.right - dst.visrect.left;
425 dst.height = dst.visrect.bottom - dst.visrect.top;
426 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
428 /* query the bitmap format */
429 info->bmiHeader.biSize = sizeof(info->bmiHeader);
430 info->bmiHeader.biPlanes = 1;
431 info->bmiHeader.biBitCount = 0;
432 info->bmiHeader.biCompression = BI_RGB;
433 info->bmiHeader.biXPelsPerMeter = 0;
434 info->bmiHeader.biYPelsPerMeter = 0;
435 info->bmiHeader.biClrUsed = 0;
436 info->bmiHeader.biClrImportant = 0;
437 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
438 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
439 info->bmiHeader.biSizeImage = get_dib_image_size( info );
440 dev = GET_DC_PHYSDEV( dc, pPutImage );
441 err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
442 if ((err && err != ERROR_BAD_FORMAT) ||
443 !(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
445 ret = FALSE;
446 goto done;
448 bits.is_copy = TRUE;
449 bits.free = free_heap_bits;
451 /* make src and points relative to the bitmap */
452 src = dst;
453 src.x -= dst.visrect.left;
454 src.y -= dst.visrect.top;
455 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
456 for (i = 0; i < nvert; i++)
458 pts[i].x -= dst.visrect.left;
459 pts[i].y -= dst.visrect.top;
462 rgn = CreateRectRgn( 0, 0, 0, 0 );
463 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
464 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
465 if (dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY )) ret = FALSE;
467 if (bits.free) bits.free( &bits );
468 DeleteObject( rgn );
470 done:
471 HeapFree( GetProcessHeap(), 0, pts );
472 return ret;
475 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
477 DC *dc = get_nulldrv_dc( dev );
478 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
479 BITMAPINFO *info = (BITMAPINFO *)buffer;
480 struct bitblt_coords src;
481 struct gdi_image_bits bits;
482 COLORREF ret;
484 src.visrect.left = x;
485 src.visrect.top = y;
486 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
487 src.visrect.right = src.visrect.left + 1;
488 src.visrect.bottom = src.visrect.top + 1;
489 src.x = src.visrect.left;
490 src.y = src.visrect.top;
491 src.width = src.height = 1;
493 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
495 dev = GET_DC_PHYSDEV( dc, pGetImage );
496 if (dev->funcs->pGetImage( dev, 0, info, &bits, &src )) return CLR_INVALID;
498 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
499 if (bits.free) bits.free( &bits );
500 return ret;
504 /***********************************************************************
505 * PatBlt (GDI32.@)
507 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
509 DC * dc;
510 BOOL ret = FALSE;
512 if (rop_uses_src( rop )) return FALSE;
513 if ((dc = get_dc_ptr( hdc )))
515 struct bitblt_coords dst;
516 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
518 update_dc( dc );
520 dst.log_x = left;
521 dst.log_y = top;
522 dst.log_width = width;
523 dst.log_height = height;
524 dst.layout = dc->layout;
525 if (rop & NOMIRRORBITMAP)
527 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
528 rop &= ~NOMIRRORBITMAP;
530 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
532 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
533 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
534 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
536 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
538 release_dc_ptr( dc );
540 return ret;
544 /***********************************************************************
545 * BitBlt (GDI32.@)
547 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
548 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
550 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
551 else return StretchBlt( hdcDst, xDst, yDst, width, height,
552 hdcSrc, xSrc, ySrc, width, height, rop );
556 /***********************************************************************
557 * StretchBlt (GDI32.@)
559 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
560 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
562 BOOL ret = FALSE;
563 DC *dcDst, *dcSrc;
565 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
567 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
569 if ((dcSrc = get_dc_ptr( hdcSrc )))
571 struct bitblt_coords src, dst;
572 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
573 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
575 update_dc( dcSrc );
576 update_dc( dcDst );
578 src.log_x = xSrc;
579 src.log_y = ySrc;
580 src.log_width = widthSrc;
581 src.log_height = heightSrc;
582 src.layout = dcSrc->layout;
583 dst.log_x = xDst;
584 dst.log_y = yDst;
585 dst.log_width = widthDst;
586 dst.log_height = heightDst;
587 dst.layout = dcDst->layout;
588 if (rop & NOMIRRORBITMAP)
590 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
591 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
592 rop &= ~NOMIRRORBITMAP;
594 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
596 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",
597 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
598 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
599 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
600 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
602 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
603 release_dc_ptr( dcSrc );
605 release_dc_ptr( dcDst );
606 return ret;
609 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
610 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
612 /***********************************************************************
613 * MaskBlt [GDI32.@]
615 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
616 INT nWidth, INT nHeight, HDC hdcSrc,
617 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
618 INT xMask, INT yMask, DWORD dwRop)
620 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
621 HDC hDC1, hDC2;
622 HBRUSH hbrMask, hbrDst, hbrTmp;
624 static const DWORD ROP3Table[256] =
626 0x00000042, 0x00010289,
627 0x00020C89, 0x000300AA,
628 0x00040C88, 0x000500A9,
629 0x00060865, 0x000702C5,
630 0x00080F08, 0x00090245,
631 0x000A0329, 0x000B0B2A,
632 0x000C0324, 0x000D0B25,
633 0x000E08A5, 0x000F0001,
634 0x00100C85, 0x001100A6,
635 0x00120868, 0x001302C8,
636 0x00140869, 0x001502C9,
637 0x00165CCA, 0x00171D54,
638 0x00180D59, 0x00191CC8,
639 0x001A06C5, 0x001B0768,
640 0x001C06CA, 0x001D0766,
641 0x001E01A5, 0x001F0385,
642 0x00200F09, 0x00210248,
643 0x00220326, 0x00230B24,
644 0x00240D55, 0x00251CC5,
645 0x002606C8, 0x00271868,
646 0x00280369, 0x002916CA,
647 0x002A0CC9, 0x002B1D58,
648 0x002C0784, 0x002D060A,
649 0x002E064A, 0x002F0E2A,
650 0x0030032A, 0x00310B28,
651 0x00320688, 0x00330008,
652 0x003406C4, 0x00351864,
653 0x003601A8, 0x00370388,
654 0x0038078A, 0x00390604,
655 0x003A0644, 0x003B0E24,
656 0x003C004A, 0x003D18A4,
657 0x003E1B24, 0x003F00EA,
658 0x00400F0A, 0x00410249,
659 0x00420D5D, 0x00431CC4,
660 0x00440328, 0x00450B29,
661 0x004606C6, 0x0047076A,
662 0x00480368, 0x004916C5,
663 0x004A0789, 0x004B0605,
664 0x004C0CC8, 0x004D1954,
665 0x004E0645, 0x004F0E25,
666 0x00500325, 0x00510B26,
667 0x005206C9, 0x00530764,
668 0x005408A9, 0x00550009,
669 0x005601A9, 0x00570389,
670 0x00580785, 0x00590609,
671 0x005A0049, 0x005B18A9,
672 0x005C0649, 0x005D0E29,
673 0x005E1B29, 0x005F00E9,
674 0x00600365, 0x006116C6,
675 0x00620786, 0x00630608,
676 0x00640788, 0x00650606,
677 0x00660046, 0x006718A8,
678 0x006858A6, 0x00690145,
679 0x006A01E9, 0x006B178A,
680 0x006C01E8, 0x006D1785,
681 0x006E1E28, 0x006F0C65,
682 0x00700CC5, 0x00711D5C,
683 0x00720648, 0x00730E28,
684 0x00740646, 0x00750E26,
685 0x00761B28, 0x007700E6,
686 0x007801E5, 0x00791786,
687 0x007A1E29, 0x007B0C68,
688 0x007C1E24, 0x007D0C69,
689 0x007E0955, 0x007F03C9,
690 0x008003E9, 0x00810975,
691 0x00820C49, 0x00831E04,
692 0x00840C48, 0x00851E05,
693 0x008617A6, 0x008701C5,
694 0x008800C6, 0x00891B08,
695 0x008A0E06, 0x008B0666,
696 0x008C0E08, 0x008D0668,
697 0x008E1D7C, 0x008F0CE5,
698 0x00900C45, 0x00911E08,
699 0x009217A9, 0x009301C4,
700 0x009417AA, 0x009501C9,
701 0x00960169, 0x0097588A,
702 0x00981888, 0x00990066,
703 0x009A0709, 0x009B07A8,
704 0x009C0704, 0x009D07A6,
705 0x009E16E6, 0x009F0345,
706 0x00A000C9, 0x00A11B05,
707 0x00A20E09, 0x00A30669,
708 0x00A41885, 0x00A50065,
709 0x00A60706, 0x00A707A5,
710 0x00A803A9, 0x00A90189,
711 0x00AA0029, 0x00AB0889,
712 0x00AC0744, 0x00AD06E9,
713 0x00AE0B06, 0x00AF0229,
714 0x00B00E05, 0x00B10665,
715 0x00B21974, 0x00B30CE8,
716 0x00B4070A, 0x00B507A9,
717 0x00B616E9, 0x00B70348,
718 0x00B8074A, 0x00B906E6,
719 0x00BA0B09, 0x00BB0226,
720 0x00BC1CE4, 0x00BD0D7D,
721 0x00BE0269, 0x00BF08C9,
722 0x00C000CA, 0x00C11B04,
723 0x00C21884, 0x00C3006A,
724 0x00C40E04, 0x00C50664,
725 0x00C60708, 0x00C707AA,
726 0x00C803A8, 0x00C90184,
727 0x00CA0749, 0x00CB06E4,
728 0x00CC0020, 0x00CD0888,
729 0x00CE0B08, 0x00CF0224,
730 0x00D00E0A, 0x00D1066A,
731 0x00D20705, 0x00D307A4,
732 0x00D41D78, 0x00D50CE9,
733 0x00D616EA, 0x00D70349,
734 0x00D80745, 0x00D906E8,
735 0x00DA1CE9, 0x00DB0D75,
736 0x00DC0B04, 0x00DD0228,
737 0x00DE0268, 0x00DF08C8,
738 0x00E003A5, 0x00E10185,
739 0x00E20746, 0x00E306EA,
740 0x00E40748, 0x00E506E5,
741 0x00E61CE8, 0x00E70D79,
742 0x00E81D74, 0x00E95CE6,
743 0x00EA02E9, 0x00EB0849,
744 0x00EC02E8, 0x00ED0848,
745 0x00EE0086, 0x00EF0A08,
746 0x00F00021, 0x00F10885,
747 0x00F20B05, 0x00F3022A,
748 0x00F40B0A, 0x00F50225,
749 0x00F60265, 0x00F708C5,
750 0x00F802E5, 0x00F90845,
751 0x00FA0089, 0x00FB0A09,
752 0x00FC008A, 0x00FD0A0A,
753 0x00FE02A9, 0x00FF0062,
756 if (!hbmMask)
757 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
759 hbrMask = CreatePatternBrush(hbmMask);
760 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
762 /* make bitmap */
763 hDC1 = CreateCompatibleDC(hdcDest);
764 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
765 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
767 /* draw using bkgnd rop */
768 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
769 hbrTmp = SelectObject(hDC1, hbrDst);
770 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
771 SelectObject(hDC1, hbrTmp);
773 /* make bitmap */
774 hDC2 = CreateCompatibleDC(hdcDest);
775 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
776 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
778 /* draw using foregnd rop */
779 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
780 hbrTmp = SelectObject(hDC2, hbrDst);
781 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
783 /* combine both using the mask as a pattern brush */
784 SelectObject(hDC2, hbrMask);
785 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
786 SelectObject(hDC2, hbrTmp);
788 /* blit to dst */
789 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
791 /* restore all objects */
792 SelectObject(hdcDest, hbrDst);
793 SelectObject(hDC1, hOldBitmap1);
794 SelectObject(hDC2, hOldBitmap2);
796 /* delete all temp objects */
797 DeleteObject(hBitmap1);
798 DeleteObject(hBitmap2);
799 DeleteObject(hbrMask);
801 DeleteDC(hDC1);
802 DeleteDC(hDC2);
804 return TRUE;
807 /******************************************************************************
808 * GdiTransparentBlt [GDI32.@]
810 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
811 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
812 UINT crTransparent )
814 BOOL ret = FALSE;
815 HDC hdcWork;
816 HBITMAP bmpWork;
817 HGDIOBJ oldWork;
818 HDC hdcMask = NULL;
819 HBITMAP bmpMask = NULL;
820 HBITMAP oldMask = NULL;
821 COLORREF oldBackground;
822 COLORREF oldForeground;
823 int oldStretchMode;
825 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
826 TRACE("Cannot mirror\n");
827 return FALSE;
830 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
831 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
833 /* Stretch bitmap */
834 oldStretchMode = GetStretchBltMode(hdcSrc);
835 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
836 SetStretchBltMode(hdcSrc, COLORONCOLOR);
837 hdcWork = CreateCompatibleDC(hdcDest);
838 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
839 oldWork = SelectObject(hdcWork, bmpWork);
840 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
841 TRACE("Failed to stretch\n");
842 goto error;
844 SetBkColor(hdcWork, crTransparent);
846 /* Create mask */
847 hdcMask = CreateCompatibleDC(hdcDest);
848 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
849 oldMask = SelectObject(hdcMask, bmpMask);
850 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
851 TRACE("Failed to create mask\n");
852 goto error;
855 /* Replace transparent color with black */
856 SetBkColor(hdcWork, RGB(0,0,0));
857 SetTextColor(hdcWork, RGB(255,255,255));
858 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
859 TRACE("Failed to mask out background\n");
860 goto error;
863 /* Replace non-transparent area on destination with black */
864 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
865 TRACE("Failed to clear destination area\n");
866 goto error;
869 /* Draw the image */
870 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
871 TRACE("Failed to paint image\n");
872 goto error;
875 ret = TRUE;
876 error:
877 SetStretchBltMode(hdcSrc, oldStretchMode);
878 SetBkColor(hdcDest, oldBackground);
879 SetTextColor(hdcDest, oldForeground);
880 if(hdcWork) {
881 SelectObject(hdcWork, oldWork);
882 DeleteDC(hdcWork);
884 if(bmpWork) DeleteObject(bmpWork);
885 if(hdcMask) {
886 SelectObject(hdcMask, oldMask);
887 DeleteDC(hdcMask);
889 if(bmpMask) DeleteObject(bmpMask);
890 return ret;
893 /******************************************************************************
894 * GdiAlphaBlend [GDI32.@]
896 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
897 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
898 BLENDFUNCTION blendFunction)
900 BOOL ret = FALSE;
901 DC *dcDst, *dcSrc;
903 dcSrc = get_dc_ptr( hdcSrc );
904 if (!dcSrc) return FALSE;
906 if ((dcDst = get_dc_ptr( hdcDst )))
908 struct bitblt_coords src, dst;
909 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
910 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
912 update_dc( dcSrc );
913 update_dc( dcDst );
915 src.log_x = xSrc;
916 src.log_y = ySrc;
917 src.log_width = widthSrc;
918 src.log_height = heightSrc;
919 src.layout = GetLayout( src_dev->hdc );
920 dst.log_x = xDst;
921 dst.log_y = yDst;
922 dst.log_width = widthDst;
923 dst.log_height = heightDst;
924 dst.layout = GetLayout( dst_dev->hdc );
925 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
927 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",
928 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
929 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
930 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
931 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
932 blendFunction.BlendOp, blendFunction.BlendFlags,
933 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
935 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
936 (dcSrc->header.type == OBJ_MEMDC &&
937 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
938 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
940 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
941 SetLastError( ERROR_INVALID_PARAMETER );
942 ret = FALSE;
944 else if (dst.width < 0 || dst.height < 0)
946 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
947 SetLastError( ERROR_INVALID_PARAMETER );
948 ret = FALSE;
950 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
951 src.y + src.height > dst.y && src.y < dst.y + dst.height)
953 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
954 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
955 SetLastError( ERROR_INVALID_PARAMETER );
956 ret = FALSE;
958 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
960 release_dc_ptr( dcDst );
962 release_dc_ptr( dcSrc );
963 return ret;
966 /*********************************************************************
967 * PlgBlt [GDI32.@]
970 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
971 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
972 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
974 int oldgMode;
975 /* parallelogram coords */
976 POINT plg[3];
977 /* rect coords */
978 POINT rect[3];
979 XFORM xf;
980 XFORM SrcXf;
981 XFORM oldDestXf;
982 double det;
984 /* save actual mode, set GM_ADVANCED */
985 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
986 if (oldgMode == 0)
987 return FALSE;
989 memcpy(plg,lpPoint,sizeof(POINT)*3);
990 rect[0].x = nXSrc;
991 rect[0].y = nYSrc;
992 rect[1].x = nXSrc + nWidth;
993 rect[1].y = nYSrc;
994 rect[2].x = nXSrc;
995 rect[2].y = nYSrc + nHeight;
996 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
997 /* determinant */
998 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);
1000 if (fabs(det) < 1e-5)
1002 SetGraphicsMode(hdcDest,oldgMode);
1003 return FALSE;
1006 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1007 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1009 /* X components */
1010 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;
1011 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;
1012 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1013 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1014 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1015 ) / det;
1017 /* Y components */
1018 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;
1019 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;
1020 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1021 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1022 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1023 ) / det;
1025 GetWorldTransform(hdcSrc,&SrcXf);
1026 CombineTransform(&xf,&xf,&SrcXf);
1028 /* save actual dest transform */
1029 GetWorldTransform(hdcDest,&oldDestXf);
1031 SetWorldTransform(hdcDest,&xf);
1032 /* now destination and source DCs use same coords */
1033 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1034 hdcSrc, nXSrc,nYSrc,
1035 hbmMask,xMask,yMask,
1036 SRCCOPY);
1037 /* restore dest DC */
1038 SetWorldTransform(hdcDest,&oldDestXf);
1039 SetGraphicsMode(hdcDest,oldgMode);
1041 return TRUE;