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