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 );
256 bits.free = free_heap_bits;
259 /* get rid of the fake 1-bpp table */
260 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
261 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
264 else err = ERROR_OUTOFMEMORY;
267 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
268 ((src->width != dst->width) || (src->height != dst->height)))
270 FIXME( "should stretch %dx%d -> %dx%d\n",
271 src->width, src->height, dst->width, dst->height );
274 if (bits.free) bits.free( &bits );
278 /***********************************************************************
281 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
286 if (rop_uses_src( rop )) return FALSE;
287 if ((dc = get_dc_ptr( hdc )))
289 struct bitblt_coords dst;
290 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
296 dst.log_width = width;
297 dst.log_height = height;
298 dst.layout = dc->layout;
299 if (rop & NOMIRRORBITMAP)
301 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
302 rop &= ~NOMIRRORBITMAP;
304 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
306 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
307 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
308 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
310 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
312 release_dc_ptr( dc );
318 /***********************************************************************
321 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
322 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
324 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
325 else return StretchBlt( hdcDst, xDst, yDst, width, height,
326 hdcSrc, xSrc, ySrc, width, height, rop );
330 /***********************************************************************
331 * StretchBlt (GDI32.@)
333 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
334 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
339 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
341 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
343 if ((dcSrc = get_dc_ptr( hdcSrc )))
345 struct bitblt_coords src, dst;
346 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
347 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
354 src.log_width = widthSrc;
355 src.log_height = heightSrc;
356 src.layout = dcSrc->layout;
359 dst.log_width = widthDst;
360 dst.log_height = heightDst;
361 dst.layout = dcDst->layout;
362 if (rop & NOMIRRORBITMAP)
364 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
365 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
366 rop &= ~NOMIRRORBITMAP;
368 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
370 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",
371 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
372 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
373 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
374 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
376 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
377 release_dc_ptr( dcSrc );
379 release_dc_ptr( dcDst );
383 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
384 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
386 /***********************************************************************
389 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
390 INT nWidth, INT nHeight, HDC hdcSrc,
391 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
392 INT xMask, INT yMask, DWORD dwRop)
394 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
396 HBRUSH hbrMask, hbrDst, hbrTmp;
398 static const DWORD ROP3Table[256] =
400 0x00000042, 0x00010289,
401 0x00020C89, 0x000300AA,
402 0x00040C88, 0x000500A9,
403 0x00060865, 0x000702C5,
404 0x00080F08, 0x00090245,
405 0x000A0329, 0x000B0B2A,
406 0x000C0324, 0x000D0B25,
407 0x000E08A5, 0x000F0001,
408 0x00100C85, 0x001100A6,
409 0x00120868, 0x001302C8,
410 0x00140869, 0x001502C9,
411 0x00165CCA, 0x00171D54,
412 0x00180D59, 0x00191CC8,
413 0x001A06C5, 0x001B0768,
414 0x001C06CA, 0x001D0766,
415 0x001E01A5, 0x001F0385,
416 0x00200F09, 0x00210248,
417 0x00220326, 0x00230B24,
418 0x00240D55, 0x00251CC5,
419 0x002606C8, 0x00271868,
420 0x00280369, 0x002916CA,
421 0x002A0CC9, 0x002B1D58,
422 0x002C0784, 0x002D060A,
423 0x002E064A, 0x002F0E2A,
424 0x0030032A, 0x00310B28,
425 0x00320688, 0x00330008,
426 0x003406C4, 0x00351864,
427 0x003601A8, 0x00370388,
428 0x0038078A, 0x00390604,
429 0x003A0644, 0x003B0E24,
430 0x003C004A, 0x003D18A4,
431 0x003E1B24, 0x003F00EA,
432 0x00400F0A, 0x00410249,
433 0x00420D5D, 0x00431CC4,
434 0x00440328, 0x00450B29,
435 0x004606C6, 0x0047076A,
436 0x00480368, 0x004916C5,
437 0x004A0789, 0x004B0605,
438 0x004C0CC8, 0x004D1954,
439 0x004E0645, 0x004F0E25,
440 0x00500325, 0x00510B26,
441 0x005206C9, 0x00530764,
442 0x005408A9, 0x00550009,
443 0x005601A9, 0x00570389,
444 0x00580785, 0x00590609,
445 0x005A0049, 0x005B18A9,
446 0x005C0649, 0x005D0E29,
447 0x005E1B29, 0x005F00E9,
448 0x00600365, 0x006116C6,
449 0x00620786, 0x00630608,
450 0x00640788, 0x00650606,
451 0x00660046, 0x006718A8,
452 0x006858A6, 0x00690145,
453 0x006A01E9, 0x006B178A,
454 0x006C01E8, 0x006D1785,
455 0x006E1E28, 0x006F0C65,
456 0x00700CC5, 0x00711D5C,
457 0x00720648, 0x00730E28,
458 0x00740646, 0x00750E26,
459 0x00761B28, 0x007700E6,
460 0x007801E5, 0x00791786,
461 0x007A1E29, 0x007B0C68,
462 0x007C1E24, 0x007D0C69,
463 0x007E0955, 0x007F03C9,
464 0x008003E9, 0x00810975,
465 0x00820C49, 0x00831E04,
466 0x00840C48, 0x00851E05,
467 0x008617A6, 0x008701C5,
468 0x008800C6, 0x00891B08,
469 0x008A0E06, 0x008B0666,
470 0x008C0E08, 0x008D0668,
471 0x008E1D7C, 0x008F0CE5,
472 0x00900C45, 0x00911E08,
473 0x009217A9, 0x009301C4,
474 0x009417AA, 0x009501C9,
475 0x00960169, 0x0097588A,
476 0x00981888, 0x00990066,
477 0x009A0709, 0x009B07A8,
478 0x009C0704, 0x009D07A6,
479 0x009E16E6, 0x009F0345,
480 0x00A000C9, 0x00A11B05,
481 0x00A20E09, 0x00A30669,
482 0x00A41885, 0x00A50065,
483 0x00A60706, 0x00A707A5,
484 0x00A803A9, 0x00A90189,
485 0x00AA0029, 0x00AB0889,
486 0x00AC0744, 0x00AD06E9,
487 0x00AE0B06, 0x00AF0229,
488 0x00B00E05, 0x00B10665,
489 0x00B21974, 0x00B30CE8,
490 0x00B4070A, 0x00B507A9,
491 0x00B616E9, 0x00B70348,
492 0x00B8074A, 0x00B906E6,
493 0x00BA0B09, 0x00BB0226,
494 0x00BC1CE4, 0x00BD0D7D,
495 0x00BE0269, 0x00BF08C9,
496 0x00C000CA, 0x00C11B04,
497 0x00C21884, 0x00C3006A,
498 0x00C40E04, 0x00C50664,
499 0x00C60708, 0x00C707AA,
500 0x00C803A8, 0x00C90184,
501 0x00CA0749, 0x00CB06E4,
502 0x00CC0020, 0x00CD0888,
503 0x00CE0B08, 0x00CF0224,
504 0x00D00E0A, 0x00D1066A,
505 0x00D20705, 0x00D307A4,
506 0x00D41D78, 0x00D50CE9,
507 0x00D616EA, 0x00D70349,
508 0x00D80745, 0x00D906E8,
509 0x00DA1CE9, 0x00DB0D75,
510 0x00DC0B04, 0x00DD0228,
511 0x00DE0268, 0x00DF08C8,
512 0x00E003A5, 0x00E10185,
513 0x00E20746, 0x00E306EA,
514 0x00E40748, 0x00E506E5,
515 0x00E61CE8, 0x00E70D79,
516 0x00E81D74, 0x00E95CE6,
517 0x00EA02E9, 0x00EB0849,
518 0x00EC02E8, 0x00ED0848,
519 0x00EE0086, 0x00EF0A08,
520 0x00F00021, 0x00F10885,
521 0x00F20B05, 0x00F3022A,
522 0x00F40B0A, 0x00F50225,
523 0x00F60265, 0x00F708C5,
524 0x00F802E5, 0x00F90845,
525 0x00FA0089, 0x00FB0A09,
526 0x00FC008A, 0x00FD0A0A,
527 0x00FE02A9, 0x00FF0062,
531 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
533 hbrMask = CreatePatternBrush(hbmMask);
534 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
537 hDC1 = CreateCompatibleDC(hdcDest);
538 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
539 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
541 /* draw using bkgnd rop */
542 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
543 hbrTmp = SelectObject(hDC1, hbrDst);
544 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
545 SelectObject(hDC1, hbrTmp);
548 hDC2 = CreateCompatibleDC(hdcDest);
549 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
550 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
552 /* draw using foregnd rop */
553 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
554 hbrTmp = SelectObject(hDC2, hbrDst);
555 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
557 /* combine both using the mask as a pattern brush */
558 SelectObject(hDC2, hbrMask);
559 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
560 SelectObject(hDC2, hbrTmp);
563 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
565 /* restore all objects */
566 SelectObject(hdcDest, hbrDst);
567 SelectObject(hDC1, hOldBitmap1);
568 SelectObject(hDC2, hOldBitmap2);
570 /* delete all temp objects */
571 DeleteObject(hBitmap1);
572 DeleteObject(hBitmap2);
573 DeleteObject(hbrMask);
581 /******************************************************************************
582 * GdiTransparentBlt [GDI32.@]
584 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
585 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
593 HBITMAP bmpMask = NULL;
594 HBITMAP oldMask = NULL;
595 COLORREF oldBackground;
596 COLORREF oldForeground;
599 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
600 TRACE("Cannot mirror\n");
604 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
605 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
608 oldStretchMode = GetStretchBltMode(hdcSrc);
609 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
610 SetStretchBltMode(hdcSrc, COLORONCOLOR);
611 hdcWork = CreateCompatibleDC(hdcDest);
612 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
613 oldWork = SelectObject(hdcWork, bmpWork);
614 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
615 TRACE("Failed to stretch\n");
618 SetBkColor(hdcWork, crTransparent);
621 hdcMask = CreateCompatibleDC(hdcDest);
622 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
623 oldMask = SelectObject(hdcMask, bmpMask);
624 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
625 TRACE("Failed to create mask\n");
629 /* Replace transparent color with black */
630 SetBkColor(hdcWork, RGB(0,0,0));
631 SetTextColor(hdcWork, RGB(255,255,255));
632 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
633 TRACE("Failed to mask out background\n");
637 /* Replace non-transparent area on destination with black */
638 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
639 TRACE("Failed to clear destination area\n");
644 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
645 TRACE("Failed to paint image\n");
651 SetStretchBltMode(hdcSrc, oldStretchMode);
652 SetBkColor(hdcDest, oldBackground);
653 SetTextColor(hdcDest, oldForeground);
655 SelectObject(hdcWork, oldWork);
658 if(bmpWork) DeleteObject(bmpWork);
660 SelectObject(hdcMask, oldMask);
663 if(bmpMask) DeleteObject(bmpMask);
667 /******************************************************************************
668 * GdiAlphaBlend [GDI32.@]
670 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
671 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
672 BLENDFUNCTION blendFunction)
677 dcSrc = get_dc_ptr( hdcSrc );
678 if (!dcSrc) return FALSE;
680 if ((dcDst = get_dc_ptr( hdcDst )))
682 struct bitblt_coords src, dst;
683 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
684 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
691 src.log_width = widthSrc;
692 src.log_height = heightSrc;
693 src.layout = GetLayout( src_dev->hdc );
696 dst.log_width = widthDst;
697 dst.log_height = heightDst;
698 dst.layout = GetLayout( dst_dev->hdc );
699 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
701 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",
702 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
703 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
704 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
705 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
706 blendFunction.BlendOp, blendFunction.BlendFlags,
707 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
709 if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
710 release_dc_ptr( dcDst );
712 release_dc_ptr( dcSrc );
716 /*********************************************************************
720 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
721 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
722 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
725 /* parallelogram coords */
734 /* save actual mode, set GM_ADVANCED */
735 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
739 memcpy(plg,lpPoint,sizeof(POINT)*3);
742 rect[1].x = nXSrc + nWidth;
745 rect[2].y = nYSrc + nHeight;
746 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
748 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);
750 if (fabs(det) < 1e-5)
752 SetGraphicsMode(hdcDest,oldgMode);
756 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
757 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
760 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;
761 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;
762 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
763 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
764 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
768 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;
769 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;
770 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
771 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
772 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
775 GetWorldTransform(hdcSrc,&SrcXf);
776 CombineTransform(&xf,&xf,&SrcXf);
778 /* save actual dest transform */
779 GetWorldTransform(hdcDest,&oldDestXf);
781 SetWorldTransform(hdcDest,&xf);
782 /* now destination and source DCs use same coords */
783 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
787 /* restore dest DC */
788 SetWorldTransform(hdcDest,&oldDestXf);
789 SetGraphicsMode(hdcDest,oldgMode);