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
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 static inline void swap_ints( int *i, int *j )
50 static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 )
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);
59 static inline void offset_rect( RECT *rect, int offset_x, int offset_y )
61 rect->left += offset_x;
62 rect->top += offset_y;
63 rect->right += offset_x;
64 rect->bottom += offset_y;
67 static void get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
68 DC *dc_src, struct bitblt_coords *src )
72 /* get the destination visible rectangle */
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 );
81 dst->width = rect.right - rect.left;
82 dst->height = rect.bottom - rect.top;
83 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
85 swap_ints( &rect.left, &rect.right );
87 dst->width = rect.right - rect.left;
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++; }
92 get_clip_box( dc_dst, &clip );
93 intersect_rect( &dst->visrect, &rect, &clip );
95 /* get the source visible rectangle */
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 );
106 src->width = rect.right - rect.left;
107 src->height = rect.bottom - rect.top;
108 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
110 swap_ints( &rect.left, &rect.right );
112 src->width = rect.right - rect.left;
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++; }
117 /* source is not clipped */
118 if (dc_src->header.type == OBJ_MEMDC)
119 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
121 src->visrect = rect; /* FIXME: clip to device size */
123 /* intersect the rectangles */
125 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
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 );
132 else /* stretching */
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 );
142 /* avoid rounding errors */
147 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return;
149 /* map destination rectangle back to source coordinates */
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 );
158 /* avoid rounding errors */
163 intersect_rect( &src->visrect, &rect, &src->visrect );
167 /* nulldrv fallback implementation using StretchDIBits */
168 BOOL CDECL nulldrv_StretchBlt( PHYSDEV dst_dev, INT xDst, INT yDst, INT widthDst, INT heightDst,
169 PHYSDEV src_dev, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
172 DC *dc = get_nulldrv_dc( dst_dev );
174 BITMAPINFOHEADER info_hdr;
180 /* make sure we have a real implementation for StretchDIBits */
181 if (GET_DC_PHYSDEV( dc, pStretchDIBits ) == dst_dev) return 0;
185 pts[1].x = xSrc + widthSrc;
186 pts[1].y = ySrc + heightSrc;
187 LPtoDP( src_dev->hdc, pts, 2 );
190 widthSrc = pts[1].x - pts[0].x;
191 heightSrc = pts[1].y - pts[0].y;
193 if (GetObjectType( src_dev->hdc ) != OBJ_MEMDC) return FALSE;
194 if (!GetObjectW( GetCurrentObject( src_dev->hdc, OBJ_BITMAP ), sizeof(bm), &bm )) return FALSE;
196 info_hdr.biSize = sizeof(info_hdr);
197 info_hdr.biWidth = bm.bmWidth;
198 info_hdr.biHeight = bm.bmHeight;
199 info_hdr.biPlanes = 1;
200 info_hdr.biBitCount = 32;
201 info_hdr.biCompression = BI_RGB;
202 info_hdr.biSizeImage = 0;
203 info_hdr.biXPelsPerMeter = 0;
204 info_hdr.biYPelsPerMeter = 0;
205 info_hdr.biClrUsed = 0;
206 info_hdr.biClrImportant = 0;
208 if (!(bits = HeapAlloc(GetProcessHeap(), 0, bm.bmHeight * bm.bmWidth * 4)))
211 /* Select out the src bitmap before calling GetDIBits */
212 hbm = SelectObject( src_dev->hdc, GetStockObject(DEFAULT_BITMAP) );
213 lines = GetDIBits( src_dev->hdc, hbm, 0, bm.bmHeight, bits, (BITMAPINFO*)&info_hdr, DIB_RGB_COLORS );
214 SelectObject( src_dev->hdc, hbm );
216 if (lines) lines = StretchDIBits( dst_dev->hdc, xDst, yDst, widthDst, heightDst,
217 xSrc, bm.bmHeight - heightSrc - ySrc, widthSrc, heightSrc,
218 bits, (BITMAPINFO*)&info_hdr, DIB_RGB_COLORS, rop );
219 HeapFree( GetProcessHeap(), 0, bits );
220 return (lines == heightSrc);
223 /***********************************************************************
226 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
231 TRACE("%p %d,%d %dx%d %06x\n", hdc, left, top, width, height, rop );
233 if (rop_uses_src( rop )) return FALSE;
234 if ((dc = get_dc_ptr( hdc )))
236 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
238 bRet = physdev->funcs->pPatBlt( physdev, left, top, width, height, rop );
239 release_dc_ptr( dc );
245 /***********************************************************************
248 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
249 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
251 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
252 else return StretchBlt( hdcDst, xDst, yDst, width, height,
253 hdcSrc, xSrc, ySrc, width, height, rop );
257 /***********************************************************************
258 * StretchBlt (GDI32.@)
260 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
261 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
266 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
268 TRACE("%p %d,%d %dx%d -> %p %d,%d %dx%d rop=%06x\n",
269 hdcSrc, xSrc, ySrc, widthSrc, heightSrc,
270 hdcDst, xDst, yDst, widthDst, heightDst, rop );
272 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
274 if ((dcSrc = get_dc_ptr( hdcSrc )))
276 struct bitblt_coords src, dst;
277 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
278 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
285 src.log_width = widthSrc;
286 src.log_height = heightSrc;
287 src.layout = dcSrc->layout;
290 dst.log_width = widthDst;
291 dst.log_height = heightDst;
292 dst.layout = dcDst->layout;
293 if (rop & NOMIRRORBITMAP)
295 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
296 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
297 rop &= ~NOMIRRORBITMAP;
299 get_vis_rectangles( dcDst, &dst, dcSrc, &src );
300 ret = dst_dev->funcs->pStretchBlt( dst_dev, xDst, yDst, widthDst, heightDst,
301 src_dev, xSrc, ySrc, widthSrc, heightSrc, rop );
302 release_dc_ptr( dcSrc );
304 release_dc_ptr( dcDst );
308 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
309 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
311 /***********************************************************************
314 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
315 INT nWidth, INT nHeight, HDC hdcSrc,
316 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
317 INT xMask, INT yMask, DWORD dwRop)
319 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
321 HBRUSH hbrMask, hbrDst, hbrTmp;
323 static const DWORD ROP3Table[256] =
325 0x00000042, 0x00010289,
326 0x00020C89, 0x000300AA,
327 0x00040C88, 0x000500A9,
328 0x00060865, 0x000702C5,
329 0x00080F08, 0x00090245,
330 0x000A0329, 0x000B0B2A,
331 0x000C0324, 0x000D0B25,
332 0x000E08A5, 0x000F0001,
333 0x00100C85, 0x001100A6,
334 0x00120868, 0x001302C8,
335 0x00140869, 0x001502C9,
336 0x00165CCA, 0x00171D54,
337 0x00180D59, 0x00191CC8,
338 0x001A06C5, 0x001B0768,
339 0x001C06CA, 0x001D0766,
340 0x001E01A5, 0x001F0385,
341 0x00200F09, 0x00210248,
342 0x00220326, 0x00230B24,
343 0x00240D55, 0x00251CC5,
344 0x002606C8, 0x00271868,
345 0x00280369, 0x002916CA,
346 0x002A0CC9, 0x002B1D58,
347 0x002C0784, 0x002D060A,
348 0x002E064A, 0x002F0E2A,
349 0x0030032A, 0x00310B28,
350 0x00320688, 0x00330008,
351 0x003406C4, 0x00351864,
352 0x003601A8, 0x00370388,
353 0x0038078A, 0x00390604,
354 0x003A0644, 0x003B0E24,
355 0x003C004A, 0x003D18A4,
356 0x003E1B24, 0x003F00EA,
357 0x00400F0A, 0x00410249,
358 0x00420D5D, 0x00431CC4,
359 0x00440328, 0x00450B29,
360 0x004606C6, 0x0047076A,
361 0x00480368, 0x004916C5,
362 0x004A0789, 0x004B0605,
363 0x004C0CC8, 0x004D1954,
364 0x004E0645, 0x004F0E25,
365 0x00500325, 0x00510B26,
366 0x005206C9, 0x00530764,
367 0x005408A9, 0x00550009,
368 0x005601A9, 0x00570389,
369 0x00580785, 0x00590609,
370 0x005A0049, 0x005B18A9,
371 0x005C0649, 0x005D0E29,
372 0x005E1B29, 0x005F00E9,
373 0x00600365, 0x006116C6,
374 0x00620786, 0x00630608,
375 0x00640788, 0x00650606,
376 0x00660046, 0x006718A8,
377 0x006858A6, 0x00690145,
378 0x006A01E9, 0x006B178A,
379 0x006C01E8, 0x006D1785,
380 0x006E1E28, 0x006F0C65,
381 0x00700CC5, 0x00711D5C,
382 0x00720648, 0x00730E28,
383 0x00740646, 0x00750E26,
384 0x00761B28, 0x007700E6,
385 0x007801E5, 0x00791786,
386 0x007A1E29, 0x007B0C68,
387 0x007C1E24, 0x007D0C69,
388 0x007E0955, 0x007F03C9,
389 0x008003E9, 0x00810975,
390 0x00820C49, 0x00831E04,
391 0x00840C48, 0x00851E05,
392 0x008617A6, 0x008701C5,
393 0x008800C6, 0x00891B08,
394 0x008A0E06, 0x008B0666,
395 0x008C0E08, 0x008D0668,
396 0x008E1D7C, 0x008F0CE5,
397 0x00900C45, 0x00911E08,
398 0x009217A9, 0x009301C4,
399 0x009417AA, 0x009501C9,
400 0x00960169, 0x0097588A,
401 0x00981888, 0x00990066,
402 0x009A0709, 0x009B07A8,
403 0x009C0704, 0x009D07A6,
404 0x009E16E6, 0x009F0345,
405 0x00A000C9, 0x00A11B05,
406 0x00A20E09, 0x00A30669,
407 0x00A41885, 0x00A50065,
408 0x00A60706, 0x00A707A5,
409 0x00A803A9, 0x00A90189,
410 0x00AA0029, 0x00AB0889,
411 0x00AC0744, 0x00AD06E9,
412 0x00AE0B06, 0x00AF0229,
413 0x00B00E05, 0x00B10665,
414 0x00B21974, 0x00B30CE8,
415 0x00B4070A, 0x00B507A9,
416 0x00B616E9, 0x00B70348,
417 0x00B8074A, 0x00B906E6,
418 0x00BA0B09, 0x00BB0226,
419 0x00BC1CE4, 0x00BD0D7D,
420 0x00BE0269, 0x00BF08C9,
421 0x00C000CA, 0x00C11B04,
422 0x00C21884, 0x00C3006A,
423 0x00C40E04, 0x00C50664,
424 0x00C60708, 0x00C707AA,
425 0x00C803A8, 0x00C90184,
426 0x00CA0749, 0x00CB06E4,
427 0x00CC0020, 0x00CD0888,
428 0x00CE0B08, 0x00CF0224,
429 0x00D00E0A, 0x00D1066A,
430 0x00D20705, 0x00D307A4,
431 0x00D41D78, 0x00D50CE9,
432 0x00D616EA, 0x00D70349,
433 0x00D80745, 0x00D906E8,
434 0x00DA1CE9, 0x00DB0D75,
435 0x00DC0B04, 0x00DD0228,
436 0x00DE0268, 0x00DF08C8,
437 0x00E003A5, 0x00E10185,
438 0x00E20746, 0x00E306EA,
439 0x00E40748, 0x00E506E5,
440 0x00E61CE8, 0x00E70D79,
441 0x00E81D74, 0x00E95CE6,
442 0x00EA02E9, 0x00EB0849,
443 0x00EC02E8, 0x00ED0848,
444 0x00EE0086, 0x00EF0A08,
445 0x00F00021, 0x00F10885,
446 0x00F20B05, 0x00F3022A,
447 0x00F40B0A, 0x00F50225,
448 0x00F60265, 0x00F708C5,
449 0x00F802E5, 0x00F90845,
450 0x00FA0089, 0x00FB0A09,
451 0x00FC008A, 0x00FD0A0A,
452 0x00FE02A9, 0x00FF0062,
456 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
458 hbrMask = CreatePatternBrush(hbmMask);
459 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
462 hDC1 = CreateCompatibleDC(hdcDest);
463 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
464 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
466 /* draw using bkgnd rop */
467 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
468 hbrTmp = SelectObject(hDC1, hbrDst);
469 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
470 SelectObject(hDC1, hbrTmp);
473 hDC2 = CreateCompatibleDC(hdcDest);
474 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
475 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
477 /* draw using foregnd rop */
478 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
479 hbrTmp = SelectObject(hDC2, hbrDst);
480 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
482 /* combine both using the mask as a pattern brush */
483 SelectObject(hDC2, hbrMask);
484 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
485 SelectObject(hDC2, hbrTmp);
488 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
490 /* restore all objects */
491 SelectObject(hdcDest, hbrDst);
492 SelectObject(hDC1, hOldBitmap1);
493 SelectObject(hDC2, hOldBitmap2);
495 /* delete all temp objects */
496 DeleteObject(hBitmap1);
497 DeleteObject(hBitmap2);
498 DeleteObject(hbrMask);
506 /******************************************************************************
507 * GdiTransparentBlt [GDI32.@]
509 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
510 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
518 HBITMAP bmpMask = NULL;
519 HBITMAP oldMask = NULL;
520 COLORREF oldBackground;
521 COLORREF oldForeground;
524 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
525 TRACE("Cannot mirror\n");
529 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
530 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
533 oldStretchMode = GetStretchBltMode(hdcSrc);
534 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
535 SetStretchBltMode(hdcSrc, COLORONCOLOR);
536 hdcWork = CreateCompatibleDC(hdcDest);
537 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
538 oldWork = SelectObject(hdcWork, bmpWork);
539 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
540 TRACE("Failed to stretch\n");
543 SetBkColor(hdcWork, crTransparent);
546 hdcMask = CreateCompatibleDC(hdcDest);
547 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
548 oldMask = SelectObject(hdcMask, bmpMask);
549 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
550 TRACE("Failed to create mask\n");
554 /* Replace transparent color with black */
555 SetBkColor(hdcWork, RGB(0,0,0));
556 SetTextColor(hdcWork, RGB(255,255,255));
557 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
558 TRACE("Failed to mask out background\n");
562 /* Replace non-transparent area on destination with black */
563 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
564 TRACE("Failed to clear destination area\n");
569 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
570 TRACE("Failed to paint image\n");
576 SetStretchBltMode(hdcSrc, oldStretchMode);
577 SetBkColor(hdcDest, oldBackground);
578 SetTextColor(hdcDest, oldForeground);
580 SelectObject(hdcWork, oldWork);
583 if(bmpWork) DeleteObject(bmpWork);
585 SelectObject(hdcMask, oldMask);
588 if(bmpMask) DeleteObject(bmpMask);
592 /******************************************************************************
593 * GdiAlphaBlend [GDI32.@]
595 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
596 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
597 BLENDFUNCTION blendFunction)
602 TRACE( "%p %d,%d %dx%d -> %p %d,%d %dx%d op=%02x flags=%02x srcconstalpha=%02x alphafmt=%02x\n",
603 hdcSrc, xSrc, ySrc, widthSrc, heightSrc, hdcDst, xDst, yDst, widthDst, heightDst,
604 blendFunction.BlendOp, blendFunction.BlendFlags,
605 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
607 dcSrc = get_dc_ptr( hdcSrc );
608 if (!dcSrc) return FALSE;
610 if ((dcDst = get_dc_ptr( hdcDst )))
612 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
613 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
616 ret = dst_dev->funcs->pAlphaBlend( dst_dev, xDst, yDst, widthDst, heightDst,
617 src_dev, xSrc, ySrc, widthSrc, heightSrc, blendFunction );
618 release_dc_ptr( dcDst );
620 release_dc_ptr( dcSrc );
624 /*********************************************************************
628 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
629 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
630 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
633 /* parallelogram coords */
642 /* save actual mode, set GM_ADVANCED */
643 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
647 memcpy(plg,lpPoint,sizeof(POINT)*3);
650 rect[1].x = nXSrc + nWidth;
653 rect[2].y = nYSrc + nHeight;
654 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
656 det = rect[1].x*(rect[2].y - rect[0].y) - rect[2].x*(rect[1].y - rect[0].y) - rect[0].x*(rect[2].y - rect[1].y);
658 if (fabs(det) < 1e-5)
660 SetGraphicsMode(hdcDest,oldgMode);
664 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
665 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
668 xf.eM11 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;
669 xf.eM21 = (rect[1].x*(plg[2].x - plg[0].x) - rect[2].x*(plg[1].x - plg[0].x) - rect[0].x*(plg[2].x - plg[1].x)) / det;
670 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
671 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
672 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
676 xf.eM12 = (plg[1].y*(rect[2].y - rect[0].y) - plg[2].y*(rect[1].y - rect[0].y) - plg[0].y*(rect[2].y - rect[1].y)) / det;
677 xf.eM22 = (plg[1].x*(rect[2].y - rect[0].y) - plg[2].x*(rect[1].y - rect[0].y) - plg[0].x*(rect[2].y - rect[1].y)) / det;
678 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
679 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
680 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
683 GetWorldTransform(hdcSrc,&SrcXf);
684 CombineTransform(&xf,&xf,&SrcXf);
686 /* save actual dest transform */
687 GetWorldTransform(hdcDest,&oldDestXf);
689 SetWorldTransform(hdcDest,&xf);
690 /* now destination and source DCs use same coords */
691 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
695 /* restore dest DC */
696 SetWorldTransform(hdcDest,&oldDestXf);
697 SetGraphicsMode(hdcDest,oldgMode);