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