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