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