gdi32: Add an intermediate pointer to avoid a compiler warning.
[wine.git] / dlls / gdi32 / bitblt.c
blob08ebfd9966a801a0d369fc9fb6899dba67eb6585
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 )
163 void *ptr;
164 DWORD err;
165 BOOL top_down = dst_info->bmiHeader.biHeight < 0;
167 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
168 dst_info->bmiHeader.biHeight = src->visrect.bottom - src->visrect.top;
169 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
170 if (top_down) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
172 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
173 return ERROR_OUTOFMEMORY;
175 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
176 if (bits->free) bits->free( bits );
177 bits->ptr = ptr;
178 bits->is_copy = TRUE;
179 bits->free = free_heap_bits;
180 return err;
183 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
184 BITMAPINFO *dst_info, struct bitblt_coords *dst,
185 struct gdi_image_bits *bits, int mode )
187 void *ptr;
188 DWORD err;
190 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
191 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
192 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
194 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
195 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
196 return ERROR_OUTOFMEMORY;
198 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
199 if (bits->free) bits->free( bits );
200 bits->ptr = ptr;
201 bits->is_copy = TRUE;
202 bits->free = free_heap_bits;
203 return err;
206 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
207 struct bitblt_coords *src, BITMAPINFO *dst_info,
208 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
210 if (!dst_bits->is_copy)
212 int size = dst_info->bmiHeader.biSizeImage;
213 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
214 if (!ptr) return ERROR_OUTOFMEMORY;
215 memcpy( ptr, dst_bits->ptr, size );
216 if (dst_bits->free) dst_bits->free( dst_bits );
217 dst_bits->ptr = ptr;
218 dst_bits->is_copy = TRUE;
219 dst_bits->free = free_heap_bits;
221 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
224 /* helper to retrieve either both colors or only the background color for monochrome blits */
225 static void get_mono_dc_colors( HDC hdc, BITMAPINFO *info, int count )
227 RGBQUAD *colors = info->bmiColors;
228 COLORREF color = GetBkColor( hdc );
230 colors[count - 1].rgbRed = GetRValue( color );
231 colors[count - 1].rgbGreen = GetGValue( color );
232 colors[count - 1].rgbBlue = GetBValue( color );
233 colors[count - 1].rgbReserved = 0;
235 if (count > 1)
237 color = GetTextColor( hdc );
238 colors[0].rgbRed = GetRValue( color );
239 colors[0].rgbGreen = GetGValue( color );
240 colors[0].rgbBlue = GetBValue( color );
241 colors[0].rgbReserved = 0;
243 info->bmiHeader.biClrUsed = count;
246 /***********************************************************************
247 * null driver fallback implementations
250 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
251 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
253 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
254 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
255 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
256 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
257 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
258 DWORD err;
259 struct gdi_image_bits bits;
261 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
262 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
263 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
265 release_dc_ptr( dc_src );
266 return FALSE;
269 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
270 copy_bitmapinfo( dst_info, src_info );
271 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
272 if (err == ERROR_BAD_FORMAT)
274 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
276 /* 1-bpp source without a color table uses the destination DC colors */
277 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
278 get_mono_dc_colors( dst_dev->hdc, src_info, 2 );
280 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
282 /* 1-bpp destination without a color table requires a fake 1-entry table
283 * that contains only the background color; except with a 1-bpp source,
284 * in which case it uses the source colors */
285 if (src_info->bmiHeader.biBitCount > 1)
286 get_mono_dc_colors( src_dev->hdc, dst_info, 1 );
287 else
288 get_mono_dc_colors( src_dev->hdc, dst_info, 2 );
291 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
293 /* get rid of the fake destination table */
294 dst_info->bmiHeader.biClrUsed = dst_colors;
295 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
299 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
300 ((src->width != dst->width) || (src->height != dst->height)))
302 copy_bitmapinfo( src_info, dst_info );
303 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
304 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
307 if (bits.free) bits.free( &bits );
308 release_dc_ptr( dc_src );
309 return !err;
313 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
314 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
316 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
317 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
318 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
319 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
320 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
321 DWORD err;
322 struct gdi_image_bits bits;
324 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
325 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
326 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
327 if (err) goto done;
329 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
330 copy_bitmapinfo( dst_info, src_info );
331 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
332 if (err == ERROR_BAD_FORMAT)
334 err = convert_bits( src_info, src, dst_info, &bits );
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 release_dc_ptr( dc_src );
349 if (err) SetLastError( err );
350 return !err;
354 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
355 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
357 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
358 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
359 struct gdi_image_bits dst_bits;
360 struct bitblt_coords orig_dst;
361 DWORD *masks = (DWORD *)info->bmiColors;
362 DC *dc = get_nulldrv_dc( dev );
363 DWORD err;
365 if (info->bmiHeader.biPlanes != 1) goto update_format;
366 if (info->bmiHeader.biBitCount != 32) goto update_format;
367 if (info->bmiHeader.biCompression == BI_BITFIELDS)
369 if (blend.AlphaFormat & AC_SRC_ALPHA) return ERROR_INVALID_PARAMETER;
370 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
371 goto update_format;
374 if (!bits) return ERROR_SUCCESS;
375 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
377 dev = GET_DC_PHYSDEV( dc, pGetImage );
378 orig_dst = *dst;
379 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
380 if (err) return err;
382 dev = GET_DC_PHYSDEV( dc, pPutImage );
383 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
384 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
386 if (dst_bits.free) dst_bits.free( &dst_bits );
387 return err;
389 update_format:
390 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
391 return ERROR_INVALID_PARAMETER;
393 info->bmiHeader.biPlanes = 1;
394 info->bmiHeader.biBitCount = 32;
395 info->bmiHeader.biCompression = BI_BITFIELDS;
396 info->bmiHeader.biClrUsed = 0;
397 masks[0] = 0xff0000;
398 masks[1] = 0x00ff00;
399 masks[2] = 0x0000ff;
400 return ERROR_BAD_FORMAT;
403 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
404 void * grad_array, ULONG ngrad, ULONG mode )
406 DC *dc = get_nulldrv_dc( dev );
407 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
408 BITMAPINFO *info = (BITMAPINFO *)buffer;
409 struct bitblt_coords src, dst;
410 struct gdi_image_bits bits;
411 unsigned int i;
412 POINT *pts;
413 BOOL ret = FALSE;
414 DWORD err;
415 HRGN rgn;
417 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
418 for (i = 0; i < nvert; i++)
420 pts[i].x = vert_array[i].x;
421 pts[i].y = vert_array[i].y;
423 LPtoDP( dev->hdc, pts, nvert );
425 /* compute bounding rect of all the rectangles/triangles */
426 reset_bounds( &dst.visrect );
427 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
429 ULONG v = ((ULONG *)grad_array)[i];
430 dst.visrect.left = min( dst.visrect.left, pts[v].x );
431 dst.visrect.top = min( dst.visrect.top, pts[v].y );
432 dst.visrect.right = max( dst.visrect.right, pts[v].x );
433 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
436 dst.x = dst.visrect.left;
437 dst.y = dst.visrect.top;
438 dst.width = dst.visrect.right - dst.visrect.left;
439 dst.height = dst.visrect.bottom - dst.visrect.top;
440 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
442 /* query the bitmap format */
443 info->bmiHeader.biSize = sizeof(info->bmiHeader);
444 info->bmiHeader.biPlanes = 1;
445 info->bmiHeader.biBitCount = 0;
446 info->bmiHeader.biCompression = BI_RGB;
447 info->bmiHeader.biXPelsPerMeter = 0;
448 info->bmiHeader.biYPelsPerMeter = 0;
449 info->bmiHeader.biClrUsed = 0;
450 info->bmiHeader.biClrImportant = 0;
451 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
452 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
453 info->bmiHeader.biSizeImage = 0;
454 dev = GET_DC_PHYSDEV( dc, pPutImage );
455 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
456 if (err && err != ERROR_BAD_FORMAT) goto done;
458 info->bmiHeader.biSizeImage = get_dib_image_size( info );
459 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
460 goto done;
461 bits.is_copy = TRUE;
462 bits.free = free_heap_bits;
464 /* make src and points relative to the bitmap */
465 src = dst;
466 src.x -= dst.visrect.left;
467 src.y -= dst.visrect.top;
468 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
469 for (i = 0; i < nvert; i++)
471 pts[i].x -= dst.visrect.left;
472 pts[i].y -= dst.visrect.top;
475 rgn = CreateRectRgn( 0, 0, 0, 0 );
476 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
477 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
478 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
480 if (bits.free) bits.free( &bits );
481 DeleteObject( rgn );
483 done:
484 HeapFree( GetProcessHeap(), 0, pts );
485 return ret;
488 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
490 DC *dc = get_nulldrv_dc( dev );
491 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
492 BITMAPINFO *info = (BITMAPINFO *)buffer;
493 struct bitblt_coords src;
494 struct gdi_image_bits bits;
495 COLORREF ret;
497 src.visrect.left = x;
498 src.visrect.top = y;
499 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
500 src.visrect.right = src.visrect.left + 1;
501 src.visrect.bottom = src.visrect.top + 1;
502 src.x = src.visrect.left;
503 src.y = src.visrect.top;
504 src.width = src.height = 1;
506 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
508 dev = GET_DC_PHYSDEV( dc, pGetImage );
509 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
511 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
512 if (bits.free) bits.free( &bits );
513 return ret;
517 /***********************************************************************
518 * PatBlt (GDI32.@)
520 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
522 DC * dc;
523 BOOL ret = FALSE;
525 if (rop_uses_src( rop )) return FALSE;
526 if ((dc = get_dc_ptr( hdc )))
528 struct bitblt_coords dst;
530 update_dc( dc );
532 dst.log_x = left;
533 dst.log_y = top;
534 dst.log_width = width;
535 dst.log_height = height;
536 dst.layout = dc->layout;
537 if (rop & NOMIRRORBITMAP)
539 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
540 rop &= ~NOMIRRORBITMAP;
542 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
544 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
545 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
546 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
548 if (!ret)
550 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
551 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
553 release_dc_ptr( dc );
555 return ret;
559 /***********************************************************************
560 * BitBlt (GDI32.@)
562 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
563 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
565 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
566 else return StretchBlt( hdcDst, xDst, yDst, width, height,
567 hdcSrc, xSrc, ySrc, width, height, rop );
571 /***********************************************************************
572 * StretchBlt (GDI32.@)
574 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
575 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
577 BOOL ret = FALSE;
578 DC *dcDst, *dcSrc;
580 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
582 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
584 if ((dcSrc = get_dc_ptr( hdcSrc )))
586 struct bitblt_coords src, dst;
588 update_dc( dcSrc );
589 update_dc( dcDst );
591 src.log_x = xSrc;
592 src.log_y = ySrc;
593 src.log_width = widthSrc;
594 src.log_height = heightSrc;
595 src.layout = dcSrc->layout;
596 dst.log_x = xDst;
597 dst.log_y = yDst;
598 dst.log_width = widthDst;
599 dst.log_height = heightDst;
600 dst.layout = dcDst->layout;
601 if (rop & NOMIRRORBITMAP)
603 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
604 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
605 rop &= ~NOMIRRORBITMAP;
607 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
609 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",
610 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
611 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
612 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
613 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
615 if (!ret)
617 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
618 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
619 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
621 release_dc_ptr( dcSrc );
623 release_dc_ptr( dcDst );
624 return ret;
627 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
628 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
630 /***********************************************************************
631 * MaskBlt [GDI32.@]
633 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
634 INT nWidth, INT nHeight, HDC hdcSrc,
635 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
636 INT xMask, INT yMask, DWORD dwRop)
638 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
639 HDC hDC1, hDC2;
640 HBRUSH hbrMask, hbrDst, hbrTmp;
642 static const DWORD ROP3Table[256] =
644 0x00000042, 0x00010289,
645 0x00020C89, 0x000300AA,
646 0x00040C88, 0x000500A9,
647 0x00060865, 0x000702C5,
648 0x00080F08, 0x00090245,
649 0x000A0329, 0x000B0B2A,
650 0x000C0324, 0x000D0B25,
651 0x000E08A5, 0x000F0001,
652 0x00100C85, 0x001100A6,
653 0x00120868, 0x001302C8,
654 0x00140869, 0x001502C9,
655 0x00165CCA, 0x00171D54,
656 0x00180D59, 0x00191CC8,
657 0x001A06C5, 0x001B0768,
658 0x001C06CA, 0x001D0766,
659 0x001E01A5, 0x001F0385,
660 0x00200F09, 0x00210248,
661 0x00220326, 0x00230B24,
662 0x00240D55, 0x00251CC5,
663 0x002606C8, 0x00271868,
664 0x00280369, 0x002916CA,
665 0x002A0CC9, 0x002B1D58,
666 0x002C0784, 0x002D060A,
667 0x002E064A, 0x002F0E2A,
668 0x0030032A, 0x00310B28,
669 0x00320688, 0x00330008,
670 0x003406C4, 0x00351864,
671 0x003601A8, 0x00370388,
672 0x0038078A, 0x00390604,
673 0x003A0644, 0x003B0E24,
674 0x003C004A, 0x003D18A4,
675 0x003E1B24, 0x003F00EA,
676 0x00400F0A, 0x00410249,
677 0x00420D5D, 0x00431CC4,
678 0x00440328, 0x00450B29,
679 0x004606C6, 0x0047076A,
680 0x00480368, 0x004916C5,
681 0x004A0789, 0x004B0605,
682 0x004C0CC8, 0x004D1954,
683 0x004E0645, 0x004F0E25,
684 0x00500325, 0x00510B26,
685 0x005206C9, 0x00530764,
686 0x005408A9, 0x00550009,
687 0x005601A9, 0x00570389,
688 0x00580785, 0x00590609,
689 0x005A0049, 0x005B18A9,
690 0x005C0649, 0x005D0E29,
691 0x005E1B29, 0x005F00E9,
692 0x00600365, 0x006116C6,
693 0x00620786, 0x00630608,
694 0x00640788, 0x00650606,
695 0x00660046, 0x006718A8,
696 0x006858A6, 0x00690145,
697 0x006A01E9, 0x006B178A,
698 0x006C01E8, 0x006D1785,
699 0x006E1E28, 0x006F0C65,
700 0x00700CC5, 0x00711D5C,
701 0x00720648, 0x00730E28,
702 0x00740646, 0x00750E26,
703 0x00761B28, 0x007700E6,
704 0x007801E5, 0x00791786,
705 0x007A1E29, 0x007B0C68,
706 0x007C1E24, 0x007D0C69,
707 0x007E0955, 0x007F03C9,
708 0x008003E9, 0x00810975,
709 0x00820C49, 0x00831E04,
710 0x00840C48, 0x00851E05,
711 0x008617A6, 0x008701C5,
712 0x008800C6, 0x00891B08,
713 0x008A0E06, 0x008B0666,
714 0x008C0E08, 0x008D0668,
715 0x008E1D7C, 0x008F0CE5,
716 0x00900C45, 0x00911E08,
717 0x009217A9, 0x009301C4,
718 0x009417AA, 0x009501C9,
719 0x00960169, 0x0097588A,
720 0x00981888, 0x00990066,
721 0x009A0709, 0x009B07A8,
722 0x009C0704, 0x009D07A6,
723 0x009E16E6, 0x009F0345,
724 0x00A000C9, 0x00A11B05,
725 0x00A20E09, 0x00A30669,
726 0x00A41885, 0x00A50065,
727 0x00A60706, 0x00A707A5,
728 0x00A803A9, 0x00A90189,
729 0x00AA0029, 0x00AB0889,
730 0x00AC0744, 0x00AD06E9,
731 0x00AE0B06, 0x00AF0229,
732 0x00B00E05, 0x00B10665,
733 0x00B21974, 0x00B30CE8,
734 0x00B4070A, 0x00B507A9,
735 0x00B616E9, 0x00B70348,
736 0x00B8074A, 0x00B906E6,
737 0x00BA0B09, 0x00BB0226,
738 0x00BC1CE4, 0x00BD0D7D,
739 0x00BE0269, 0x00BF08C9,
740 0x00C000CA, 0x00C11B04,
741 0x00C21884, 0x00C3006A,
742 0x00C40E04, 0x00C50664,
743 0x00C60708, 0x00C707AA,
744 0x00C803A8, 0x00C90184,
745 0x00CA0749, 0x00CB06E4,
746 0x00CC0020, 0x00CD0888,
747 0x00CE0B08, 0x00CF0224,
748 0x00D00E0A, 0x00D1066A,
749 0x00D20705, 0x00D307A4,
750 0x00D41D78, 0x00D50CE9,
751 0x00D616EA, 0x00D70349,
752 0x00D80745, 0x00D906E8,
753 0x00DA1CE9, 0x00DB0D75,
754 0x00DC0B04, 0x00DD0228,
755 0x00DE0268, 0x00DF08C8,
756 0x00E003A5, 0x00E10185,
757 0x00E20746, 0x00E306EA,
758 0x00E40748, 0x00E506E5,
759 0x00E61CE8, 0x00E70D79,
760 0x00E81D74, 0x00E95CE6,
761 0x00EA02E9, 0x00EB0849,
762 0x00EC02E8, 0x00ED0848,
763 0x00EE0086, 0x00EF0A08,
764 0x00F00021, 0x00F10885,
765 0x00F20B05, 0x00F3022A,
766 0x00F40B0A, 0x00F50225,
767 0x00F60265, 0x00F708C5,
768 0x00F802E5, 0x00F90845,
769 0x00FA0089, 0x00FB0A09,
770 0x00FC008A, 0x00FD0A0A,
771 0x00FE02A9, 0x00FF0062,
774 if (!hbmMask)
775 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
777 hbrMask = CreatePatternBrush(hbmMask);
778 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
780 /* make bitmap */
781 hDC1 = CreateCompatibleDC(hdcDest);
782 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
783 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
785 /* draw using bkgnd rop */
786 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
787 hbrTmp = SelectObject(hDC1, hbrDst);
788 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
789 SelectObject(hDC1, hbrTmp);
791 /* make bitmap */
792 hDC2 = CreateCompatibleDC(hdcDest);
793 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
794 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
796 /* draw using foregnd rop */
797 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
798 hbrTmp = SelectObject(hDC2, hbrDst);
799 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
801 /* combine both using the mask as a pattern brush */
802 SelectObject(hDC2, hbrMask);
803 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
804 SelectObject(hDC2, hbrTmp);
806 /* blit to dst */
807 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
809 /* restore all objects */
810 SelectObject(hdcDest, hbrDst);
811 SelectObject(hDC1, hOldBitmap1);
812 SelectObject(hDC2, hOldBitmap2);
814 /* delete all temp objects */
815 DeleteObject(hBitmap1);
816 DeleteObject(hBitmap2);
817 DeleteObject(hbrMask);
819 DeleteDC(hDC1);
820 DeleteDC(hDC2);
822 return TRUE;
825 /******************************************************************************
826 * GdiTransparentBlt [GDI32.@]
828 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
829 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
830 UINT crTransparent )
832 BOOL ret = FALSE;
833 HDC hdcWork;
834 HBITMAP bmpWork;
835 HGDIOBJ oldWork;
836 HDC hdcMask = NULL;
837 HBITMAP bmpMask = NULL;
838 HBITMAP oldMask = NULL;
839 COLORREF oldBackground;
840 COLORREF oldForeground;
841 int oldStretchMode;
843 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
844 TRACE("Cannot mirror\n");
845 return FALSE;
848 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
849 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
851 /* Stretch bitmap */
852 oldStretchMode = GetStretchBltMode(hdcSrc);
853 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
854 SetStretchBltMode(hdcSrc, COLORONCOLOR);
855 hdcWork = CreateCompatibleDC(hdcDest);
856 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
857 oldWork = SelectObject(hdcWork, bmpWork);
858 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
859 TRACE("Failed to stretch\n");
860 goto error;
862 SetBkColor(hdcWork, crTransparent);
864 /* Create mask */
865 hdcMask = CreateCompatibleDC(hdcDest);
866 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
867 oldMask = SelectObject(hdcMask, bmpMask);
868 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
869 TRACE("Failed to create mask\n");
870 goto error;
873 /* Replace transparent color with black */
874 SetBkColor(hdcWork, RGB(0,0,0));
875 SetTextColor(hdcWork, RGB(255,255,255));
876 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
877 TRACE("Failed to mask out background\n");
878 goto error;
881 /* Replace non-transparent area on destination with black */
882 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
883 TRACE("Failed to clear destination area\n");
884 goto error;
887 /* Draw the image */
888 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
889 TRACE("Failed to paint image\n");
890 goto error;
893 ret = TRUE;
894 error:
895 SetStretchBltMode(hdcSrc, oldStretchMode);
896 SetBkColor(hdcDest, oldBackground);
897 SetTextColor(hdcDest, oldForeground);
898 if(hdcWork) {
899 SelectObject(hdcWork, oldWork);
900 DeleteDC(hdcWork);
902 if(bmpWork) DeleteObject(bmpWork);
903 if(hdcMask) {
904 SelectObject(hdcMask, oldMask);
905 DeleteDC(hdcMask);
907 if(bmpMask) DeleteObject(bmpMask);
908 return ret;
911 /******************************************************************************
912 * GdiAlphaBlend [GDI32.@]
914 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
915 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
916 BLENDFUNCTION blendFunction)
918 BOOL ret = FALSE;
919 DC *dcDst, *dcSrc;
921 dcSrc = get_dc_ptr( hdcSrc );
922 if (!dcSrc) return FALSE;
924 if ((dcDst = get_dc_ptr( hdcDst )))
926 struct bitblt_coords src, dst;
928 update_dc( dcSrc );
929 update_dc( dcDst );
931 src.log_x = xSrc;
932 src.log_y = ySrc;
933 src.log_width = widthSrc;
934 src.log_height = heightSrc;
935 src.layout = GetLayout( hdcSrc );
936 dst.log_x = xDst;
937 dst.log_y = yDst;
938 dst.log_width = widthDst;
939 dst.log_height = heightDst;
940 dst.layout = GetLayout( hdcDst );
941 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
943 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",
944 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
945 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
946 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
947 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
948 blendFunction.BlendOp, blendFunction.BlendFlags,
949 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
951 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
952 src.log_width < 0 || src.log_height < 0 ||
953 (!is_rect_empty( &dcSrc->device_rect ) &&
954 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
955 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
957 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
958 SetLastError( ERROR_INVALID_PARAMETER );
959 ret = FALSE;
961 else if (dst.log_width < 0 || dst.log_height < 0)
963 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
964 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
965 SetLastError( ERROR_INVALID_PARAMETER );
966 ret = FALSE;
968 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
969 src.y + src.height > dst.y && src.y < dst.y + dst.height)
971 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
972 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
973 SetLastError( ERROR_INVALID_PARAMETER );
974 ret = FALSE;
976 else if (!ret)
978 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
979 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
980 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
982 release_dc_ptr( dcDst );
984 release_dc_ptr( dcSrc );
985 return ret;
988 /*********************************************************************
989 * PlgBlt [GDI32.@]
992 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
993 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
994 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
996 int oldgMode;
997 /* parallelogram coords */
998 POINT plg[3];
999 /* rect coords */
1000 POINT rect[3];
1001 XFORM xf;
1002 XFORM SrcXf;
1003 XFORM oldDestXf;
1004 double det;
1006 /* save actual mode, set GM_ADVANCED */
1007 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1008 if (oldgMode == 0)
1009 return FALSE;
1011 memcpy(plg,lpPoint,sizeof(POINT)*3);
1012 rect[0].x = nXSrc;
1013 rect[0].y = nYSrc;
1014 rect[1].x = nXSrc + nWidth;
1015 rect[1].y = nYSrc;
1016 rect[2].x = nXSrc;
1017 rect[2].y = nYSrc + nHeight;
1018 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1019 /* determinant */
1020 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);
1022 if (fabs(det) < 1e-5)
1024 SetGraphicsMode(hdcDest,oldgMode);
1025 return FALSE;
1028 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1029 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1031 /* X components */
1032 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;
1033 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;
1034 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1035 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1036 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1037 ) / det;
1039 /* Y components */
1040 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;
1041 xf.eM22 = (rect[1].x*(plg[2].y - plg[0].y) - rect[2].x*(plg[1].y - plg[0].y) - rect[0].x*(plg[2].y - plg[1].y)) / det;
1042 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1043 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1044 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1045 ) / det;
1047 GetWorldTransform(hdcSrc,&SrcXf);
1048 CombineTransform(&xf,&xf,&SrcXf);
1050 /* save actual dest transform */
1051 GetWorldTransform(hdcDest,&oldDestXf);
1053 SetWorldTransform(hdcDest,&xf);
1054 /* now destination and source DCs use same coords */
1055 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1056 hdcSrc, nXSrc,nYSrc,
1057 hbmMask,xMask,yMask,
1058 SRCCOPY);
1059 /* restore dest DC */
1060 SetWorldTransform(hdcDest,&oldDestXf);
1061 SetGraphicsMode(hdcDest,oldgMode);
1063 return TRUE;