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