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 */
124 offset_rect( &rect, -min( src->x, src->x + src->width + 1),
125 -min( src->y, src->y + src->height + 1) );
126 rect.left = dst->x + rect.left * dst->width / abs(src->width);
127 rect.top = dst->y + rect.top * dst->height / abs(src->height);
128 rect.right = dst->x + rect.right * dst->width / abs(src->width);
129 rect.bottom = dst->y + rect.bottom * dst->height / abs(src->height);
130 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
131 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
133 /* avoid rounding errors */
138 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
140 /* map destination rectangle back to source coordinates */
142 offset_rect( &rect, -min( dst->x, dst->x + dst->width + 1),
143 -min( dst->y, dst->y + dst->height + 1) );
144 rect.left = src->x + rect.left * src->width / abs(dst->width);
145 rect.top = src->y + rect.top * src->height / abs(dst->height);
146 rect.right = src->x + rect.right * src->width / abs(dst->width);
147 rect.bottom = src->y + rect.bottom * src->height / abs(dst->height);
148 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
149 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
151 /* avoid rounding errors */
156 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
161 void free_heap_bits( struct gdi_image_bits *bits )
163 HeapFree( GetProcessHeap(), 0, bits->ptr );
166 static DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
167 BITMAPINFO *dst_info, struct gdi_image_bits *bits )
172 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
173 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
174 return ERROR_OUTOFMEMORY;
176 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
177 if (bits->free) bits->free( bits );
179 bits->is_copy = TRUE;
180 bits->free = free_heap_bits;
184 static DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
185 BITMAPINFO *dst_info, struct bitblt_coords *dst,
186 struct gdi_image_bits *bits, int mode )
191 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
192 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
193 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
194 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
195 return ERROR_OUTOFMEMORY;
197 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
198 if (bits->free) bits->free( bits );
200 bits->is_copy = TRUE;
201 bits->free = free_heap_bits;
205 /***********************************************************************
206 * null driver fallback implementations
209 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
210 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
212 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
213 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
214 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
215 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
216 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
218 struct gdi_image_bits bits;
220 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
221 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
222 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
223 release_dc_ptr( dc_src );
224 if (err) return FALSE;
226 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
227 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
228 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
229 if (err == ERROR_BAD_FORMAT)
231 /* 1-bpp source without a color table uses the destination DC colors */
232 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
234 COLORREF color = GetTextColor( dst_dev->hdc );
235 src_info->bmiColors[0].rgbRed = GetRValue( color );
236 src_info->bmiColors[0].rgbGreen = GetGValue( color );
237 src_info->bmiColors[0].rgbBlue = GetBValue( color );
238 src_info->bmiColors[0].rgbReserved = 0;
239 color = GetBkColor( dst_dev->hdc );
240 src_info->bmiColors[1].rgbRed = GetRValue( color );
241 src_info->bmiColors[1].rgbGreen = GetGValue( color );
242 src_info->bmiColors[1].rgbBlue = GetBValue( color );
243 src_info->bmiColors[1].rgbReserved = 0;
244 src_info->bmiHeader.biClrUsed = 2;
247 /* 1-bpp destination without a color table requires a fake 1-entry table
248 * that contains only the background color */
249 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
251 COLORREF color = GetBkColor( src_dev->hdc );
252 dst_info->bmiColors[0].rgbRed = GetRValue( color );
253 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
254 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
255 dst_info->bmiColors[0].rgbReserved = 0;
256 dst_info->bmiHeader.biClrUsed = 1;
259 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
261 /* get rid of the fake 1-bpp table */
262 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
263 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
267 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
268 ((src->width != dst->width) || (src->height != dst->height)))
270 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
271 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
272 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
275 if (bits.free) bits.free( &bits );
280 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
281 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
283 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
284 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
285 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
286 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
287 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
289 struct gdi_image_bits bits;
291 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
292 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
293 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
294 release_dc_ptr( dc_src );
295 if (err) return FALSE;
297 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
298 memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
299 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
300 if (err == ERROR_BAD_FORMAT)
302 /* 1-bpp source without a color table uses black & white */
303 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
305 src_info->bmiColors[0].rgbRed = 0;
306 src_info->bmiColors[0].rgbGreen = 0;
307 src_info->bmiColors[0].rgbBlue = 0;
308 src_info->bmiColors[0].rgbReserved = 0;
309 src_info->bmiColors[1].rgbRed = 0xff;
310 src_info->bmiColors[1].rgbGreen = 0xff;
311 src_info->bmiColors[1].rgbBlue = 0xff;
312 src_info->bmiColors[1].rgbReserved = 0;
313 src_info->bmiHeader.biClrUsed = 2;
316 err = convert_bits( src_info, src, dst_info, &bits );
317 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
320 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
321 ((src->width != dst->width) || (src->height != dst->height)))
323 memcpy( src_info, dst_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
324 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
325 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
328 if (bits.free) bits.free( &bits );
333 /***********************************************************************
336 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
341 if (rop_uses_src( rop )) return FALSE;
342 if ((dc = get_dc_ptr( hdc )))
344 struct bitblt_coords dst;
345 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
351 dst.log_width = width;
352 dst.log_height = height;
353 dst.layout = dc->layout;
354 if (rop & NOMIRRORBITMAP)
356 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
357 rop &= ~NOMIRRORBITMAP;
359 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
361 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
362 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
363 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
365 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
367 release_dc_ptr( dc );
373 /***********************************************************************
376 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
377 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
379 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
380 else return StretchBlt( hdcDst, xDst, yDst, width, height,
381 hdcSrc, xSrc, ySrc, width, height, rop );
385 /***********************************************************************
386 * StretchBlt (GDI32.@)
388 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
389 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
394 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
396 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
398 if ((dcSrc = get_dc_ptr( hdcSrc )))
400 struct bitblt_coords src, dst;
401 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
402 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
409 src.log_width = widthSrc;
410 src.log_height = heightSrc;
411 src.layout = dcSrc->layout;
414 dst.log_width = widthDst;
415 dst.log_height = heightDst;
416 dst.layout = dcDst->layout;
417 if (rop & NOMIRRORBITMAP)
419 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
420 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
421 rop &= ~NOMIRRORBITMAP;
423 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
425 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",
426 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
427 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
428 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
429 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
431 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
432 release_dc_ptr( dcSrc );
434 release_dc_ptr( dcDst );
438 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
439 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
441 /***********************************************************************
444 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
445 INT nWidth, INT nHeight, HDC hdcSrc,
446 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
447 INT xMask, INT yMask, DWORD dwRop)
449 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
451 HBRUSH hbrMask, hbrDst, hbrTmp;
453 static const DWORD ROP3Table[256] =
455 0x00000042, 0x00010289,
456 0x00020C89, 0x000300AA,
457 0x00040C88, 0x000500A9,
458 0x00060865, 0x000702C5,
459 0x00080F08, 0x00090245,
460 0x000A0329, 0x000B0B2A,
461 0x000C0324, 0x000D0B25,
462 0x000E08A5, 0x000F0001,
463 0x00100C85, 0x001100A6,
464 0x00120868, 0x001302C8,
465 0x00140869, 0x001502C9,
466 0x00165CCA, 0x00171D54,
467 0x00180D59, 0x00191CC8,
468 0x001A06C5, 0x001B0768,
469 0x001C06CA, 0x001D0766,
470 0x001E01A5, 0x001F0385,
471 0x00200F09, 0x00210248,
472 0x00220326, 0x00230B24,
473 0x00240D55, 0x00251CC5,
474 0x002606C8, 0x00271868,
475 0x00280369, 0x002916CA,
476 0x002A0CC9, 0x002B1D58,
477 0x002C0784, 0x002D060A,
478 0x002E064A, 0x002F0E2A,
479 0x0030032A, 0x00310B28,
480 0x00320688, 0x00330008,
481 0x003406C4, 0x00351864,
482 0x003601A8, 0x00370388,
483 0x0038078A, 0x00390604,
484 0x003A0644, 0x003B0E24,
485 0x003C004A, 0x003D18A4,
486 0x003E1B24, 0x003F00EA,
487 0x00400F0A, 0x00410249,
488 0x00420D5D, 0x00431CC4,
489 0x00440328, 0x00450B29,
490 0x004606C6, 0x0047076A,
491 0x00480368, 0x004916C5,
492 0x004A0789, 0x004B0605,
493 0x004C0CC8, 0x004D1954,
494 0x004E0645, 0x004F0E25,
495 0x00500325, 0x00510B26,
496 0x005206C9, 0x00530764,
497 0x005408A9, 0x00550009,
498 0x005601A9, 0x00570389,
499 0x00580785, 0x00590609,
500 0x005A0049, 0x005B18A9,
501 0x005C0649, 0x005D0E29,
502 0x005E1B29, 0x005F00E9,
503 0x00600365, 0x006116C6,
504 0x00620786, 0x00630608,
505 0x00640788, 0x00650606,
506 0x00660046, 0x006718A8,
507 0x006858A6, 0x00690145,
508 0x006A01E9, 0x006B178A,
509 0x006C01E8, 0x006D1785,
510 0x006E1E28, 0x006F0C65,
511 0x00700CC5, 0x00711D5C,
512 0x00720648, 0x00730E28,
513 0x00740646, 0x00750E26,
514 0x00761B28, 0x007700E6,
515 0x007801E5, 0x00791786,
516 0x007A1E29, 0x007B0C68,
517 0x007C1E24, 0x007D0C69,
518 0x007E0955, 0x007F03C9,
519 0x008003E9, 0x00810975,
520 0x00820C49, 0x00831E04,
521 0x00840C48, 0x00851E05,
522 0x008617A6, 0x008701C5,
523 0x008800C6, 0x00891B08,
524 0x008A0E06, 0x008B0666,
525 0x008C0E08, 0x008D0668,
526 0x008E1D7C, 0x008F0CE5,
527 0x00900C45, 0x00911E08,
528 0x009217A9, 0x009301C4,
529 0x009417AA, 0x009501C9,
530 0x00960169, 0x0097588A,
531 0x00981888, 0x00990066,
532 0x009A0709, 0x009B07A8,
533 0x009C0704, 0x009D07A6,
534 0x009E16E6, 0x009F0345,
535 0x00A000C9, 0x00A11B05,
536 0x00A20E09, 0x00A30669,
537 0x00A41885, 0x00A50065,
538 0x00A60706, 0x00A707A5,
539 0x00A803A9, 0x00A90189,
540 0x00AA0029, 0x00AB0889,
541 0x00AC0744, 0x00AD06E9,
542 0x00AE0B06, 0x00AF0229,
543 0x00B00E05, 0x00B10665,
544 0x00B21974, 0x00B30CE8,
545 0x00B4070A, 0x00B507A9,
546 0x00B616E9, 0x00B70348,
547 0x00B8074A, 0x00B906E6,
548 0x00BA0B09, 0x00BB0226,
549 0x00BC1CE4, 0x00BD0D7D,
550 0x00BE0269, 0x00BF08C9,
551 0x00C000CA, 0x00C11B04,
552 0x00C21884, 0x00C3006A,
553 0x00C40E04, 0x00C50664,
554 0x00C60708, 0x00C707AA,
555 0x00C803A8, 0x00C90184,
556 0x00CA0749, 0x00CB06E4,
557 0x00CC0020, 0x00CD0888,
558 0x00CE0B08, 0x00CF0224,
559 0x00D00E0A, 0x00D1066A,
560 0x00D20705, 0x00D307A4,
561 0x00D41D78, 0x00D50CE9,
562 0x00D616EA, 0x00D70349,
563 0x00D80745, 0x00D906E8,
564 0x00DA1CE9, 0x00DB0D75,
565 0x00DC0B04, 0x00DD0228,
566 0x00DE0268, 0x00DF08C8,
567 0x00E003A5, 0x00E10185,
568 0x00E20746, 0x00E306EA,
569 0x00E40748, 0x00E506E5,
570 0x00E61CE8, 0x00E70D79,
571 0x00E81D74, 0x00E95CE6,
572 0x00EA02E9, 0x00EB0849,
573 0x00EC02E8, 0x00ED0848,
574 0x00EE0086, 0x00EF0A08,
575 0x00F00021, 0x00F10885,
576 0x00F20B05, 0x00F3022A,
577 0x00F40B0A, 0x00F50225,
578 0x00F60265, 0x00F708C5,
579 0x00F802E5, 0x00F90845,
580 0x00FA0089, 0x00FB0A09,
581 0x00FC008A, 0x00FD0A0A,
582 0x00FE02A9, 0x00FF0062,
586 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
588 hbrMask = CreatePatternBrush(hbmMask);
589 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
592 hDC1 = CreateCompatibleDC(hdcDest);
593 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
594 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
596 /* draw using bkgnd rop */
597 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
598 hbrTmp = SelectObject(hDC1, hbrDst);
599 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
600 SelectObject(hDC1, hbrTmp);
603 hDC2 = CreateCompatibleDC(hdcDest);
604 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
605 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
607 /* draw using foregnd rop */
608 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
609 hbrTmp = SelectObject(hDC2, hbrDst);
610 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
612 /* combine both using the mask as a pattern brush */
613 SelectObject(hDC2, hbrMask);
614 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
615 SelectObject(hDC2, hbrTmp);
618 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
620 /* restore all objects */
621 SelectObject(hdcDest, hbrDst);
622 SelectObject(hDC1, hOldBitmap1);
623 SelectObject(hDC2, hOldBitmap2);
625 /* delete all temp objects */
626 DeleteObject(hBitmap1);
627 DeleteObject(hBitmap2);
628 DeleteObject(hbrMask);
636 /******************************************************************************
637 * GdiTransparentBlt [GDI32.@]
639 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
640 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
648 HBITMAP bmpMask = NULL;
649 HBITMAP oldMask = NULL;
650 COLORREF oldBackground;
651 COLORREF oldForeground;
654 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
655 TRACE("Cannot mirror\n");
659 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
660 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
663 oldStretchMode = GetStretchBltMode(hdcSrc);
664 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
665 SetStretchBltMode(hdcSrc, COLORONCOLOR);
666 hdcWork = CreateCompatibleDC(hdcDest);
667 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
668 oldWork = SelectObject(hdcWork, bmpWork);
669 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
670 TRACE("Failed to stretch\n");
673 SetBkColor(hdcWork, crTransparent);
676 hdcMask = CreateCompatibleDC(hdcDest);
677 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
678 oldMask = SelectObject(hdcMask, bmpMask);
679 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
680 TRACE("Failed to create mask\n");
684 /* Replace transparent color with black */
685 SetBkColor(hdcWork, RGB(0,0,0));
686 SetTextColor(hdcWork, RGB(255,255,255));
687 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
688 TRACE("Failed to mask out background\n");
692 /* Replace non-transparent area on destination with black */
693 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
694 TRACE("Failed to clear destination area\n");
699 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
700 TRACE("Failed to paint image\n");
706 SetStretchBltMode(hdcSrc, oldStretchMode);
707 SetBkColor(hdcDest, oldBackground);
708 SetTextColor(hdcDest, oldForeground);
710 SelectObject(hdcWork, oldWork);
713 if(bmpWork) DeleteObject(bmpWork);
715 SelectObject(hdcMask, oldMask);
718 if(bmpMask) DeleteObject(bmpMask);
722 /******************************************************************************
723 * GdiAlphaBlend [GDI32.@]
725 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
726 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
727 BLENDFUNCTION blendFunction)
732 dcSrc = get_dc_ptr( hdcSrc );
733 if (!dcSrc) return FALSE;
735 if ((dcDst = get_dc_ptr( hdcDst )))
737 struct bitblt_coords src, dst;
738 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
739 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
746 src.log_width = widthSrc;
747 src.log_height = heightSrc;
748 src.layout = GetLayout( src_dev->hdc );
751 dst.log_width = widthDst;
752 dst.log_height = heightDst;
753 dst.layout = GetLayout( dst_dev->hdc );
754 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
756 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",
757 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
758 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
759 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
760 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
761 blendFunction.BlendOp, blendFunction.BlendFlags,
762 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
764 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
765 (dcSrc->header.type == OBJ_MEMDC &&
766 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
767 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
769 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
770 SetLastError( ERROR_INVALID_PARAMETER );
773 else if (dst.width < 0 || dst.height < 0)
775 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
776 SetLastError( ERROR_INVALID_PARAMETER );
779 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
781 release_dc_ptr( dcDst );
783 release_dc_ptr( dcSrc );
787 /*********************************************************************
791 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
792 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
793 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
796 /* parallelogram coords */
805 /* save actual mode, set GM_ADVANCED */
806 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
810 memcpy(plg,lpPoint,sizeof(POINT)*3);
813 rect[1].x = nXSrc + nWidth;
816 rect[2].y = nYSrc + nHeight;
817 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
819 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);
821 if (fabs(det) < 1e-5)
823 SetGraphicsMode(hdcDest,oldgMode);
827 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
828 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
831 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;
832 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;
833 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
834 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
835 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
839 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;
840 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;
841 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
842 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
843 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
846 GetWorldTransform(hdcSrc,&SrcXf);
847 CombineTransform(&xf,&xf,&SrcXf);
849 /* save actual dest transform */
850 GetWorldTransform(hdcDest,&oldDestXf);
852 SetWorldTransform(hdcDest,&xf);
853 /* now destination and source DCs use same coords */
854 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
858 /* restore dest DC */
859 SetWorldTransform(hdcDest,&oldDestXf);
860 SetGraphicsMode(hdcDest,oldgMode);