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