gdi32: Add missing check for empty visible rects in the non-stretching case.
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
blobabd4dfc7fe94127caf687c9b75d63758ad57cb0d
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 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
174 return ERROR_OUTOFMEMORY;
176 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
177 if (bits->free) bits->free( bits );
178 bits->ptr = ptr;
179 bits->is_copy = TRUE;
180 bits->free = free_heap_bits;
181 return err;
184 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
185 BITMAPINFO *dst_info, struct bitblt_coords *dst,
186 struct gdi_image_bits *bits, int mode )
188 void *ptr;
189 DWORD err;
191 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
192 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
193 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
194 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
195 return ERROR_OUTOFMEMORY;
197 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
198 if (bits->free) bits->free( bits );
199 bits->ptr = ptr;
200 bits->is_copy = TRUE;
201 bits->free = free_heap_bits;
202 return err;
205 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
206 struct bitblt_coords *src, BITMAPINFO *dst_info,
207 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
209 if (!dst_bits->is_copy)
211 int size = get_dib_image_size( dst_info );
212 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
213 if (!ptr) return ERROR_OUTOFMEMORY;
214 memcpy( ptr, dst_bits->ptr, size );
215 if (dst_bits->free) dst_bits->free( dst_bits );
216 dst_bits->ptr = ptr;
217 dst_bits->is_copy = TRUE;
218 dst_bits->free = free_heap_bits;
220 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
223 /***********************************************************************
224 * null driver fallback implementations
227 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
228 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
230 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
231 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
232 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
233 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
234 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
235 DWORD err;
236 struct gdi_image_bits bits;
238 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
239 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
240 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
241 release_dc_ptr( dc_src );
242 if (err) return FALSE;
244 /* 1-bpp source without a color table uses the destination DC colors */
245 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
247 COLORREF color = GetTextColor( dst_dev->hdc );
248 src_info->bmiColors[0].rgbRed = GetRValue( color );
249 src_info->bmiColors[0].rgbGreen = GetGValue( color );
250 src_info->bmiColors[0].rgbBlue = GetBValue( color );
251 src_info->bmiColors[0].rgbReserved = 0;
252 color = GetBkColor( dst_dev->hdc );
253 src_info->bmiColors[1].rgbRed = GetRValue( color );
254 src_info->bmiColors[1].rgbGreen = GetGValue( color );
255 src_info->bmiColors[1].rgbBlue = GetBValue( color );
256 src_info->bmiColors[1].rgbReserved = 0;
257 src_info->bmiHeader.biClrUsed = 2;
260 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
261 copy_bitmapinfo( dst_info, src_info );
262 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
263 if (err == ERROR_BAD_FORMAT)
265 /* 1-bpp destination without a color table requires a fake 1-entry table
266 * that contains only the background color */
267 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
269 COLORREF color = GetBkColor( src_dev->hdc );
270 dst_info->bmiColors[0].rgbRed = GetRValue( color );
271 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
272 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
273 dst_info->bmiColors[0].rgbReserved = 0;
274 dst_info->bmiHeader.biClrUsed = 1;
277 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
279 /* get rid of the fake 1-bpp table */
280 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
281 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
285 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
286 ((src->width != dst->width) || (src->height != dst->height)))
288 copy_bitmapinfo( src_info, dst_info );
289 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
290 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
293 if (bits.free) bits.free( &bits );
294 return !err;
298 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
299 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
301 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
302 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
303 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
304 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
305 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
306 DWORD err;
307 struct gdi_image_bits bits;
309 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
310 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
311 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
312 release_dc_ptr( dc_src );
313 if (err) goto done;
315 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
316 copy_bitmapinfo( dst_info, src_info );
317 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
318 if (err == ERROR_BAD_FORMAT)
320 /* 1-bpp source without a color table uses black & white */
321 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
323 src_info->bmiColors[0].rgbRed = 0;
324 src_info->bmiColors[0].rgbGreen = 0;
325 src_info->bmiColors[0].rgbBlue = 0;
326 src_info->bmiColors[0].rgbReserved = 0;
327 src_info->bmiColors[1].rgbRed = 0xff;
328 src_info->bmiColors[1].rgbGreen = 0xff;
329 src_info->bmiColors[1].rgbBlue = 0xff;
330 src_info->bmiColors[1].rgbReserved = 0;
331 src_info->bmiHeader.biClrUsed = 2;
334 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
335 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
338 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
339 ((src->width != dst->width) || (src->height != dst->height)))
341 copy_bitmapinfo( src_info, dst_info );
342 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
343 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
346 if (bits.free) bits.free( &bits );
347 done:
348 if (err) SetLastError( err );
349 return !err;
353 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
354 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
356 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
357 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
358 struct gdi_image_bits dst_bits;
359 struct bitblt_coords orig_dst;
360 DC *dc = get_nulldrv_dc( dev );
361 DWORD err;
363 if (info->bmiHeader.biPlanes != 1) goto update_format;
364 if (info->bmiHeader.biBitCount != 32) goto update_format;
365 if (info->bmiHeader.biCompression == BI_BITFIELDS)
367 DWORD *masks = (DWORD *)info->bmiColors;
368 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
369 goto update_format;
372 if (!bits) return ERROR_SUCCESS;
373 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
375 dev = GET_DC_PHYSDEV( dc, pGetImage );
376 orig_dst = *dst;
377 err = dev->funcs->pGetImage( dev, 0, dst_info, &dst_bits, dst );
378 if (err) return err;
380 dev = GET_DC_PHYSDEV( dc, pPutImage );
381 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
382 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
384 if (dst_bits.free) dst_bits.free( &dst_bits );
385 return err;
387 update_format:
388 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
389 return ERROR_INVALID_PARAMETER;
391 info->bmiHeader.biPlanes = 1;
392 info->bmiHeader.biBitCount = 32;
393 info->bmiHeader.biCompression = BI_RGB;
394 info->bmiHeader.biClrUsed = 0;
395 return ERROR_BAD_FORMAT;
398 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
399 void * grad_array, ULONG ngrad, ULONG mode )
401 DC *dc = get_nulldrv_dc( dev );
402 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
403 BITMAPINFO *info = (BITMAPINFO *)buffer;
404 struct bitblt_coords src, dst;
405 struct gdi_image_bits bits;
406 unsigned int i;
407 POINT *pts;
408 BOOL ret = TRUE;
409 DWORD err;
410 HRGN rgn;
412 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
413 for (i = 0; i < nvert; i++)
415 pts[i].x = vert_array[i].x;
416 pts[i].y = vert_array[i].y;
418 LPtoDP( dev->hdc, pts, nvert );
420 /* compute bounding rect of all the rectangles/triangles */
421 dst.visrect.left = dst.visrect.top = INT_MAX;
422 dst.visrect.right = dst.visrect.bottom = INT_MIN;
423 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
425 ULONG v = ((ULONG *)grad_array)[i];
426 dst.visrect.left = min( dst.visrect.left, pts[v].x );
427 dst.visrect.top = min( dst.visrect.top, pts[v].y );
428 dst.visrect.right = max( dst.visrect.right, pts[v].x );
429 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
432 dst.x = dst.visrect.left;
433 dst.y = dst.visrect.top;
434 dst.width = dst.visrect.right - dst.visrect.left;
435 dst.height = dst.visrect.bottom - dst.visrect.top;
436 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
438 /* query the bitmap format */
439 info->bmiHeader.biSize = sizeof(info->bmiHeader);
440 info->bmiHeader.biPlanes = 1;
441 info->bmiHeader.biBitCount = 0;
442 info->bmiHeader.biCompression = BI_RGB;
443 info->bmiHeader.biXPelsPerMeter = 0;
444 info->bmiHeader.biYPelsPerMeter = 0;
445 info->bmiHeader.biClrUsed = 0;
446 info->bmiHeader.biClrImportant = 0;
447 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
448 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
449 info->bmiHeader.biSizeImage = 0;
450 dev = GET_DC_PHYSDEV( dc, pPutImage );
451 err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
452 if ((err && err != ERROR_BAD_FORMAT) ||
453 !(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ))))
455 ret = FALSE;
456 goto done;
458 bits.is_copy = TRUE;
459 bits.free = free_heap_bits;
461 /* make src and points relative to the bitmap */
462 src = dst;
463 src.x -= dst.visrect.left;
464 src.y -= dst.visrect.top;
465 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
466 for (i = 0; i < nvert; i++)
468 pts[i].x -= dst.visrect.left;
469 pts[i].y -= dst.visrect.top;
472 rgn = CreateRectRgn( 0, 0, 0, 0 );
473 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
474 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
475 if (dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY )) ret = FALSE;
477 if (bits.free) bits.free( &bits );
478 DeleteObject( rgn );
480 done:
481 HeapFree( GetProcessHeap(), 0, pts );
482 return ret;
485 /***********************************************************************
486 * PatBlt (GDI32.@)
488 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
490 DC * dc;
491 BOOL ret = FALSE;
493 if (rop_uses_src( rop )) return FALSE;
494 if ((dc = get_dc_ptr( hdc )))
496 struct bitblt_coords dst;
497 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
499 update_dc( dc );
501 dst.log_x = left;
502 dst.log_y = top;
503 dst.log_width = width;
504 dst.log_height = height;
505 dst.layout = dc->layout;
506 if (rop & NOMIRRORBITMAP)
508 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
509 rop &= ~NOMIRRORBITMAP;
511 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
513 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
514 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
515 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
517 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
519 release_dc_ptr( dc );
521 return ret;
525 /***********************************************************************
526 * BitBlt (GDI32.@)
528 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
529 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
531 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
532 else return StretchBlt( hdcDst, xDst, yDst, width, height,
533 hdcSrc, xSrc, ySrc, width, height, rop );
537 /***********************************************************************
538 * StretchBlt (GDI32.@)
540 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
541 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
543 BOOL ret = FALSE;
544 DC *dcDst, *dcSrc;
546 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
548 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
550 if ((dcSrc = get_dc_ptr( hdcSrc )))
552 struct bitblt_coords src, dst;
553 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
554 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
556 update_dc( dcSrc );
557 update_dc( dcDst );
559 src.log_x = xSrc;
560 src.log_y = ySrc;
561 src.log_width = widthSrc;
562 src.log_height = heightSrc;
563 src.layout = dcSrc->layout;
564 dst.log_x = xDst;
565 dst.log_y = yDst;
566 dst.log_width = widthDst;
567 dst.log_height = heightDst;
568 dst.layout = dcDst->layout;
569 if (rop & NOMIRRORBITMAP)
571 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
572 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
573 rop &= ~NOMIRRORBITMAP;
575 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
577 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",
578 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
579 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
580 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
581 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
583 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
584 release_dc_ptr( dcSrc );
586 release_dc_ptr( dcDst );
587 return ret;
590 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
591 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
593 /***********************************************************************
594 * MaskBlt [GDI32.@]
596 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
597 INT nWidth, INT nHeight, HDC hdcSrc,
598 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
599 INT xMask, INT yMask, DWORD dwRop)
601 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
602 HDC hDC1, hDC2;
603 HBRUSH hbrMask, hbrDst, hbrTmp;
605 static const DWORD ROP3Table[256] =
607 0x00000042, 0x00010289,
608 0x00020C89, 0x000300AA,
609 0x00040C88, 0x000500A9,
610 0x00060865, 0x000702C5,
611 0x00080F08, 0x00090245,
612 0x000A0329, 0x000B0B2A,
613 0x000C0324, 0x000D0B25,
614 0x000E08A5, 0x000F0001,
615 0x00100C85, 0x001100A6,
616 0x00120868, 0x001302C8,
617 0x00140869, 0x001502C9,
618 0x00165CCA, 0x00171D54,
619 0x00180D59, 0x00191CC8,
620 0x001A06C5, 0x001B0768,
621 0x001C06CA, 0x001D0766,
622 0x001E01A5, 0x001F0385,
623 0x00200F09, 0x00210248,
624 0x00220326, 0x00230B24,
625 0x00240D55, 0x00251CC5,
626 0x002606C8, 0x00271868,
627 0x00280369, 0x002916CA,
628 0x002A0CC9, 0x002B1D58,
629 0x002C0784, 0x002D060A,
630 0x002E064A, 0x002F0E2A,
631 0x0030032A, 0x00310B28,
632 0x00320688, 0x00330008,
633 0x003406C4, 0x00351864,
634 0x003601A8, 0x00370388,
635 0x0038078A, 0x00390604,
636 0x003A0644, 0x003B0E24,
637 0x003C004A, 0x003D18A4,
638 0x003E1B24, 0x003F00EA,
639 0x00400F0A, 0x00410249,
640 0x00420D5D, 0x00431CC4,
641 0x00440328, 0x00450B29,
642 0x004606C6, 0x0047076A,
643 0x00480368, 0x004916C5,
644 0x004A0789, 0x004B0605,
645 0x004C0CC8, 0x004D1954,
646 0x004E0645, 0x004F0E25,
647 0x00500325, 0x00510B26,
648 0x005206C9, 0x00530764,
649 0x005408A9, 0x00550009,
650 0x005601A9, 0x00570389,
651 0x00580785, 0x00590609,
652 0x005A0049, 0x005B18A9,
653 0x005C0649, 0x005D0E29,
654 0x005E1B29, 0x005F00E9,
655 0x00600365, 0x006116C6,
656 0x00620786, 0x00630608,
657 0x00640788, 0x00650606,
658 0x00660046, 0x006718A8,
659 0x006858A6, 0x00690145,
660 0x006A01E9, 0x006B178A,
661 0x006C01E8, 0x006D1785,
662 0x006E1E28, 0x006F0C65,
663 0x00700CC5, 0x00711D5C,
664 0x00720648, 0x00730E28,
665 0x00740646, 0x00750E26,
666 0x00761B28, 0x007700E6,
667 0x007801E5, 0x00791786,
668 0x007A1E29, 0x007B0C68,
669 0x007C1E24, 0x007D0C69,
670 0x007E0955, 0x007F03C9,
671 0x008003E9, 0x00810975,
672 0x00820C49, 0x00831E04,
673 0x00840C48, 0x00851E05,
674 0x008617A6, 0x008701C5,
675 0x008800C6, 0x00891B08,
676 0x008A0E06, 0x008B0666,
677 0x008C0E08, 0x008D0668,
678 0x008E1D7C, 0x008F0CE5,
679 0x00900C45, 0x00911E08,
680 0x009217A9, 0x009301C4,
681 0x009417AA, 0x009501C9,
682 0x00960169, 0x0097588A,
683 0x00981888, 0x00990066,
684 0x009A0709, 0x009B07A8,
685 0x009C0704, 0x009D07A6,
686 0x009E16E6, 0x009F0345,
687 0x00A000C9, 0x00A11B05,
688 0x00A20E09, 0x00A30669,
689 0x00A41885, 0x00A50065,
690 0x00A60706, 0x00A707A5,
691 0x00A803A9, 0x00A90189,
692 0x00AA0029, 0x00AB0889,
693 0x00AC0744, 0x00AD06E9,
694 0x00AE0B06, 0x00AF0229,
695 0x00B00E05, 0x00B10665,
696 0x00B21974, 0x00B30CE8,
697 0x00B4070A, 0x00B507A9,
698 0x00B616E9, 0x00B70348,
699 0x00B8074A, 0x00B906E6,
700 0x00BA0B09, 0x00BB0226,
701 0x00BC1CE4, 0x00BD0D7D,
702 0x00BE0269, 0x00BF08C9,
703 0x00C000CA, 0x00C11B04,
704 0x00C21884, 0x00C3006A,
705 0x00C40E04, 0x00C50664,
706 0x00C60708, 0x00C707AA,
707 0x00C803A8, 0x00C90184,
708 0x00CA0749, 0x00CB06E4,
709 0x00CC0020, 0x00CD0888,
710 0x00CE0B08, 0x00CF0224,
711 0x00D00E0A, 0x00D1066A,
712 0x00D20705, 0x00D307A4,
713 0x00D41D78, 0x00D50CE9,
714 0x00D616EA, 0x00D70349,
715 0x00D80745, 0x00D906E8,
716 0x00DA1CE9, 0x00DB0D75,
717 0x00DC0B04, 0x00DD0228,
718 0x00DE0268, 0x00DF08C8,
719 0x00E003A5, 0x00E10185,
720 0x00E20746, 0x00E306EA,
721 0x00E40748, 0x00E506E5,
722 0x00E61CE8, 0x00E70D79,
723 0x00E81D74, 0x00E95CE6,
724 0x00EA02E9, 0x00EB0849,
725 0x00EC02E8, 0x00ED0848,
726 0x00EE0086, 0x00EF0A08,
727 0x00F00021, 0x00F10885,
728 0x00F20B05, 0x00F3022A,
729 0x00F40B0A, 0x00F50225,
730 0x00F60265, 0x00F708C5,
731 0x00F802E5, 0x00F90845,
732 0x00FA0089, 0x00FB0A09,
733 0x00FC008A, 0x00FD0A0A,
734 0x00FE02A9, 0x00FF0062,
737 if (!hbmMask)
738 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
740 hbrMask = CreatePatternBrush(hbmMask);
741 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
743 /* make bitmap */
744 hDC1 = CreateCompatibleDC(hdcDest);
745 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
746 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
748 /* draw using bkgnd rop */
749 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
750 hbrTmp = SelectObject(hDC1, hbrDst);
751 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
752 SelectObject(hDC1, hbrTmp);
754 /* make bitmap */
755 hDC2 = CreateCompatibleDC(hdcDest);
756 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
757 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
759 /* draw using foregnd rop */
760 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
761 hbrTmp = SelectObject(hDC2, hbrDst);
762 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
764 /* combine both using the mask as a pattern brush */
765 SelectObject(hDC2, hbrMask);
766 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
767 SelectObject(hDC2, hbrTmp);
769 /* blit to dst */
770 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
772 /* restore all objects */
773 SelectObject(hdcDest, hbrDst);
774 SelectObject(hDC1, hOldBitmap1);
775 SelectObject(hDC2, hOldBitmap2);
777 /* delete all temp objects */
778 DeleteObject(hBitmap1);
779 DeleteObject(hBitmap2);
780 DeleteObject(hbrMask);
782 DeleteDC(hDC1);
783 DeleteDC(hDC2);
785 return TRUE;
788 /******************************************************************************
789 * GdiTransparentBlt [GDI32.@]
791 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
792 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
793 UINT crTransparent )
795 BOOL ret = FALSE;
796 HDC hdcWork;
797 HBITMAP bmpWork;
798 HGDIOBJ oldWork;
799 HDC hdcMask = NULL;
800 HBITMAP bmpMask = NULL;
801 HBITMAP oldMask = NULL;
802 COLORREF oldBackground;
803 COLORREF oldForeground;
804 int oldStretchMode;
806 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
807 TRACE("Cannot mirror\n");
808 return FALSE;
811 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
812 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
814 /* Stretch bitmap */
815 oldStretchMode = GetStretchBltMode(hdcSrc);
816 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
817 SetStretchBltMode(hdcSrc, COLORONCOLOR);
818 hdcWork = CreateCompatibleDC(hdcDest);
819 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
820 oldWork = SelectObject(hdcWork, bmpWork);
821 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
822 TRACE("Failed to stretch\n");
823 goto error;
825 SetBkColor(hdcWork, crTransparent);
827 /* Create mask */
828 hdcMask = CreateCompatibleDC(hdcDest);
829 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
830 oldMask = SelectObject(hdcMask, bmpMask);
831 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
832 TRACE("Failed to create mask\n");
833 goto error;
836 /* Replace transparent color with black */
837 SetBkColor(hdcWork, RGB(0,0,0));
838 SetTextColor(hdcWork, RGB(255,255,255));
839 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
840 TRACE("Failed to mask out background\n");
841 goto error;
844 /* Replace non-transparent area on destination with black */
845 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
846 TRACE("Failed to clear destination area\n");
847 goto error;
850 /* Draw the image */
851 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
852 TRACE("Failed to paint image\n");
853 goto error;
856 ret = TRUE;
857 error:
858 SetStretchBltMode(hdcSrc, oldStretchMode);
859 SetBkColor(hdcDest, oldBackground);
860 SetTextColor(hdcDest, oldForeground);
861 if(hdcWork) {
862 SelectObject(hdcWork, oldWork);
863 DeleteDC(hdcWork);
865 if(bmpWork) DeleteObject(bmpWork);
866 if(hdcMask) {
867 SelectObject(hdcMask, oldMask);
868 DeleteDC(hdcMask);
870 if(bmpMask) DeleteObject(bmpMask);
871 return ret;
874 /******************************************************************************
875 * GdiAlphaBlend [GDI32.@]
877 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
878 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
879 BLENDFUNCTION blendFunction)
881 BOOL ret = FALSE;
882 DC *dcDst, *dcSrc;
884 dcSrc = get_dc_ptr( hdcSrc );
885 if (!dcSrc) return FALSE;
887 if ((dcDst = get_dc_ptr( hdcDst )))
889 struct bitblt_coords src, dst;
890 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
891 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
893 update_dc( dcSrc );
894 update_dc( dcDst );
896 src.log_x = xSrc;
897 src.log_y = ySrc;
898 src.log_width = widthSrc;
899 src.log_height = heightSrc;
900 src.layout = GetLayout( src_dev->hdc );
901 dst.log_x = xDst;
902 dst.log_y = yDst;
903 dst.log_width = widthDst;
904 dst.log_height = heightDst;
905 dst.layout = GetLayout( dst_dev->hdc );
906 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
908 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",
909 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
910 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
911 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
912 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
913 blendFunction.BlendOp, blendFunction.BlendFlags,
914 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
916 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
917 (dcSrc->header.type == OBJ_MEMDC &&
918 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
919 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
921 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
922 SetLastError( ERROR_INVALID_PARAMETER );
923 ret = FALSE;
925 else if (dst.width < 0 || dst.height < 0)
927 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
928 SetLastError( ERROR_INVALID_PARAMETER );
929 ret = FALSE;
931 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
932 src.y + src.height > dst.y && src.y < dst.y + dst.height)
934 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
935 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
936 SetLastError( ERROR_INVALID_PARAMETER );
937 ret = FALSE;
939 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
941 release_dc_ptr( dcDst );
943 release_dc_ptr( dcSrc );
944 return ret;
947 /*********************************************************************
948 * PlgBlt [GDI32.@]
951 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
952 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
953 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
955 int oldgMode;
956 /* parallelogram coords */
957 POINT plg[3];
958 /* rect coords */
959 POINT rect[3];
960 XFORM xf;
961 XFORM SrcXf;
962 XFORM oldDestXf;
963 double det;
965 /* save actual mode, set GM_ADVANCED */
966 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
967 if (oldgMode == 0)
968 return FALSE;
970 memcpy(plg,lpPoint,sizeof(POINT)*3);
971 rect[0].x = nXSrc;
972 rect[0].y = nYSrc;
973 rect[1].x = nXSrc + nWidth;
974 rect[1].y = nYSrc;
975 rect[2].x = nXSrc;
976 rect[2].y = nYSrc + nHeight;
977 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
978 /* determinant */
979 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);
981 if (fabs(det) < 1e-5)
983 SetGraphicsMode(hdcDest,oldgMode);
984 return FALSE;
987 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
988 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
990 /* X components */
991 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;
992 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;
993 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
994 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
995 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
996 ) / det;
998 /* Y components */
999 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;
1000 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;
1001 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1002 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1003 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1004 ) / det;
1006 GetWorldTransform(hdcSrc,&SrcXf);
1007 CombineTransform(&xf,&xf,&SrcXf);
1009 /* save actual dest transform */
1010 GetWorldTransform(hdcDest,&oldDestXf);
1012 SetWorldTransform(hdcDest,&xf);
1013 /* now destination and source DCs use same coords */
1014 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1015 hdcSrc, nXSrc,nYSrc,
1016 hbmMask,xMask,yMask,
1017 SRCCOPY);
1018 /* restore dest DC */
1019 SetWorldTransform(hdcDest,&oldDestXf);
1020 SetGraphicsMode(hdcDest,oldgMode);
1022 return TRUE;