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
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 )
50 static void get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
51 DC *dc_src, struct bitblt_coords *src )
55 /* get the destination visible rectangle */
57 rect.left = dst->log_x;
58 rect.top = dst->log_y;
59 rect.right = dst->log_x + dst->log_width;
60 rect.bottom = dst->log_y + dst->log_height;
61 LPtoDP( dc_dst->hSelf, (POINT *)&rect, 2 );
64 dst->width = rect.right - rect.left;
65 dst->height = rect.bottom - rect.top;
66 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
68 swap_ints( &rect.left, &rect.right );
70 dst->width = rect.right - rect.left;
72 if (rect.left > rect.right) { swap_ints( &rect.left, &rect.right ); rect.left++; rect.right++; }
73 if (rect.top > rect.bottom) { swap_ints( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
75 if (get_clip_box( dc_dst, &clip ))
76 intersect_rect( &dst->visrect, &rect, &clip );
80 /* get the source visible rectangle */
84 rect.left = src->log_x;
85 rect.top = src->log_y;
86 rect.right = src->log_x + src->log_width;
87 rect.bottom = src->log_y + src->log_height;
88 LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
91 src->width = rect.right - rect.left;
92 src->height = rect.bottom - rect.top;
93 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
95 swap_ints( &rect.left, &rect.right );
97 src->width = rect.right - rect.left;
99 if (rect.left > rect.right) { swap_ints( &rect.left, &rect.right ); rect.left++; rect.right++; }
100 if (rect.top > rect.bottom) { swap_ints( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
102 /* source is not clipped */
103 if (dc_src->header.type == OBJ_MEMDC)
104 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
106 src->visrect = rect; /* FIXME: clip to device size */
108 /* intersect the rectangles */
110 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
112 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
113 intersect_rect( &rect, &src->visrect, &dst->visrect );
114 src->visrect = dst->visrect = rect;
115 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
117 else /* stretching */
119 /* map source rectangle into destination coordinates */
120 rect.left = dst->x + (src->visrect.left - src->x)*dst->width/src->width;
121 rect.top = dst->y + (src->visrect.top - src->y)*dst->height/src->height;
122 rect.right = dst->x + (src->visrect.right - src->x)*dst->width/src->width;
123 rect.bottom = dst->y + (src->visrect.bottom - src->y)*dst->height/src->height;
124 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
125 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
127 /* avoid rounding errors */
132 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return;
134 /* map destination rectangle back to source coordinates */
136 rect.left = src->x + (dst->visrect.left - dst->x)*src->width/dst->width;
137 rect.top = src->y + (dst->visrect.top - dst->y)*src->height/dst->height;
138 rect.right = src->x + (dst->visrect.right - dst->x)*src->width/dst->width;
139 rect.bottom = src->y + (dst->visrect.bottom - dst->y)*src->height/dst->height;
140 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
141 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
143 /* avoid rounding errors */
148 intersect_rect( &src->visrect, &rect, &src->visrect );
152 static void free_heap_bits( struct gdi_image_bits *bits )
154 HeapFree( GetProcessHeap(), 0, bits->ptr );
157 /* nulldrv fallback implementation using StretchDIBits */
158 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
159 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
161 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
162 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
163 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
164 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
165 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
167 struct gdi_image_bits src_bits, dst_bits;
173 if (dst->visrect.left >= dst->visrect.right || dst->visrect.top >= dst->visrect.bottom) return TRUE;
175 /* make sure we have a real implementation for StretchDIBits */
176 if (GET_DC_PHYSDEV( dc_dst, pStretchDIBits ) == dst_dev) goto try_get_image;
178 if (GetObjectType( src_dev->hdc ) != OBJ_MEMDC) return FALSE;
179 if (!GetObjectW( GetCurrentObject( src_dev->hdc, OBJ_BITMAP ), sizeof(bm), &bm )) return FALSE;
181 src_info->bmiHeader.biSize = sizeof(src_info->bmiHeader);
182 src_info->bmiHeader.biWidth = bm.bmWidth;
183 src_info->bmiHeader.biHeight = bm.bmHeight;
184 src_info->bmiHeader.biPlanes = 1;
185 src_info->bmiHeader.biBitCount = 32;
186 src_info->bmiHeader.biCompression = BI_RGB;
187 src_info->bmiHeader.biSizeImage = 0;
188 src_info->bmiHeader.biXPelsPerMeter = 0;
189 src_info->bmiHeader.biYPelsPerMeter = 0;
190 src_info->bmiHeader.biClrUsed = 0;
191 src_info->bmiHeader.biClrImportant = 0;
193 if (!(bits = HeapAlloc(GetProcessHeap(), 0, bm.bmHeight * bm.bmWidth * 4)))
196 /* Select out the src bitmap before calling GetDIBits */
197 hbm = SelectObject( src_dev->hdc, GetStockObject(DEFAULT_BITMAP) );
198 lines = GetDIBits( src_dev->hdc, hbm, 0, bm.bmHeight, bits, src_info, DIB_RGB_COLORS );
199 SelectObject( src_dev->hdc, hbm );
201 if (lines) lines = StretchDIBits( dst_dev->hdc, dst->log_x, dst->log_y, dst->log_width, dst->log_height,
202 src->x, bm.bmHeight - src->height - src->y, src->width, src->height,
203 bits, src_info, DIB_RGB_COLORS, rop );
204 HeapFree( GetProcessHeap(), 0, bits );
205 return (lines == src->height);
209 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
210 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
211 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &src_bits, &src->visrect );
212 release_dc_ptr( dc_src );
213 if (err) return FALSE;
215 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
217 if ((src->width != dst->width) || (src->height != dst->height))
218 FIXME( "should stretch %dx%d -> %dx%d\n",
219 src->width, src->height, dst->width, dst->height );
221 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
222 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &src_bits, &dst->visrect, rop );
223 if (err == ERROR_BAD_FORMAT)
225 RECT src_rect = src->visrect;
227 /* 1-bpp source without a color table uses the destination DC colors */
228 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
230 COLORREF color = GetTextColor( dst_dev->hdc );
231 src_info->bmiColors[0].rgbRed = GetRValue( color );
232 src_info->bmiColors[0].rgbGreen = GetGValue( color );
233 src_info->bmiColors[0].rgbBlue = GetBValue( color );
234 src_info->bmiColors[0].rgbReserved = 0;
235 color = GetBkColor( dst_dev->hdc );
236 src_info->bmiColors[1].rgbRed = GetRValue( color );
237 src_info->bmiColors[1].rgbGreen = GetGValue( color );
238 src_info->bmiColors[1].rgbBlue = GetBValue( color );
239 src_info->bmiColors[1].rgbReserved = 0;
240 src_info->bmiHeader.biClrUsed = 2;
243 /* 1-bpp destination without a color table requires a fake 1-entry table
244 * that contains only the background color */
245 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
247 COLORREF color = GetBkColor( src_dev->hdc );
248 dst_info->bmiColors[0].rgbRed = GetRValue( color );
249 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
250 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
251 dst_info->bmiColors[0].rgbReserved = 0;
252 dst_info->bmiHeader.biClrUsed = 1;
255 offset_rect( &src_rect, src_bits.offset - src->visrect.left, -src->visrect.top );
256 dst_info->bmiHeader.biWidth = src_rect.right - src_rect.left;
257 dst_bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ));
260 dst_bits.is_copy = TRUE;
262 dst_bits.free = free_heap_bits;
263 if (!(err = convert_bitmapinfo( src_info, src_bits.ptr, &src_rect, dst_info, dst_bits.ptr )))
265 /* get rid of the fake 1-bpp table */
266 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
267 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &dst_bits, &dst->visrect, rop );
269 if (dst_bits.free) dst_bits.free( &dst_bits );
271 else err = ERROR_OUTOFMEMORY;
273 if (src_bits.free) src_bits.free( &src_bits );
277 /***********************************************************************
280 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
285 if (rop_uses_src( rop )) return FALSE;
286 if ((dc = get_dc_ptr( hdc )))
288 struct bitblt_coords dst;
289 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
295 dst.log_width = width;
296 dst.log_height = height;
297 dst.layout = dc->layout;
298 if (rop & NOMIRRORBITMAP)
300 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
301 rop &= ~NOMIRRORBITMAP;
303 get_vis_rectangles( dc, &dst, NULL, NULL );
305 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
306 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
307 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
309 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
311 release_dc_ptr( dc );
317 /***********************************************************************
320 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
321 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
323 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
324 else return StretchBlt( hdcDst, xDst, yDst, width, height,
325 hdcSrc, xSrc, ySrc, width, height, rop );
329 /***********************************************************************
330 * StretchBlt (GDI32.@)
332 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
333 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
338 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
340 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
342 if ((dcSrc = get_dc_ptr( hdcSrc )))
344 struct bitblt_coords src, dst;
345 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
346 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
353 src.log_width = widthSrc;
354 src.log_height = heightSrc;
355 src.layout = dcSrc->layout;
358 dst.log_width = widthDst;
359 dst.log_height = heightDst;
360 dst.layout = dcDst->layout;
361 if (rop & NOMIRRORBITMAP)
363 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
364 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
365 rop &= ~NOMIRRORBITMAP;
367 get_vis_rectangles( dcDst, &dst, dcSrc, &src );
369 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",
370 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
371 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
372 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
373 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
375 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
376 release_dc_ptr( dcSrc );
378 release_dc_ptr( dcDst );
382 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
383 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
385 /***********************************************************************
388 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
389 INT nWidth, INT nHeight, HDC hdcSrc,
390 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
391 INT xMask, INT yMask, DWORD dwRop)
393 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
395 HBRUSH hbrMask, hbrDst, hbrTmp;
397 static const DWORD ROP3Table[256] =
399 0x00000042, 0x00010289,
400 0x00020C89, 0x000300AA,
401 0x00040C88, 0x000500A9,
402 0x00060865, 0x000702C5,
403 0x00080F08, 0x00090245,
404 0x000A0329, 0x000B0B2A,
405 0x000C0324, 0x000D0B25,
406 0x000E08A5, 0x000F0001,
407 0x00100C85, 0x001100A6,
408 0x00120868, 0x001302C8,
409 0x00140869, 0x001502C9,
410 0x00165CCA, 0x00171D54,
411 0x00180D59, 0x00191CC8,
412 0x001A06C5, 0x001B0768,
413 0x001C06CA, 0x001D0766,
414 0x001E01A5, 0x001F0385,
415 0x00200F09, 0x00210248,
416 0x00220326, 0x00230B24,
417 0x00240D55, 0x00251CC5,
418 0x002606C8, 0x00271868,
419 0x00280369, 0x002916CA,
420 0x002A0CC9, 0x002B1D58,
421 0x002C0784, 0x002D060A,
422 0x002E064A, 0x002F0E2A,
423 0x0030032A, 0x00310B28,
424 0x00320688, 0x00330008,
425 0x003406C4, 0x00351864,
426 0x003601A8, 0x00370388,
427 0x0038078A, 0x00390604,
428 0x003A0644, 0x003B0E24,
429 0x003C004A, 0x003D18A4,
430 0x003E1B24, 0x003F00EA,
431 0x00400F0A, 0x00410249,
432 0x00420D5D, 0x00431CC4,
433 0x00440328, 0x00450B29,
434 0x004606C6, 0x0047076A,
435 0x00480368, 0x004916C5,
436 0x004A0789, 0x004B0605,
437 0x004C0CC8, 0x004D1954,
438 0x004E0645, 0x004F0E25,
439 0x00500325, 0x00510B26,
440 0x005206C9, 0x00530764,
441 0x005408A9, 0x00550009,
442 0x005601A9, 0x00570389,
443 0x00580785, 0x00590609,
444 0x005A0049, 0x005B18A9,
445 0x005C0649, 0x005D0E29,
446 0x005E1B29, 0x005F00E9,
447 0x00600365, 0x006116C6,
448 0x00620786, 0x00630608,
449 0x00640788, 0x00650606,
450 0x00660046, 0x006718A8,
451 0x006858A6, 0x00690145,
452 0x006A01E9, 0x006B178A,
453 0x006C01E8, 0x006D1785,
454 0x006E1E28, 0x006F0C65,
455 0x00700CC5, 0x00711D5C,
456 0x00720648, 0x00730E28,
457 0x00740646, 0x00750E26,
458 0x00761B28, 0x007700E6,
459 0x007801E5, 0x00791786,
460 0x007A1E29, 0x007B0C68,
461 0x007C1E24, 0x007D0C69,
462 0x007E0955, 0x007F03C9,
463 0x008003E9, 0x00810975,
464 0x00820C49, 0x00831E04,
465 0x00840C48, 0x00851E05,
466 0x008617A6, 0x008701C5,
467 0x008800C6, 0x00891B08,
468 0x008A0E06, 0x008B0666,
469 0x008C0E08, 0x008D0668,
470 0x008E1D7C, 0x008F0CE5,
471 0x00900C45, 0x00911E08,
472 0x009217A9, 0x009301C4,
473 0x009417AA, 0x009501C9,
474 0x00960169, 0x0097588A,
475 0x00981888, 0x00990066,
476 0x009A0709, 0x009B07A8,
477 0x009C0704, 0x009D07A6,
478 0x009E16E6, 0x009F0345,
479 0x00A000C9, 0x00A11B05,
480 0x00A20E09, 0x00A30669,
481 0x00A41885, 0x00A50065,
482 0x00A60706, 0x00A707A5,
483 0x00A803A9, 0x00A90189,
484 0x00AA0029, 0x00AB0889,
485 0x00AC0744, 0x00AD06E9,
486 0x00AE0B06, 0x00AF0229,
487 0x00B00E05, 0x00B10665,
488 0x00B21974, 0x00B30CE8,
489 0x00B4070A, 0x00B507A9,
490 0x00B616E9, 0x00B70348,
491 0x00B8074A, 0x00B906E6,
492 0x00BA0B09, 0x00BB0226,
493 0x00BC1CE4, 0x00BD0D7D,
494 0x00BE0269, 0x00BF08C9,
495 0x00C000CA, 0x00C11B04,
496 0x00C21884, 0x00C3006A,
497 0x00C40E04, 0x00C50664,
498 0x00C60708, 0x00C707AA,
499 0x00C803A8, 0x00C90184,
500 0x00CA0749, 0x00CB06E4,
501 0x00CC0020, 0x00CD0888,
502 0x00CE0B08, 0x00CF0224,
503 0x00D00E0A, 0x00D1066A,
504 0x00D20705, 0x00D307A4,
505 0x00D41D78, 0x00D50CE9,
506 0x00D616EA, 0x00D70349,
507 0x00D80745, 0x00D906E8,
508 0x00DA1CE9, 0x00DB0D75,
509 0x00DC0B04, 0x00DD0228,
510 0x00DE0268, 0x00DF08C8,
511 0x00E003A5, 0x00E10185,
512 0x00E20746, 0x00E306EA,
513 0x00E40748, 0x00E506E5,
514 0x00E61CE8, 0x00E70D79,
515 0x00E81D74, 0x00E95CE6,
516 0x00EA02E9, 0x00EB0849,
517 0x00EC02E8, 0x00ED0848,
518 0x00EE0086, 0x00EF0A08,
519 0x00F00021, 0x00F10885,
520 0x00F20B05, 0x00F3022A,
521 0x00F40B0A, 0x00F50225,
522 0x00F60265, 0x00F708C5,
523 0x00F802E5, 0x00F90845,
524 0x00FA0089, 0x00FB0A09,
525 0x00FC008A, 0x00FD0A0A,
526 0x00FE02A9, 0x00FF0062,
530 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
532 hbrMask = CreatePatternBrush(hbmMask);
533 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
536 hDC1 = CreateCompatibleDC(hdcDest);
537 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
538 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
540 /* draw using bkgnd rop */
541 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
542 hbrTmp = SelectObject(hDC1, hbrDst);
543 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
544 SelectObject(hDC1, hbrTmp);
547 hDC2 = CreateCompatibleDC(hdcDest);
548 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
549 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
551 /* draw using foregnd rop */
552 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
553 hbrTmp = SelectObject(hDC2, hbrDst);
554 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
556 /* combine both using the mask as a pattern brush */
557 SelectObject(hDC2, hbrMask);
558 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
559 SelectObject(hDC2, hbrTmp);
562 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
564 /* restore all objects */
565 SelectObject(hdcDest, hbrDst);
566 SelectObject(hDC1, hOldBitmap1);
567 SelectObject(hDC2, hOldBitmap2);
569 /* delete all temp objects */
570 DeleteObject(hBitmap1);
571 DeleteObject(hBitmap2);
572 DeleteObject(hbrMask);
580 /******************************************************************************
581 * GdiTransparentBlt [GDI32.@]
583 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
584 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
592 HBITMAP bmpMask = NULL;
593 HBITMAP oldMask = NULL;
594 COLORREF oldBackground;
595 COLORREF oldForeground;
598 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
599 TRACE("Cannot mirror\n");
603 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
604 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
607 oldStretchMode = GetStretchBltMode(hdcSrc);
608 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
609 SetStretchBltMode(hdcSrc, COLORONCOLOR);
610 hdcWork = CreateCompatibleDC(hdcDest);
611 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
612 oldWork = SelectObject(hdcWork, bmpWork);
613 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
614 TRACE("Failed to stretch\n");
617 SetBkColor(hdcWork, crTransparent);
620 hdcMask = CreateCompatibleDC(hdcDest);
621 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
622 oldMask = SelectObject(hdcMask, bmpMask);
623 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
624 TRACE("Failed to create mask\n");
628 /* Replace transparent color with black */
629 SetBkColor(hdcWork, RGB(0,0,0));
630 SetTextColor(hdcWork, RGB(255,255,255));
631 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
632 TRACE("Failed to mask out background\n");
636 /* Replace non-transparent area on destination with black */
637 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
638 TRACE("Failed to clear destination area\n");
643 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
644 TRACE("Failed to paint image\n");
650 SetStretchBltMode(hdcSrc, oldStretchMode);
651 SetBkColor(hdcDest, oldBackground);
652 SetTextColor(hdcDest, oldForeground);
654 SelectObject(hdcWork, oldWork);
657 if(bmpWork) DeleteObject(bmpWork);
659 SelectObject(hdcMask, oldMask);
662 if(bmpMask) DeleteObject(bmpMask);
666 /******************************************************************************
667 * GdiAlphaBlend [GDI32.@]
669 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
670 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
671 BLENDFUNCTION blendFunction)
676 dcSrc = get_dc_ptr( hdcSrc );
677 if (!dcSrc) return FALSE;
679 if ((dcDst = get_dc_ptr( hdcDst )))
681 struct bitblt_coords src, dst;
682 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
683 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
690 src.log_width = widthSrc;
691 src.log_height = heightSrc;
692 src.layout = GetLayout( src_dev->hdc );
695 dst.log_width = widthDst;
696 dst.log_height = heightDst;
697 dst.layout = GetLayout( dst_dev->hdc );
698 get_vis_rectangles( dcDst, &dst, dcSrc, &src );
700 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",
701 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
702 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
703 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
704 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
705 blendFunction.BlendOp, blendFunction.BlendFlags,
706 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
708 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
709 release_dc_ptr( dcDst );
711 release_dc_ptr( dcSrc );
715 /*********************************************************************
719 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
720 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
721 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
724 /* parallelogram coords */
733 /* save actual mode, set GM_ADVANCED */
734 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
738 memcpy(plg,lpPoint,sizeof(POINT)*3);
741 rect[1].x = nXSrc + nWidth;
744 rect[2].y = nYSrc + nHeight;
745 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
747 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);
749 if (fabs(det) < 1e-5)
751 SetGraphicsMode(hdcDest,oldgMode);
755 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
756 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
759 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;
760 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;
761 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
762 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
763 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
767 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;
768 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;
769 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
770 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
771 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
774 GetWorldTransform(hdcSrc,&SrcXf);
775 CombineTransform(&xf,&xf,&SrcXf);
777 /* save actual dest transform */
778 GetWorldTransform(hdcDest,&oldDestXf);
780 SetWorldTransform(hdcDest,&xf);
781 /* now destination and source DCs use same coords */
782 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
786 /* restore dest DC */
787 SetWorldTransform(hdcDest,&oldDestXf);
788 SetGraphicsMode(hdcDest,oldgMode);