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