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