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