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)
69 dst->width = -dst->width;
71 get_bounding_rect( &rect, dst->x, dst->y, dst->width, dst->height );
73 if (get_clip_box( dc_dst, &clip ))
74 intersect_rect( &dst->visrect, &rect, &clip );
78 /* get the source visible rectangle */
80 if (!src) return !is_rect_empty( &dst->visrect );
82 rect.left = src->log_x;
83 rect.top = src->log_y;
84 rect.right = src->log_x + src->log_width;
85 rect.bottom = src->log_y + src->log_height;
86 LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
89 src->width = rect.right - rect.left;
90 src->height = rect.bottom - rect.top;
91 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
94 src->width = -src->width;
96 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
98 /* source is not clipped */
99 if (dc_src->header.type == OBJ_MEMDC)
100 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
102 src->visrect = rect; /* FIXME: clip to device size */
104 if (is_rect_empty( &src->visrect )) return FALSE;
105 if (is_rect_empty( &dst->visrect )) return FALSE;
107 /* intersect the rectangles */
109 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
111 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
112 intersect_rect( &rect, &src->visrect, &dst->visrect );
113 src->visrect = dst->visrect = rect;
114 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
116 else /* stretching */
118 /* map source rectangle into destination coordinates */
120 offset_rect( &rect, -min( src->x, src->x + src->width + 1),
121 -min( src->y, src->y + src->height + 1) );
122 rect.left = dst->x + rect.left * dst->width / abs(src->width);
123 rect.top = dst->y + rect.top * dst->height / abs(src->height);
124 rect.right = dst->x + rect.right * dst->width / abs(src->width);
125 rect.bottom = dst->y + rect.bottom * dst->height / abs(src->height);
126 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
127 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
129 /* avoid rounding errors */
134 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
136 /* map destination rectangle back to source coordinates */
138 offset_rect( &rect, -min( dst->x, dst->x + dst->width + 1),
139 -min( dst->y, dst->y + dst->height + 1) );
140 rect.left = src->x + rect.left * src->width / abs(dst->width);
141 rect.top = src->y + rect.top * src->height / abs(dst->height);
142 rect.right = src->x + rect.right * src->width / abs(dst->width);
143 rect.bottom = src->y + rect.bottom * src->height / abs(dst->height);
144 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
145 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
147 /* avoid rounding errors */
152 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
157 void free_heap_bits( struct gdi_image_bits *bits )
159 HeapFree( GetProcessHeap(), 0, bits->ptr );
162 static DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
163 BITMAPINFO *dst_info, struct gdi_image_bits *bits )
168 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
169 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
170 return ERROR_OUTOFMEMORY;
172 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
173 if (bits->free) bits->free( bits );
175 bits->is_copy = TRUE;
176 bits->free = free_heap_bits;
180 static DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
181 BITMAPINFO *dst_info, struct bitblt_coords *dst,
182 struct gdi_image_bits *bits, int mode )
187 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
188 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
189 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
190 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
191 return ERROR_OUTOFMEMORY;
193 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
194 if (bits->free) bits->free( bits );
196 bits->is_copy = TRUE;
197 bits->free = free_heap_bits;
201 /***********************************************************************
202 * null driver fallback implementations
205 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
206 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
208 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
209 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
210 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
211 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
212 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
214 struct gdi_image_bits bits;
216 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
217 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
218 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
219 release_dc_ptr( dc_src );
220 if (err) return FALSE;
222 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
223 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
224 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
225 if (err == ERROR_BAD_FORMAT)
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 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
257 /* get rid of the fake 1-bpp table */
258 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
259 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
263 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
264 ((src->width != dst->width) || (src->height != dst->height)))
266 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
267 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
268 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
271 if (bits.free) bits.free( &bits );
276 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
277 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
279 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
280 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
281 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
282 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
283 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
285 struct gdi_image_bits bits;
287 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
288 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
289 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
290 release_dc_ptr( dc_src );
293 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
294 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
295 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
296 if (err == ERROR_BAD_FORMAT)
298 /* 1-bpp source without a color table uses black & white */
299 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
301 src_info->bmiColors[0].rgbRed = 0;
302 src_info->bmiColors[0].rgbGreen = 0;
303 src_info->bmiColors[0].rgbBlue = 0;
304 src_info->bmiColors[0].rgbReserved = 0;
305 src_info->bmiColors[1].rgbRed = 0xff;
306 src_info->bmiColors[1].rgbGreen = 0xff;
307 src_info->bmiColors[1].rgbBlue = 0xff;
308 src_info->bmiColors[1].rgbReserved = 0;
309 src_info->bmiHeader.biClrUsed = 2;
312 err = convert_bits( src_info, src, dst_info, &bits );
313 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
316 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
317 ((src->width != dst->width) || (src->height != dst->height)))
319 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
320 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
321 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
324 if (bits.free) bits.free( &bits );
326 if (err) SetLastError( err );
331 /***********************************************************************
334 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
339 if (rop_uses_src( rop )) return FALSE;
340 if ((dc = get_dc_ptr( hdc )))
342 struct bitblt_coords dst;
343 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
349 dst.log_width = width;
350 dst.log_height = height;
351 dst.layout = dc->layout;
352 if (rop & NOMIRRORBITMAP)
354 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
355 rop &= ~NOMIRRORBITMAP;
357 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
359 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
360 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
361 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
363 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
365 release_dc_ptr( dc );
371 /***********************************************************************
374 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
375 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
377 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
378 else return StretchBlt( hdcDst, xDst, yDst, width, height,
379 hdcSrc, xSrc, ySrc, width, height, rop );
383 /***********************************************************************
384 * StretchBlt (GDI32.@)
386 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
387 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
392 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
394 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
396 if ((dcSrc = get_dc_ptr( hdcSrc )))
398 struct bitblt_coords src, dst;
399 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
400 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
407 src.log_width = widthSrc;
408 src.log_height = heightSrc;
409 src.layout = dcSrc->layout;
412 dst.log_width = widthDst;
413 dst.log_height = heightDst;
414 dst.layout = dcDst->layout;
415 if (rop & NOMIRRORBITMAP)
417 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
418 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
419 rop &= ~NOMIRRORBITMAP;
421 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
423 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",
424 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
425 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
426 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
427 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
429 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
430 release_dc_ptr( dcSrc );
432 release_dc_ptr( dcDst );
436 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
437 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
439 /***********************************************************************
442 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
443 INT nWidth, INT nHeight, HDC hdcSrc,
444 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
445 INT xMask, INT yMask, DWORD dwRop)
447 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
449 HBRUSH hbrMask, hbrDst, hbrTmp;
451 static const DWORD ROP3Table[256] =
453 0x00000042, 0x00010289,
454 0x00020C89, 0x000300AA,
455 0x00040C88, 0x000500A9,
456 0x00060865, 0x000702C5,
457 0x00080F08, 0x00090245,
458 0x000A0329, 0x000B0B2A,
459 0x000C0324, 0x000D0B25,
460 0x000E08A5, 0x000F0001,
461 0x00100C85, 0x001100A6,
462 0x00120868, 0x001302C8,
463 0x00140869, 0x001502C9,
464 0x00165CCA, 0x00171D54,
465 0x00180D59, 0x00191CC8,
466 0x001A06C5, 0x001B0768,
467 0x001C06CA, 0x001D0766,
468 0x001E01A5, 0x001F0385,
469 0x00200F09, 0x00210248,
470 0x00220326, 0x00230B24,
471 0x00240D55, 0x00251CC5,
472 0x002606C8, 0x00271868,
473 0x00280369, 0x002916CA,
474 0x002A0CC9, 0x002B1D58,
475 0x002C0784, 0x002D060A,
476 0x002E064A, 0x002F0E2A,
477 0x0030032A, 0x00310B28,
478 0x00320688, 0x00330008,
479 0x003406C4, 0x00351864,
480 0x003601A8, 0x00370388,
481 0x0038078A, 0x00390604,
482 0x003A0644, 0x003B0E24,
483 0x003C004A, 0x003D18A4,
484 0x003E1B24, 0x003F00EA,
485 0x00400F0A, 0x00410249,
486 0x00420D5D, 0x00431CC4,
487 0x00440328, 0x00450B29,
488 0x004606C6, 0x0047076A,
489 0x00480368, 0x004916C5,
490 0x004A0789, 0x004B0605,
491 0x004C0CC8, 0x004D1954,
492 0x004E0645, 0x004F0E25,
493 0x00500325, 0x00510B26,
494 0x005206C9, 0x00530764,
495 0x005408A9, 0x00550009,
496 0x005601A9, 0x00570389,
497 0x00580785, 0x00590609,
498 0x005A0049, 0x005B18A9,
499 0x005C0649, 0x005D0E29,
500 0x005E1B29, 0x005F00E9,
501 0x00600365, 0x006116C6,
502 0x00620786, 0x00630608,
503 0x00640788, 0x00650606,
504 0x00660046, 0x006718A8,
505 0x006858A6, 0x00690145,
506 0x006A01E9, 0x006B178A,
507 0x006C01E8, 0x006D1785,
508 0x006E1E28, 0x006F0C65,
509 0x00700CC5, 0x00711D5C,
510 0x00720648, 0x00730E28,
511 0x00740646, 0x00750E26,
512 0x00761B28, 0x007700E6,
513 0x007801E5, 0x00791786,
514 0x007A1E29, 0x007B0C68,
515 0x007C1E24, 0x007D0C69,
516 0x007E0955, 0x007F03C9,
517 0x008003E9, 0x00810975,
518 0x00820C49, 0x00831E04,
519 0x00840C48, 0x00851E05,
520 0x008617A6, 0x008701C5,
521 0x008800C6, 0x00891B08,
522 0x008A0E06, 0x008B0666,
523 0x008C0E08, 0x008D0668,
524 0x008E1D7C, 0x008F0CE5,
525 0x00900C45, 0x00911E08,
526 0x009217A9, 0x009301C4,
527 0x009417AA, 0x009501C9,
528 0x00960169, 0x0097588A,
529 0x00981888, 0x00990066,
530 0x009A0709, 0x009B07A8,
531 0x009C0704, 0x009D07A6,
532 0x009E16E6, 0x009F0345,
533 0x00A000C9, 0x00A11B05,
534 0x00A20E09, 0x00A30669,
535 0x00A41885, 0x00A50065,
536 0x00A60706, 0x00A707A5,
537 0x00A803A9, 0x00A90189,
538 0x00AA0029, 0x00AB0889,
539 0x00AC0744, 0x00AD06E9,
540 0x00AE0B06, 0x00AF0229,
541 0x00B00E05, 0x00B10665,
542 0x00B21974, 0x00B30CE8,
543 0x00B4070A, 0x00B507A9,
544 0x00B616E9, 0x00B70348,
545 0x00B8074A, 0x00B906E6,
546 0x00BA0B09, 0x00BB0226,
547 0x00BC1CE4, 0x00BD0D7D,
548 0x00BE0269, 0x00BF08C9,
549 0x00C000CA, 0x00C11B04,
550 0x00C21884, 0x00C3006A,
551 0x00C40E04, 0x00C50664,
552 0x00C60708, 0x00C707AA,
553 0x00C803A8, 0x00C90184,
554 0x00CA0749, 0x00CB06E4,
555 0x00CC0020, 0x00CD0888,
556 0x00CE0B08, 0x00CF0224,
557 0x00D00E0A, 0x00D1066A,
558 0x00D20705, 0x00D307A4,
559 0x00D41D78, 0x00D50CE9,
560 0x00D616EA, 0x00D70349,
561 0x00D80745, 0x00D906E8,
562 0x00DA1CE9, 0x00DB0D75,
563 0x00DC0B04, 0x00DD0228,
564 0x00DE0268, 0x00DF08C8,
565 0x00E003A5, 0x00E10185,
566 0x00E20746, 0x00E306EA,
567 0x00E40748, 0x00E506E5,
568 0x00E61CE8, 0x00E70D79,
569 0x00E81D74, 0x00E95CE6,
570 0x00EA02E9, 0x00EB0849,
571 0x00EC02E8, 0x00ED0848,
572 0x00EE0086, 0x00EF0A08,
573 0x00F00021, 0x00F10885,
574 0x00F20B05, 0x00F3022A,
575 0x00F40B0A, 0x00F50225,
576 0x00F60265, 0x00F708C5,
577 0x00F802E5, 0x00F90845,
578 0x00FA0089, 0x00FB0A09,
579 0x00FC008A, 0x00FD0A0A,
580 0x00FE02A9, 0x00FF0062,
584 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
586 hbrMask = CreatePatternBrush(hbmMask);
587 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
590 hDC1 = CreateCompatibleDC(hdcDest);
591 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
592 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
594 /* draw using bkgnd rop */
595 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
596 hbrTmp = SelectObject(hDC1, hbrDst);
597 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
598 SelectObject(hDC1, hbrTmp);
601 hDC2 = CreateCompatibleDC(hdcDest);
602 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
603 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
605 /* draw using foregnd rop */
606 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
607 hbrTmp = SelectObject(hDC2, hbrDst);
608 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
610 /* combine both using the mask as a pattern brush */
611 SelectObject(hDC2, hbrMask);
612 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
613 SelectObject(hDC2, hbrTmp);
616 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
618 /* restore all objects */
619 SelectObject(hdcDest, hbrDst);
620 SelectObject(hDC1, hOldBitmap1);
621 SelectObject(hDC2, hOldBitmap2);
623 /* delete all temp objects */
624 DeleteObject(hBitmap1);
625 DeleteObject(hBitmap2);
626 DeleteObject(hbrMask);
634 /******************************************************************************
635 * GdiTransparentBlt [GDI32.@]
637 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
638 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
646 HBITMAP bmpMask = NULL;
647 HBITMAP oldMask = NULL;
648 COLORREF oldBackground;
649 COLORREF oldForeground;
652 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
653 TRACE("Cannot mirror\n");
657 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
658 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
661 oldStretchMode = GetStretchBltMode(hdcSrc);
662 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
663 SetStretchBltMode(hdcSrc, COLORONCOLOR);
664 hdcWork = CreateCompatibleDC(hdcDest);
665 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
666 oldWork = SelectObject(hdcWork, bmpWork);
667 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
668 TRACE("Failed to stretch\n");
671 SetBkColor(hdcWork, crTransparent);
674 hdcMask = CreateCompatibleDC(hdcDest);
675 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
676 oldMask = SelectObject(hdcMask, bmpMask);
677 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
678 TRACE("Failed to create mask\n");
682 /* Replace transparent color with black */
683 SetBkColor(hdcWork, RGB(0,0,0));
684 SetTextColor(hdcWork, RGB(255,255,255));
685 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
686 TRACE("Failed to mask out background\n");
690 /* Replace non-transparent area on destination with black */
691 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
692 TRACE("Failed to clear destination area\n");
697 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
698 TRACE("Failed to paint image\n");
704 SetStretchBltMode(hdcSrc, oldStretchMode);
705 SetBkColor(hdcDest, oldBackground);
706 SetTextColor(hdcDest, oldForeground);
708 SelectObject(hdcWork, oldWork);
711 if(bmpWork) DeleteObject(bmpWork);
713 SelectObject(hdcMask, oldMask);
716 if(bmpMask) DeleteObject(bmpMask);
720 /******************************************************************************
721 * GdiAlphaBlend [GDI32.@]
723 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
724 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
725 BLENDFUNCTION blendFunction)
730 dcSrc = get_dc_ptr( hdcSrc );
731 if (!dcSrc) return FALSE;
733 if ((dcDst = get_dc_ptr( hdcDst )))
735 struct bitblt_coords src, dst;
736 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
737 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
744 src.log_width = widthSrc;
745 src.log_height = heightSrc;
746 src.layout = GetLayout( src_dev->hdc );
749 dst.log_width = widthDst;
750 dst.log_height = heightDst;
751 dst.layout = GetLayout( dst_dev->hdc );
752 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
754 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",
755 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
756 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
757 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
758 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
759 blendFunction.BlendOp, blendFunction.BlendFlags,
760 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
762 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
763 (dcSrc->header.type == OBJ_MEMDC &&
764 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
765 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
767 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
768 SetLastError( ERROR_INVALID_PARAMETER );
771 else if (dst.width < 0 || dst.height < 0)
773 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
774 SetLastError( ERROR_INVALID_PARAMETER );
777 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
779 release_dc_ptr( dcDst );
781 release_dc_ptr( dcSrc );
785 /*********************************************************************
789 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
790 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
791 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
794 /* parallelogram coords */
803 /* save actual mode, set GM_ADVANCED */
804 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
808 memcpy(plg,lpPoint,sizeof(POINT)*3);
811 rect[1].x = nXSrc + nWidth;
814 rect[2].y = nYSrc + nHeight;
815 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
817 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);
819 if (fabs(det) < 1e-5)
821 SetGraphicsMode(hdcDest,oldgMode);
825 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
826 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
829 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;
830 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;
831 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
832 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
833 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
837 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;
838 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;
839 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
840 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
841 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
844 GetWorldTransform(hdcSrc,&SrcXf);
845 CombineTransform(&xf,&xf,&SrcXf);
847 /* save actual dest transform */
848 GetWorldTransform(hdcDest,&oldDestXf);
850 SetWorldTransform(hdcDest,&xf);
851 /* now destination and source DCs use same coords */
852 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
856 /* restore dest DC */
857 SetWorldTransform(hdcDest,&oldDestXf);
858 SetGraphicsMode(hdcDest,oldgMode);