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