gdi32: Move coordinate checks into the common part of GdiAlphaBlend.
[wine] / dlls / gdi32 / bitblt.c
1 /*
2  * GDI bit-blit operations
3  *
4  * Copyright 1993, 1994  Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #include <math.h>
26 #ifdef HAVE_FLOAT_H
27 #include <float.h>
28 #endif
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "gdi_private.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
37
38 static inline BOOL rop_uses_src( DWORD rop )
39 {
40     return ((rop >> 2) & 0x330000) != (rop & 0x330000);
41 }
42
43 static inline void swap_ints( int *i, int *j )
44 {
45     int tmp = *i;
46     *i = *j;
47     *j = tmp;
48 }
49
50 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
51                                 DC *dc_src, struct bitblt_coords *src )
52 {
53     RECT rect, clip;
54
55     /* get the destination visible rectangle */
56
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 );
62     dst->x      = rect.left;
63     dst->y      = rect.top;
64     dst->width  = rect.right - rect.left;
65     dst->height = rect.bottom - rect.top;
66     if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
67     {
68         swap_ints( &rect.left, &rect.right );
69         dst->x = rect.left;
70         dst->width = rect.right - rect.left;
71     }
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++; }
74
75     if (get_clip_box( dc_dst, &clip ))
76         intersect_rect( &dst->visrect, &rect, &clip );
77     else
78         dst->visrect = rect;
79
80     /* get the source visible rectangle */
81
82     if (!src) return !is_rect_empty( &dst->visrect );
83
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 );
89     src->x      = rect.left;
90     src->y      = rect.top;
91     src->width  = rect.right - rect.left;
92     src->height = rect.bottom - rect.top;
93     if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
94     {
95         swap_ints( &rect.left, &rect.right );
96         src->x = rect.left;
97         src->width = rect.right - rect.left;
98     }
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++; }
101
102     /* source is not clipped */
103     if (dc_src->header.type == OBJ_MEMDC)
104         intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
105     else
106         src->visrect = rect;  /* FIXME: clip to device size */
107
108     if (is_rect_empty( &src->visrect )) return FALSE;
109     if (is_rect_empty( &dst->visrect )) return FALSE;
110
111     /* intersect the rectangles */
112
113     if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
114     {
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 );
119     }
120     else  /* stretching */
121     {
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 );
129
130         /* avoid rounding errors */
131         rect.left--;
132         rect.top--;
133         rect.right++;
134         rect.bottom++;
135         if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
136
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 );
144
145         /* avoid rounding errors */
146         rect.left--;
147         rect.top--;
148         rect.right++;
149         rect.bottom++;
150         if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
151     }
152     return TRUE;
153 }
154
155 void free_heap_bits( struct gdi_image_bits *bits )
156 {
157     HeapFree( GetProcessHeap(), 0, bits->ptr );
158 }
159
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 )
163 {
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;
169     DWORD err;
170     struct gdi_image_bits bits;
171     LPVOID ptr;
172
173     if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
174     src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
175     err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
176     release_dc_ptr( dc_src );
177     if (err) return FALSE;
178
179     dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
180     memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
181     err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
182     if (err == ERROR_BAD_FORMAT)
183     {
184         /* 1-bpp source without a color table uses the destination DC colors */
185         if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
186         {
187             COLORREF color = GetTextColor( dst_dev->hdc );
188             src_info->bmiColors[0].rgbRed      = GetRValue( color );
189             src_info->bmiColors[0].rgbGreen    = GetGValue( color );
190             src_info->bmiColors[0].rgbBlue     = GetBValue( color );
191             src_info->bmiColors[0].rgbReserved = 0;
192             color = GetBkColor( dst_dev->hdc );
193             src_info->bmiColors[1].rgbRed      = GetRValue( color );
194             src_info->bmiColors[1].rgbGreen    = GetGValue( color );
195             src_info->bmiColors[1].rgbBlue     = GetBValue( color );
196             src_info->bmiColors[1].rgbReserved = 0;
197             src_info->bmiHeader.biClrUsed = 2;
198         }
199
200         /* 1-bpp destination without a color table requires a fake 1-entry table
201          * that contains only the background color */
202         if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
203         {
204             COLORREF color = GetBkColor( src_dev->hdc );
205             dst_info->bmiColors[0].rgbRed      = GetRValue( color );
206             dst_info->bmiColors[0].rgbGreen    = GetGValue( color );
207             dst_info->bmiColors[0].rgbBlue     = GetBValue( color );
208             dst_info->bmiColors[0].rgbReserved = 0;
209             dst_info->bmiHeader.biClrUsed = 1;
210         }
211
212         dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
213         if ((ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
214         {
215             err = convert_bitmapinfo( src_info, bits.ptr, src, dst_info, ptr );
216             if (bits.free) bits.free( &bits );
217             bits.ptr = ptr;
218             bits.is_copy = TRUE;
219             bits.free = free_heap_bits;
220             if (!err)
221             {
222                 /* get rid of the fake 1-bpp table */
223                 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
224                 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
225             }
226         }
227         else err = ERROR_OUTOFMEMORY;
228     }
229
230     if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
231         ((src->width != dst->width) || (src->height != dst->height)))
232     {
233         FIXME( "should stretch %dx%d -> %dx%d\n",
234                src->width, src->height, dst->width, dst->height );
235     }
236
237     if (bits.free) bits.free( &bits );
238     return !err;
239 }
240
241 /***********************************************************************
242  *           PatBlt    (GDI32.@)
243  */
244 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
245 {
246     DC * dc;
247     BOOL ret = FALSE;
248
249     if (rop_uses_src( rop )) return FALSE;
250     if ((dc = get_dc_ptr( hdc )))
251     {
252         struct bitblt_coords dst;
253         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
254
255         update_dc( dc );
256
257         dst.log_x      = left;
258         dst.log_y      = top;
259         dst.log_width  = width;
260         dst.log_height = height;
261         dst.layout     = dc->layout;
262         if (rop & NOMIRRORBITMAP)
263         {
264             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
265             rop &= ~NOMIRRORBITMAP;
266         }
267         ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
268
269         TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s  rop=%06x\n",
270               hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
271               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
272
273         if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
274
275         release_dc_ptr( dc );
276     }
277     return ret;
278 }
279
280
281 /***********************************************************************
282  *           BitBlt    (GDI32.@)
283  */
284 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
285                     INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
286 {
287     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
288     else return StretchBlt( hdcDst, xDst, yDst, width, height,
289                             hdcSrc, xSrc, ySrc, width, height, rop );
290 }
291
292
293 /***********************************************************************
294  *           StretchBlt    (GDI32.@)
295  */
296 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
297                         HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
298 {
299     BOOL ret = FALSE;
300     DC *dcDst, *dcSrc;
301
302     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
303
304     if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
305
306     if ((dcSrc = get_dc_ptr( hdcSrc )))
307     {
308         struct bitblt_coords src, dst;
309         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
310         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
311
312         update_dc( dcSrc );
313         update_dc( dcDst );
314
315         src.log_x      = xSrc;
316         src.log_y      = ySrc;
317         src.log_width  = widthSrc;
318         src.log_height = heightSrc;
319         src.layout     = dcSrc->layout;
320         dst.log_x      = xDst;
321         dst.log_y      = yDst;
322         dst.log_width  = widthDst;
323         dst.log_height = heightDst;
324         dst.layout     = dcDst->layout;
325         if (rop & NOMIRRORBITMAP)
326         {
327             src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
328             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
329             rop &= ~NOMIRRORBITMAP;
330         }
331         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
332
333         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",
334               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
335               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
336               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
337               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
338
339         if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
340         release_dc_ptr( dcSrc );
341     }
342     release_dc_ptr( dcDst );
343     return ret;
344 }
345
346 #define FRGND_ROP3(ROP4)        ((ROP4) & 0x00FFFFFF)
347 #define BKGND_ROP3(ROP4)        (ROP3Table[((ROP4)>>24) & 0xFF])
348
349 /***********************************************************************
350  *           MaskBlt [GDI32.@]
351  */
352 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
353                         INT nWidth, INT nHeight, HDC hdcSrc,
354                         INT nXSrc, INT nYSrc, HBITMAP hbmMask,
355                         INT xMask, INT yMask, DWORD dwRop)
356 {
357     HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
358     HDC hDC1, hDC2;
359     HBRUSH hbrMask, hbrDst, hbrTmp;
360
361     static const DWORD ROP3Table[256] = 
362     {
363         0x00000042, 0x00010289,
364         0x00020C89, 0x000300AA,
365         0x00040C88, 0x000500A9,
366         0x00060865, 0x000702C5,
367         0x00080F08, 0x00090245,
368         0x000A0329, 0x000B0B2A,
369         0x000C0324, 0x000D0B25,
370         0x000E08A5, 0x000F0001,
371         0x00100C85, 0x001100A6,
372         0x00120868, 0x001302C8,
373         0x00140869, 0x001502C9,
374         0x00165CCA, 0x00171D54,
375         0x00180D59, 0x00191CC8,
376         0x001A06C5, 0x001B0768,
377         0x001C06CA, 0x001D0766,
378         0x001E01A5, 0x001F0385,
379         0x00200F09, 0x00210248,
380         0x00220326, 0x00230B24,
381         0x00240D55, 0x00251CC5,
382         0x002606C8, 0x00271868,
383         0x00280369, 0x002916CA,
384         0x002A0CC9, 0x002B1D58,
385         0x002C0784, 0x002D060A,
386         0x002E064A, 0x002F0E2A,
387         0x0030032A, 0x00310B28,
388         0x00320688, 0x00330008,
389         0x003406C4, 0x00351864,
390         0x003601A8, 0x00370388,
391         0x0038078A, 0x00390604,
392         0x003A0644, 0x003B0E24,
393         0x003C004A, 0x003D18A4,
394         0x003E1B24, 0x003F00EA,
395         0x00400F0A, 0x00410249,
396         0x00420D5D, 0x00431CC4,
397         0x00440328, 0x00450B29,
398         0x004606C6, 0x0047076A,
399         0x00480368, 0x004916C5,
400         0x004A0789, 0x004B0605,
401         0x004C0CC8, 0x004D1954,
402         0x004E0645, 0x004F0E25,
403         0x00500325, 0x00510B26,
404         0x005206C9, 0x00530764,
405         0x005408A9, 0x00550009,
406         0x005601A9, 0x00570389,
407         0x00580785, 0x00590609,
408         0x005A0049, 0x005B18A9,
409         0x005C0649, 0x005D0E29,
410         0x005E1B29, 0x005F00E9,
411         0x00600365, 0x006116C6,
412         0x00620786, 0x00630608,
413         0x00640788, 0x00650606,
414         0x00660046, 0x006718A8,
415         0x006858A6, 0x00690145,
416         0x006A01E9, 0x006B178A,
417         0x006C01E8, 0x006D1785,
418         0x006E1E28, 0x006F0C65,
419         0x00700CC5, 0x00711D5C,
420         0x00720648, 0x00730E28,
421         0x00740646, 0x00750E26,
422         0x00761B28, 0x007700E6,
423         0x007801E5, 0x00791786,
424         0x007A1E29, 0x007B0C68,
425         0x007C1E24, 0x007D0C69,
426         0x007E0955, 0x007F03C9,
427         0x008003E9, 0x00810975,
428         0x00820C49, 0x00831E04,
429         0x00840C48, 0x00851E05,
430         0x008617A6, 0x008701C5,
431         0x008800C6, 0x00891B08,
432         0x008A0E06, 0x008B0666,
433         0x008C0E08, 0x008D0668,
434         0x008E1D7C, 0x008F0CE5,
435         0x00900C45, 0x00911E08,
436         0x009217A9, 0x009301C4,
437         0x009417AA, 0x009501C9,
438         0x00960169, 0x0097588A,
439         0x00981888, 0x00990066,
440         0x009A0709, 0x009B07A8,
441         0x009C0704, 0x009D07A6,
442         0x009E16E6, 0x009F0345,
443         0x00A000C9, 0x00A11B05,
444         0x00A20E09, 0x00A30669,
445         0x00A41885, 0x00A50065,
446         0x00A60706, 0x00A707A5,
447         0x00A803A9, 0x00A90189,
448         0x00AA0029, 0x00AB0889,
449         0x00AC0744, 0x00AD06E9,
450         0x00AE0B06, 0x00AF0229,
451         0x00B00E05, 0x00B10665,
452         0x00B21974, 0x00B30CE8,
453         0x00B4070A, 0x00B507A9,
454         0x00B616E9, 0x00B70348,
455         0x00B8074A, 0x00B906E6,
456         0x00BA0B09, 0x00BB0226,
457         0x00BC1CE4, 0x00BD0D7D,
458         0x00BE0269, 0x00BF08C9,
459         0x00C000CA, 0x00C11B04,
460         0x00C21884, 0x00C3006A,
461         0x00C40E04, 0x00C50664,
462         0x00C60708, 0x00C707AA,
463         0x00C803A8, 0x00C90184,
464         0x00CA0749, 0x00CB06E4,
465         0x00CC0020, 0x00CD0888,
466         0x00CE0B08, 0x00CF0224,
467         0x00D00E0A, 0x00D1066A,
468         0x00D20705, 0x00D307A4,
469         0x00D41D78, 0x00D50CE9,
470         0x00D616EA, 0x00D70349,
471         0x00D80745, 0x00D906E8,
472         0x00DA1CE9, 0x00DB0D75,
473         0x00DC0B04, 0x00DD0228,
474         0x00DE0268, 0x00DF08C8,
475         0x00E003A5, 0x00E10185,
476         0x00E20746, 0x00E306EA,
477         0x00E40748, 0x00E506E5,
478         0x00E61CE8, 0x00E70D79,
479         0x00E81D74, 0x00E95CE6,
480         0x00EA02E9, 0x00EB0849,
481         0x00EC02E8, 0x00ED0848,
482         0x00EE0086, 0x00EF0A08,
483         0x00F00021, 0x00F10885,
484         0x00F20B05, 0x00F3022A,
485         0x00F40B0A, 0x00F50225,
486         0x00F60265, 0x00F708C5,
487         0x00F802E5, 0x00F90845,
488         0x00FA0089, 0x00FB0A09,
489         0x00FC008A, 0x00FD0A0A,
490         0x00FE02A9, 0x00FF0062,
491     };
492
493     if (!hbmMask)
494         return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
495
496     hbrMask = CreatePatternBrush(hbmMask);
497     hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
498
499     /* make bitmap */
500     hDC1 = CreateCompatibleDC(hdcDest);
501     hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
502     hOldBitmap1 = SelectObject(hDC1, hBitmap1);
503
504     /* draw using bkgnd rop */
505     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
506     hbrTmp = SelectObject(hDC1, hbrDst);
507     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
508     SelectObject(hDC1, hbrTmp);
509
510     /* make bitmap */
511     hDC2 = CreateCompatibleDC(hdcDest);
512     hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
513     hOldBitmap2 = SelectObject(hDC2, hBitmap2);
514
515     /* draw using foregnd rop */
516     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
517     hbrTmp = SelectObject(hDC2, hbrDst);
518     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
519
520     /* combine both using the mask as a pattern brush */
521     SelectObject(hDC2, hbrMask);
522     BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */ 
523     SelectObject(hDC2, hbrTmp);
524
525     /* blit to dst */
526     BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
527
528     /* restore all objects */
529     SelectObject(hdcDest, hbrDst);
530     SelectObject(hDC1, hOldBitmap1);
531     SelectObject(hDC2, hOldBitmap2);
532
533     /* delete all temp objects */
534     DeleteObject(hBitmap1);
535     DeleteObject(hBitmap2);
536     DeleteObject(hbrMask);
537
538     DeleteDC(hDC1);
539     DeleteDC(hDC2);
540
541     return TRUE;
542 }
543
544 /******************************************************************************
545  *           GdiTransparentBlt [GDI32.@]
546  */
547 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
548                             HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
549                             UINT crTransparent )
550 {
551     BOOL ret = FALSE;
552     HDC hdcWork;
553     HBITMAP bmpWork;
554     HGDIOBJ oldWork;
555     HDC hdcMask = NULL;
556     HBITMAP bmpMask = NULL;
557     HBITMAP oldMask = NULL;
558     COLORREF oldBackground;
559     COLORREF oldForeground;
560     int oldStretchMode;
561
562     if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
563         TRACE("Cannot mirror\n");
564         return FALSE;
565     }
566
567     oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
568     oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
569
570     /* Stretch bitmap */
571     oldStretchMode = GetStretchBltMode(hdcSrc);
572     if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
573         SetStretchBltMode(hdcSrc, COLORONCOLOR);
574     hdcWork = CreateCompatibleDC(hdcDest);
575     bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
576     oldWork = SelectObject(hdcWork, bmpWork);
577     if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
578         TRACE("Failed to stretch\n");
579         goto error;
580     }
581     SetBkColor(hdcWork, crTransparent);
582
583     /* Create mask */
584     hdcMask = CreateCompatibleDC(hdcDest);
585     bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
586     oldMask = SelectObject(hdcMask, bmpMask);
587     if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
588         TRACE("Failed to create mask\n");
589         goto error;
590     }
591
592     /* Replace transparent color with black */
593     SetBkColor(hdcWork, RGB(0,0,0));
594     SetTextColor(hdcWork, RGB(255,255,255));
595     if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
596         TRACE("Failed to mask out background\n");
597         goto error;
598     }
599
600     /* Replace non-transparent area on destination with black */
601     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
602         TRACE("Failed to clear destination area\n");
603         goto error;
604     }
605
606     /* Draw the image */
607     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
608         TRACE("Failed to paint image\n");
609         goto error;
610     }
611
612     ret = TRUE;
613 error:
614     SetStretchBltMode(hdcSrc, oldStretchMode);
615     SetBkColor(hdcDest, oldBackground);
616     SetTextColor(hdcDest, oldForeground);
617     if(hdcWork) {
618         SelectObject(hdcWork, oldWork);
619         DeleteDC(hdcWork);
620     }
621     if(bmpWork) DeleteObject(bmpWork);
622     if(hdcMask) {
623         SelectObject(hdcMask, oldMask);
624         DeleteDC(hdcMask);
625     }
626     if(bmpMask) DeleteObject(bmpMask);
627     return ret;
628 }
629
630 /******************************************************************************
631  *           GdiAlphaBlend [GDI32.@]
632  */
633 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
634                           HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
635                           BLENDFUNCTION blendFunction)
636 {
637     BOOL ret = FALSE;
638     DC *dcDst, *dcSrc;
639
640     dcSrc = get_dc_ptr( hdcSrc );
641     if (!dcSrc) return FALSE;
642
643     if ((dcDst = get_dc_ptr( hdcDst )))
644     {
645         struct bitblt_coords src, dst;
646         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
647         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
648
649         update_dc( dcSrc );
650         update_dc( dcDst );
651
652         src.log_x      = xSrc;
653         src.log_y      = ySrc;
654         src.log_width  = widthSrc;
655         src.log_height = heightSrc;
656         src.layout     = GetLayout( src_dev->hdc );
657         dst.log_x      = xDst;
658         dst.log_y      = yDst;
659         dst.log_width  = widthDst;
660         dst.log_height = heightDst;
661         dst.layout     = GetLayout( dst_dev->hdc );
662         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
663
664         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",
665               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
666               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
667               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
668               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
669               blendFunction.BlendOp, blendFunction.BlendFlags,
670               blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
671
672         if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
673             (dcSrc->header.type == OBJ_MEMDC &&
674              (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
675               src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
676         {
677             WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
678             SetLastError( ERROR_INVALID_PARAMETER );
679             ret = FALSE;
680         }
681         else if (dst.width < 0 || dst.height < 0)
682         {
683             WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
684             SetLastError( ERROR_INVALID_PARAMETER );
685             ret = FALSE;
686         }
687         else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
688
689         release_dc_ptr( dcDst );
690     }
691     release_dc_ptr( dcSrc );
692     return ret;
693 }
694
695 /*********************************************************************
696  *      PlgBlt [GDI32.@]
697  *
698  */
699 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
700                         HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
701                         INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
702 {
703     int oldgMode;
704     /* parallelogram coords */
705     POINT plg[3];
706     /* rect coords */
707     POINT rect[3];
708     XFORM xf;
709     XFORM SrcXf;
710     XFORM oldDestXf;
711     double det;
712
713     /* save actual mode, set GM_ADVANCED */
714     oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
715     if (oldgMode == 0)
716         return FALSE;
717
718     memcpy(plg,lpPoint,sizeof(POINT)*3);
719     rect[0].x = nXSrc;
720     rect[0].y = nYSrc;
721     rect[1].x = nXSrc + nWidth;
722     rect[1].y = nYSrc;
723     rect[2].x = nXSrc;
724     rect[2].y = nYSrc + nHeight;
725     /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
726     /* determinant */
727     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);
728
729     if (fabs(det) < 1e-5)
730     {
731         SetGraphicsMode(hdcDest,oldgMode);
732         return FALSE;
733     }
734
735     TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
736         hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
737
738     /* X components */
739     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;
740     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;
741     xf.eDx  = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
742                rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
743                rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
744                ) / det;
745
746     /* Y components */
747     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;
748     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;
749     xf.eDy  = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
750                rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
751                rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
752                ) / det;
753
754     GetWorldTransform(hdcSrc,&SrcXf);
755     CombineTransform(&xf,&xf,&SrcXf);
756
757     /* save actual dest transform */
758     GetWorldTransform(hdcDest,&oldDestXf);
759
760     SetWorldTransform(hdcDest,&xf);
761     /* now destination and source DCs use same coords */
762     MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
763             hdcSrc, nXSrc,nYSrc,
764             hbmMask,xMask,yMask,
765             SRCCOPY);
766     /* restore dest DC */
767     SetWorldTransform(hdcDest,&oldDestXf);
768     SetGraphicsMode(hdcDest,oldgMode);
769
770     return TRUE;
771 }