gdi32: Introduce a unified function to perform COLORREF to pixel color mapping.
[wine.git] / dlls / gdi32 / bitblt.c
blob486266a790532a2e46e2f443dc86b7fe0f8d9983
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>
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 intersect_rect( &rect, &src->visrect, &dst->visrect );
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, clip;
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 if (get_clip_box( dc_dst, &clip ))
128 intersect_rect( &dst->visrect, &rect, &clip );
129 else
130 dst->visrect = rect;
132 /* get the source visible rectangle */
134 if (!src) return !is_rect_empty( &dst->visrect );
136 rect.left = src->log_x;
137 rect.top = src->log_y;
138 rect.right = src->log_x + src->log_width;
139 rect.bottom = src->log_y + src->log_height;
140 LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
141 src->x = rect.left;
142 src->y = rect.top;
143 src->width = rect.right - rect.left;
144 src->height = rect.bottom - rect.top;
145 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
147 src->x += src->width;
148 src->width = -src->width;
150 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
152 /* source is not clipped */
153 if (dc_src->header.type == OBJ_MEMDC)
154 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
155 else
156 src->visrect = rect; /* FIXME: clip to device size */
158 if (is_rect_empty( &src->visrect )) return FALSE;
159 if (is_rect_empty( &dst->visrect )) return FALSE;
161 return intersect_vis_rectangles( dst, src );
164 void free_heap_bits( struct gdi_image_bits *bits )
166 HeapFree( GetProcessHeap(), 0, bits->ptr );
169 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
170 BITMAPINFO *dst_info, struct gdi_image_bits *bits, BOOL add_alpha )
172 void *ptr;
173 DWORD err;
175 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
176 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
177 return ERROR_OUTOFMEMORY;
179 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
180 if (bits->free) bits->free( bits );
181 bits->ptr = ptr;
182 bits->is_copy = TRUE;
183 bits->free = free_heap_bits;
184 return err;
187 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
188 BITMAPINFO *dst_info, struct bitblt_coords *dst,
189 struct gdi_image_bits *bits, int mode )
191 void *ptr;
192 DWORD err;
194 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
195 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
196 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
197 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
198 return ERROR_OUTOFMEMORY;
200 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
201 if (bits->free) bits->free( bits );
202 bits->ptr = ptr;
203 bits->is_copy = TRUE;
204 bits->free = free_heap_bits;
205 return err;
208 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
209 struct bitblt_coords *src, BITMAPINFO *dst_info,
210 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
212 if (!dst_bits->is_copy)
214 int size = get_dib_image_size( dst_info );
215 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
216 if (!ptr) return ERROR_OUTOFMEMORY;
217 memcpy( ptr, dst_bits->ptr, size );
218 if (dst_bits->free) dst_bits->free( dst_bits );
219 dst_bits->ptr = ptr;
220 dst_bits->is_copy = TRUE;
221 dst_bits->free = free_heap_bits;
223 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
226 /***********************************************************************
227 * null driver fallback implementations
230 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
231 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
233 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
234 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
235 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
236 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
237 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
238 DWORD err;
239 struct gdi_image_bits bits;
241 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
242 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
243 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
244 release_dc_ptr( dc_src );
245 if (err) return FALSE;
247 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
248 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
249 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
250 if (err == ERROR_BAD_FORMAT)
252 /* 1-bpp source without a color table uses the destination DC colors */
253 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
255 COLORREF color = GetTextColor( dst_dev->hdc );
256 src_info->bmiColors[0].rgbRed = GetRValue( color );
257 src_info->bmiColors[0].rgbGreen = GetGValue( color );
258 src_info->bmiColors[0].rgbBlue = GetBValue( color );
259 src_info->bmiColors[0].rgbReserved = 0;
260 color = GetBkColor( dst_dev->hdc );
261 src_info->bmiColors[1].rgbRed = GetRValue( color );
262 src_info->bmiColors[1].rgbGreen = GetGValue( color );
263 src_info->bmiColors[1].rgbBlue = GetBValue( color );
264 src_info->bmiColors[1].rgbReserved = 0;
265 src_info->bmiHeader.biClrUsed = 2;
268 /* 1-bpp destination without a color table requires a fake 1-entry table
269 * that contains only the background color */
270 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
272 COLORREF color = GetBkColor( src_dev->hdc );
273 dst_info->bmiColors[0].rgbRed = GetRValue( color );
274 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
275 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
276 dst_info->bmiColors[0].rgbReserved = 0;
277 dst_info->bmiHeader.biClrUsed = 1;
280 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
282 /* get rid of the fake 1-bpp table */
283 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
284 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
288 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
289 ((src->width != dst->width) || (src->height != dst->height)))
291 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
292 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
293 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
296 if (bits.free) bits.free( &bits );
297 return !err;
301 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
302 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
304 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
305 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
306 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
307 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
308 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
309 DWORD err;
310 struct gdi_image_bits bits;
312 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
313 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
314 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
315 release_dc_ptr( dc_src );
316 if (err) goto done;
318 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
319 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
320 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
321 if (err == ERROR_BAD_FORMAT)
323 /* 1-bpp source without a color table uses black & white */
324 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
326 src_info->bmiColors[0].rgbRed = 0;
327 src_info->bmiColors[0].rgbGreen = 0;
328 src_info->bmiColors[0].rgbBlue = 0;
329 src_info->bmiColors[0].rgbReserved = 0;
330 src_info->bmiColors[1].rgbRed = 0xff;
331 src_info->bmiColors[1].rgbGreen = 0xff;
332 src_info->bmiColors[1].rgbBlue = 0xff;
333 src_info->bmiColors[1].rgbReserved = 0;
334 src_info->bmiHeader.biClrUsed = 2;
337 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
338 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
341 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
342 ((src->width != dst->width) || (src->height != dst->height)))
344 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
345 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
346 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
349 if (bits.free) bits.free( &bits );
350 done:
351 if (err) SetLastError( err );
352 return !err;
356 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
357 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
359 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
360 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
361 struct gdi_image_bits dst_bits;
362 struct bitblt_coords orig_dst;
363 DC *dc = get_nulldrv_dc( dev );
364 DWORD err;
366 if (info->bmiHeader.biPlanes != 1) goto update_format;
367 if (info->bmiHeader.biBitCount != 32) goto update_format;
368 if (info->bmiHeader.biCompression == BI_BITFIELDS)
370 DWORD *masks = (DWORD *)info->bmiColors;
371 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
372 goto update_format;
375 if (!bits) return ERROR_SUCCESS;
376 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
378 dev = GET_DC_PHYSDEV( dc, pGetImage );
379 orig_dst = *dst;
380 err = dev->funcs->pGetImage( dev, 0, dst_info, &dst_bits, dst );
381 if (err) return err;
383 dev = GET_DC_PHYSDEV( dc, pPutImage );
384 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
385 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
387 if (dst_bits.free) dst_bits.free( &dst_bits );
388 return err;
390 update_format:
391 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
392 return ERROR_INVALID_PARAMETER;
394 info->bmiHeader.biPlanes = 1;
395 info->bmiHeader.biBitCount = 32;
396 info->bmiHeader.biCompression = BI_RGB;
397 info->bmiHeader.biClrUsed = 0;
398 return ERROR_BAD_FORMAT;
401 /***********************************************************************
402 * PatBlt (GDI32.@)
404 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
406 DC * dc;
407 BOOL ret = FALSE;
409 if (rop_uses_src( rop )) return FALSE;
410 if ((dc = get_dc_ptr( hdc )))
412 struct bitblt_coords dst;
413 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
415 update_dc( dc );
417 dst.log_x = left;
418 dst.log_y = top;
419 dst.log_width = width;
420 dst.log_height = height;
421 dst.layout = dc->layout;
422 if (rop & NOMIRRORBITMAP)
424 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
425 rop &= ~NOMIRRORBITMAP;
427 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
429 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
430 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
431 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
433 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
435 release_dc_ptr( dc );
437 return ret;
441 /***********************************************************************
442 * BitBlt (GDI32.@)
444 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
445 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
447 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
448 else return StretchBlt( hdcDst, xDst, yDst, width, height,
449 hdcSrc, xSrc, ySrc, width, height, rop );
453 /***********************************************************************
454 * StretchBlt (GDI32.@)
456 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
457 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
459 BOOL ret = FALSE;
460 DC *dcDst, *dcSrc;
462 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
464 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
466 if ((dcSrc = get_dc_ptr( hdcSrc )))
468 struct bitblt_coords src, dst;
469 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
470 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
472 update_dc( dcSrc );
473 update_dc( dcDst );
475 src.log_x = xSrc;
476 src.log_y = ySrc;
477 src.log_width = widthSrc;
478 src.log_height = heightSrc;
479 src.layout = dcSrc->layout;
480 dst.log_x = xDst;
481 dst.log_y = yDst;
482 dst.log_width = widthDst;
483 dst.log_height = heightDst;
484 dst.layout = dcDst->layout;
485 if (rop & NOMIRRORBITMAP)
487 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
488 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
489 rop &= ~NOMIRRORBITMAP;
491 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
493 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",
494 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
495 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
496 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
497 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
499 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
500 release_dc_ptr( dcSrc );
502 release_dc_ptr( dcDst );
503 return ret;
506 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
507 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
509 /***********************************************************************
510 * MaskBlt [GDI32.@]
512 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
513 INT nWidth, INT nHeight, HDC hdcSrc,
514 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
515 INT xMask, INT yMask, DWORD dwRop)
517 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
518 HDC hDC1, hDC2;
519 HBRUSH hbrMask, hbrDst, hbrTmp;
521 static const DWORD ROP3Table[256] =
523 0x00000042, 0x00010289,
524 0x00020C89, 0x000300AA,
525 0x00040C88, 0x000500A9,
526 0x00060865, 0x000702C5,
527 0x00080F08, 0x00090245,
528 0x000A0329, 0x000B0B2A,
529 0x000C0324, 0x000D0B25,
530 0x000E08A5, 0x000F0001,
531 0x00100C85, 0x001100A6,
532 0x00120868, 0x001302C8,
533 0x00140869, 0x001502C9,
534 0x00165CCA, 0x00171D54,
535 0x00180D59, 0x00191CC8,
536 0x001A06C5, 0x001B0768,
537 0x001C06CA, 0x001D0766,
538 0x001E01A5, 0x001F0385,
539 0x00200F09, 0x00210248,
540 0x00220326, 0x00230B24,
541 0x00240D55, 0x00251CC5,
542 0x002606C8, 0x00271868,
543 0x00280369, 0x002916CA,
544 0x002A0CC9, 0x002B1D58,
545 0x002C0784, 0x002D060A,
546 0x002E064A, 0x002F0E2A,
547 0x0030032A, 0x00310B28,
548 0x00320688, 0x00330008,
549 0x003406C4, 0x00351864,
550 0x003601A8, 0x00370388,
551 0x0038078A, 0x00390604,
552 0x003A0644, 0x003B0E24,
553 0x003C004A, 0x003D18A4,
554 0x003E1B24, 0x003F00EA,
555 0x00400F0A, 0x00410249,
556 0x00420D5D, 0x00431CC4,
557 0x00440328, 0x00450B29,
558 0x004606C6, 0x0047076A,
559 0x00480368, 0x004916C5,
560 0x004A0789, 0x004B0605,
561 0x004C0CC8, 0x004D1954,
562 0x004E0645, 0x004F0E25,
563 0x00500325, 0x00510B26,
564 0x005206C9, 0x00530764,
565 0x005408A9, 0x00550009,
566 0x005601A9, 0x00570389,
567 0x00580785, 0x00590609,
568 0x005A0049, 0x005B18A9,
569 0x005C0649, 0x005D0E29,
570 0x005E1B29, 0x005F00E9,
571 0x00600365, 0x006116C6,
572 0x00620786, 0x00630608,
573 0x00640788, 0x00650606,
574 0x00660046, 0x006718A8,
575 0x006858A6, 0x00690145,
576 0x006A01E9, 0x006B178A,
577 0x006C01E8, 0x006D1785,
578 0x006E1E28, 0x006F0C65,
579 0x00700CC5, 0x00711D5C,
580 0x00720648, 0x00730E28,
581 0x00740646, 0x00750E26,
582 0x00761B28, 0x007700E6,
583 0x007801E5, 0x00791786,
584 0x007A1E29, 0x007B0C68,
585 0x007C1E24, 0x007D0C69,
586 0x007E0955, 0x007F03C9,
587 0x008003E9, 0x00810975,
588 0x00820C49, 0x00831E04,
589 0x00840C48, 0x00851E05,
590 0x008617A6, 0x008701C5,
591 0x008800C6, 0x00891B08,
592 0x008A0E06, 0x008B0666,
593 0x008C0E08, 0x008D0668,
594 0x008E1D7C, 0x008F0CE5,
595 0x00900C45, 0x00911E08,
596 0x009217A9, 0x009301C4,
597 0x009417AA, 0x009501C9,
598 0x00960169, 0x0097588A,
599 0x00981888, 0x00990066,
600 0x009A0709, 0x009B07A8,
601 0x009C0704, 0x009D07A6,
602 0x009E16E6, 0x009F0345,
603 0x00A000C9, 0x00A11B05,
604 0x00A20E09, 0x00A30669,
605 0x00A41885, 0x00A50065,
606 0x00A60706, 0x00A707A5,
607 0x00A803A9, 0x00A90189,
608 0x00AA0029, 0x00AB0889,
609 0x00AC0744, 0x00AD06E9,
610 0x00AE0B06, 0x00AF0229,
611 0x00B00E05, 0x00B10665,
612 0x00B21974, 0x00B30CE8,
613 0x00B4070A, 0x00B507A9,
614 0x00B616E9, 0x00B70348,
615 0x00B8074A, 0x00B906E6,
616 0x00BA0B09, 0x00BB0226,
617 0x00BC1CE4, 0x00BD0D7D,
618 0x00BE0269, 0x00BF08C9,
619 0x00C000CA, 0x00C11B04,
620 0x00C21884, 0x00C3006A,
621 0x00C40E04, 0x00C50664,
622 0x00C60708, 0x00C707AA,
623 0x00C803A8, 0x00C90184,
624 0x00CA0749, 0x00CB06E4,
625 0x00CC0020, 0x00CD0888,
626 0x00CE0B08, 0x00CF0224,
627 0x00D00E0A, 0x00D1066A,
628 0x00D20705, 0x00D307A4,
629 0x00D41D78, 0x00D50CE9,
630 0x00D616EA, 0x00D70349,
631 0x00D80745, 0x00D906E8,
632 0x00DA1CE9, 0x00DB0D75,
633 0x00DC0B04, 0x00DD0228,
634 0x00DE0268, 0x00DF08C8,
635 0x00E003A5, 0x00E10185,
636 0x00E20746, 0x00E306EA,
637 0x00E40748, 0x00E506E5,
638 0x00E61CE8, 0x00E70D79,
639 0x00E81D74, 0x00E95CE6,
640 0x00EA02E9, 0x00EB0849,
641 0x00EC02E8, 0x00ED0848,
642 0x00EE0086, 0x00EF0A08,
643 0x00F00021, 0x00F10885,
644 0x00F20B05, 0x00F3022A,
645 0x00F40B0A, 0x00F50225,
646 0x00F60265, 0x00F708C5,
647 0x00F802E5, 0x00F90845,
648 0x00FA0089, 0x00FB0A09,
649 0x00FC008A, 0x00FD0A0A,
650 0x00FE02A9, 0x00FF0062,
653 if (!hbmMask)
654 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
656 hbrMask = CreatePatternBrush(hbmMask);
657 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
659 /* make bitmap */
660 hDC1 = CreateCompatibleDC(hdcDest);
661 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
662 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
664 /* draw using bkgnd rop */
665 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
666 hbrTmp = SelectObject(hDC1, hbrDst);
667 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
668 SelectObject(hDC1, hbrTmp);
670 /* make bitmap */
671 hDC2 = CreateCompatibleDC(hdcDest);
672 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
673 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
675 /* draw using foregnd rop */
676 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
677 hbrTmp = SelectObject(hDC2, hbrDst);
678 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
680 /* combine both using the mask as a pattern brush */
681 SelectObject(hDC2, hbrMask);
682 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
683 SelectObject(hDC2, hbrTmp);
685 /* blit to dst */
686 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
688 /* restore all objects */
689 SelectObject(hdcDest, hbrDst);
690 SelectObject(hDC1, hOldBitmap1);
691 SelectObject(hDC2, hOldBitmap2);
693 /* delete all temp objects */
694 DeleteObject(hBitmap1);
695 DeleteObject(hBitmap2);
696 DeleteObject(hbrMask);
698 DeleteDC(hDC1);
699 DeleteDC(hDC2);
701 return TRUE;
704 /******************************************************************************
705 * GdiTransparentBlt [GDI32.@]
707 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
708 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
709 UINT crTransparent )
711 BOOL ret = FALSE;
712 HDC hdcWork;
713 HBITMAP bmpWork;
714 HGDIOBJ oldWork;
715 HDC hdcMask = NULL;
716 HBITMAP bmpMask = NULL;
717 HBITMAP oldMask = NULL;
718 COLORREF oldBackground;
719 COLORREF oldForeground;
720 int oldStretchMode;
722 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
723 TRACE("Cannot mirror\n");
724 return FALSE;
727 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
728 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
730 /* Stretch bitmap */
731 oldStretchMode = GetStretchBltMode(hdcSrc);
732 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
733 SetStretchBltMode(hdcSrc, COLORONCOLOR);
734 hdcWork = CreateCompatibleDC(hdcDest);
735 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
736 oldWork = SelectObject(hdcWork, bmpWork);
737 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
738 TRACE("Failed to stretch\n");
739 goto error;
741 SetBkColor(hdcWork, crTransparent);
743 /* Create mask */
744 hdcMask = CreateCompatibleDC(hdcDest);
745 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
746 oldMask = SelectObject(hdcMask, bmpMask);
747 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
748 TRACE("Failed to create mask\n");
749 goto error;
752 /* Replace transparent color with black */
753 SetBkColor(hdcWork, RGB(0,0,0));
754 SetTextColor(hdcWork, RGB(255,255,255));
755 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
756 TRACE("Failed to mask out background\n");
757 goto error;
760 /* Replace non-transparent area on destination with black */
761 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
762 TRACE("Failed to clear destination area\n");
763 goto error;
766 /* Draw the image */
767 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
768 TRACE("Failed to paint image\n");
769 goto error;
772 ret = TRUE;
773 error:
774 SetStretchBltMode(hdcSrc, oldStretchMode);
775 SetBkColor(hdcDest, oldBackground);
776 SetTextColor(hdcDest, oldForeground);
777 if(hdcWork) {
778 SelectObject(hdcWork, oldWork);
779 DeleteDC(hdcWork);
781 if(bmpWork) DeleteObject(bmpWork);
782 if(hdcMask) {
783 SelectObject(hdcMask, oldMask);
784 DeleteDC(hdcMask);
786 if(bmpMask) DeleteObject(bmpMask);
787 return ret;
790 /******************************************************************************
791 * GdiAlphaBlend [GDI32.@]
793 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
794 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
795 BLENDFUNCTION blendFunction)
797 BOOL ret = FALSE;
798 DC *dcDst, *dcSrc;
800 dcSrc = get_dc_ptr( hdcSrc );
801 if (!dcSrc) return FALSE;
803 if ((dcDst = get_dc_ptr( hdcDst )))
805 struct bitblt_coords src, dst;
806 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
807 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
809 update_dc( dcSrc );
810 update_dc( dcDst );
812 src.log_x = xSrc;
813 src.log_y = ySrc;
814 src.log_width = widthSrc;
815 src.log_height = heightSrc;
816 src.layout = GetLayout( src_dev->hdc );
817 dst.log_x = xDst;
818 dst.log_y = yDst;
819 dst.log_width = widthDst;
820 dst.log_height = heightDst;
821 dst.layout = GetLayout( dst_dev->hdc );
822 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
824 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",
825 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
826 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
827 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
828 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
829 blendFunction.BlendOp, blendFunction.BlendFlags,
830 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
832 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
833 (dcSrc->header.type == OBJ_MEMDC &&
834 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
835 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
837 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
838 SetLastError( ERROR_INVALID_PARAMETER );
839 ret = FALSE;
841 else if (dst.width < 0 || dst.height < 0)
843 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
844 SetLastError( ERROR_INVALID_PARAMETER );
845 ret = FALSE;
847 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
848 src.y + src.height > dst.y && src.y < dst.y + dst.height)
850 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
851 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
852 SetLastError( ERROR_INVALID_PARAMETER );
853 ret = FALSE;
855 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
857 release_dc_ptr( dcDst );
859 release_dc_ptr( dcSrc );
860 return ret;
863 /*********************************************************************
864 * PlgBlt [GDI32.@]
867 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
868 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
869 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
871 int oldgMode;
872 /* parallelogram coords */
873 POINT plg[3];
874 /* rect coords */
875 POINT rect[3];
876 XFORM xf;
877 XFORM SrcXf;
878 XFORM oldDestXf;
879 double det;
881 /* save actual mode, set GM_ADVANCED */
882 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
883 if (oldgMode == 0)
884 return FALSE;
886 memcpy(plg,lpPoint,sizeof(POINT)*3);
887 rect[0].x = nXSrc;
888 rect[0].y = nYSrc;
889 rect[1].x = nXSrc + nWidth;
890 rect[1].y = nYSrc;
891 rect[2].x = nXSrc;
892 rect[2].y = nYSrc + nHeight;
893 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
894 /* determinant */
895 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);
897 if (fabs(det) < 1e-5)
899 SetGraphicsMode(hdcDest,oldgMode);
900 return FALSE;
903 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
904 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
906 /* X components */
907 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;
908 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;
909 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
910 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
911 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
912 ) / det;
914 /* Y components */
915 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;
916 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;
917 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
918 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
919 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
920 ) / det;
922 GetWorldTransform(hdcSrc,&SrcXf);
923 CombineTransform(&xf,&xf,&SrcXf);
925 /* save actual dest transform */
926 GetWorldTransform(hdcDest,&oldDestXf);
928 SetWorldTransform(hdcDest,&xf);
929 /* now destination and source DCs use same coords */
930 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
931 hdcSrc, nXSrc,nYSrc,
932 hbmMask,xMask,yMask,
933 SRCCOPY);
934 /* restore dest DC */
935 SetWorldTransform(hdcDest,&oldDestXf);
936 SetGraphicsMode(hdcDest,oldgMode);
938 return TRUE;