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 BOOL 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 */
82 if (!src) return !is_rect_empty( &dst->visrect );
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 if (is_rect_empty( &src->visrect )) return FALSE;
109 if (is_rect_empty( &dst->visrect )) return FALSE;
111 /* intersect the rectangles */
113 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
115 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
116 intersect_rect( &rect, &src->visrect, &dst->visrect );
117 src->visrect = dst->visrect = rect;
118 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
120 else /* stretching */
122 /* map source rectangle into destination coordinates */
123 rect.left = dst->x + (src->visrect.left - src->x)*dst->width/src->width;
124 rect.top = dst->y + (src->visrect.top - src->y)*dst->height/src->height;
125 rect.right = dst->x + (src->visrect.right - src->x)*dst->width/src->width;
126 rect.bottom = dst->y + (src->visrect.bottom - src->y)*dst->height/src->height;
127 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
128 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
130 /* avoid rounding errors */
135 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
137 /* map destination rectangle back to source coordinates */
138 rect.left = src->x + (dst->visrect.left - dst->x)*src->width/dst->width;
139 rect.top = src->y + (dst->visrect.top - dst->y)*src->height/dst->height;
140 rect.right = src->x + (dst->visrect.right - dst->x)*src->width/dst->width;
141 rect.bottom = src->y + (dst->visrect.bottom - dst->y)*src->height/dst->height;
142 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
143 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
145 /* avoid rounding errors */
150 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
155 static void free_heap_bits( struct gdi_image_bits *bits )
157 HeapFree( GetProcessHeap(), 0, bits->ptr );
160 /* nulldrv fallback implementation using StretchDIBits */
161 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
162 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
164 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
165 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
166 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
167 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
168 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
170 struct gdi_image_bits bits;
176 /* make sure we have a real implementation for StretchDIBits */
177 if (GET_DC_PHYSDEV( dc_dst, pStretchDIBits ) == dst_dev) goto try_get_image;
179 if (GetObjectType( src_dev->hdc ) != OBJ_MEMDC) return FALSE;
180 if (!GetObjectW( GetCurrentObject( src_dev->hdc, OBJ_BITMAP ), sizeof(bm), &bm )) return FALSE;
182 src_info->bmiHeader.biSize = sizeof(src_info->bmiHeader);
183 src_info->bmiHeader.biWidth = bm.bmWidth;
184 src_info->bmiHeader.biHeight = bm.bmHeight;
185 src_info->bmiHeader.biPlanes = 1;
186 src_info->bmiHeader.biBitCount = 32;
187 src_info->bmiHeader.biCompression = BI_RGB;
188 src_info->bmiHeader.biSizeImage = 0;
189 src_info->bmiHeader.biXPelsPerMeter = 0;
190 src_info->bmiHeader.biYPelsPerMeter = 0;
191 src_info->bmiHeader.biClrUsed = 0;
192 src_info->bmiHeader.biClrImportant = 0;
194 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, bm.bmHeight * bm.bmWidth * 4)))
197 /* Select out the src bitmap before calling GetDIBits */
198 hbm = SelectObject( src_dev->hdc, GetStockObject(DEFAULT_BITMAP) );
199 lines = GetDIBits( src_dev->hdc, hbm, 0, bm.bmHeight, ptr, src_info, DIB_RGB_COLORS );
200 SelectObject( src_dev->hdc, hbm );
202 if (lines) lines = StretchDIBits( dst_dev->hdc, dst->log_x, dst->log_y, dst->log_width, dst->log_height,
203 src->x, bm.bmHeight - src->height - src->y, src->width, src->height,
204 ptr, src_info, DIB_RGB_COLORS, rop );
205 HeapFree( GetProcessHeap(), 0, ptr );
206 return (lines == src->height);
210 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
211 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
212 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
213 release_dc_ptr( dc_src );
214 if (err) return FALSE;
216 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
217 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
218 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
219 if (err == ERROR_BAD_FORMAT)
221 /* 1-bpp source without a color table uses the destination DC colors */
222 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
224 COLORREF color = GetTextColor( dst_dev->hdc );
225 src_info->bmiColors[0].rgbRed = GetRValue( color );
226 src_info->bmiColors[0].rgbGreen = GetGValue( color );
227 src_info->bmiColors[0].rgbBlue = GetBValue( color );
228 src_info->bmiColors[0].rgbReserved = 0;
229 color = GetBkColor( dst_dev->hdc );
230 src_info->bmiColors[1].rgbRed = GetRValue( color );
231 src_info->bmiColors[1].rgbGreen = GetGValue( color );
232 src_info->bmiColors[1].rgbBlue = GetBValue( color );
233 src_info->bmiColors[1].rgbReserved = 0;
234 src_info->bmiHeader.biClrUsed = 2;
237 /* 1-bpp destination without a color table requires a fake 1-entry table
238 * that contains only the background color */
239 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
241 COLORREF color = GetBkColor( src_dev->hdc );
242 dst_info->bmiColors[0].rgbRed = GetRValue( color );
243 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
244 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
245 dst_info->bmiColors[0].rgbReserved = 0;
246 dst_info->bmiHeader.biClrUsed = 1;
249 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
250 if ((ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
252 err = convert_bitmapinfo( src_info, bits.ptr, &src->visrect, dst_info, ptr );
253 if (bits.free) bits.free( &bits );
257 bits.free = free_heap_bits;
260 /* get rid of the fake 1-bpp table */
261 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
262 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
265 else err = ERROR_OUTOFMEMORY;
268 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
269 ((src->width != dst->width) || (src->height != dst->height)))
271 FIXME( "should stretch %dx%d -> %dx%d\n",
272 src->width, src->height, dst->width, dst->height );
275 if (bits.free) bits.free( &bits );
279 /***********************************************************************
282 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
287 if (rop_uses_src( rop )) return FALSE;
288 if ((dc = get_dc_ptr( hdc )))
290 struct bitblt_coords dst;
291 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
297 dst.log_width = width;
298 dst.log_height = height;
299 dst.layout = dc->layout;
300 if (rop & NOMIRRORBITMAP)
302 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
303 rop &= ~NOMIRRORBITMAP;
305 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
307 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
308 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
309 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
311 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
313 release_dc_ptr( dc );
319 /***********************************************************************
322 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
323 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
325 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
326 else return StretchBlt( hdcDst, xDst, yDst, width, height,
327 hdcSrc, xSrc, ySrc, width, height, rop );
331 /***********************************************************************
332 * StretchBlt (GDI32.@)
334 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
335 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
340 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
342 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
344 if ((dcSrc = get_dc_ptr( hdcSrc )))
346 struct bitblt_coords src, dst;
347 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
348 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
355 src.log_width = widthSrc;
356 src.log_height = heightSrc;
357 src.layout = dcSrc->layout;
360 dst.log_width = widthDst;
361 dst.log_height = heightDst;
362 dst.layout = dcDst->layout;
363 if (rop & NOMIRRORBITMAP)
365 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
366 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
367 rop &= ~NOMIRRORBITMAP;
369 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
371 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",
372 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
373 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
374 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
375 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
377 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
378 release_dc_ptr( dcSrc );
380 release_dc_ptr( dcDst );
384 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
385 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
387 /***********************************************************************
390 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
391 INT nWidth, INT nHeight, HDC hdcSrc,
392 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
393 INT xMask, INT yMask, DWORD dwRop)
395 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
397 HBRUSH hbrMask, hbrDst, hbrTmp;
399 static const DWORD ROP3Table[256] =
401 0x00000042, 0x00010289,
402 0x00020C89, 0x000300AA,
403 0x00040C88, 0x000500A9,
404 0x00060865, 0x000702C5,
405 0x00080F08, 0x00090245,
406 0x000A0329, 0x000B0B2A,
407 0x000C0324, 0x000D0B25,
408 0x000E08A5, 0x000F0001,
409 0x00100C85, 0x001100A6,
410 0x00120868, 0x001302C8,
411 0x00140869, 0x001502C9,
412 0x00165CCA, 0x00171D54,
413 0x00180D59, 0x00191CC8,
414 0x001A06C5, 0x001B0768,
415 0x001C06CA, 0x001D0766,
416 0x001E01A5, 0x001F0385,
417 0x00200F09, 0x00210248,
418 0x00220326, 0x00230B24,
419 0x00240D55, 0x00251CC5,
420 0x002606C8, 0x00271868,
421 0x00280369, 0x002916CA,
422 0x002A0CC9, 0x002B1D58,
423 0x002C0784, 0x002D060A,
424 0x002E064A, 0x002F0E2A,
425 0x0030032A, 0x00310B28,
426 0x00320688, 0x00330008,
427 0x003406C4, 0x00351864,
428 0x003601A8, 0x00370388,
429 0x0038078A, 0x00390604,
430 0x003A0644, 0x003B0E24,
431 0x003C004A, 0x003D18A4,
432 0x003E1B24, 0x003F00EA,
433 0x00400F0A, 0x00410249,
434 0x00420D5D, 0x00431CC4,
435 0x00440328, 0x00450B29,
436 0x004606C6, 0x0047076A,
437 0x00480368, 0x004916C5,
438 0x004A0789, 0x004B0605,
439 0x004C0CC8, 0x004D1954,
440 0x004E0645, 0x004F0E25,
441 0x00500325, 0x00510B26,
442 0x005206C9, 0x00530764,
443 0x005408A9, 0x00550009,
444 0x005601A9, 0x00570389,
445 0x00580785, 0x00590609,
446 0x005A0049, 0x005B18A9,
447 0x005C0649, 0x005D0E29,
448 0x005E1B29, 0x005F00E9,
449 0x00600365, 0x006116C6,
450 0x00620786, 0x00630608,
451 0x00640788, 0x00650606,
452 0x00660046, 0x006718A8,
453 0x006858A6, 0x00690145,
454 0x006A01E9, 0x006B178A,
455 0x006C01E8, 0x006D1785,
456 0x006E1E28, 0x006F0C65,
457 0x00700CC5, 0x00711D5C,
458 0x00720648, 0x00730E28,
459 0x00740646, 0x00750E26,
460 0x00761B28, 0x007700E6,
461 0x007801E5, 0x00791786,
462 0x007A1E29, 0x007B0C68,
463 0x007C1E24, 0x007D0C69,
464 0x007E0955, 0x007F03C9,
465 0x008003E9, 0x00810975,
466 0x00820C49, 0x00831E04,
467 0x00840C48, 0x00851E05,
468 0x008617A6, 0x008701C5,
469 0x008800C6, 0x00891B08,
470 0x008A0E06, 0x008B0666,
471 0x008C0E08, 0x008D0668,
472 0x008E1D7C, 0x008F0CE5,
473 0x00900C45, 0x00911E08,
474 0x009217A9, 0x009301C4,
475 0x009417AA, 0x009501C9,
476 0x00960169, 0x0097588A,
477 0x00981888, 0x00990066,
478 0x009A0709, 0x009B07A8,
479 0x009C0704, 0x009D07A6,
480 0x009E16E6, 0x009F0345,
481 0x00A000C9, 0x00A11B05,
482 0x00A20E09, 0x00A30669,
483 0x00A41885, 0x00A50065,
484 0x00A60706, 0x00A707A5,
485 0x00A803A9, 0x00A90189,
486 0x00AA0029, 0x00AB0889,
487 0x00AC0744, 0x00AD06E9,
488 0x00AE0B06, 0x00AF0229,
489 0x00B00E05, 0x00B10665,
490 0x00B21974, 0x00B30CE8,
491 0x00B4070A, 0x00B507A9,
492 0x00B616E9, 0x00B70348,
493 0x00B8074A, 0x00B906E6,
494 0x00BA0B09, 0x00BB0226,
495 0x00BC1CE4, 0x00BD0D7D,
496 0x00BE0269, 0x00BF08C9,
497 0x00C000CA, 0x00C11B04,
498 0x00C21884, 0x00C3006A,
499 0x00C40E04, 0x00C50664,
500 0x00C60708, 0x00C707AA,
501 0x00C803A8, 0x00C90184,
502 0x00CA0749, 0x00CB06E4,
503 0x00CC0020, 0x00CD0888,
504 0x00CE0B08, 0x00CF0224,
505 0x00D00E0A, 0x00D1066A,
506 0x00D20705, 0x00D307A4,
507 0x00D41D78, 0x00D50CE9,
508 0x00D616EA, 0x00D70349,
509 0x00D80745, 0x00D906E8,
510 0x00DA1CE9, 0x00DB0D75,
511 0x00DC0B04, 0x00DD0228,
512 0x00DE0268, 0x00DF08C8,
513 0x00E003A5, 0x00E10185,
514 0x00E20746, 0x00E306EA,
515 0x00E40748, 0x00E506E5,
516 0x00E61CE8, 0x00E70D79,
517 0x00E81D74, 0x00E95CE6,
518 0x00EA02E9, 0x00EB0849,
519 0x00EC02E8, 0x00ED0848,
520 0x00EE0086, 0x00EF0A08,
521 0x00F00021, 0x00F10885,
522 0x00F20B05, 0x00F3022A,
523 0x00F40B0A, 0x00F50225,
524 0x00F60265, 0x00F708C5,
525 0x00F802E5, 0x00F90845,
526 0x00FA0089, 0x00FB0A09,
527 0x00FC008A, 0x00FD0A0A,
528 0x00FE02A9, 0x00FF0062,
532 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
534 hbrMask = CreatePatternBrush(hbmMask);
535 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
538 hDC1 = CreateCompatibleDC(hdcDest);
539 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
540 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
542 /* draw using bkgnd rop */
543 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
544 hbrTmp = SelectObject(hDC1, hbrDst);
545 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
546 SelectObject(hDC1, hbrTmp);
549 hDC2 = CreateCompatibleDC(hdcDest);
550 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
551 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
553 /* draw using foregnd rop */
554 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
555 hbrTmp = SelectObject(hDC2, hbrDst);
556 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
558 /* combine both using the mask as a pattern brush */
559 SelectObject(hDC2, hbrMask);
560 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
561 SelectObject(hDC2, hbrTmp);
564 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
566 /* restore all objects */
567 SelectObject(hdcDest, hbrDst);
568 SelectObject(hDC1, hOldBitmap1);
569 SelectObject(hDC2, hOldBitmap2);
571 /* delete all temp objects */
572 DeleteObject(hBitmap1);
573 DeleteObject(hBitmap2);
574 DeleteObject(hbrMask);
582 /******************************************************************************
583 * GdiTransparentBlt [GDI32.@]
585 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
586 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
594 HBITMAP bmpMask = NULL;
595 HBITMAP oldMask = NULL;
596 COLORREF oldBackground;
597 COLORREF oldForeground;
600 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
601 TRACE("Cannot mirror\n");
605 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
606 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
609 oldStretchMode = GetStretchBltMode(hdcSrc);
610 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
611 SetStretchBltMode(hdcSrc, COLORONCOLOR);
612 hdcWork = CreateCompatibleDC(hdcDest);
613 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
614 oldWork = SelectObject(hdcWork, bmpWork);
615 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
616 TRACE("Failed to stretch\n");
619 SetBkColor(hdcWork, crTransparent);
622 hdcMask = CreateCompatibleDC(hdcDest);
623 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
624 oldMask = SelectObject(hdcMask, bmpMask);
625 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
626 TRACE("Failed to create mask\n");
630 /* Replace transparent color with black */
631 SetBkColor(hdcWork, RGB(0,0,0));
632 SetTextColor(hdcWork, RGB(255,255,255));
633 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
634 TRACE("Failed to mask out background\n");
638 /* Replace non-transparent area on destination with black */
639 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
640 TRACE("Failed to clear destination area\n");
645 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
646 TRACE("Failed to paint image\n");
652 SetStretchBltMode(hdcSrc, oldStretchMode);
653 SetBkColor(hdcDest, oldBackground);
654 SetTextColor(hdcDest, oldForeground);
656 SelectObject(hdcWork, oldWork);
659 if(bmpWork) DeleteObject(bmpWork);
661 SelectObject(hdcMask, oldMask);
664 if(bmpMask) DeleteObject(bmpMask);
668 /******************************************************************************
669 * GdiAlphaBlend [GDI32.@]
671 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
672 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
673 BLENDFUNCTION blendFunction)
678 dcSrc = get_dc_ptr( hdcSrc );
679 if (!dcSrc) return FALSE;
681 if ((dcDst = get_dc_ptr( hdcDst )))
683 struct bitblt_coords src, dst;
684 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
685 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
692 src.log_width = widthSrc;
693 src.log_height = heightSrc;
694 src.layout = GetLayout( src_dev->hdc );
697 dst.log_width = widthDst;
698 dst.log_height = heightDst;
699 dst.layout = GetLayout( dst_dev->hdc );
700 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
702 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",
703 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
704 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
705 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
706 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
707 blendFunction.BlendOp, blendFunction.BlendFlags,
708 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
710 if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
711 release_dc_ptr( dcDst );
713 release_dc_ptr( dcSrc );
717 /*********************************************************************
721 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
722 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
723 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
726 /* parallelogram coords */
735 /* save actual mode, set GM_ADVANCED */
736 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
740 memcpy(plg,lpPoint,sizeof(POINT)*3);
743 rect[1].x = nXSrc + nWidth;
746 rect[2].y = nYSrc + nHeight;
747 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
749 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);
751 if (fabs(det) < 1e-5)
753 SetGraphicsMode(hdcDest,oldgMode);
757 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
758 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
761 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;
762 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;
763 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
764 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
765 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
769 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;
770 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;
771 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
772 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
773 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
776 GetWorldTransform(hdcSrc,&SrcXf);
777 CombineTransform(&xf,&xf,&SrcXf);
779 /* save actual dest transform */
780 GetWorldTransform(hdcDest,&oldDestXf);
782 SetWorldTransform(hdcDest,&xf);
783 /* now destination and source DCs use same coords */
784 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
788 /* restore dest DC */
789 SetWorldTransform(hdcDest,&oldDestXf);
790 SetGraphicsMode(hdcDest,oldgMode);