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