gdi32: Get rid of the offset in the gdi_image_bits structure now that we are passing...
[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.free = free_heap_bits;
257             if (!err)
258             {
259                 /* get rid of the fake 1-bpp table */
260                 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
261                 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
262             }
263         }
264         else err = ERROR_OUTOFMEMORY;
265     }
266
267     if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
268         ((src->width != dst->width) || (src->height != dst->height)))
269     {
270         FIXME( "should stretch %dx%d -> %dx%d\n",
271                src->width, src->height, dst->width, dst->height );
272     }
273
274     if (bits.free) bits.free( &bits );
275     return !err;
276 }
277
278 /***********************************************************************
279  *           PatBlt    (GDI32.@)
280  */
281 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
282 {
283     DC * dc;
284     BOOL ret = FALSE;
285
286     if (rop_uses_src( rop )) return FALSE;
287     if ((dc = get_dc_ptr( hdc )))
288     {
289         struct bitblt_coords dst;
290         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
291
292         update_dc( dc );
293
294         dst.log_x      = left;
295         dst.log_y      = top;
296         dst.log_width  = width;
297         dst.log_height = height;
298         dst.layout     = dc->layout;
299         if (rop & NOMIRRORBITMAP)
300         {
301             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
302             rop &= ~NOMIRRORBITMAP;
303         }
304         ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
305
306         TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s  rop=%06x\n",
307               hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
308               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
309
310         if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
311
312         release_dc_ptr( dc );
313     }
314     return ret;
315 }
316
317
318 /***********************************************************************
319  *           BitBlt    (GDI32.@)
320  */
321 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
322                     INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
323 {
324     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
325     else return StretchBlt( hdcDst, xDst, yDst, width, height,
326                             hdcSrc, xSrc, ySrc, width, height, rop );
327 }
328
329
330 /***********************************************************************
331  *           StretchBlt    (GDI32.@)
332  */
333 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
334                         HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
335 {
336     BOOL ret = FALSE;
337     DC *dcDst, *dcSrc;
338
339     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
340
341     if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
342
343     if ((dcSrc = get_dc_ptr( hdcSrc )))
344     {
345         struct bitblt_coords src, dst;
346         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
347         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
348
349         update_dc( dcSrc );
350         update_dc( dcDst );
351
352         src.log_x      = xSrc;
353         src.log_y      = ySrc;
354         src.log_width  = widthSrc;
355         src.log_height = heightSrc;
356         src.layout     = dcSrc->layout;
357         dst.log_x      = xDst;
358         dst.log_y      = yDst;
359         dst.log_width  = widthDst;
360         dst.log_height = heightDst;
361         dst.layout     = dcDst->layout;
362         if (rop & NOMIRRORBITMAP)
363         {
364             src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
365             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
366             rop &= ~NOMIRRORBITMAP;
367         }
368         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
369
370         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",
371               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
372               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
373               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
374               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
375
376         if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
377         release_dc_ptr( dcSrc );
378     }
379     release_dc_ptr( dcDst );
380     return ret;
381 }
382
383 #define FRGND_ROP3(ROP4)        ((ROP4) & 0x00FFFFFF)
384 #define BKGND_ROP3(ROP4)        (ROP3Table[((ROP4)>>24) & 0xFF])
385
386 /***********************************************************************
387  *           MaskBlt [GDI32.@]
388  */
389 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
390                         INT nWidth, INT nHeight, HDC hdcSrc,
391                         INT nXSrc, INT nYSrc, HBITMAP hbmMask,
392                         INT xMask, INT yMask, DWORD dwRop)
393 {
394     HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
395     HDC hDC1, hDC2;
396     HBRUSH hbrMask, hbrDst, hbrTmp;
397
398     static const DWORD ROP3Table[256] = 
399     {
400         0x00000042, 0x00010289,
401         0x00020C89, 0x000300AA,
402         0x00040C88, 0x000500A9,
403         0x00060865, 0x000702C5,
404         0x00080F08, 0x00090245,
405         0x000A0329, 0x000B0B2A,
406         0x000C0324, 0x000D0B25,
407         0x000E08A5, 0x000F0001,
408         0x00100C85, 0x001100A6,
409         0x00120868, 0x001302C8,
410         0x00140869, 0x001502C9,
411         0x00165CCA, 0x00171D54,
412         0x00180D59, 0x00191CC8,
413         0x001A06C5, 0x001B0768,
414         0x001C06CA, 0x001D0766,
415         0x001E01A5, 0x001F0385,
416         0x00200F09, 0x00210248,
417         0x00220326, 0x00230B24,
418         0x00240D55, 0x00251CC5,
419         0x002606C8, 0x00271868,
420         0x00280369, 0x002916CA,
421         0x002A0CC9, 0x002B1D58,
422         0x002C0784, 0x002D060A,
423         0x002E064A, 0x002F0E2A,
424         0x0030032A, 0x00310B28,
425         0x00320688, 0x00330008,
426         0x003406C4, 0x00351864,
427         0x003601A8, 0x00370388,
428         0x0038078A, 0x00390604,
429         0x003A0644, 0x003B0E24,
430         0x003C004A, 0x003D18A4,
431         0x003E1B24, 0x003F00EA,
432         0x00400F0A, 0x00410249,
433         0x00420D5D, 0x00431CC4,
434         0x00440328, 0x00450B29,
435         0x004606C6, 0x0047076A,
436         0x00480368, 0x004916C5,
437         0x004A0789, 0x004B0605,
438         0x004C0CC8, 0x004D1954,
439         0x004E0645, 0x004F0E25,
440         0x00500325, 0x00510B26,
441         0x005206C9, 0x00530764,
442         0x005408A9, 0x00550009,
443         0x005601A9, 0x00570389,
444         0x00580785, 0x00590609,
445         0x005A0049, 0x005B18A9,
446         0x005C0649, 0x005D0E29,
447         0x005E1B29, 0x005F00E9,
448         0x00600365, 0x006116C6,
449         0x00620786, 0x00630608,
450         0x00640788, 0x00650606,
451         0x00660046, 0x006718A8,
452         0x006858A6, 0x00690145,
453         0x006A01E9, 0x006B178A,
454         0x006C01E8, 0x006D1785,
455         0x006E1E28, 0x006F0C65,
456         0x00700CC5, 0x00711D5C,
457         0x00720648, 0x00730E28,
458         0x00740646, 0x00750E26,
459         0x00761B28, 0x007700E6,
460         0x007801E5, 0x00791786,
461         0x007A1E29, 0x007B0C68,
462         0x007C1E24, 0x007D0C69,
463         0x007E0955, 0x007F03C9,
464         0x008003E9, 0x00810975,
465         0x00820C49, 0x00831E04,
466         0x00840C48, 0x00851E05,
467         0x008617A6, 0x008701C5,
468         0x008800C6, 0x00891B08,
469         0x008A0E06, 0x008B0666,
470         0x008C0E08, 0x008D0668,
471         0x008E1D7C, 0x008F0CE5,
472         0x00900C45, 0x00911E08,
473         0x009217A9, 0x009301C4,
474         0x009417AA, 0x009501C9,
475         0x00960169, 0x0097588A,
476         0x00981888, 0x00990066,
477         0x009A0709, 0x009B07A8,
478         0x009C0704, 0x009D07A6,
479         0x009E16E6, 0x009F0345,
480         0x00A000C9, 0x00A11B05,
481         0x00A20E09, 0x00A30669,
482         0x00A41885, 0x00A50065,
483         0x00A60706, 0x00A707A5,
484         0x00A803A9, 0x00A90189,
485         0x00AA0029, 0x00AB0889,
486         0x00AC0744, 0x00AD06E9,
487         0x00AE0B06, 0x00AF0229,
488         0x00B00E05, 0x00B10665,
489         0x00B21974, 0x00B30CE8,
490         0x00B4070A, 0x00B507A9,
491         0x00B616E9, 0x00B70348,
492         0x00B8074A, 0x00B906E6,
493         0x00BA0B09, 0x00BB0226,
494         0x00BC1CE4, 0x00BD0D7D,
495         0x00BE0269, 0x00BF08C9,
496         0x00C000CA, 0x00C11B04,
497         0x00C21884, 0x00C3006A,
498         0x00C40E04, 0x00C50664,
499         0x00C60708, 0x00C707AA,
500         0x00C803A8, 0x00C90184,
501         0x00CA0749, 0x00CB06E4,
502         0x00CC0020, 0x00CD0888,
503         0x00CE0B08, 0x00CF0224,
504         0x00D00E0A, 0x00D1066A,
505         0x00D20705, 0x00D307A4,
506         0x00D41D78, 0x00D50CE9,
507         0x00D616EA, 0x00D70349,
508         0x00D80745, 0x00D906E8,
509         0x00DA1CE9, 0x00DB0D75,
510         0x00DC0B04, 0x00DD0228,
511         0x00DE0268, 0x00DF08C8,
512         0x00E003A5, 0x00E10185,
513         0x00E20746, 0x00E306EA,
514         0x00E40748, 0x00E506E5,
515         0x00E61CE8, 0x00E70D79,
516         0x00E81D74, 0x00E95CE6,
517         0x00EA02E9, 0x00EB0849,
518         0x00EC02E8, 0x00ED0848,
519         0x00EE0086, 0x00EF0A08,
520         0x00F00021, 0x00F10885,
521         0x00F20B05, 0x00F3022A,
522         0x00F40B0A, 0x00F50225,
523         0x00F60265, 0x00F708C5,
524         0x00F802E5, 0x00F90845,
525         0x00FA0089, 0x00FB0A09,
526         0x00FC008A, 0x00FD0A0A,
527         0x00FE02A9, 0x00FF0062,
528     };
529
530     if (!hbmMask)
531         return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
532
533     hbrMask = CreatePatternBrush(hbmMask);
534     hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
535
536     /* make bitmap */
537     hDC1 = CreateCompatibleDC(hdcDest);
538     hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
539     hOldBitmap1 = SelectObject(hDC1, hBitmap1);
540
541     /* draw using bkgnd rop */
542     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
543     hbrTmp = SelectObject(hDC1, hbrDst);
544     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
545     SelectObject(hDC1, hbrTmp);
546
547     /* make bitmap */
548     hDC2 = CreateCompatibleDC(hdcDest);
549     hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
550     hOldBitmap2 = SelectObject(hDC2, hBitmap2);
551
552     /* draw using foregnd rop */
553     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
554     hbrTmp = SelectObject(hDC2, hbrDst);
555     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
556
557     /* combine both using the mask as a pattern brush */
558     SelectObject(hDC2, hbrMask);
559     BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */ 
560     SelectObject(hDC2, hbrTmp);
561
562     /* blit to dst */
563     BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
564
565     /* restore all objects */
566     SelectObject(hdcDest, hbrDst);
567     SelectObject(hDC1, hOldBitmap1);
568     SelectObject(hDC2, hOldBitmap2);
569
570     /* delete all temp objects */
571     DeleteObject(hBitmap1);
572     DeleteObject(hBitmap2);
573     DeleteObject(hbrMask);
574
575     DeleteDC(hDC1);
576     DeleteDC(hDC2);
577
578     return TRUE;
579 }
580
581 /******************************************************************************
582  *           GdiTransparentBlt [GDI32.@]
583  */
584 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
585                             HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
586                             UINT crTransparent )
587 {
588     BOOL ret = FALSE;
589     HDC hdcWork;
590     HBITMAP bmpWork;
591     HGDIOBJ oldWork;
592     HDC hdcMask = NULL;
593     HBITMAP bmpMask = NULL;
594     HBITMAP oldMask = NULL;
595     COLORREF oldBackground;
596     COLORREF oldForeground;
597     int oldStretchMode;
598
599     if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
600         TRACE("Cannot mirror\n");
601         return FALSE;
602     }
603
604     oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
605     oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
606
607     /* Stretch bitmap */
608     oldStretchMode = GetStretchBltMode(hdcSrc);
609     if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
610         SetStretchBltMode(hdcSrc, COLORONCOLOR);
611     hdcWork = CreateCompatibleDC(hdcDest);
612     bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
613     oldWork = SelectObject(hdcWork, bmpWork);
614     if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
615         TRACE("Failed to stretch\n");
616         goto error;
617     }
618     SetBkColor(hdcWork, crTransparent);
619
620     /* Create mask */
621     hdcMask = CreateCompatibleDC(hdcDest);
622     bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
623     oldMask = SelectObject(hdcMask, bmpMask);
624     if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
625         TRACE("Failed to create mask\n");
626         goto error;
627     }
628
629     /* Replace transparent color with black */
630     SetBkColor(hdcWork, RGB(0,0,0));
631     SetTextColor(hdcWork, RGB(255,255,255));
632     if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
633         TRACE("Failed to mask out background\n");
634         goto error;
635     }
636
637     /* Replace non-transparent area on destination with black */
638     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
639         TRACE("Failed to clear destination area\n");
640         goto error;
641     }
642
643     /* Draw the image */
644     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
645         TRACE("Failed to paint image\n");
646         goto error;
647     }
648
649     ret = TRUE;
650 error:
651     SetStretchBltMode(hdcSrc, oldStretchMode);
652     SetBkColor(hdcDest, oldBackground);
653     SetTextColor(hdcDest, oldForeground);
654     if(hdcWork) {
655         SelectObject(hdcWork, oldWork);
656         DeleteDC(hdcWork);
657     }
658     if(bmpWork) DeleteObject(bmpWork);
659     if(hdcMask) {
660         SelectObject(hdcMask, oldMask);
661         DeleteDC(hdcMask);
662     }
663     if(bmpMask) DeleteObject(bmpMask);
664     return ret;
665 }
666
667 /******************************************************************************
668  *           GdiAlphaBlend [GDI32.@]
669  */
670 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
671                           HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
672                           BLENDFUNCTION blendFunction)
673 {
674     BOOL ret = FALSE;
675     DC *dcDst, *dcSrc;
676
677     dcSrc = get_dc_ptr( hdcSrc );
678     if (!dcSrc) return FALSE;
679
680     if ((dcDst = get_dc_ptr( hdcDst )))
681     {
682         struct bitblt_coords src, dst;
683         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
684         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
685
686         update_dc( dcSrc );
687         update_dc( dcDst );
688
689         src.log_x      = xSrc;
690         src.log_y      = ySrc;
691         src.log_width  = widthSrc;
692         src.log_height = heightSrc;
693         src.layout     = GetLayout( src_dev->hdc );
694         dst.log_x      = xDst;
695         dst.log_y      = yDst;
696         dst.log_width  = widthDst;
697         dst.log_height = heightDst;
698         dst.layout     = GetLayout( dst_dev->hdc );
699         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
700
701         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",
702               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
703               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
704               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
705               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
706               blendFunction.BlendOp, blendFunction.BlendFlags,
707               blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
708
709         if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
710         release_dc_ptr( dcDst );
711     }
712     release_dc_ptr( dcSrc );
713     return ret;
714 }
715
716 /*********************************************************************
717  *      PlgBlt [GDI32.@]
718  *
719  */
720 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
721                         HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
722                         INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
723 {
724     int oldgMode;
725     /* parallelogram coords */
726     POINT plg[3];
727     /* rect coords */
728     POINT rect[3];
729     XFORM xf;
730     XFORM SrcXf;
731     XFORM oldDestXf;
732     double det;
733
734     /* save actual mode, set GM_ADVANCED */
735     oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
736     if (oldgMode == 0)
737         return FALSE;
738
739     memcpy(plg,lpPoint,sizeof(POINT)*3);
740     rect[0].x = nXSrc;
741     rect[0].y = nYSrc;
742     rect[1].x = nXSrc + nWidth;
743     rect[1].y = nYSrc;
744     rect[2].x = nXSrc;
745     rect[2].y = nYSrc + nHeight;
746     /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
747     /* determinant */
748     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);
749
750     if (fabs(det) < 1e-5)
751     {
752         SetGraphicsMode(hdcDest,oldgMode);
753         return FALSE;
754     }
755
756     TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
757         hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
758
759     /* X components */
760     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;
761     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;
762     xf.eDx  = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
763                rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
764                rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
765                ) / det;
766
767     /* Y components */
768     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;
769     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;
770     xf.eDy  = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
771                rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
772                rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
773                ) / det;
774
775     GetWorldTransform(hdcSrc,&SrcXf);
776     CombineTransform(&xf,&xf,&SrcXf);
777
778     /* save actual dest transform */
779     GetWorldTransform(hdcDest,&oldDestXf);
780
781     SetWorldTransform(hdcDest,&xf);
782     /* now destination and source DCs use same coords */
783     MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
784             hdcSrc, nXSrc,nYSrc,
785             hbmMask,xMask,yMask,
786             SRCCOPY);
787     /* restore dest DC */
788     SetWorldTransform(hdcDest,&oldDestXf);
789     SetGraphicsMode(hdcDest,oldgMode);
790
791     return TRUE;
792 }