winex11: Use an XVisualInfo structure to store color formats in Get/PutImage.
[wine.git] / dlls / gdi32 / bitblt.c
blob6b99e4385e795acd8699605023f229d853df3d33
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <math.h>
26 #ifdef HAVE_FLOAT_H
27 #include <float.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "gdi_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
38 static inline BOOL rop_uses_src( DWORD rop )
40 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
43 static inline void swap_ints( int *i, int *j )
45 int tmp = *i;
46 *i = *j;
47 *j = tmp;
50 BOOL intersect_vis_rectangles( struct bitblt_coords *dst, struct bitblt_coords *src )
52 RECT rect;
54 /* intersect the rectangles */
56 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
58 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
59 if (!intersect_rect( &rect, &src->visrect, &dst->visrect )) return FALSE;
60 src->visrect = dst->visrect = rect;
61 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
63 else /* stretching */
65 /* map source rectangle into destination coordinates */
66 rect = src->visrect;
67 offset_rect( &rect, -min( src->x, src->x + src->width + 1),
68 -min( src->y, src->y + src->height + 1) );
69 rect.left = dst->x + rect.left * dst->width / abs(src->width);
70 rect.top = dst->y + rect.top * dst->height / abs(src->height);
71 rect.right = dst->x + rect.right * dst->width / abs(src->width);
72 rect.bottom = dst->y + rect.bottom * dst->height / abs(src->height);
73 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
74 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
76 /* avoid rounding errors */
77 rect.left--;
78 rect.top--;
79 rect.right++;
80 rect.bottom++;
81 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
83 /* map destination rectangle back to source coordinates */
84 rect = dst->visrect;
85 offset_rect( &rect, -min( dst->x, dst->x + dst->width + 1),
86 -min( dst->y, dst->y + dst->height + 1) );
87 rect.left = src->x + rect.left * src->width / abs(dst->width);
88 rect.top = src->y + rect.top * src->height / abs(dst->height);
89 rect.right = src->x + rect.right * src->width / abs(dst->width);
90 rect.bottom = src->y + rect.bottom * src->height / abs(dst->height);
91 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
92 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
94 /* avoid rounding errors */
95 rect.left--;
96 rect.top--;
97 rect.right++;
98 rect.bottom++;
99 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
101 return TRUE;
104 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
105 DC *dc_src, struct bitblt_coords *src )
107 RECT rect;
109 /* get the destination visible rectangle */
111 rect.left = dst->log_x;
112 rect.top = dst->log_y;
113 rect.right = dst->log_x + dst->log_width;
114 rect.bottom = dst->log_y + dst->log_height;
115 LPtoDP( dc_dst->hSelf, (POINT *)&rect, 2 );
116 dst->x = rect.left;
117 dst->y = rect.top;
118 dst->width = rect.right - rect.left;
119 dst->height = rect.bottom - rect.top;
120 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
122 dst->x += dst->width;
123 dst->width = -dst->width;
125 get_bounding_rect( &rect, dst->x, dst->y, dst->width, dst->height );
127 clip_visrect( dc_dst, &dst->visrect, &rect );
129 /* get the source visible rectangle */
131 if (!src) return !is_rect_empty( &dst->visrect );
133 rect.left = src->log_x;
134 rect.top = src->log_y;
135 rect.right = src->log_x + src->log_width;
136 rect.bottom = src->log_y + src->log_height;
137 LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
138 src->x = rect.left;
139 src->y = rect.top;
140 src->width = rect.right - rect.left;
141 src->height = rect.bottom - rect.top;
142 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
144 src->x += src->width;
145 src->width = -src->width;
147 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
149 if (!clip_device_rect( dc_src, &src->visrect, &rect )) return FALSE;
150 if (is_rect_empty( &dst->visrect )) return FALSE;
152 return intersect_vis_rectangles( dst, src );
155 void free_heap_bits( struct gdi_image_bits *bits )
157 HeapFree( GetProcessHeap(), 0, bits->ptr );
160 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
161 BITMAPINFO *dst_info, struct gdi_image_bits *bits, BOOL add_alpha )
163 void *ptr;
164 DWORD err;
166 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
167 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
169 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
170 return ERROR_OUTOFMEMORY;
172 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
173 if (bits->free) bits->free( bits );
174 bits->ptr = ptr;
175 bits->is_copy = TRUE;
176 bits->free = free_heap_bits;
177 return err;
180 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
181 BITMAPINFO *dst_info, struct bitblt_coords *dst,
182 struct gdi_image_bits *bits, int mode )
184 void *ptr;
185 DWORD err;
187 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
188 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
189 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
191 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
192 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
193 return ERROR_OUTOFMEMORY;
195 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
196 if (bits->free) bits->free( bits );
197 bits->ptr = ptr;
198 bits->is_copy = TRUE;
199 bits->free = free_heap_bits;
200 return err;
203 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
204 struct bitblt_coords *src, BITMAPINFO *dst_info,
205 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
207 if (!dst_bits->is_copy)
209 int size = dst_info->bmiHeader.biSizeImage;
210 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
211 if (!ptr) return ERROR_OUTOFMEMORY;
212 memcpy( ptr, dst_bits->ptr, size );
213 if (dst_bits->free) dst_bits->free( dst_bits );
214 dst_bits->ptr = ptr;
215 dst_bits->is_copy = TRUE;
216 dst_bits->free = free_heap_bits;
218 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
221 /***********************************************************************
222 * null driver fallback implementations
225 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
226 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
228 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
229 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
230 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
231 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
232 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
233 DWORD err;
234 struct gdi_image_bits bits;
236 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
237 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
238 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
239 release_dc_ptr( dc_src );
240 if (err) return FALSE;
242 /* 1-bpp source without a color table uses the destination DC colors */
243 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
245 COLORREF color = GetTextColor( dst_dev->hdc );
246 src_info->bmiColors[0].rgbRed = GetRValue( color );
247 src_info->bmiColors[0].rgbGreen = GetGValue( color );
248 src_info->bmiColors[0].rgbBlue = GetBValue( color );
249 src_info->bmiColors[0].rgbReserved = 0;
250 color = GetBkColor( dst_dev->hdc );
251 src_info->bmiColors[1].rgbRed = GetRValue( color );
252 src_info->bmiColors[1].rgbGreen = GetGValue( color );
253 src_info->bmiColors[1].rgbBlue = GetBValue( color );
254 src_info->bmiColors[1].rgbReserved = 0;
255 src_info->bmiHeader.biClrUsed = 2;
258 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
259 copy_bitmapinfo( dst_info, src_info );
260 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
261 if (err == ERROR_BAD_FORMAT)
263 /* 1-bpp destination without a color table requires a fake 1-entry table
264 * that contains only the background color */
265 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
267 COLORREF color = GetBkColor( src_dev->hdc );
268 dst_info->bmiColors[0].rgbRed = GetRValue( color );
269 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
270 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
271 dst_info->bmiColors[0].rgbReserved = 0;
272 dst_info->bmiHeader.biClrUsed = 1;
275 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
277 /* get rid of the fake 1-bpp table */
278 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
279 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
283 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
284 ((src->width != dst->width) || (src->height != dst->height)))
286 copy_bitmapinfo( src_info, dst_info );
287 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
288 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
291 if (bits.free) bits.free( &bits );
292 return !err;
296 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
297 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
299 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
300 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
301 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
302 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
303 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
304 DWORD err;
305 struct gdi_image_bits bits;
307 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
308 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
309 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
310 release_dc_ptr( dc_src );
311 if (err) goto done;
313 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
314 copy_bitmapinfo( dst_info, src_info );
315 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
316 if (err == ERROR_BAD_FORMAT)
318 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
319 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
322 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
323 ((src->width != dst->width) || (src->height != dst->height)))
325 copy_bitmapinfo( src_info, dst_info );
326 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
327 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
330 if (bits.free) bits.free( &bits );
331 done:
332 if (err) SetLastError( err );
333 return !err;
337 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
338 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
340 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
341 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
342 struct gdi_image_bits dst_bits;
343 struct bitblt_coords orig_dst;
344 DC *dc = get_nulldrv_dc( dev );
345 DWORD err;
347 if (info->bmiHeader.biPlanes != 1) goto update_format;
348 if (info->bmiHeader.biBitCount != 32) goto update_format;
349 if (info->bmiHeader.biCompression == BI_BITFIELDS)
351 DWORD *masks = (DWORD *)info->bmiColors;
352 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
353 goto update_format;
356 if (!bits) return ERROR_SUCCESS;
357 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
359 dev = GET_DC_PHYSDEV( dc, pGetImage );
360 orig_dst = *dst;
361 err = dev->funcs->pGetImage( dev, 0, dst_info, &dst_bits, dst );
362 if (err) return err;
364 dev = GET_DC_PHYSDEV( dc, pPutImage );
365 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
366 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
368 if (dst_bits.free) dst_bits.free( &dst_bits );
369 return err;
371 update_format:
372 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
373 return ERROR_INVALID_PARAMETER;
375 info->bmiHeader.biPlanes = 1;
376 info->bmiHeader.biBitCount = 32;
377 info->bmiHeader.biCompression = BI_RGB;
378 info->bmiHeader.biClrUsed = 0;
379 return ERROR_BAD_FORMAT;
382 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
383 void * grad_array, ULONG ngrad, ULONG mode )
385 DC *dc = get_nulldrv_dc( dev );
386 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
387 BITMAPINFO *info = (BITMAPINFO *)buffer;
388 struct bitblt_coords src, dst;
389 struct gdi_image_bits bits;
390 unsigned int i;
391 POINT *pts;
392 BOOL ret = FALSE;
393 DWORD err;
394 HRGN rgn;
396 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
397 for (i = 0; i < nvert; i++)
399 pts[i].x = vert_array[i].x;
400 pts[i].y = vert_array[i].y;
402 LPtoDP( dev->hdc, pts, nvert );
404 /* compute bounding rect of all the rectangles/triangles */
405 reset_bounds( &dst.visrect );
406 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
408 ULONG v = ((ULONG *)grad_array)[i];
409 dst.visrect.left = min( dst.visrect.left, pts[v].x );
410 dst.visrect.top = min( dst.visrect.top, pts[v].y );
411 dst.visrect.right = max( dst.visrect.right, pts[v].x );
412 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
415 dst.x = dst.visrect.left;
416 dst.y = dst.visrect.top;
417 dst.width = dst.visrect.right - dst.visrect.left;
418 dst.height = dst.visrect.bottom - dst.visrect.top;
419 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
421 /* query the bitmap format */
422 info->bmiHeader.biSize = sizeof(info->bmiHeader);
423 info->bmiHeader.biPlanes = 1;
424 info->bmiHeader.biBitCount = 0;
425 info->bmiHeader.biCompression = BI_RGB;
426 info->bmiHeader.biXPelsPerMeter = 0;
427 info->bmiHeader.biYPelsPerMeter = 0;
428 info->bmiHeader.biClrUsed = 0;
429 info->bmiHeader.biClrImportant = 0;
430 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
431 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
432 info->bmiHeader.biSizeImage = 0;
433 dev = GET_DC_PHYSDEV( dc, pPutImage );
434 err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
435 if (err && err != ERROR_BAD_FORMAT) goto done;
437 info->bmiHeader.biSizeImage = get_dib_image_size( info );
438 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
439 goto done;
440 bits.is_copy = TRUE;
441 bits.free = free_heap_bits;
443 /* make src and points relative to the bitmap */
444 src = dst;
445 src.x -= dst.visrect.left;
446 src.y -= dst.visrect.top;
447 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
448 for (i = 0; i < nvert; i++)
450 pts[i].x -= dst.visrect.left;
451 pts[i].y -= dst.visrect.top;
454 rgn = CreateRectRgn( 0, 0, 0, 0 );
455 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
456 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
457 ret = !dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY );
459 if (bits.free) bits.free( &bits );
460 DeleteObject( rgn );
462 done:
463 HeapFree( GetProcessHeap(), 0, pts );
464 return ret;
467 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
469 DC *dc = get_nulldrv_dc( dev );
470 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
471 BITMAPINFO *info = (BITMAPINFO *)buffer;
472 struct bitblt_coords src;
473 struct gdi_image_bits bits;
474 COLORREF ret;
476 src.visrect.left = x;
477 src.visrect.top = y;
478 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
479 src.visrect.right = src.visrect.left + 1;
480 src.visrect.bottom = src.visrect.top + 1;
481 src.x = src.visrect.left;
482 src.y = src.visrect.top;
483 src.width = src.height = 1;
485 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
487 dev = GET_DC_PHYSDEV( dc, pGetImage );
488 if (dev->funcs->pGetImage( dev, 0, info, &bits, &src )) return CLR_INVALID;
490 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
491 if (bits.free) bits.free( &bits );
492 return ret;
496 /***********************************************************************
497 * PatBlt (GDI32.@)
499 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
501 DC * dc;
502 BOOL ret = FALSE;
504 if (rop_uses_src( rop )) return FALSE;
505 if ((dc = get_dc_ptr( hdc )))
507 struct bitblt_coords dst;
508 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
510 update_dc( dc );
512 dst.log_x = left;
513 dst.log_y = top;
514 dst.log_width = width;
515 dst.log_height = height;
516 dst.layout = dc->layout;
517 if (rop & NOMIRRORBITMAP)
519 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
520 rop &= ~NOMIRRORBITMAP;
522 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
524 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
525 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
526 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
528 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
530 release_dc_ptr( dc );
532 return ret;
536 /***********************************************************************
537 * BitBlt (GDI32.@)
539 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
540 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
542 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
543 else return StretchBlt( hdcDst, xDst, yDst, width, height,
544 hdcSrc, xSrc, ySrc, width, height, rop );
548 /***********************************************************************
549 * StretchBlt (GDI32.@)
551 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
552 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
554 BOOL ret = FALSE;
555 DC *dcDst, *dcSrc;
557 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
559 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
561 if ((dcSrc = get_dc_ptr( hdcSrc )))
563 struct bitblt_coords src, dst;
564 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
565 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
567 update_dc( dcSrc );
568 update_dc( dcDst );
570 src.log_x = xSrc;
571 src.log_y = ySrc;
572 src.log_width = widthSrc;
573 src.log_height = heightSrc;
574 src.layout = dcSrc->layout;
575 dst.log_x = xDst;
576 dst.log_y = yDst;
577 dst.log_width = widthDst;
578 dst.log_height = heightDst;
579 dst.layout = dcDst->layout;
580 if (rop & NOMIRRORBITMAP)
582 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
583 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
584 rop &= ~NOMIRRORBITMAP;
586 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
588 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",
589 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
590 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
591 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
592 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
594 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
595 release_dc_ptr( dcSrc );
597 release_dc_ptr( dcDst );
598 return ret;
601 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
602 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
604 /***********************************************************************
605 * MaskBlt [GDI32.@]
607 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
608 INT nWidth, INT nHeight, HDC hdcSrc,
609 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
610 INT xMask, INT yMask, DWORD dwRop)
612 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
613 HDC hDC1, hDC2;
614 HBRUSH hbrMask, hbrDst, hbrTmp;
616 static const DWORD ROP3Table[256] =
618 0x00000042, 0x00010289,
619 0x00020C89, 0x000300AA,
620 0x00040C88, 0x000500A9,
621 0x00060865, 0x000702C5,
622 0x00080F08, 0x00090245,
623 0x000A0329, 0x000B0B2A,
624 0x000C0324, 0x000D0B25,
625 0x000E08A5, 0x000F0001,
626 0x00100C85, 0x001100A6,
627 0x00120868, 0x001302C8,
628 0x00140869, 0x001502C9,
629 0x00165CCA, 0x00171D54,
630 0x00180D59, 0x00191CC8,
631 0x001A06C5, 0x001B0768,
632 0x001C06CA, 0x001D0766,
633 0x001E01A5, 0x001F0385,
634 0x00200F09, 0x00210248,
635 0x00220326, 0x00230B24,
636 0x00240D55, 0x00251CC5,
637 0x002606C8, 0x00271868,
638 0x00280369, 0x002916CA,
639 0x002A0CC9, 0x002B1D58,
640 0x002C0784, 0x002D060A,
641 0x002E064A, 0x002F0E2A,
642 0x0030032A, 0x00310B28,
643 0x00320688, 0x00330008,
644 0x003406C4, 0x00351864,
645 0x003601A8, 0x00370388,
646 0x0038078A, 0x00390604,
647 0x003A0644, 0x003B0E24,
648 0x003C004A, 0x003D18A4,
649 0x003E1B24, 0x003F00EA,
650 0x00400F0A, 0x00410249,
651 0x00420D5D, 0x00431CC4,
652 0x00440328, 0x00450B29,
653 0x004606C6, 0x0047076A,
654 0x00480368, 0x004916C5,
655 0x004A0789, 0x004B0605,
656 0x004C0CC8, 0x004D1954,
657 0x004E0645, 0x004F0E25,
658 0x00500325, 0x00510B26,
659 0x005206C9, 0x00530764,
660 0x005408A9, 0x00550009,
661 0x005601A9, 0x00570389,
662 0x00580785, 0x00590609,
663 0x005A0049, 0x005B18A9,
664 0x005C0649, 0x005D0E29,
665 0x005E1B29, 0x005F00E9,
666 0x00600365, 0x006116C6,
667 0x00620786, 0x00630608,
668 0x00640788, 0x00650606,
669 0x00660046, 0x006718A8,
670 0x006858A6, 0x00690145,
671 0x006A01E9, 0x006B178A,
672 0x006C01E8, 0x006D1785,
673 0x006E1E28, 0x006F0C65,
674 0x00700CC5, 0x00711D5C,
675 0x00720648, 0x00730E28,
676 0x00740646, 0x00750E26,
677 0x00761B28, 0x007700E6,
678 0x007801E5, 0x00791786,
679 0x007A1E29, 0x007B0C68,
680 0x007C1E24, 0x007D0C69,
681 0x007E0955, 0x007F03C9,
682 0x008003E9, 0x00810975,
683 0x00820C49, 0x00831E04,
684 0x00840C48, 0x00851E05,
685 0x008617A6, 0x008701C5,
686 0x008800C6, 0x00891B08,
687 0x008A0E06, 0x008B0666,
688 0x008C0E08, 0x008D0668,
689 0x008E1D7C, 0x008F0CE5,
690 0x00900C45, 0x00911E08,
691 0x009217A9, 0x009301C4,
692 0x009417AA, 0x009501C9,
693 0x00960169, 0x0097588A,
694 0x00981888, 0x00990066,
695 0x009A0709, 0x009B07A8,
696 0x009C0704, 0x009D07A6,
697 0x009E16E6, 0x009F0345,
698 0x00A000C9, 0x00A11B05,
699 0x00A20E09, 0x00A30669,
700 0x00A41885, 0x00A50065,
701 0x00A60706, 0x00A707A5,
702 0x00A803A9, 0x00A90189,
703 0x00AA0029, 0x00AB0889,
704 0x00AC0744, 0x00AD06E9,
705 0x00AE0B06, 0x00AF0229,
706 0x00B00E05, 0x00B10665,
707 0x00B21974, 0x00B30CE8,
708 0x00B4070A, 0x00B507A9,
709 0x00B616E9, 0x00B70348,
710 0x00B8074A, 0x00B906E6,
711 0x00BA0B09, 0x00BB0226,
712 0x00BC1CE4, 0x00BD0D7D,
713 0x00BE0269, 0x00BF08C9,
714 0x00C000CA, 0x00C11B04,
715 0x00C21884, 0x00C3006A,
716 0x00C40E04, 0x00C50664,
717 0x00C60708, 0x00C707AA,
718 0x00C803A8, 0x00C90184,
719 0x00CA0749, 0x00CB06E4,
720 0x00CC0020, 0x00CD0888,
721 0x00CE0B08, 0x00CF0224,
722 0x00D00E0A, 0x00D1066A,
723 0x00D20705, 0x00D307A4,
724 0x00D41D78, 0x00D50CE9,
725 0x00D616EA, 0x00D70349,
726 0x00D80745, 0x00D906E8,
727 0x00DA1CE9, 0x00DB0D75,
728 0x00DC0B04, 0x00DD0228,
729 0x00DE0268, 0x00DF08C8,
730 0x00E003A5, 0x00E10185,
731 0x00E20746, 0x00E306EA,
732 0x00E40748, 0x00E506E5,
733 0x00E61CE8, 0x00E70D79,
734 0x00E81D74, 0x00E95CE6,
735 0x00EA02E9, 0x00EB0849,
736 0x00EC02E8, 0x00ED0848,
737 0x00EE0086, 0x00EF0A08,
738 0x00F00021, 0x00F10885,
739 0x00F20B05, 0x00F3022A,
740 0x00F40B0A, 0x00F50225,
741 0x00F60265, 0x00F708C5,
742 0x00F802E5, 0x00F90845,
743 0x00FA0089, 0x00FB0A09,
744 0x00FC008A, 0x00FD0A0A,
745 0x00FE02A9, 0x00FF0062,
748 if (!hbmMask)
749 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
751 hbrMask = CreatePatternBrush(hbmMask);
752 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
754 /* make bitmap */
755 hDC1 = CreateCompatibleDC(hdcDest);
756 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
757 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
759 /* draw using bkgnd rop */
760 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
761 hbrTmp = SelectObject(hDC1, hbrDst);
762 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
763 SelectObject(hDC1, hbrTmp);
765 /* make bitmap */
766 hDC2 = CreateCompatibleDC(hdcDest);
767 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
768 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
770 /* draw using foregnd rop */
771 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
772 hbrTmp = SelectObject(hDC2, hbrDst);
773 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
775 /* combine both using the mask as a pattern brush */
776 SelectObject(hDC2, hbrMask);
777 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
778 SelectObject(hDC2, hbrTmp);
780 /* blit to dst */
781 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
783 /* restore all objects */
784 SelectObject(hdcDest, hbrDst);
785 SelectObject(hDC1, hOldBitmap1);
786 SelectObject(hDC2, hOldBitmap2);
788 /* delete all temp objects */
789 DeleteObject(hBitmap1);
790 DeleteObject(hBitmap2);
791 DeleteObject(hbrMask);
793 DeleteDC(hDC1);
794 DeleteDC(hDC2);
796 return TRUE;
799 /******************************************************************************
800 * GdiTransparentBlt [GDI32.@]
802 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
803 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
804 UINT crTransparent )
806 BOOL ret = FALSE;
807 HDC hdcWork;
808 HBITMAP bmpWork;
809 HGDIOBJ oldWork;
810 HDC hdcMask = NULL;
811 HBITMAP bmpMask = NULL;
812 HBITMAP oldMask = NULL;
813 COLORREF oldBackground;
814 COLORREF oldForeground;
815 int oldStretchMode;
817 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
818 TRACE("Cannot mirror\n");
819 return FALSE;
822 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
823 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
825 /* Stretch bitmap */
826 oldStretchMode = GetStretchBltMode(hdcSrc);
827 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
828 SetStretchBltMode(hdcSrc, COLORONCOLOR);
829 hdcWork = CreateCompatibleDC(hdcDest);
830 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
831 oldWork = SelectObject(hdcWork, bmpWork);
832 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
833 TRACE("Failed to stretch\n");
834 goto error;
836 SetBkColor(hdcWork, crTransparent);
838 /* Create mask */
839 hdcMask = CreateCompatibleDC(hdcDest);
840 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
841 oldMask = SelectObject(hdcMask, bmpMask);
842 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
843 TRACE("Failed to create mask\n");
844 goto error;
847 /* Replace transparent color with black */
848 SetBkColor(hdcWork, RGB(0,0,0));
849 SetTextColor(hdcWork, RGB(255,255,255));
850 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
851 TRACE("Failed to mask out background\n");
852 goto error;
855 /* Replace non-transparent area on destination with black */
856 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
857 TRACE("Failed to clear destination area\n");
858 goto error;
861 /* Draw the image */
862 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
863 TRACE("Failed to paint image\n");
864 goto error;
867 ret = TRUE;
868 error:
869 SetStretchBltMode(hdcSrc, oldStretchMode);
870 SetBkColor(hdcDest, oldBackground);
871 SetTextColor(hdcDest, oldForeground);
872 if(hdcWork) {
873 SelectObject(hdcWork, oldWork);
874 DeleteDC(hdcWork);
876 if(bmpWork) DeleteObject(bmpWork);
877 if(hdcMask) {
878 SelectObject(hdcMask, oldMask);
879 DeleteDC(hdcMask);
881 if(bmpMask) DeleteObject(bmpMask);
882 return ret;
885 /******************************************************************************
886 * GdiAlphaBlend [GDI32.@]
888 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
889 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
890 BLENDFUNCTION blendFunction)
892 BOOL ret = FALSE;
893 DC *dcDst, *dcSrc;
895 dcSrc = get_dc_ptr( hdcSrc );
896 if (!dcSrc) return FALSE;
898 if ((dcDst = get_dc_ptr( hdcDst )))
900 struct bitblt_coords src, dst;
901 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
902 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
904 update_dc( dcSrc );
905 update_dc( dcDst );
907 src.log_x = xSrc;
908 src.log_y = ySrc;
909 src.log_width = widthSrc;
910 src.log_height = heightSrc;
911 src.layout = GetLayout( src_dev->hdc );
912 dst.log_x = xDst;
913 dst.log_y = yDst;
914 dst.log_width = widthDst;
915 dst.log_height = heightDst;
916 dst.layout = GetLayout( dst_dev->hdc );
917 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
919 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",
920 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
921 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
922 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
923 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
924 blendFunction.BlendOp, blendFunction.BlendFlags,
925 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
927 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
928 src.log_width < 0 || src.log_height < 0 ||
929 (!is_rect_empty( &dcSrc->device_rect ) &&
930 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
931 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
933 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
934 SetLastError( ERROR_INVALID_PARAMETER );
935 ret = FALSE;
937 else if (dst.log_width < 0 || dst.log_height < 0)
939 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
940 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
941 SetLastError( ERROR_INVALID_PARAMETER );
942 ret = FALSE;
944 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
945 src.y + src.height > dst.y && src.y < dst.y + dst.height)
947 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
948 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
949 SetLastError( ERROR_INVALID_PARAMETER );
950 ret = FALSE;
952 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
954 release_dc_ptr( dcDst );
956 release_dc_ptr( dcSrc );
957 return ret;
960 /*********************************************************************
961 * PlgBlt [GDI32.@]
964 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
965 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
966 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
968 int oldgMode;
969 /* parallelogram coords */
970 POINT plg[3];
971 /* rect coords */
972 POINT rect[3];
973 XFORM xf;
974 XFORM SrcXf;
975 XFORM oldDestXf;
976 double det;
978 /* save actual mode, set GM_ADVANCED */
979 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
980 if (oldgMode == 0)
981 return FALSE;
983 memcpy(plg,lpPoint,sizeof(POINT)*3);
984 rect[0].x = nXSrc;
985 rect[0].y = nYSrc;
986 rect[1].x = nXSrc + nWidth;
987 rect[1].y = nYSrc;
988 rect[2].x = nXSrc;
989 rect[2].y = nYSrc + nHeight;
990 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
991 /* determinant */
992 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);
994 if (fabs(det) < 1e-5)
996 SetGraphicsMode(hdcDest,oldgMode);
997 return FALSE;
1000 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1001 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1003 /* X components */
1004 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;
1005 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;
1006 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1007 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1008 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1009 ) / det;
1011 /* Y components */
1012 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;
1013 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;
1014 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1015 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1016 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1017 ) / det;
1019 GetWorldTransform(hdcSrc,&SrcXf);
1020 CombineTransform(&xf,&xf,&SrcXf);
1022 /* save actual dest transform */
1023 GetWorldTransform(hdcDest,&oldDestXf);
1025 SetWorldTransform(hdcDest,&xf);
1026 /* now destination and source DCs use same coords */
1027 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1028 hdcSrc, nXSrc,nYSrc,
1029 hbmMask,xMask,yMask,
1030 SRCCOPY);
1031 /* restore dest DC */
1032 SetWorldTransform(hdcDest,&oldDestXf);
1033 SetGraphicsMode(hdcDest,oldgMode);
1035 return TRUE;