msxml3: Support comment nodes in MXWriter.
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
blob71b8e8f14b847ceb0b526f6ad4fae8ae7932abb7
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 = FALSE;
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 = 0;
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) goto done;
444 info->bmiHeader.biSizeImage = get_dib_image_size( info );
445 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
446 goto done;
447 bits.is_copy = TRUE;
448 bits.free = free_heap_bits;
450 /* make src and points relative to the bitmap */
451 src = dst;
452 src.x -= dst.visrect.left;
453 src.y -= dst.visrect.top;
454 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
455 for (i = 0; i < nvert; i++)
457 pts[i].x -= dst.visrect.left;
458 pts[i].y -= dst.visrect.top;
461 rgn = CreateRectRgn( 0, 0, 0, 0 );
462 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
463 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
464 ret = !dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY );
466 if (bits.free) bits.free( &bits );
467 DeleteObject( rgn );
469 done:
470 HeapFree( GetProcessHeap(), 0, pts );
471 return ret;
474 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
476 DC *dc = get_nulldrv_dc( dev );
477 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
478 BITMAPINFO *info = (BITMAPINFO *)buffer;
479 struct bitblt_coords src;
480 struct gdi_image_bits bits;
481 COLORREF ret;
483 src.visrect.left = x;
484 src.visrect.top = y;
485 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
486 src.visrect.right = src.visrect.left + 1;
487 src.visrect.bottom = src.visrect.top + 1;
488 src.x = src.visrect.left;
489 src.y = src.visrect.top;
490 src.width = src.height = 1;
492 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
494 dev = GET_DC_PHYSDEV( dc, pGetImage );
495 if (dev->funcs->pGetImage( dev, 0, info, &bits, &src )) return CLR_INVALID;
497 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
498 if (bits.free) bits.free( &bits );
499 return ret;
503 /***********************************************************************
504 * PatBlt (GDI32.@)
506 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
508 DC * dc;
509 BOOL ret = FALSE;
511 if (rop_uses_src( rop )) return FALSE;
512 if ((dc = get_dc_ptr( hdc )))
514 struct bitblt_coords dst;
515 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
517 update_dc( dc );
519 dst.log_x = left;
520 dst.log_y = top;
521 dst.log_width = width;
522 dst.log_height = height;
523 dst.layout = dc->layout;
524 if (rop & NOMIRRORBITMAP)
526 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
527 rop &= ~NOMIRRORBITMAP;
529 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
531 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
532 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
533 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
535 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
537 release_dc_ptr( dc );
539 return ret;
543 /***********************************************************************
544 * BitBlt (GDI32.@)
546 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
547 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
549 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
550 else return StretchBlt( hdcDst, xDst, yDst, width, height,
551 hdcSrc, xSrc, ySrc, width, height, rop );
555 /***********************************************************************
556 * StretchBlt (GDI32.@)
558 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
559 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
561 BOOL ret = FALSE;
562 DC *dcDst, *dcSrc;
564 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
566 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
568 if ((dcSrc = get_dc_ptr( hdcSrc )))
570 struct bitblt_coords src, dst;
571 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
572 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
574 update_dc( dcSrc );
575 update_dc( dcDst );
577 src.log_x = xSrc;
578 src.log_y = ySrc;
579 src.log_width = widthSrc;
580 src.log_height = heightSrc;
581 src.layout = dcSrc->layout;
582 dst.log_x = xDst;
583 dst.log_y = yDst;
584 dst.log_width = widthDst;
585 dst.log_height = heightDst;
586 dst.layout = dcDst->layout;
587 if (rop & NOMIRRORBITMAP)
589 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
590 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
591 rop &= ~NOMIRRORBITMAP;
593 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
595 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",
596 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
597 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
598 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
599 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
601 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
602 release_dc_ptr( dcSrc );
604 release_dc_ptr( dcDst );
605 return ret;
608 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
609 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
611 /***********************************************************************
612 * MaskBlt [GDI32.@]
614 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
615 INT nWidth, INT nHeight, HDC hdcSrc,
616 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
617 INT xMask, INT yMask, DWORD dwRop)
619 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
620 HDC hDC1, hDC2;
621 HBRUSH hbrMask, hbrDst, hbrTmp;
623 static const DWORD ROP3Table[256] =
625 0x00000042, 0x00010289,
626 0x00020C89, 0x000300AA,
627 0x00040C88, 0x000500A9,
628 0x00060865, 0x000702C5,
629 0x00080F08, 0x00090245,
630 0x000A0329, 0x000B0B2A,
631 0x000C0324, 0x000D0B25,
632 0x000E08A5, 0x000F0001,
633 0x00100C85, 0x001100A6,
634 0x00120868, 0x001302C8,
635 0x00140869, 0x001502C9,
636 0x00165CCA, 0x00171D54,
637 0x00180D59, 0x00191CC8,
638 0x001A06C5, 0x001B0768,
639 0x001C06CA, 0x001D0766,
640 0x001E01A5, 0x001F0385,
641 0x00200F09, 0x00210248,
642 0x00220326, 0x00230B24,
643 0x00240D55, 0x00251CC5,
644 0x002606C8, 0x00271868,
645 0x00280369, 0x002916CA,
646 0x002A0CC9, 0x002B1D58,
647 0x002C0784, 0x002D060A,
648 0x002E064A, 0x002F0E2A,
649 0x0030032A, 0x00310B28,
650 0x00320688, 0x00330008,
651 0x003406C4, 0x00351864,
652 0x003601A8, 0x00370388,
653 0x0038078A, 0x00390604,
654 0x003A0644, 0x003B0E24,
655 0x003C004A, 0x003D18A4,
656 0x003E1B24, 0x003F00EA,
657 0x00400F0A, 0x00410249,
658 0x00420D5D, 0x00431CC4,
659 0x00440328, 0x00450B29,
660 0x004606C6, 0x0047076A,
661 0x00480368, 0x004916C5,
662 0x004A0789, 0x004B0605,
663 0x004C0CC8, 0x004D1954,
664 0x004E0645, 0x004F0E25,
665 0x00500325, 0x00510B26,
666 0x005206C9, 0x00530764,
667 0x005408A9, 0x00550009,
668 0x005601A9, 0x00570389,
669 0x00580785, 0x00590609,
670 0x005A0049, 0x005B18A9,
671 0x005C0649, 0x005D0E29,
672 0x005E1B29, 0x005F00E9,
673 0x00600365, 0x006116C6,
674 0x00620786, 0x00630608,
675 0x00640788, 0x00650606,
676 0x00660046, 0x006718A8,
677 0x006858A6, 0x00690145,
678 0x006A01E9, 0x006B178A,
679 0x006C01E8, 0x006D1785,
680 0x006E1E28, 0x006F0C65,
681 0x00700CC5, 0x00711D5C,
682 0x00720648, 0x00730E28,
683 0x00740646, 0x00750E26,
684 0x00761B28, 0x007700E6,
685 0x007801E5, 0x00791786,
686 0x007A1E29, 0x007B0C68,
687 0x007C1E24, 0x007D0C69,
688 0x007E0955, 0x007F03C9,
689 0x008003E9, 0x00810975,
690 0x00820C49, 0x00831E04,
691 0x00840C48, 0x00851E05,
692 0x008617A6, 0x008701C5,
693 0x008800C6, 0x00891B08,
694 0x008A0E06, 0x008B0666,
695 0x008C0E08, 0x008D0668,
696 0x008E1D7C, 0x008F0CE5,
697 0x00900C45, 0x00911E08,
698 0x009217A9, 0x009301C4,
699 0x009417AA, 0x009501C9,
700 0x00960169, 0x0097588A,
701 0x00981888, 0x00990066,
702 0x009A0709, 0x009B07A8,
703 0x009C0704, 0x009D07A6,
704 0x009E16E6, 0x009F0345,
705 0x00A000C9, 0x00A11B05,
706 0x00A20E09, 0x00A30669,
707 0x00A41885, 0x00A50065,
708 0x00A60706, 0x00A707A5,
709 0x00A803A9, 0x00A90189,
710 0x00AA0029, 0x00AB0889,
711 0x00AC0744, 0x00AD06E9,
712 0x00AE0B06, 0x00AF0229,
713 0x00B00E05, 0x00B10665,
714 0x00B21974, 0x00B30CE8,
715 0x00B4070A, 0x00B507A9,
716 0x00B616E9, 0x00B70348,
717 0x00B8074A, 0x00B906E6,
718 0x00BA0B09, 0x00BB0226,
719 0x00BC1CE4, 0x00BD0D7D,
720 0x00BE0269, 0x00BF08C9,
721 0x00C000CA, 0x00C11B04,
722 0x00C21884, 0x00C3006A,
723 0x00C40E04, 0x00C50664,
724 0x00C60708, 0x00C707AA,
725 0x00C803A8, 0x00C90184,
726 0x00CA0749, 0x00CB06E4,
727 0x00CC0020, 0x00CD0888,
728 0x00CE0B08, 0x00CF0224,
729 0x00D00E0A, 0x00D1066A,
730 0x00D20705, 0x00D307A4,
731 0x00D41D78, 0x00D50CE9,
732 0x00D616EA, 0x00D70349,
733 0x00D80745, 0x00D906E8,
734 0x00DA1CE9, 0x00DB0D75,
735 0x00DC0B04, 0x00DD0228,
736 0x00DE0268, 0x00DF08C8,
737 0x00E003A5, 0x00E10185,
738 0x00E20746, 0x00E306EA,
739 0x00E40748, 0x00E506E5,
740 0x00E61CE8, 0x00E70D79,
741 0x00E81D74, 0x00E95CE6,
742 0x00EA02E9, 0x00EB0849,
743 0x00EC02E8, 0x00ED0848,
744 0x00EE0086, 0x00EF0A08,
745 0x00F00021, 0x00F10885,
746 0x00F20B05, 0x00F3022A,
747 0x00F40B0A, 0x00F50225,
748 0x00F60265, 0x00F708C5,
749 0x00F802E5, 0x00F90845,
750 0x00FA0089, 0x00FB0A09,
751 0x00FC008A, 0x00FD0A0A,
752 0x00FE02A9, 0x00FF0062,
755 if (!hbmMask)
756 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
758 hbrMask = CreatePatternBrush(hbmMask);
759 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
761 /* make bitmap */
762 hDC1 = CreateCompatibleDC(hdcDest);
763 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
764 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
766 /* draw using bkgnd rop */
767 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
768 hbrTmp = SelectObject(hDC1, hbrDst);
769 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
770 SelectObject(hDC1, hbrTmp);
772 /* make bitmap */
773 hDC2 = CreateCompatibleDC(hdcDest);
774 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
775 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
777 /* draw using foregnd rop */
778 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
779 hbrTmp = SelectObject(hDC2, hbrDst);
780 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
782 /* combine both using the mask as a pattern brush */
783 SelectObject(hDC2, hbrMask);
784 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
785 SelectObject(hDC2, hbrTmp);
787 /* blit to dst */
788 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
790 /* restore all objects */
791 SelectObject(hdcDest, hbrDst);
792 SelectObject(hDC1, hOldBitmap1);
793 SelectObject(hDC2, hOldBitmap2);
795 /* delete all temp objects */
796 DeleteObject(hBitmap1);
797 DeleteObject(hBitmap2);
798 DeleteObject(hbrMask);
800 DeleteDC(hDC1);
801 DeleteDC(hDC2);
803 return TRUE;
806 /******************************************************************************
807 * GdiTransparentBlt [GDI32.@]
809 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
810 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
811 UINT crTransparent )
813 BOOL ret = FALSE;
814 HDC hdcWork;
815 HBITMAP bmpWork;
816 HGDIOBJ oldWork;
817 HDC hdcMask = NULL;
818 HBITMAP bmpMask = NULL;
819 HBITMAP oldMask = NULL;
820 COLORREF oldBackground;
821 COLORREF oldForeground;
822 int oldStretchMode;
824 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
825 TRACE("Cannot mirror\n");
826 return FALSE;
829 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
830 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
832 /* Stretch bitmap */
833 oldStretchMode = GetStretchBltMode(hdcSrc);
834 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
835 SetStretchBltMode(hdcSrc, COLORONCOLOR);
836 hdcWork = CreateCompatibleDC(hdcDest);
837 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
838 oldWork = SelectObject(hdcWork, bmpWork);
839 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
840 TRACE("Failed to stretch\n");
841 goto error;
843 SetBkColor(hdcWork, crTransparent);
845 /* Create mask */
846 hdcMask = CreateCompatibleDC(hdcDest);
847 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
848 oldMask = SelectObject(hdcMask, bmpMask);
849 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
850 TRACE("Failed to create mask\n");
851 goto error;
854 /* Replace transparent color with black */
855 SetBkColor(hdcWork, RGB(0,0,0));
856 SetTextColor(hdcWork, RGB(255,255,255));
857 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
858 TRACE("Failed to mask out background\n");
859 goto error;
862 /* Replace non-transparent area on destination with black */
863 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
864 TRACE("Failed to clear destination area\n");
865 goto error;
868 /* Draw the image */
869 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
870 TRACE("Failed to paint image\n");
871 goto error;
874 ret = TRUE;
875 error:
876 SetStretchBltMode(hdcSrc, oldStretchMode);
877 SetBkColor(hdcDest, oldBackground);
878 SetTextColor(hdcDest, oldForeground);
879 if(hdcWork) {
880 SelectObject(hdcWork, oldWork);
881 DeleteDC(hdcWork);
883 if(bmpWork) DeleteObject(bmpWork);
884 if(hdcMask) {
885 SelectObject(hdcMask, oldMask);
886 DeleteDC(hdcMask);
888 if(bmpMask) DeleteObject(bmpMask);
889 return ret;
892 /******************************************************************************
893 * GdiAlphaBlend [GDI32.@]
895 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
896 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
897 BLENDFUNCTION blendFunction)
899 BOOL ret = FALSE;
900 DC *dcDst, *dcSrc;
902 dcSrc = get_dc_ptr( hdcSrc );
903 if (!dcSrc) return FALSE;
905 if ((dcDst = get_dc_ptr( hdcDst )))
907 struct bitblt_coords src, dst;
908 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
909 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
911 update_dc( dcSrc );
912 update_dc( dcDst );
914 src.log_x = xSrc;
915 src.log_y = ySrc;
916 src.log_width = widthSrc;
917 src.log_height = heightSrc;
918 src.layout = GetLayout( src_dev->hdc );
919 dst.log_x = xDst;
920 dst.log_y = yDst;
921 dst.log_width = widthDst;
922 dst.log_height = heightDst;
923 dst.layout = GetLayout( dst_dev->hdc );
924 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
926 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",
927 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
928 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
929 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
930 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
931 blendFunction.BlendOp, blendFunction.BlendFlags,
932 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
934 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
935 src.log_width < 0 || src.log_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.log_width < 0 || dst.log_height < 0)
946 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
947 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
948 SetLastError( ERROR_INVALID_PARAMETER );
949 ret = FALSE;
951 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
952 src.y + src.height > dst.y && src.y < dst.y + dst.height)
954 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
955 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
956 SetLastError( ERROR_INVALID_PARAMETER );
957 ret = FALSE;
959 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
961 release_dc_ptr( dcDst );
963 release_dc_ptr( dcSrc );
964 return ret;
967 /*********************************************************************
968 * PlgBlt [GDI32.@]
971 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
972 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
973 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
975 int oldgMode;
976 /* parallelogram coords */
977 POINT plg[3];
978 /* rect coords */
979 POINT rect[3];
980 XFORM xf;
981 XFORM SrcXf;
982 XFORM oldDestXf;
983 double det;
985 /* save actual mode, set GM_ADVANCED */
986 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
987 if (oldgMode == 0)
988 return FALSE;
990 memcpy(plg,lpPoint,sizeof(POINT)*3);
991 rect[0].x = nXSrc;
992 rect[0].y = nYSrc;
993 rect[1].x = nXSrc + nWidth;
994 rect[1].y = nYSrc;
995 rect[2].x = nXSrc;
996 rect[2].y = nYSrc + nHeight;
997 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
998 /* determinant */
999 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);
1001 if (fabs(det) < 1e-5)
1003 SetGraphicsMode(hdcDest,oldgMode);
1004 return FALSE;
1007 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1008 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1010 /* X components */
1011 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;
1012 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;
1013 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1014 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1015 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1016 ) / det;
1018 /* Y components */
1019 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;
1020 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;
1021 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1022 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1023 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1024 ) / det;
1026 GetWorldTransform(hdcSrc,&SrcXf);
1027 CombineTransform(&xf,&xf,&SrcXf);
1029 /* save actual dest transform */
1030 GetWorldTransform(hdcDest,&oldDestXf);
1032 SetWorldTransform(hdcDest,&xf);
1033 /* now destination and source DCs use same coords */
1034 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1035 hdcSrc, nXSrc,nYSrc,
1036 hbmMask,xMask,yMask,
1037 SRCCOPY);
1038 /* restore dest DC */
1039 SetWorldTransform(hdcDest,&oldDestXf);
1040 SetGraphicsMode(hdcDest,oldgMode);
1042 return TRUE;