gdi32: Allow the PutImage entry point to optionally support stretching.
[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 BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
51                                 DC *dc_src, struct bitblt_coords *src )
52 {
53     RECT rect, clip;
54
55     /* get the destination visible rectangle */
56
57     rect.left   = dst->log_x;
58     rect.top    = dst->log_y;
59     rect.right  = dst->log_x + dst->log_width;
60     rect.bottom = dst->log_y + dst->log_height;
61     LPtoDP( dc_dst->hSelf, (POINT *)&rect, 2 );
62     dst->x      = rect.left;
63     dst->y      = rect.top;
64     dst->width  = rect.right - rect.left;
65     dst->height = rect.bottom - rect.top;
66     if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
67     {
68         swap_ints( &rect.left, &rect.right );
69         dst->x = rect.left;
70         dst->width = rect.right - rect.left;
71     }
72     if (rect.left > rect.right) { swap_ints( &rect.left, &rect.right ); rect.left++; rect.right++; }
73     if (rect.top > rect.bottom) { swap_ints( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
74
75     if (get_clip_box( dc_dst, &clip ))
76         intersect_rect( &dst->visrect, &rect, &clip );
77     else
78         dst->visrect = rect;
79
80     /* get the source visible rectangle */
81
82     if (!src) return !is_rect_empty( &dst->visrect );
83
84     rect.left   = src->log_x;
85     rect.top    = src->log_y;
86     rect.right  = src->log_x + src->log_width;
87     rect.bottom = src->log_y + src->log_height;
88     LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
89     src->x      = rect.left;
90     src->y      = rect.top;
91     src->width  = rect.right - rect.left;
92     src->height = rect.bottom - rect.top;
93     if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
94     {
95         swap_ints( &rect.left, &rect.right );
96         src->x = rect.left;
97         src->width = rect.right - rect.left;
98     }
99     if (rect.left > rect.right) { swap_ints( &rect.left, &rect.right ); rect.left++; rect.right++; }
100     if (rect.top > rect.bottom) { swap_ints( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; }
101
102     /* source is not clipped */
103     if (dc_src->header.type == OBJ_MEMDC)
104         intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
105     else
106         src->visrect = rect;  /* FIXME: clip to device size */
107
108     if (is_rect_empty( &src->visrect )) return FALSE;
109     if (is_rect_empty( &dst->visrect )) return FALSE;
110
111     /* intersect the rectangles */
112
113     if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
114     {
115         offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
116         intersect_rect( &rect, &src->visrect, &dst->visrect );
117         src->visrect = dst->visrect = rect;
118         offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
119     }
120     else  /* stretching */
121     {
122         /* map source rectangle into destination coordinates */
123         rect.left   = dst->x + (src->visrect.left - src->x)*dst->width/src->width;
124         rect.top    = dst->y + (src->visrect.top - src->y)*dst->height/src->height;
125         rect.right  = dst->x + (src->visrect.right - src->x)*dst->width/src->width;
126         rect.bottom = dst->y + (src->visrect.bottom - src->y)*dst->height/src->height;
127         if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
128         if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
129
130         /* avoid rounding errors */
131         rect.left--;
132         rect.top--;
133         rect.right++;
134         rect.bottom++;
135         if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
136
137         /* map destination rectangle back to source coordinates */
138         rect.left   = src->x + (dst->visrect.left - dst->x)*src->width/dst->width;
139         rect.top    = src->y + (dst->visrect.top - dst->y)*src->height/dst->height;
140         rect.right  = src->x + (dst->visrect.right - dst->x)*src->width/dst->width;
141         rect.bottom = src->y + (dst->visrect.bottom - dst->y)*src->height/dst->height;
142         if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
143         if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
144
145         /* avoid rounding errors */
146         rect.left--;
147         rect.top--;
148         rect.right++;
149         rect.bottom++;
150         if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
151     }
152     return TRUE;
153 }
154
155 static void free_heap_bits( struct gdi_image_bits *bits )
156 {
157     HeapFree( GetProcessHeap(), 0, bits->ptr );
158 }
159
160 /* nulldrv fallback implementation using StretchDIBits */
161 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
162                          PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
163 {
164     DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
165     char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
166     char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
167     BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
168     BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
169     DWORD err;
170     struct gdi_image_bits bits;
171     BITMAP bm;
172     HBITMAP hbm;
173     LPVOID ptr;
174     INT lines;
175
176     /* make sure we have a real implementation for StretchDIBits */
177     if (GET_DC_PHYSDEV( dc_dst, pStretchDIBits ) == dst_dev) goto try_get_image;
178
179     if (GetObjectType( src_dev->hdc ) != OBJ_MEMDC) return FALSE;
180     if (!GetObjectW( GetCurrentObject( src_dev->hdc, OBJ_BITMAP ), sizeof(bm), &bm )) return FALSE;
181
182     src_info->bmiHeader.biSize = sizeof(src_info->bmiHeader);
183     src_info->bmiHeader.biWidth = bm.bmWidth;
184     src_info->bmiHeader.biHeight = bm.bmHeight;
185     src_info->bmiHeader.biPlanes = 1;
186     src_info->bmiHeader.biBitCount = 32;
187     src_info->bmiHeader.biCompression = BI_RGB;
188     src_info->bmiHeader.biSizeImage = 0;
189     src_info->bmiHeader.biXPelsPerMeter = 0;
190     src_info->bmiHeader.biYPelsPerMeter = 0;
191     src_info->bmiHeader.biClrUsed = 0;
192     src_info->bmiHeader.biClrImportant = 0;
193
194     if (!(ptr = HeapAlloc(GetProcessHeap(), 0, bm.bmHeight * bm.bmWidth * 4)))
195         return FALSE;
196
197     /* Select out the src bitmap before calling GetDIBits */
198     hbm = SelectObject( src_dev->hdc, GetStockObject(DEFAULT_BITMAP) );
199     lines = GetDIBits( src_dev->hdc, hbm, 0, bm.bmHeight, ptr, src_info, DIB_RGB_COLORS );
200     SelectObject( src_dev->hdc, hbm );
201
202     if (lines) lines = StretchDIBits( dst_dev->hdc, dst->log_x, dst->log_y, dst->log_width, dst->log_height,
203                                       src->x, bm.bmHeight - src->height - src->y, src->width, src->height,
204                                       ptr, src_info, DIB_RGB_COLORS, rop );
205     HeapFree( GetProcessHeap(), 0, ptr );
206     return (lines == src->height);
207
208 try_get_image:
209
210     if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
211     src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
212     err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
213     release_dc_ptr( dc_src );
214     if (err) return FALSE;
215
216     dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
217     memcpy( dst_info, src_info, FIELD_OFFSET( BITMAPINFO, bmiColors[256] ));
218     err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
219     if (err == ERROR_BAD_FORMAT)
220     {
221         /* 1-bpp source without a color table uses the destination DC colors */
222         if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
223         {
224             COLORREF color = GetTextColor( dst_dev->hdc );
225             src_info->bmiColors[0].rgbRed      = GetRValue( color );
226             src_info->bmiColors[0].rgbGreen    = GetGValue( color );
227             src_info->bmiColors[0].rgbBlue     = GetBValue( color );
228             src_info->bmiColors[0].rgbReserved = 0;
229             color = GetBkColor( dst_dev->hdc );
230             src_info->bmiColors[1].rgbRed      = GetRValue( color );
231             src_info->bmiColors[1].rgbGreen    = GetGValue( color );
232             src_info->bmiColors[1].rgbBlue     = GetBValue( color );
233             src_info->bmiColors[1].rgbReserved = 0;
234             src_info->bmiHeader.biClrUsed = 2;
235         }
236
237         /* 1-bpp destination without a color table requires a fake 1-entry table
238          * that contains only the background color */
239         if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
240         {
241             COLORREF color = GetBkColor( src_dev->hdc );
242             dst_info->bmiColors[0].rgbRed      = GetRValue( color );
243             dst_info->bmiColors[0].rgbGreen    = GetGValue( color );
244             dst_info->bmiColors[0].rgbBlue     = GetBValue( color );
245             dst_info->bmiColors[0].rgbReserved = 0;
246             dst_info->bmiHeader.biClrUsed = 1;
247         }
248
249         dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
250         if ((ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
251         {
252             err = convert_bitmapinfo( src_info, bits.ptr, &src->visrect, dst_info, ptr );
253             if (bits.free) bits.free( &bits );
254             bits.ptr = ptr;
255             bits.is_copy = TRUE;
256             bits.offset = 0;
257             bits.free = free_heap_bits;
258             if (!err)
259             {
260                 /* get rid of the fake 1-bpp table */
261                 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
262                 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
263             }
264         }
265         else err = ERROR_OUTOFMEMORY;
266     }
267
268     if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
269         ((src->width != dst->width) || (src->height != dst->height)))
270     {
271         FIXME( "should stretch %dx%d -> %dx%d\n",
272                src->width, src->height, dst->width, dst->height );
273     }
274
275     if (bits.free) bits.free( &bits );
276     return !err;
277 }
278
279 /***********************************************************************
280  *           PatBlt    (GDI32.@)
281  */
282 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
283 {
284     DC * dc;
285     BOOL ret = FALSE;
286
287     if (rop_uses_src( rop )) return FALSE;
288     if ((dc = get_dc_ptr( hdc )))
289     {
290         struct bitblt_coords dst;
291         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
292
293         update_dc( dc );
294
295         dst.log_x      = left;
296         dst.log_y      = top;
297         dst.log_width  = width;
298         dst.log_height = height;
299         dst.layout     = dc->layout;
300         if (rop & NOMIRRORBITMAP)
301         {
302             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
303             rop &= ~NOMIRRORBITMAP;
304         }
305         ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
306
307         TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s  rop=%06x\n",
308               hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
309               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
310
311         if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
312
313         release_dc_ptr( dc );
314     }
315     return ret;
316 }
317
318
319 /***********************************************************************
320  *           BitBlt    (GDI32.@)
321  */
322 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
323                     INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
324 {
325     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
326     else return StretchBlt( hdcDst, xDst, yDst, width, height,
327                             hdcSrc, xSrc, ySrc, width, height, rop );
328 }
329
330
331 /***********************************************************************
332  *           StretchBlt    (GDI32.@)
333  */
334 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
335                         HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
336 {
337     BOOL ret = FALSE;
338     DC *dcDst, *dcSrc;
339
340     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
341
342     if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
343
344     if ((dcSrc = get_dc_ptr( hdcSrc )))
345     {
346         struct bitblt_coords src, dst;
347         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
348         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
349
350         update_dc( dcSrc );
351         update_dc( dcDst );
352
353         src.log_x      = xSrc;
354         src.log_y      = ySrc;
355         src.log_width  = widthSrc;
356         src.log_height = heightSrc;
357         src.layout     = dcSrc->layout;
358         dst.log_x      = xDst;
359         dst.log_y      = yDst;
360         dst.log_width  = widthDst;
361         dst.log_height = heightDst;
362         dst.layout     = dcDst->layout;
363         if (rop & NOMIRRORBITMAP)
364         {
365             src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
366             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
367             rop &= ~NOMIRRORBITMAP;
368         }
369         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
370
371         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",
372               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
373               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
374               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
375               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
376
377         if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
378         release_dc_ptr( dcSrc );
379     }
380     release_dc_ptr( dcDst );
381     return ret;
382 }
383
384 #define FRGND_ROP3(ROP4)        ((ROP4) & 0x00FFFFFF)
385 #define BKGND_ROP3(ROP4)        (ROP3Table[((ROP4)>>24) & 0xFF])
386
387 /***********************************************************************
388  *           MaskBlt [GDI32.@]
389  */
390 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
391                         INT nWidth, INT nHeight, HDC hdcSrc,
392                         INT nXSrc, INT nYSrc, HBITMAP hbmMask,
393                         INT xMask, INT yMask, DWORD dwRop)
394 {
395     HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
396     HDC hDC1, hDC2;
397     HBRUSH hbrMask, hbrDst, hbrTmp;
398
399     static const DWORD ROP3Table[256] = 
400     {
401         0x00000042, 0x00010289,
402         0x00020C89, 0x000300AA,
403         0x00040C88, 0x000500A9,
404         0x00060865, 0x000702C5,
405         0x00080F08, 0x00090245,
406         0x000A0329, 0x000B0B2A,
407         0x000C0324, 0x000D0B25,
408         0x000E08A5, 0x000F0001,
409         0x00100C85, 0x001100A6,
410         0x00120868, 0x001302C8,
411         0x00140869, 0x001502C9,
412         0x00165CCA, 0x00171D54,
413         0x00180D59, 0x00191CC8,
414         0x001A06C5, 0x001B0768,
415         0x001C06CA, 0x001D0766,
416         0x001E01A5, 0x001F0385,
417         0x00200F09, 0x00210248,
418         0x00220326, 0x00230B24,
419         0x00240D55, 0x00251CC5,
420         0x002606C8, 0x00271868,
421         0x00280369, 0x002916CA,
422         0x002A0CC9, 0x002B1D58,
423         0x002C0784, 0x002D060A,
424         0x002E064A, 0x002F0E2A,
425         0x0030032A, 0x00310B28,
426         0x00320688, 0x00330008,
427         0x003406C4, 0x00351864,
428         0x003601A8, 0x00370388,
429         0x0038078A, 0x00390604,
430         0x003A0644, 0x003B0E24,
431         0x003C004A, 0x003D18A4,
432         0x003E1B24, 0x003F00EA,
433         0x00400F0A, 0x00410249,
434         0x00420D5D, 0x00431CC4,
435         0x00440328, 0x00450B29,
436         0x004606C6, 0x0047076A,
437         0x00480368, 0x004916C5,
438         0x004A0789, 0x004B0605,
439         0x004C0CC8, 0x004D1954,
440         0x004E0645, 0x004F0E25,
441         0x00500325, 0x00510B26,
442         0x005206C9, 0x00530764,
443         0x005408A9, 0x00550009,
444         0x005601A9, 0x00570389,
445         0x00580785, 0x00590609,
446         0x005A0049, 0x005B18A9,
447         0x005C0649, 0x005D0E29,
448         0x005E1B29, 0x005F00E9,
449         0x00600365, 0x006116C6,
450         0x00620786, 0x00630608,
451         0x00640788, 0x00650606,
452         0x00660046, 0x006718A8,
453         0x006858A6, 0x00690145,
454         0x006A01E9, 0x006B178A,
455         0x006C01E8, 0x006D1785,
456         0x006E1E28, 0x006F0C65,
457         0x00700CC5, 0x00711D5C,
458         0x00720648, 0x00730E28,
459         0x00740646, 0x00750E26,
460         0x00761B28, 0x007700E6,
461         0x007801E5, 0x00791786,
462         0x007A1E29, 0x007B0C68,
463         0x007C1E24, 0x007D0C69,
464         0x007E0955, 0x007F03C9,
465         0x008003E9, 0x00810975,
466         0x00820C49, 0x00831E04,
467         0x00840C48, 0x00851E05,
468         0x008617A6, 0x008701C5,
469         0x008800C6, 0x00891B08,
470         0x008A0E06, 0x008B0666,
471         0x008C0E08, 0x008D0668,
472         0x008E1D7C, 0x008F0CE5,
473         0x00900C45, 0x00911E08,
474         0x009217A9, 0x009301C4,
475         0x009417AA, 0x009501C9,
476         0x00960169, 0x0097588A,
477         0x00981888, 0x00990066,
478         0x009A0709, 0x009B07A8,
479         0x009C0704, 0x009D07A6,
480         0x009E16E6, 0x009F0345,
481         0x00A000C9, 0x00A11B05,
482         0x00A20E09, 0x00A30669,
483         0x00A41885, 0x00A50065,
484         0x00A60706, 0x00A707A5,
485         0x00A803A9, 0x00A90189,
486         0x00AA0029, 0x00AB0889,
487         0x00AC0744, 0x00AD06E9,
488         0x00AE0B06, 0x00AF0229,
489         0x00B00E05, 0x00B10665,
490         0x00B21974, 0x00B30CE8,
491         0x00B4070A, 0x00B507A9,
492         0x00B616E9, 0x00B70348,
493         0x00B8074A, 0x00B906E6,
494         0x00BA0B09, 0x00BB0226,
495         0x00BC1CE4, 0x00BD0D7D,
496         0x00BE0269, 0x00BF08C9,
497         0x00C000CA, 0x00C11B04,
498         0x00C21884, 0x00C3006A,
499         0x00C40E04, 0x00C50664,
500         0x00C60708, 0x00C707AA,
501         0x00C803A8, 0x00C90184,
502         0x00CA0749, 0x00CB06E4,
503         0x00CC0020, 0x00CD0888,
504         0x00CE0B08, 0x00CF0224,
505         0x00D00E0A, 0x00D1066A,
506         0x00D20705, 0x00D307A4,
507         0x00D41D78, 0x00D50CE9,
508         0x00D616EA, 0x00D70349,
509         0x00D80745, 0x00D906E8,
510         0x00DA1CE9, 0x00DB0D75,
511         0x00DC0B04, 0x00DD0228,
512         0x00DE0268, 0x00DF08C8,
513         0x00E003A5, 0x00E10185,
514         0x00E20746, 0x00E306EA,
515         0x00E40748, 0x00E506E5,
516         0x00E61CE8, 0x00E70D79,
517         0x00E81D74, 0x00E95CE6,
518         0x00EA02E9, 0x00EB0849,
519         0x00EC02E8, 0x00ED0848,
520         0x00EE0086, 0x00EF0A08,
521         0x00F00021, 0x00F10885,
522         0x00F20B05, 0x00F3022A,
523         0x00F40B0A, 0x00F50225,
524         0x00F60265, 0x00F708C5,
525         0x00F802E5, 0x00F90845,
526         0x00FA0089, 0x00FB0A09,
527         0x00FC008A, 0x00FD0A0A,
528         0x00FE02A9, 0x00FF0062,
529     };
530
531     if (!hbmMask)
532         return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
533
534     hbrMask = CreatePatternBrush(hbmMask);
535     hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
536
537     /* make bitmap */
538     hDC1 = CreateCompatibleDC(hdcDest);
539     hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
540     hOldBitmap1 = SelectObject(hDC1, hBitmap1);
541
542     /* draw using bkgnd rop */
543     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
544     hbrTmp = SelectObject(hDC1, hbrDst);
545     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
546     SelectObject(hDC1, hbrTmp);
547
548     /* make bitmap */
549     hDC2 = CreateCompatibleDC(hdcDest);
550     hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
551     hOldBitmap2 = SelectObject(hDC2, hBitmap2);
552
553     /* draw using foregnd rop */
554     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
555     hbrTmp = SelectObject(hDC2, hbrDst);
556     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
557
558     /* combine both using the mask as a pattern brush */
559     SelectObject(hDC2, hbrMask);
560     BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */ 
561     SelectObject(hDC2, hbrTmp);
562
563     /* blit to dst */
564     BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
565
566     /* restore all objects */
567     SelectObject(hdcDest, hbrDst);
568     SelectObject(hDC1, hOldBitmap1);
569     SelectObject(hDC2, hOldBitmap2);
570
571     /* delete all temp objects */
572     DeleteObject(hBitmap1);
573     DeleteObject(hBitmap2);
574     DeleteObject(hbrMask);
575
576     DeleteDC(hDC1);
577     DeleteDC(hDC2);
578
579     return TRUE;
580 }
581
582 /******************************************************************************
583  *           GdiTransparentBlt [GDI32.@]
584  */
585 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
586                             HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
587                             UINT crTransparent )
588 {
589     BOOL ret = FALSE;
590     HDC hdcWork;
591     HBITMAP bmpWork;
592     HGDIOBJ oldWork;
593     HDC hdcMask = NULL;
594     HBITMAP bmpMask = NULL;
595     HBITMAP oldMask = NULL;
596     COLORREF oldBackground;
597     COLORREF oldForeground;
598     int oldStretchMode;
599
600     if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
601         TRACE("Cannot mirror\n");
602         return FALSE;
603     }
604
605     oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
606     oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
607
608     /* Stretch bitmap */
609     oldStretchMode = GetStretchBltMode(hdcSrc);
610     if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
611         SetStretchBltMode(hdcSrc, COLORONCOLOR);
612     hdcWork = CreateCompatibleDC(hdcDest);
613     bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
614     oldWork = SelectObject(hdcWork, bmpWork);
615     if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
616         TRACE("Failed to stretch\n");
617         goto error;
618     }
619     SetBkColor(hdcWork, crTransparent);
620
621     /* Create mask */
622     hdcMask = CreateCompatibleDC(hdcDest);
623     bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
624     oldMask = SelectObject(hdcMask, bmpMask);
625     if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
626         TRACE("Failed to create mask\n");
627         goto error;
628     }
629
630     /* Replace transparent color with black */
631     SetBkColor(hdcWork, RGB(0,0,0));
632     SetTextColor(hdcWork, RGB(255,255,255));
633     if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
634         TRACE("Failed to mask out background\n");
635         goto error;
636     }
637
638     /* Replace non-transparent area on destination with black */
639     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
640         TRACE("Failed to clear destination area\n");
641         goto error;
642     }
643
644     /* Draw the image */
645     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
646         TRACE("Failed to paint image\n");
647         goto error;
648     }
649
650     ret = TRUE;
651 error:
652     SetStretchBltMode(hdcSrc, oldStretchMode);
653     SetBkColor(hdcDest, oldBackground);
654     SetTextColor(hdcDest, oldForeground);
655     if(hdcWork) {
656         SelectObject(hdcWork, oldWork);
657         DeleteDC(hdcWork);
658     }
659     if(bmpWork) DeleteObject(bmpWork);
660     if(hdcMask) {
661         SelectObject(hdcMask, oldMask);
662         DeleteDC(hdcMask);
663     }
664     if(bmpMask) DeleteObject(bmpMask);
665     return ret;
666 }
667
668 /******************************************************************************
669  *           GdiAlphaBlend [GDI32.@]
670  */
671 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
672                           HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
673                           BLENDFUNCTION blendFunction)
674 {
675     BOOL ret = FALSE;
676     DC *dcDst, *dcSrc;
677
678     dcSrc = get_dc_ptr( hdcSrc );
679     if (!dcSrc) return FALSE;
680
681     if ((dcDst = get_dc_ptr( hdcDst )))
682     {
683         struct bitblt_coords src, dst;
684         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
685         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
686
687         update_dc( dcSrc );
688         update_dc( dcDst );
689
690         src.log_x      = xSrc;
691         src.log_y      = ySrc;
692         src.log_width  = widthSrc;
693         src.log_height = heightSrc;
694         src.layout     = GetLayout( src_dev->hdc );
695         dst.log_x      = xDst;
696         dst.log_y      = yDst;
697         dst.log_width  = widthDst;
698         dst.log_height = heightDst;
699         dst.layout     = GetLayout( dst_dev->hdc );
700         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
701
702         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",
703               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
704               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
705               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
706               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
707               blendFunction.BlendOp, blendFunction.BlendFlags,
708               blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
709
710         if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
711         release_dc_ptr( dcDst );
712     }
713     release_dc_ptr( dcSrc );
714     return ret;
715 }
716
717 /*********************************************************************
718  *      PlgBlt [GDI32.@]
719  *
720  */
721 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
722                         HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
723                         INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
724 {
725     int oldgMode;
726     /* parallelogram coords */
727     POINT plg[3];
728     /* rect coords */
729     POINT rect[3];
730     XFORM xf;
731     XFORM SrcXf;
732     XFORM oldDestXf;
733     double det;
734
735     /* save actual mode, set GM_ADVANCED */
736     oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
737     if (oldgMode == 0)
738         return FALSE;
739
740     memcpy(plg,lpPoint,sizeof(POINT)*3);
741     rect[0].x = nXSrc;
742     rect[0].y = nYSrc;
743     rect[1].x = nXSrc + nWidth;
744     rect[1].y = nYSrc;
745     rect[2].x = nXSrc;
746     rect[2].y = nYSrc + nHeight;
747     /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
748     /* determinant */
749     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);
750
751     if (fabs(det) < 1e-5)
752     {
753         SetGraphicsMode(hdcDest,oldgMode);
754         return FALSE;
755     }
756
757     TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
758         hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
759
760     /* X components */
761     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;
762     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;
763     xf.eDx  = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
764                rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
765                rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
766                ) / det;
767
768     /* Y components */
769     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;
770     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;
771     xf.eDy  = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
772                rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
773                rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
774                ) / det;
775
776     GetWorldTransform(hdcSrc,&SrcXf);
777     CombineTransform(&xf,&xf,&SrcXf);
778
779     /* save actual dest transform */
780     GetWorldTransform(hdcDest,&oldDestXf);
781
782     SetWorldTransform(hdcDest,&xf);
783     /* now destination and source DCs use same coords */
784     MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
785             hdcSrc, nXSrc,nYSrc,
786             hbmMask,xMask,yMask,
787             SRCCOPY);
788     /* restore dest DC */
789     SetWorldTransform(hdcDest,&oldDestXf);
790     SetGraphicsMode(hdcDest,oldgMode);
791
792     return TRUE;
793 }