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 void free_heap_bits( struct gdi_image_bits *bits )
157 HeapFree( GetProcessHeap(), 0, bits->ptr );
160 static DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
161 BITMAPINFO *dst_info, struct gdi_image_bits *bits )
166 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
167 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
168 return ERROR_OUTOFMEMORY;
170 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
171 if (bits->free) bits->free( bits );
173 bits->is_copy = TRUE;
174 bits->free = free_heap_bits;
178 static DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
179 BITMAPINFO *dst_info, struct bitblt_coords *dst,
180 struct gdi_image_bits *bits, int mode )
185 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
186 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
187 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
188 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
189 return ERROR_OUTOFMEMORY;
191 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
192 if (bits->free) bits->free( bits );
194 bits->is_copy = TRUE;
195 bits->free = free_heap_bits;
199 /***********************************************************************
200 * null driver fallback implementations
203 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
204 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
206 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
207 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
208 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
209 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
210 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
212 struct gdi_image_bits bits;
214 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
215 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
216 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
217 release_dc_ptr( dc_src );
218 if (err) return FALSE;
220 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
221 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
222 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
223 if (err == ERROR_BAD_FORMAT)
225 /* 1-bpp source without a color table uses the destination DC colors */
226 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
228 COLORREF color = GetTextColor( dst_dev->hdc );
229 src_info->bmiColors[0].rgbRed = GetRValue( color );
230 src_info->bmiColors[0].rgbGreen = GetGValue( color );
231 src_info->bmiColors[0].rgbBlue = GetBValue( color );
232 src_info->bmiColors[0].rgbReserved = 0;
233 color = GetBkColor( dst_dev->hdc );
234 src_info->bmiColors[1].rgbRed = GetRValue( color );
235 src_info->bmiColors[1].rgbGreen = GetGValue( color );
236 src_info->bmiColors[1].rgbBlue = GetBValue( color );
237 src_info->bmiColors[1].rgbReserved = 0;
238 src_info->bmiHeader.biClrUsed = 2;
241 /* 1-bpp destination without a color table requires a fake 1-entry table
242 * that contains only the background color */
243 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
245 COLORREF color = GetBkColor( src_dev->hdc );
246 dst_info->bmiColors[0].rgbRed = GetRValue( color );
247 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
248 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
249 dst_info->bmiColors[0].rgbReserved = 0;
250 dst_info->bmiHeader.biClrUsed = 1;
253 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
255 /* get rid of the fake 1-bpp table */
256 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
257 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
261 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
262 ((src->width != dst->width) || (src->height != dst->height)))
264 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
265 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
266 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
269 if (bits.free) bits.free( &bits );
274 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
275 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
277 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
278 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
279 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
280 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
281 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
283 struct gdi_image_bits bits;
285 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
286 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
287 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
288 release_dc_ptr( dc_src );
289 if (err) return FALSE;
291 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
292 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
293 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
294 if (err == ERROR_BAD_FORMAT)
296 err = convert_bits( src_info, src, dst_info, &bits );
297 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
300 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
301 ((src->width != dst->width) || (src->height != dst->height)))
303 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
304 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
305 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
308 if (bits.free) bits.free( &bits );
313 /***********************************************************************
316 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
321 if (rop_uses_src( rop )) return FALSE;
322 if ((dc = get_dc_ptr( hdc )))
324 struct bitblt_coords dst;
325 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
331 dst.log_width = width;
332 dst.log_height = height;
333 dst.layout = dc->layout;
334 if (rop & NOMIRRORBITMAP)
336 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
337 rop &= ~NOMIRRORBITMAP;
339 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
341 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
342 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
343 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
345 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
347 release_dc_ptr( dc );
353 /***********************************************************************
356 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
357 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
359 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
360 else return StretchBlt( hdcDst, xDst, yDst, width, height,
361 hdcSrc, xSrc, ySrc, width, height, rop );
365 /***********************************************************************
366 * StretchBlt (GDI32.@)
368 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
369 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
374 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
376 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
378 if ((dcSrc = get_dc_ptr( hdcSrc )))
380 struct bitblt_coords src, dst;
381 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
382 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
389 src.log_width = widthSrc;
390 src.log_height = heightSrc;
391 src.layout = dcSrc->layout;
394 dst.log_width = widthDst;
395 dst.log_height = heightDst;
396 dst.layout = dcDst->layout;
397 if (rop & NOMIRRORBITMAP)
399 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
400 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
401 rop &= ~NOMIRRORBITMAP;
403 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
405 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",
406 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
407 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
408 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
409 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
411 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
412 release_dc_ptr( dcSrc );
414 release_dc_ptr( dcDst );
418 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
419 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
421 /***********************************************************************
424 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
425 INT nWidth, INT nHeight, HDC hdcSrc,
426 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
427 INT xMask, INT yMask, DWORD dwRop)
429 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
431 HBRUSH hbrMask, hbrDst, hbrTmp;
433 static const DWORD ROP3Table[256] =
435 0x00000042, 0x00010289,
436 0x00020C89, 0x000300AA,
437 0x00040C88, 0x000500A9,
438 0x00060865, 0x000702C5,
439 0x00080F08, 0x00090245,
440 0x000A0329, 0x000B0B2A,
441 0x000C0324, 0x000D0B25,
442 0x000E08A5, 0x000F0001,
443 0x00100C85, 0x001100A6,
444 0x00120868, 0x001302C8,
445 0x00140869, 0x001502C9,
446 0x00165CCA, 0x00171D54,
447 0x00180D59, 0x00191CC8,
448 0x001A06C5, 0x001B0768,
449 0x001C06CA, 0x001D0766,
450 0x001E01A5, 0x001F0385,
451 0x00200F09, 0x00210248,
452 0x00220326, 0x00230B24,
453 0x00240D55, 0x00251CC5,
454 0x002606C8, 0x00271868,
455 0x00280369, 0x002916CA,
456 0x002A0CC9, 0x002B1D58,
457 0x002C0784, 0x002D060A,
458 0x002E064A, 0x002F0E2A,
459 0x0030032A, 0x00310B28,
460 0x00320688, 0x00330008,
461 0x003406C4, 0x00351864,
462 0x003601A8, 0x00370388,
463 0x0038078A, 0x00390604,
464 0x003A0644, 0x003B0E24,
465 0x003C004A, 0x003D18A4,
466 0x003E1B24, 0x003F00EA,
467 0x00400F0A, 0x00410249,
468 0x00420D5D, 0x00431CC4,
469 0x00440328, 0x00450B29,
470 0x004606C6, 0x0047076A,
471 0x00480368, 0x004916C5,
472 0x004A0789, 0x004B0605,
473 0x004C0CC8, 0x004D1954,
474 0x004E0645, 0x004F0E25,
475 0x00500325, 0x00510B26,
476 0x005206C9, 0x00530764,
477 0x005408A9, 0x00550009,
478 0x005601A9, 0x00570389,
479 0x00580785, 0x00590609,
480 0x005A0049, 0x005B18A9,
481 0x005C0649, 0x005D0E29,
482 0x005E1B29, 0x005F00E9,
483 0x00600365, 0x006116C6,
484 0x00620786, 0x00630608,
485 0x00640788, 0x00650606,
486 0x00660046, 0x006718A8,
487 0x006858A6, 0x00690145,
488 0x006A01E9, 0x006B178A,
489 0x006C01E8, 0x006D1785,
490 0x006E1E28, 0x006F0C65,
491 0x00700CC5, 0x00711D5C,
492 0x00720648, 0x00730E28,
493 0x00740646, 0x00750E26,
494 0x00761B28, 0x007700E6,
495 0x007801E5, 0x00791786,
496 0x007A1E29, 0x007B0C68,
497 0x007C1E24, 0x007D0C69,
498 0x007E0955, 0x007F03C9,
499 0x008003E9, 0x00810975,
500 0x00820C49, 0x00831E04,
501 0x00840C48, 0x00851E05,
502 0x008617A6, 0x008701C5,
503 0x008800C6, 0x00891B08,
504 0x008A0E06, 0x008B0666,
505 0x008C0E08, 0x008D0668,
506 0x008E1D7C, 0x008F0CE5,
507 0x00900C45, 0x00911E08,
508 0x009217A9, 0x009301C4,
509 0x009417AA, 0x009501C9,
510 0x00960169, 0x0097588A,
511 0x00981888, 0x00990066,
512 0x009A0709, 0x009B07A8,
513 0x009C0704, 0x009D07A6,
514 0x009E16E6, 0x009F0345,
515 0x00A000C9, 0x00A11B05,
516 0x00A20E09, 0x00A30669,
517 0x00A41885, 0x00A50065,
518 0x00A60706, 0x00A707A5,
519 0x00A803A9, 0x00A90189,
520 0x00AA0029, 0x00AB0889,
521 0x00AC0744, 0x00AD06E9,
522 0x00AE0B06, 0x00AF0229,
523 0x00B00E05, 0x00B10665,
524 0x00B21974, 0x00B30CE8,
525 0x00B4070A, 0x00B507A9,
526 0x00B616E9, 0x00B70348,
527 0x00B8074A, 0x00B906E6,
528 0x00BA0B09, 0x00BB0226,
529 0x00BC1CE4, 0x00BD0D7D,
530 0x00BE0269, 0x00BF08C9,
531 0x00C000CA, 0x00C11B04,
532 0x00C21884, 0x00C3006A,
533 0x00C40E04, 0x00C50664,
534 0x00C60708, 0x00C707AA,
535 0x00C803A8, 0x00C90184,
536 0x00CA0749, 0x00CB06E4,
537 0x00CC0020, 0x00CD0888,
538 0x00CE0B08, 0x00CF0224,
539 0x00D00E0A, 0x00D1066A,
540 0x00D20705, 0x00D307A4,
541 0x00D41D78, 0x00D50CE9,
542 0x00D616EA, 0x00D70349,
543 0x00D80745, 0x00D906E8,
544 0x00DA1CE9, 0x00DB0D75,
545 0x00DC0B04, 0x00DD0228,
546 0x00DE0268, 0x00DF08C8,
547 0x00E003A5, 0x00E10185,
548 0x00E20746, 0x00E306EA,
549 0x00E40748, 0x00E506E5,
550 0x00E61CE8, 0x00E70D79,
551 0x00E81D74, 0x00E95CE6,
552 0x00EA02E9, 0x00EB0849,
553 0x00EC02E8, 0x00ED0848,
554 0x00EE0086, 0x00EF0A08,
555 0x00F00021, 0x00F10885,
556 0x00F20B05, 0x00F3022A,
557 0x00F40B0A, 0x00F50225,
558 0x00F60265, 0x00F708C5,
559 0x00F802E5, 0x00F90845,
560 0x00FA0089, 0x00FB0A09,
561 0x00FC008A, 0x00FD0A0A,
562 0x00FE02A9, 0x00FF0062,
566 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
568 hbrMask = CreatePatternBrush(hbmMask);
569 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
572 hDC1 = CreateCompatibleDC(hdcDest);
573 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
574 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
576 /* draw using bkgnd rop */
577 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
578 hbrTmp = SelectObject(hDC1, hbrDst);
579 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
580 SelectObject(hDC1, hbrTmp);
583 hDC2 = CreateCompatibleDC(hdcDest);
584 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
585 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
587 /* draw using foregnd rop */
588 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
589 hbrTmp = SelectObject(hDC2, hbrDst);
590 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
592 /* combine both using the mask as a pattern brush */
593 SelectObject(hDC2, hbrMask);
594 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
595 SelectObject(hDC2, hbrTmp);
598 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
600 /* restore all objects */
601 SelectObject(hdcDest, hbrDst);
602 SelectObject(hDC1, hOldBitmap1);
603 SelectObject(hDC2, hOldBitmap2);
605 /* delete all temp objects */
606 DeleteObject(hBitmap1);
607 DeleteObject(hBitmap2);
608 DeleteObject(hbrMask);
616 /******************************************************************************
617 * GdiTransparentBlt [GDI32.@]
619 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
620 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
628 HBITMAP bmpMask = NULL;
629 HBITMAP oldMask = NULL;
630 COLORREF oldBackground;
631 COLORREF oldForeground;
634 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
635 TRACE("Cannot mirror\n");
639 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
640 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
643 oldStretchMode = GetStretchBltMode(hdcSrc);
644 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
645 SetStretchBltMode(hdcSrc, COLORONCOLOR);
646 hdcWork = CreateCompatibleDC(hdcDest);
647 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
648 oldWork = SelectObject(hdcWork, bmpWork);
649 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
650 TRACE("Failed to stretch\n");
653 SetBkColor(hdcWork, crTransparent);
656 hdcMask = CreateCompatibleDC(hdcDest);
657 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
658 oldMask = SelectObject(hdcMask, bmpMask);
659 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
660 TRACE("Failed to create mask\n");
664 /* Replace transparent color with black */
665 SetBkColor(hdcWork, RGB(0,0,0));
666 SetTextColor(hdcWork, RGB(255,255,255));
667 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
668 TRACE("Failed to mask out background\n");
672 /* Replace non-transparent area on destination with black */
673 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
674 TRACE("Failed to clear destination area\n");
679 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
680 TRACE("Failed to paint image\n");
686 SetStretchBltMode(hdcSrc, oldStretchMode);
687 SetBkColor(hdcDest, oldBackground);
688 SetTextColor(hdcDest, oldForeground);
690 SelectObject(hdcWork, oldWork);
693 if(bmpWork) DeleteObject(bmpWork);
695 SelectObject(hdcMask, oldMask);
698 if(bmpMask) DeleteObject(bmpMask);
702 /******************************************************************************
703 * GdiAlphaBlend [GDI32.@]
705 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
706 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
707 BLENDFUNCTION blendFunction)
712 dcSrc = get_dc_ptr( hdcSrc );
713 if (!dcSrc) return FALSE;
715 if ((dcDst = get_dc_ptr( hdcDst )))
717 struct bitblt_coords src, dst;
718 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
719 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
726 src.log_width = widthSrc;
727 src.log_height = heightSrc;
728 src.layout = GetLayout( src_dev->hdc );
731 dst.log_width = widthDst;
732 dst.log_height = heightDst;
733 dst.layout = GetLayout( dst_dev->hdc );
734 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
736 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",
737 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
738 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
739 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
740 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
741 blendFunction.BlendOp, blendFunction.BlendFlags,
742 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
744 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
745 (dcSrc->header.type == OBJ_MEMDC &&
746 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
747 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
749 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
750 SetLastError( ERROR_INVALID_PARAMETER );
753 else if (dst.width < 0 || dst.height < 0)
755 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
756 SetLastError( ERROR_INVALID_PARAMETER );
759 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
761 release_dc_ptr( dcDst );
763 release_dc_ptr( dcSrc );
767 /*********************************************************************
771 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
772 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
773 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
776 /* parallelogram coords */
785 /* save actual mode, set GM_ADVANCED */
786 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
790 memcpy(plg,lpPoint,sizeof(POINT)*3);
793 rect[1].x = nXSrc + nWidth;
796 rect[2].y = nYSrc + nHeight;
797 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
799 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);
801 if (fabs(det) < 1e-5)
803 SetGraphicsMode(hdcDest,oldgMode);
807 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
808 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
811 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;
812 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;
813 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
814 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
815 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
819 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;
820 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;
821 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
822 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
823 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
826 GetWorldTransform(hdcSrc,&SrcXf);
827 CombineTransform(&xf,&xf,&SrcXf);
829 /* save actual dest transform */
830 GetWorldTransform(hdcDest,&oldDestXf);
832 SetWorldTransform(hdcDest,&xf);
833 /* now destination and source DCs use same coords */
834 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
838 /* restore dest DC */
839 SetWorldTransform(hdcDest,&oldDestXf);
840 SetGraphicsMode(hdcDest,oldgMode);