windowscodecs: Implement JpegEncoder_Frame_SetResolution.
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
bloba97231c69bcd1b331db3477bd56491cde4b7e9d1
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 reset_bounds( &dst.visrect );
412 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
414 ULONG v = ((ULONG *)grad_array)[i];
415 dst.visrect.left = min( dst.visrect.left, pts[v].x );
416 dst.visrect.top = min( dst.visrect.top, pts[v].y );
417 dst.visrect.right = max( dst.visrect.right, pts[v].x );
418 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
421 dst.x = dst.visrect.left;
422 dst.y = dst.visrect.top;
423 dst.width = dst.visrect.right - dst.visrect.left;
424 dst.height = dst.visrect.bottom - dst.visrect.top;
425 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
427 /* query the bitmap format */
428 info->bmiHeader.biSize = sizeof(info->bmiHeader);
429 info->bmiHeader.biPlanes = 1;
430 info->bmiHeader.biBitCount = 0;
431 info->bmiHeader.biCompression = BI_RGB;
432 info->bmiHeader.biXPelsPerMeter = 0;
433 info->bmiHeader.biYPelsPerMeter = 0;
434 info->bmiHeader.biClrUsed = 0;
435 info->bmiHeader.biClrImportant = 0;
436 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
437 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
438 info->bmiHeader.biSizeImage = 0;
439 dev = GET_DC_PHYSDEV( dc, pPutImage );
440 err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
441 if (err && err != ERROR_BAD_FORMAT) goto done;
443 info->bmiHeader.biSizeImage = get_dib_image_size( info );
444 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
445 goto done;
446 bits.is_copy = TRUE;
447 bits.free = free_heap_bits;
449 /* make src and points relative to the bitmap */
450 src = dst;
451 src.x -= dst.visrect.left;
452 src.y -= dst.visrect.top;
453 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
454 for (i = 0; i < nvert; i++)
456 pts[i].x -= dst.visrect.left;
457 pts[i].y -= dst.visrect.top;
460 rgn = CreateRectRgn( 0, 0, 0, 0 );
461 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
462 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
463 ret = !dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY );
465 if (bits.free) bits.free( &bits );
466 DeleteObject( rgn );
468 done:
469 HeapFree( GetProcessHeap(), 0, pts );
470 return ret;
473 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
475 DC *dc = get_nulldrv_dc( dev );
476 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
477 BITMAPINFO *info = (BITMAPINFO *)buffer;
478 struct bitblt_coords src;
479 struct gdi_image_bits bits;
480 COLORREF ret;
482 src.visrect.left = x;
483 src.visrect.top = y;
484 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
485 src.visrect.right = src.visrect.left + 1;
486 src.visrect.bottom = src.visrect.top + 1;
487 src.x = src.visrect.left;
488 src.y = src.visrect.top;
489 src.width = src.height = 1;
491 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
493 dev = GET_DC_PHYSDEV( dc, pGetImage );
494 if (dev->funcs->pGetImage( dev, 0, info, &bits, &src )) return CLR_INVALID;
496 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
497 if (bits.free) bits.free( &bits );
498 return ret;
502 /***********************************************************************
503 * PatBlt (GDI32.@)
505 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
507 DC * dc;
508 BOOL ret = FALSE;
510 if (rop_uses_src( rop )) return FALSE;
511 if ((dc = get_dc_ptr( hdc )))
513 struct bitblt_coords dst;
514 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
516 update_dc( dc );
518 dst.log_x = left;
519 dst.log_y = top;
520 dst.log_width = width;
521 dst.log_height = height;
522 dst.layout = dc->layout;
523 if (rop & NOMIRRORBITMAP)
525 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
526 rop &= ~NOMIRRORBITMAP;
528 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
530 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
531 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
532 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
534 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
536 release_dc_ptr( dc );
538 return ret;
542 /***********************************************************************
543 * BitBlt (GDI32.@)
545 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
546 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
548 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
549 else return StretchBlt( hdcDst, xDst, yDst, width, height,
550 hdcSrc, xSrc, ySrc, width, height, rop );
554 /***********************************************************************
555 * StretchBlt (GDI32.@)
557 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
558 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
560 BOOL ret = FALSE;
561 DC *dcDst, *dcSrc;
563 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
565 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
567 if ((dcSrc = get_dc_ptr( hdcSrc )))
569 struct bitblt_coords src, dst;
570 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
571 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
573 update_dc( dcSrc );
574 update_dc( dcDst );
576 src.log_x = xSrc;
577 src.log_y = ySrc;
578 src.log_width = widthSrc;
579 src.log_height = heightSrc;
580 src.layout = dcSrc->layout;
581 dst.log_x = xDst;
582 dst.log_y = yDst;
583 dst.log_width = widthDst;
584 dst.log_height = heightDst;
585 dst.layout = dcDst->layout;
586 if (rop & NOMIRRORBITMAP)
588 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
589 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
590 rop &= ~NOMIRRORBITMAP;
592 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
594 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",
595 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
596 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
597 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
598 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
600 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
601 release_dc_ptr( dcSrc );
603 release_dc_ptr( dcDst );
604 return ret;
607 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
608 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
610 /***********************************************************************
611 * MaskBlt [GDI32.@]
613 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
614 INT nWidth, INT nHeight, HDC hdcSrc,
615 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
616 INT xMask, INT yMask, DWORD dwRop)
618 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
619 HDC hDC1, hDC2;
620 HBRUSH hbrMask, hbrDst, hbrTmp;
622 static const DWORD ROP3Table[256] =
624 0x00000042, 0x00010289,
625 0x00020C89, 0x000300AA,
626 0x00040C88, 0x000500A9,
627 0x00060865, 0x000702C5,
628 0x00080F08, 0x00090245,
629 0x000A0329, 0x000B0B2A,
630 0x000C0324, 0x000D0B25,
631 0x000E08A5, 0x000F0001,
632 0x00100C85, 0x001100A6,
633 0x00120868, 0x001302C8,
634 0x00140869, 0x001502C9,
635 0x00165CCA, 0x00171D54,
636 0x00180D59, 0x00191CC8,
637 0x001A06C5, 0x001B0768,
638 0x001C06CA, 0x001D0766,
639 0x001E01A5, 0x001F0385,
640 0x00200F09, 0x00210248,
641 0x00220326, 0x00230B24,
642 0x00240D55, 0x00251CC5,
643 0x002606C8, 0x00271868,
644 0x00280369, 0x002916CA,
645 0x002A0CC9, 0x002B1D58,
646 0x002C0784, 0x002D060A,
647 0x002E064A, 0x002F0E2A,
648 0x0030032A, 0x00310B28,
649 0x00320688, 0x00330008,
650 0x003406C4, 0x00351864,
651 0x003601A8, 0x00370388,
652 0x0038078A, 0x00390604,
653 0x003A0644, 0x003B0E24,
654 0x003C004A, 0x003D18A4,
655 0x003E1B24, 0x003F00EA,
656 0x00400F0A, 0x00410249,
657 0x00420D5D, 0x00431CC4,
658 0x00440328, 0x00450B29,
659 0x004606C6, 0x0047076A,
660 0x00480368, 0x004916C5,
661 0x004A0789, 0x004B0605,
662 0x004C0CC8, 0x004D1954,
663 0x004E0645, 0x004F0E25,
664 0x00500325, 0x00510B26,
665 0x005206C9, 0x00530764,
666 0x005408A9, 0x00550009,
667 0x005601A9, 0x00570389,
668 0x00580785, 0x00590609,
669 0x005A0049, 0x005B18A9,
670 0x005C0649, 0x005D0E29,
671 0x005E1B29, 0x005F00E9,
672 0x00600365, 0x006116C6,
673 0x00620786, 0x00630608,
674 0x00640788, 0x00650606,
675 0x00660046, 0x006718A8,
676 0x006858A6, 0x00690145,
677 0x006A01E9, 0x006B178A,
678 0x006C01E8, 0x006D1785,
679 0x006E1E28, 0x006F0C65,
680 0x00700CC5, 0x00711D5C,
681 0x00720648, 0x00730E28,
682 0x00740646, 0x00750E26,
683 0x00761B28, 0x007700E6,
684 0x007801E5, 0x00791786,
685 0x007A1E29, 0x007B0C68,
686 0x007C1E24, 0x007D0C69,
687 0x007E0955, 0x007F03C9,
688 0x008003E9, 0x00810975,
689 0x00820C49, 0x00831E04,
690 0x00840C48, 0x00851E05,
691 0x008617A6, 0x008701C5,
692 0x008800C6, 0x00891B08,
693 0x008A0E06, 0x008B0666,
694 0x008C0E08, 0x008D0668,
695 0x008E1D7C, 0x008F0CE5,
696 0x00900C45, 0x00911E08,
697 0x009217A9, 0x009301C4,
698 0x009417AA, 0x009501C9,
699 0x00960169, 0x0097588A,
700 0x00981888, 0x00990066,
701 0x009A0709, 0x009B07A8,
702 0x009C0704, 0x009D07A6,
703 0x009E16E6, 0x009F0345,
704 0x00A000C9, 0x00A11B05,
705 0x00A20E09, 0x00A30669,
706 0x00A41885, 0x00A50065,
707 0x00A60706, 0x00A707A5,
708 0x00A803A9, 0x00A90189,
709 0x00AA0029, 0x00AB0889,
710 0x00AC0744, 0x00AD06E9,
711 0x00AE0B06, 0x00AF0229,
712 0x00B00E05, 0x00B10665,
713 0x00B21974, 0x00B30CE8,
714 0x00B4070A, 0x00B507A9,
715 0x00B616E9, 0x00B70348,
716 0x00B8074A, 0x00B906E6,
717 0x00BA0B09, 0x00BB0226,
718 0x00BC1CE4, 0x00BD0D7D,
719 0x00BE0269, 0x00BF08C9,
720 0x00C000CA, 0x00C11B04,
721 0x00C21884, 0x00C3006A,
722 0x00C40E04, 0x00C50664,
723 0x00C60708, 0x00C707AA,
724 0x00C803A8, 0x00C90184,
725 0x00CA0749, 0x00CB06E4,
726 0x00CC0020, 0x00CD0888,
727 0x00CE0B08, 0x00CF0224,
728 0x00D00E0A, 0x00D1066A,
729 0x00D20705, 0x00D307A4,
730 0x00D41D78, 0x00D50CE9,
731 0x00D616EA, 0x00D70349,
732 0x00D80745, 0x00D906E8,
733 0x00DA1CE9, 0x00DB0D75,
734 0x00DC0B04, 0x00DD0228,
735 0x00DE0268, 0x00DF08C8,
736 0x00E003A5, 0x00E10185,
737 0x00E20746, 0x00E306EA,
738 0x00E40748, 0x00E506E5,
739 0x00E61CE8, 0x00E70D79,
740 0x00E81D74, 0x00E95CE6,
741 0x00EA02E9, 0x00EB0849,
742 0x00EC02E8, 0x00ED0848,
743 0x00EE0086, 0x00EF0A08,
744 0x00F00021, 0x00F10885,
745 0x00F20B05, 0x00F3022A,
746 0x00F40B0A, 0x00F50225,
747 0x00F60265, 0x00F708C5,
748 0x00F802E5, 0x00F90845,
749 0x00FA0089, 0x00FB0A09,
750 0x00FC008A, 0x00FD0A0A,
751 0x00FE02A9, 0x00FF0062,
754 if (!hbmMask)
755 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
757 hbrMask = CreatePatternBrush(hbmMask);
758 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
760 /* make bitmap */
761 hDC1 = CreateCompatibleDC(hdcDest);
762 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
763 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
765 /* draw using bkgnd rop */
766 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
767 hbrTmp = SelectObject(hDC1, hbrDst);
768 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
769 SelectObject(hDC1, hbrTmp);
771 /* make bitmap */
772 hDC2 = CreateCompatibleDC(hdcDest);
773 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
774 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
776 /* draw using foregnd rop */
777 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
778 hbrTmp = SelectObject(hDC2, hbrDst);
779 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
781 /* combine both using the mask as a pattern brush */
782 SelectObject(hDC2, hbrMask);
783 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
784 SelectObject(hDC2, hbrTmp);
786 /* blit to dst */
787 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
789 /* restore all objects */
790 SelectObject(hdcDest, hbrDst);
791 SelectObject(hDC1, hOldBitmap1);
792 SelectObject(hDC2, hOldBitmap2);
794 /* delete all temp objects */
795 DeleteObject(hBitmap1);
796 DeleteObject(hBitmap2);
797 DeleteObject(hbrMask);
799 DeleteDC(hDC1);
800 DeleteDC(hDC2);
802 return TRUE;
805 /******************************************************************************
806 * GdiTransparentBlt [GDI32.@]
808 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
809 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
810 UINT crTransparent )
812 BOOL ret = FALSE;
813 HDC hdcWork;
814 HBITMAP bmpWork;
815 HGDIOBJ oldWork;
816 HDC hdcMask = NULL;
817 HBITMAP bmpMask = NULL;
818 HBITMAP oldMask = NULL;
819 COLORREF oldBackground;
820 COLORREF oldForeground;
821 int oldStretchMode;
823 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
824 TRACE("Cannot mirror\n");
825 return FALSE;
828 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
829 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
831 /* Stretch bitmap */
832 oldStretchMode = GetStretchBltMode(hdcSrc);
833 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
834 SetStretchBltMode(hdcSrc, COLORONCOLOR);
835 hdcWork = CreateCompatibleDC(hdcDest);
836 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
837 oldWork = SelectObject(hdcWork, bmpWork);
838 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
839 TRACE("Failed to stretch\n");
840 goto error;
842 SetBkColor(hdcWork, crTransparent);
844 /* Create mask */
845 hdcMask = CreateCompatibleDC(hdcDest);
846 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
847 oldMask = SelectObject(hdcMask, bmpMask);
848 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
849 TRACE("Failed to create mask\n");
850 goto error;
853 /* Replace transparent color with black */
854 SetBkColor(hdcWork, RGB(0,0,0));
855 SetTextColor(hdcWork, RGB(255,255,255));
856 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
857 TRACE("Failed to mask out background\n");
858 goto error;
861 /* Replace non-transparent area on destination with black */
862 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
863 TRACE("Failed to clear destination area\n");
864 goto error;
867 /* Draw the image */
868 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
869 TRACE("Failed to paint image\n");
870 goto error;
873 ret = TRUE;
874 error:
875 SetStretchBltMode(hdcSrc, oldStretchMode);
876 SetBkColor(hdcDest, oldBackground);
877 SetTextColor(hdcDest, oldForeground);
878 if(hdcWork) {
879 SelectObject(hdcWork, oldWork);
880 DeleteDC(hdcWork);
882 if(bmpWork) DeleteObject(bmpWork);
883 if(hdcMask) {
884 SelectObject(hdcMask, oldMask);
885 DeleteDC(hdcMask);
887 if(bmpMask) DeleteObject(bmpMask);
888 return ret;
891 /******************************************************************************
892 * GdiAlphaBlend [GDI32.@]
894 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
895 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
896 BLENDFUNCTION blendFunction)
898 BOOL ret = FALSE;
899 DC *dcDst, *dcSrc;
901 dcSrc = get_dc_ptr( hdcSrc );
902 if (!dcSrc) return FALSE;
904 if ((dcDst = get_dc_ptr( hdcDst )))
906 struct bitblt_coords src, dst;
907 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
908 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
910 update_dc( dcSrc );
911 update_dc( dcDst );
913 src.log_x = xSrc;
914 src.log_y = ySrc;
915 src.log_width = widthSrc;
916 src.log_height = heightSrc;
917 src.layout = GetLayout( src_dev->hdc );
918 dst.log_x = xDst;
919 dst.log_y = yDst;
920 dst.log_width = widthDst;
921 dst.log_height = heightDst;
922 dst.layout = GetLayout( dst_dev->hdc );
923 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
925 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",
926 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
927 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
928 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
929 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
930 blendFunction.BlendOp, blendFunction.BlendFlags,
931 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
933 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
934 src.log_width < 0 || src.log_height < 0 ||
935 (dcSrc->header.type == OBJ_MEMDC &&
936 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
937 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
939 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
940 SetLastError( ERROR_INVALID_PARAMETER );
941 ret = FALSE;
943 else if (dst.log_width < 0 || dst.log_height < 0)
945 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
946 dst.log_x, dst.log_y, dst.log_width, dst.log_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;