gdi32: Use the DIB engine and PutImage for the null driver triangular gradient implem...
[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 #include <limits.h>
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     /* 1-bpp source without a color table uses the destination DC colors */
248     if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
249     {
250         COLORREF color = GetTextColor( dst_dev->hdc );
251         src_info->bmiColors[0].rgbRed      = GetRValue( color );
252         src_info->bmiColors[0].rgbGreen    = GetGValue( color );
253         src_info->bmiColors[0].rgbBlue     = GetBValue( color );
254         src_info->bmiColors[0].rgbReserved = 0;
255         color = GetBkColor( dst_dev->hdc );
256         src_info->bmiColors[1].rgbRed      = GetRValue( color );
257         src_info->bmiColors[1].rgbGreen    = GetGValue( color );
258         src_info->bmiColors[1].rgbBlue     = GetBValue( color );
259         src_info->bmiColors[1].rgbReserved = 0;
260         src_info->bmiHeader.biClrUsed = 2;
261     }
262
263     dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
264     copy_bitmapinfo( dst_info, src_info );
265     err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
266     if (err == ERROR_BAD_FORMAT)
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         copy_bitmapinfo( src_info, dst_info );
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     copy_bitmapinfo( dst_info, src_info );
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         copy_bitmapinfo( src_info, dst_info );
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 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
402                            void * grad_array, ULONG ngrad, ULONG mode )
403 {
404     DC *dc = get_nulldrv_dc( dev );
405     char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
406     BITMAPINFO *info = (BITMAPINFO *)buffer;
407     struct bitblt_coords src, dst;
408     struct gdi_image_bits bits;
409     unsigned int i;
410     POINT *pts;
411     RECT clip;
412     BOOL ret = TRUE;
413     DWORD err;
414     HRGN rgn;
415
416     if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
417     for (i = 0; i < nvert; i++)
418     {
419         pts[i].x = vert_array[i].x;
420         pts[i].y = vert_array[i].y;
421     }
422     LPtoDP( dev->hdc, pts, nvert );
423
424     /* compute bounding rect of all the rectangles/triangles */
425     dst.visrect.left = dst.visrect.top = INT_MAX;
426     dst.visrect.right = dst.visrect.bottom = INT_MIN;
427     for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
428     {
429         ULONG v = ((ULONG *)grad_array)[i];
430         dst.visrect.left   = min( dst.visrect.left,   pts[v].x );
431         dst.visrect.top    = min( dst.visrect.top,    pts[v].y );
432         dst.visrect.right  = max( dst.visrect.right,  pts[v].x );
433         dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
434     }
435
436     dst.x = dst.visrect.left;
437     dst.y = dst.visrect.top;
438     dst.width = dst.visrect.right - dst.visrect.left;
439     dst.height = dst.visrect.bottom - dst.visrect.top;
440
441     if (get_clip_box( dc, &clip )) intersect_rect( &dst.visrect, &dst.visrect, &clip );
442     if (is_rect_empty( &dst.visrect )) goto done;
443
444     /* query the bitmap format */
445     info->bmiHeader.biSize          = sizeof(info->bmiHeader);
446     info->bmiHeader.biPlanes        = 1;
447     info->bmiHeader.biBitCount      = 0;
448     info->bmiHeader.biCompression   = BI_RGB;
449     info->bmiHeader.biXPelsPerMeter = 0;
450     info->bmiHeader.biYPelsPerMeter = 0;
451     info->bmiHeader.biClrUsed       = 0;
452     info->bmiHeader.biClrImportant  = 0;
453     info->bmiHeader.biWidth         = dst.visrect.right - dst.visrect.left;
454     info->bmiHeader.biHeight        = dst.visrect.bottom - dst.visrect.top;
455     info->bmiHeader.biSizeImage     = 0;
456     dev = GET_DC_PHYSDEV( dc, pPutImage );
457     err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
458     if ((err && err != ERROR_BAD_FORMAT) ||
459         !(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ))))
460     {
461         ret = FALSE;
462         goto done;
463     }
464     bits.is_copy = TRUE;
465     bits.free = free_heap_bits;
466
467     /* make src and points relative to the bitmap */
468     src = dst;
469     src.x -= dst.visrect.left;
470     src.y -= dst.visrect.top;
471     offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
472     for (i = 0; i < nvert; i++)
473     {
474         pts[i].x -= dst.visrect.left;
475         pts[i].y -= dst.visrect.top;
476     }
477
478     rgn = CreateRectRgn( 0, 0, 0, 0 );
479     gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
480     OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
481     if (dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY )) ret = FALSE;
482
483     if (bits.free) bits.free( &bits );
484     DeleteObject( rgn );
485
486 done:
487     HeapFree( GetProcessHeap(), 0, pts );
488     return ret;
489 }
490
491 /***********************************************************************
492  *           PatBlt    (GDI32.@)
493  */
494 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
495 {
496     DC * dc;
497     BOOL ret = FALSE;
498
499     if (rop_uses_src( rop )) return FALSE;
500     if ((dc = get_dc_ptr( hdc )))
501     {
502         struct bitblt_coords dst;
503         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
504
505         update_dc( dc );
506
507         dst.log_x      = left;
508         dst.log_y      = top;
509         dst.log_width  = width;
510         dst.log_height = height;
511         dst.layout     = dc->layout;
512         if (rop & NOMIRRORBITMAP)
513         {
514             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
515             rop &= ~NOMIRRORBITMAP;
516         }
517         ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
518
519         TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s  rop=%06x\n",
520               hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
521               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
522
523         if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
524
525         release_dc_ptr( dc );
526     }
527     return ret;
528 }
529
530
531 /***********************************************************************
532  *           BitBlt    (GDI32.@)
533  */
534 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
535                     INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
536 {
537     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
538     else return StretchBlt( hdcDst, xDst, yDst, width, height,
539                             hdcSrc, xSrc, ySrc, width, height, rop );
540 }
541
542
543 /***********************************************************************
544  *           StretchBlt    (GDI32.@)
545  */
546 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
547                         HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
548 {
549     BOOL ret = FALSE;
550     DC *dcDst, *dcSrc;
551
552     if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
553
554     if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
555
556     if ((dcSrc = get_dc_ptr( hdcSrc )))
557     {
558         struct bitblt_coords src, dst;
559         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
560         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
561
562         update_dc( dcSrc );
563         update_dc( dcDst );
564
565         src.log_x      = xSrc;
566         src.log_y      = ySrc;
567         src.log_width  = widthSrc;
568         src.log_height = heightSrc;
569         src.layout     = dcSrc->layout;
570         dst.log_x      = xDst;
571         dst.log_y      = yDst;
572         dst.log_width  = widthDst;
573         dst.log_height = heightDst;
574         dst.layout     = dcDst->layout;
575         if (rop & NOMIRRORBITMAP)
576         {
577             src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
578             dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
579             rop &= ~NOMIRRORBITMAP;
580         }
581         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
582
583         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",
584               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
585               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
586               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
587               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
588
589         if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
590         release_dc_ptr( dcSrc );
591     }
592     release_dc_ptr( dcDst );
593     return ret;
594 }
595
596 #define FRGND_ROP3(ROP4)        ((ROP4) & 0x00FFFFFF)
597 #define BKGND_ROP3(ROP4)        (ROP3Table[((ROP4)>>24) & 0xFF])
598
599 /***********************************************************************
600  *           MaskBlt [GDI32.@]
601  */
602 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
603                         INT nWidth, INT nHeight, HDC hdcSrc,
604                         INT nXSrc, INT nYSrc, HBITMAP hbmMask,
605                         INT xMask, INT yMask, DWORD dwRop)
606 {
607     HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
608     HDC hDC1, hDC2;
609     HBRUSH hbrMask, hbrDst, hbrTmp;
610
611     static const DWORD ROP3Table[256] = 
612     {
613         0x00000042, 0x00010289,
614         0x00020C89, 0x000300AA,
615         0x00040C88, 0x000500A9,
616         0x00060865, 0x000702C5,
617         0x00080F08, 0x00090245,
618         0x000A0329, 0x000B0B2A,
619         0x000C0324, 0x000D0B25,
620         0x000E08A5, 0x000F0001,
621         0x00100C85, 0x001100A6,
622         0x00120868, 0x001302C8,
623         0x00140869, 0x001502C9,
624         0x00165CCA, 0x00171D54,
625         0x00180D59, 0x00191CC8,
626         0x001A06C5, 0x001B0768,
627         0x001C06CA, 0x001D0766,
628         0x001E01A5, 0x001F0385,
629         0x00200F09, 0x00210248,
630         0x00220326, 0x00230B24,
631         0x00240D55, 0x00251CC5,
632         0x002606C8, 0x00271868,
633         0x00280369, 0x002916CA,
634         0x002A0CC9, 0x002B1D58,
635         0x002C0784, 0x002D060A,
636         0x002E064A, 0x002F0E2A,
637         0x0030032A, 0x00310B28,
638         0x00320688, 0x00330008,
639         0x003406C4, 0x00351864,
640         0x003601A8, 0x00370388,
641         0x0038078A, 0x00390604,
642         0x003A0644, 0x003B0E24,
643         0x003C004A, 0x003D18A4,
644         0x003E1B24, 0x003F00EA,
645         0x00400F0A, 0x00410249,
646         0x00420D5D, 0x00431CC4,
647         0x00440328, 0x00450B29,
648         0x004606C6, 0x0047076A,
649         0x00480368, 0x004916C5,
650         0x004A0789, 0x004B0605,
651         0x004C0CC8, 0x004D1954,
652         0x004E0645, 0x004F0E25,
653         0x00500325, 0x00510B26,
654         0x005206C9, 0x00530764,
655         0x005408A9, 0x00550009,
656         0x005601A9, 0x00570389,
657         0x00580785, 0x00590609,
658         0x005A0049, 0x005B18A9,
659         0x005C0649, 0x005D0E29,
660         0x005E1B29, 0x005F00E9,
661         0x00600365, 0x006116C6,
662         0x00620786, 0x00630608,
663         0x00640788, 0x00650606,
664         0x00660046, 0x006718A8,
665         0x006858A6, 0x00690145,
666         0x006A01E9, 0x006B178A,
667         0x006C01E8, 0x006D1785,
668         0x006E1E28, 0x006F0C65,
669         0x00700CC5, 0x00711D5C,
670         0x00720648, 0x00730E28,
671         0x00740646, 0x00750E26,
672         0x00761B28, 0x007700E6,
673         0x007801E5, 0x00791786,
674         0x007A1E29, 0x007B0C68,
675         0x007C1E24, 0x007D0C69,
676         0x007E0955, 0x007F03C9,
677         0x008003E9, 0x00810975,
678         0x00820C49, 0x00831E04,
679         0x00840C48, 0x00851E05,
680         0x008617A6, 0x008701C5,
681         0x008800C6, 0x00891B08,
682         0x008A0E06, 0x008B0666,
683         0x008C0E08, 0x008D0668,
684         0x008E1D7C, 0x008F0CE5,
685         0x00900C45, 0x00911E08,
686         0x009217A9, 0x009301C4,
687         0x009417AA, 0x009501C9,
688         0x00960169, 0x0097588A,
689         0x00981888, 0x00990066,
690         0x009A0709, 0x009B07A8,
691         0x009C0704, 0x009D07A6,
692         0x009E16E6, 0x009F0345,
693         0x00A000C9, 0x00A11B05,
694         0x00A20E09, 0x00A30669,
695         0x00A41885, 0x00A50065,
696         0x00A60706, 0x00A707A5,
697         0x00A803A9, 0x00A90189,
698         0x00AA0029, 0x00AB0889,
699         0x00AC0744, 0x00AD06E9,
700         0x00AE0B06, 0x00AF0229,
701         0x00B00E05, 0x00B10665,
702         0x00B21974, 0x00B30CE8,
703         0x00B4070A, 0x00B507A9,
704         0x00B616E9, 0x00B70348,
705         0x00B8074A, 0x00B906E6,
706         0x00BA0B09, 0x00BB0226,
707         0x00BC1CE4, 0x00BD0D7D,
708         0x00BE0269, 0x00BF08C9,
709         0x00C000CA, 0x00C11B04,
710         0x00C21884, 0x00C3006A,
711         0x00C40E04, 0x00C50664,
712         0x00C60708, 0x00C707AA,
713         0x00C803A8, 0x00C90184,
714         0x00CA0749, 0x00CB06E4,
715         0x00CC0020, 0x00CD0888,
716         0x00CE0B08, 0x00CF0224,
717         0x00D00E0A, 0x00D1066A,
718         0x00D20705, 0x00D307A4,
719         0x00D41D78, 0x00D50CE9,
720         0x00D616EA, 0x00D70349,
721         0x00D80745, 0x00D906E8,
722         0x00DA1CE9, 0x00DB0D75,
723         0x00DC0B04, 0x00DD0228,
724         0x00DE0268, 0x00DF08C8,
725         0x00E003A5, 0x00E10185,
726         0x00E20746, 0x00E306EA,
727         0x00E40748, 0x00E506E5,
728         0x00E61CE8, 0x00E70D79,
729         0x00E81D74, 0x00E95CE6,
730         0x00EA02E9, 0x00EB0849,
731         0x00EC02E8, 0x00ED0848,
732         0x00EE0086, 0x00EF0A08,
733         0x00F00021, 0x00F10885,
734         0x00F20B05, 0x00F3022A,
735         0x00F40B0A, 0x00F50225,
736         0x00F60265, 0x00F708C5,
737         0x00F802E5, 0x00F90845,
738         0x00FA0089, 0x00FB0A09,
739         0x00FC008A, 0x00FD0A0A,
740         0x00FE02A9, 0x00FF0062,
741     };
742
743     if (!hbmMask)
744         return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
745
746     hbrMask = CreatePatternBrush(hbmMask);
747     hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
748
749     /* make bitmap */
750     hDC1 = CreateCompatibleDC(hdcDest);
751     hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
752     hOldBitmap1 = SelectObject(hDC1, hBitmap1);
753
754     /* draw using bkgnd rop */
755     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
756     hbrTmp = SelectObject(hDC1, hbrDst);
757     BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
758     SelectObject(hDC1, hbrTmp);
759
760     /* make bitmap */
761     hDC2 = CreateCompatibleDC(hdcDest);
762     hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
763     hOldBitmap2 = SelectObject(hDC2, hBitmap2);
764
765     /* draw using foregnd rop */
766     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
767     hbrTmp = SelectObject(hDC2, hbrDst);
768     BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
769
770     /* combine both using the mask as a pattern brush */
771     SelectObject(hDC2, hbrMask);
772     BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */ 
773     SelectObject(hDC2, hbrTmp);
774
775     /* blit to dst */
776     BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
777
778     /* restore all objects */
779     SelectObject(hdcDest, hbrDst);
780     SelectObject(hDC1, hOldBitmap1);
781     SelectObject(hDC2, hOldBitmap2);
782
783     /* delete all temp objects */
784     DeleteObject(hBitmap1);
785     DeleteObject(hBitmap2);
786     DeleteObject(hbrMask);
787
788     DeleteDC(hDC1);
789     DeleteDC(hDC2);
790
791     return TRUE;
792 }
793
794 /******************************************************************************
795  *           GdiTransparentBlt [GDI32.@]
796  */
797 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
798                             HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
799                             UINT crTransparent )
800 {
801     BOOL ret = FALSE;
802     HDC hdcWork;
803     HBITMAP bmpWork;
804     HGDIOBJ oldWork;
805     HDC hdcMask = NULL;
806     HBITMAP bmpMask = NULL;
807     HBITMAP oldMask = NULL;
808     COLORREF oldBackground;
809     COLORREF oldForeground;
810     int oldStretchMode;
811
812     if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
813         TRACE("Cannot mirror\n");
814         return FALSE;
815     }
816
817     oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
818     oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
819
820     /* Stretch bitmap */
821     oldStretchMode = GetStretchBltMode(hdcSrc);
822     if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
823         SetStretchBltMode(hdcSrc, COLORONCOLOR);
824     hdcWork = CreateCompatibleDC(hdcDest);
825     bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
826     oldWork = SelectObject(hdcWork, bmpWork);
827     if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
828         TRACE("Failed to stretch\n");
829         goto error;
830     }
831     SetBkColor(hdcWork, crTransparent);
832
833     /* Create mask */
834     hdcMask = CreateCompatibleDC(hdcDest);
835     bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
836     oldMask = SelectObject(hdcMask, bmpMask);
837     if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
838         TRACE("Failed to create mask\n");
839         goto error;
840     }
841
842     /* Replace transparent color with black */
843     SetBkColor(hdcWork, RGB(0,0,0));
844     SetTextColor(hdcWork, RGB(255,255,255));
845     if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
846         TRACE("Failed to mask out background\n");
847         goto error;
848     }
849
850     /* Replace non-transparent area on destination with black */
851     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
852         TRACE("Failed to clear destination area\n");
853         goto error;
854     }
855
856     /* Draw the image */
857     if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
858         TRACE("Failed to paint image\n");
859         goto error;
860     }
861
862     ret = TRUE;
863 error:
864     SetStretchBltMode(hdcSrc, oldStretchMode);
865     SetBkColor(hdcDest, oldBackground);
866     SetTextColor(hdcDest, oldForeground);
867     if(hdcWork) {
868         SelectObject(hdcWork, oldWork);
869         DeleteDC(hdcWork);
870     }
871     if(bmpWork) DeleteObject(bmpWork);
872     if(hdcMask) {
873         SelectObject(hdcMask, oldMask);
874         DeleteDC(hdcMask);
875     }
876     if(bmpMask) DeleteObject(bmpMask);
877     return ret;
878 }
879
880 /******************************************************************************
881  *           GdiAlphaBlend [GDI32.@]
882  */
883 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
884                           HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
885                           BLENDFUNCTION blendFunction)
886 {
887     BOOL ret = FALSE;
888     DC *dcDst, *dcSrc;
889
890     dcSrc = get_dc_ptr( hdcSrc );
891     if (!dcSrc) return FALSE;
892
893     if ((dcDst = get_dc_ptr( hdcDst )))
894     {
895         struct bitblt_coords src, dst;
896         PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
897         PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
898
899         update_dc( dcSrc );
900         update_dc( dcDst );
901
902         src.log_x      = xSrc;
903         src.log_y      = ySrc;
904         src.log_width  = widthSrc;
905         src.log_height = heightSrc;
906         src.layout     = GetLayout( src_dev->hdc );
907         dst.log_x      = xDst;
908         dst.log_y      = yDst;
909         dst.log_width  = widthDst;
910         dst.log_height = heightDst;
911         dst.layout     = GetLayout( dst_dev->hdc );
912         ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
913
914         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",
915               hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
916               src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
917               hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
918               dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
919               blendFunction.BlendOp, blendFunction.BlendFlags,
920               blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
921
922         if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
923             (dcSrc->header.type == OBJ_MEMDC &&
924              (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
925               src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
926         {
927             WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
928             SetLastError( ERROR_INVALID_PARAMETER );
929             ret = FALSE;
930         }
931         else if (dst.width < 0 || dst.height < 0)
932         {
933             WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
934             SetLastError( ERROR_INVALID_PARAMETER );
935             ret = FALSE;
936         }
937         else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
938                  src.y + src.height > dst.y && src.y < dst.y + dst.height)
939         {
940             WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
941                   src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
942             SetLastError( ERROR_INVALID_PARAMETER );
943             ret = FALSE;
944         }
945         else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
946
947         release_dc_ptr( dcDst );
948     }
949     release_dc_ptr( dcSrc );
950     return ret;
951 }
952
953 /*********************************************************************
954  *      PlgBlt [GDI32.@]
955  *
956  */
957 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
958                         HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
959                         INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
960 {
961     int oldgMode;
962     /* parallelogram coords */
963     POINT plg[3];
964     /* rect coords */
965     POINT rect[3];
966     XFORM xf;
967     XFORM SrcXf;
968     XFORM oldDestXf;
969     double det;
970
971     /* save actual mode, set GM_ADVANCED */
972     oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
973     if (oldgMode == 0)
974         return FALSE;
975
976     memcpy(plg,lpPoint,sizeof(POINT)*3);
977     rect[0].x = nXSrc;
978     rect[0].y = nYSrc;
979     rect[1].x = nXSrc + nWidth;
980     rect[1].y = nYSrc;
981     rect[2].x = nXSrc;
982     rect[2].y = nYSrc + nHeight;
983     /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
984     /* determinant */
985     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);
986
987     if (fabs(det) < 1e-5)
988     {
989         SetGraphicsMode(hdcDest,oldgMode);
990         return FALSE;
991     }
992
993     TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
994         hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
995
996     /* X components */
997     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;
998     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;
999     xf.eDx  = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1000                rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1001                rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1002                ) / det;
1003
1004     /* Y components */
1005     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;
1006     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;
1007     xf.eDy  = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1008                rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1009                rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1010                ) / det;
1011
1012     GetWorldTransform(hdcSrc,&SrcXf);
1013     CombineTransform(&xf,&xf,&SrcXf);
1014
1015     /* save actual dest transform */
1016     GetWorldTransform(hdcDest,&oldDestXf);
1017
1018     SetWorldTransform(hdcDest,&xf);
1019     /* now destination and source DCs use same coords */
1020     MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1021             hdcSrc, nXSrc,nYSrc,
1022             hbmMask,xMask,yMask,
1023             SRCCOPY);
1024     /* restore dest DC */
1025     SetWorldTransform(hdcDest,&oldDestXf);
1026     SetGraphicsMode(hdcDest,oldgMode);
1027
1028     return TRUE;
1029 }