server: Support NamedPipeState in FilePipeLocalInformation.
[wine.git] / dlls / gdi32 / bitblt.c
blobabca82245a4b20c2e6d1f2821980bdbb5faa783f
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
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.
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.
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
21 #include "config.h"
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <math.h>
26 #ifdef HAVE_FLOAT_H
27 #include <float.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "gdi_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
38 static inline BOOL rop_uses_src( DWORD rop )
40 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
43 BOOL intersect_vis_rectangles( struct bitblt_coords *dst, struct bitblt_coords *src )
45 RECT rect;
47 /* intersect the rectangles */
49 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
51 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
52 if (!intersect_rect( &rect, &src->visrect, &dst->visrect )) return FALSE;
53 src->visrect = dst->visrect = rect;
54 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
56 else /* stretching */
58 /* map source rectangle into destination coordinates */
59 rect = src->visrect;
60 offset_rect( &rect,
61 -src->x - (src->width < 0 ? 1 : 0),
62 -src->y - (src->height < 0 ? 1 : 0));
63 rect.left = rect.left * dst->width / src->width;
64 rect.top = rect.top * dst->height / src->height;
65 rect.right = rect.right * dst->width / src->width;
66 rect.bottom = rect.bottom * dst->height / src->height;
67 order_rect( &rect );
69 /* when the source rectangle needs to flip and it doesn't fit in the source device
70 area, the destination area isn't flipped. So, adjust destination coordinates */
71 if (src->width < 0 && dst->width > 0 &&
72 (src->x + src->width + 1 < src->visrect.left || src->x > src->visrect.right))
73 dst->x += (dst->width - rect.right) - rect.left;
74 else if (src->width > 0 && dst->width < 0 &&
75 (src->x < src->visrect.left || src->x + src->width > src->visrect.right))
76 dst->x -= rect.right - (dst->width - rect.left);
78 if (src->height < 0 && dst->height > 0 &&
79 (src->y + src->height + 1 < src->visrect.top || src->y > src->visrect.bottom))
80 dst->y += (dst->height - rect.bottom) - rect.top;
81 else if (src->height > 0 && dst->height < 0 &&
82 (src->y < src->visrect.top || src->y + src->height > src->visrect.bottom))
83 dst->y -= rect.bottom - (dst->height - rect.top);
85 offset_rect( &rect, dst->x, dst->y );
87 /* avoid rounding errors */
88 rect.left--;
89 rect.top--;
90 rect.right++;
91 rect.bottom++;
92 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
94 /* map destination rectangle back to source coordinates */
95 rect = dst->visrect;
96 offset_rect( &rect,
97 -dst->x - (dst->width < 0 ? 1 : 0),
98 -dst->y - (dst->height < 0 ? 1 : 0));
99 rect.left = src->x + rect.left * src->width / dst->width;
100 rect.top = src->y + rect.top * src->height / dst->height;
101 rect.right = src->x + rect.right * src->width / dst->width;
102 rect.bottom = src->y + rect.bottom * src->height / dst->height;
103 order_rect( &rect );
105 /* avoid rounding errors */
106 rect.left--;
107 rect.top--;
108 rect.right++;
109 rect.bottom++;
110 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
112 return TRUE;
115 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
116 DC *dc_src, struct bitblt_coords *src )
118 RECT rect;
120 /* get the destination visible rectangle */
122 rect.left = dst->log_x;
123 rect.top = dst->log_y;
124 rect.right = dst->log_x + dst->log_width;
125 rect.bottom = dst->log_y + dst->log_height;
126 lp_to_dp( dc_dst, (POINT *)&rect, 2 );
127 dst->x = rect.left;
128 dst->y = rect.top;
129 dst->width = rect.right - rect.left;
130 dst->height = rect.bottom - rect.top;
131 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
133 dst->x += dst->width;
134 dst->width = -dst->width;
136 get_bounding_rect( &rect, dst->x, dst->y, dst->width, dst->height );
138 clip_visrect( dc_dst, &dst->visrect, &rect );
140 /* get the source visible rectangle */
142 if (!src) return !is_rect_empty( &dst->visrect );
144 rect.left = src->log_x;
145 rect.top = src->log_y;
146 rect.right = src->log_x + src->log_width;
147 rect.bottom = src->log_y + src->log_height;
148 lp_to_dp( dc_src, (POINT *)&rect, 2 );
149 src->x = rect.left;
150 src->y = rect.top;
151 src->width = rect.right - rect.left;
152 src->height = rect.bottom - rect.top;
153 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
155 src->x += src->width;
156 src->width = -src->width;
158 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
160 if (!clip_device_rect( dc_src, &src->visrect, &rect )) return FALSE;
161 if (is_rect_empty( &dst->visrect )) return FALSE;
163 return intersect_vis_rectangles( dst, src );
166 void free_heap_bits( struct gdi_image_bits *bits )
168 HeapFree( GetProcessHeap(), 0, bits->ptr );
171 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
172 BITMAPINFO *dst_info, struct gdi_image_bits *bits )
174 void *ptr;
175 DWORD err;
176 BOOL top_down = dst_info->bmiHeader.biHeight < 0;
178 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
179 dst_info->bmiHeader.biHeight = src->visrect.bottom - src->visrect.top;
180 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
181 if (top_down) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
183 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
184 return ERROR_OUTOFMEMORY;
186 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
187 if (bits->free) bits->free( bits );
188 bits->ptr = ptr;
189 bits->is_copy = TRUE;
190 bits->free = free_heap_bits;
191 return err;
194 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
195 BITMAPINFO *dst_info, struct bitblt_coords *dst,
196 struct gdi_image_bits *bits, int mode )
198 void *ptr;
199 DWORD err;
201 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
202 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
203 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
205 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
206 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
207 return ERROR_OUTOFMEMORY;
209 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
210 if (bits->free) bits->free( bits );
211 bits->ptr = ptr;
212 bits->is_copy = TRUE;
213 bits->free = free_heap_bits;
214 return err;
217 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
218 struct bitblt_coords *src, BITMAPINFO *dst_info,
219 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
221 if (!dst_bits->is_copy)
223 int size = dst_info->bmiHeader.biSizeImage;
224 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
225 if (!ptr) return ERROR_OUTOFMEMORY;
226 memcpy( ptr, dst_bits->ptr, size );
227 if (dst_bits->free) dst_bits->free( dst_bits );
228 dst_bits->ptr = ptr;
229 dst_bits->is_copy = TRUE;
230 dst_bits->free = free_heap_bits;
232 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
235 static RGBQUAD get_dc_rgb_color( DC *dc, int color_table_size, COLORREF color )
237 RGBQUAD ret = { 0, 0, 0, 0 };
239 if (color & (1 << 24)) /* PALETTEINDEX */
241 PALETTEENTRY pal;
243 if (!GetPaletteEntries( dc->hPalette, LOWORD(color), 1, &pal ))
244 GetPaletteEntries( dc->hPalette, 0, 1, &pal );
245 ret.rgbRed = pal.peRed;
246 ret.rgbGreen = pal.peGreen;
247 ret.rgbBlue = pal.peBlue;
248 return ret;
250 if (color >> 16 == 0x10ff) /* DIBINDEX */
252 if (color_table_size)
254 if (LOWORD(color) >= color_table_size) color = 0x10ff0000; /* fallback to index 0 */
255 *(DWORD *)&ret = color;
257 return ret;
259 ret.rgbRed = GetRValue( color );
260 ret.rgbGreen = GetGValue( color );
261 ret.rgbBlue = GetBValue( color );
262 return ret;
265 /* helper to retrieve either both colors or only the background color for monochrome blits */
266 void get_mono_dc_colors( DC *dc, int color_table_size, BITMAPINFO *info, int count )
268 info->bmiColors[count - 1] = get_dc_rgb_color( dc, color_table_size, dc->backgroundColor );
269 if (count > 1) info->bmiColors[0] = get_dc_rgb_color( dc, color_table_size, dc->textColor );
270 info->bmiHeader.biClrUsed = count;
273 /***********************************************************************
274 * null driver fallback implementations
277 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
278 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
280 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
281 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
282 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
283 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
284 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
285 DWORD err;
286 struct gdi_image_bits bits;
288 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
289 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
290 return FALSE;
292 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
293 copy_bitmapinfo( dst_info, src_info );
294 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
295 if (err == ERROR_BAD_FORMAT)
297 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
299 /* 1-bpp source without a color table uses the destination DC colors */
300 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
301 get_mono_dc_colors( dc_dst, dst_info->bmiHeader.biClrUsed, src_info, 2 );
303 /* 1-bpp destination without a color table requires a fake 1-entry table
304 * that contains only the background color */
305 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
306 get_mono_dc_colors( dc_src, src_info->bmiHeader.biClrUsed, dst_info, 1 );
308 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
310 /* get rid of the fake destination table */
311 dst_info->bmiHeader.biClrUsed = dst_colors;
312 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
316 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
317 ((src->width != dst->width) || (src->height != dst->height)))
319 copy_bitmapinfo( src_info, dst_info );
320 err = stretch_bits( src_info, src, dst_info, dst, &bits, dc_dst->stretchBltMode );
321 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
324 if (bits.free) bits.free( &bits );
325 return !err;
329 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
330 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
332 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
333 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
334 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
335 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
336 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
337 DWORD err;
338 struct gdi_image_bits bits;
340 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
341 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
342 if (err) goto done;
344 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
345 copy_bitmapinfo( dst_info, src_info );
346 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
347 if (err == ERROR_BAD_FORMAT)
349 err = convert_bits( src_info, src, dst_info, &bits );
350 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
353 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
354 ((src->width != dst->width) || (src->height != dst->height)))
356 copy_bitmapinfo( src_info, dst_info );
357 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
358 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
361 if (bits.free) bits.free( &bits );
362 done:
363 if (err) SetLastError( err );
364 return !err;
368 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
369 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
371 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
372 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
373 struct gdi_image_bits dst_bits;
374 struct bitblt_coords orig_dst;
375 DWORD *masks = (DWORD *)info->bmiColors;
376 DC *dc = get_nulldrv_dc( dev );
377 DWORD err;
379 if (info->bmiHeader.biPlanes != 1) goto update_format;
380 if (info->bmiHeader.biBitCount != 32) goto update_format;
381 if (info->bmiHeader.biCompression == BI_BITFIELDS)
383 if (blend.AlphaFormat & AC_SRC_ALPHA) return ERROR_INVALID_PARAMETER;
384 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
385 goto update_format;
388 if (!bits) return ERROR_SUCCESS;
389 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
391 dev = GET_DC_PHYSDEV( dc, pGetImage );
392 orig_dst = *dst;
393 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
394 if (err) return err;
396 dev = GET_DC_PHYSDEV( dc, pPutImage );
397 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
398 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
400 if (dst_bits.free) dst_bits.free( &dst_bits );
401 return err;
403 update_format:
404 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
405 return ERROR_INVALID_PARAMETER;
407 info->bmiHeader.biPlanes = 1;
408 info->bmiHeader.biBitCount = 32;
409 info->bmiHeader.biCompression = BI_BITFIELDS;
410 info->bmiHeader.biClrUsed = 0;
411 masks[0] = 0xff0000;
412 masks[1] = 0x00ff00;
413 masks[2] = 0x0000ff;
414 return ERROR_BAD_FORMAT;
417 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
418 void * grad_array, ULONG ngrad, ULONG mode )
420 DC *dc = get_nulldrv_dc( dev );
421 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
422 BITMAPINFO *info = (BITMAPINFO *)buffer;
423 struct bitblt_coords src, dst;
424 struct gdi_image_bits bits;
425 unsigned int i;
426 POINT *pts;
427 BOOL ret = FALSE;
428 DWORD err;
429 HRGN rgn;
431 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
432 for (i = 0; i < nvert; i++)
434 pts[i].x = vert_array[i].x;
435 pts[i].y = vert_array[i].y;
437 lp_to_dp( dc, pts, nvert );
439 /* compute bounding rect of all the rectangles/triangles */
440 reset_bounds( &dst.visrect );
441 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
443 ULONG v = ((ULONG *)grad_array)[i];
444 dst.visrect.left = min( dst.visrect.left, pts[v].x );
445 dst.visrect.top = min( dst.visrect.top, pts[v].y );
446 dst.visrect.right = max( dst.visrect.right, pts[v].x );
447 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
450 dst.x = dst.visrect.left;
451 dst.y = dst.visrect.top;
452 dst.width = dst.visrect.right - dst.visrect.left;
453 dst.height = dst.visrect.bottom - dst.visrect.top;
454 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
456 /* query the bitmap format */
457 info->bmiHeader.biSize = sizeof(info->bmiHeader);
458 info->bmiHeader.biPlanes = 1;
459 info->bmiHeader.biBitCount = 0;
460 info->bmiHeader.biCompression = BI_RGB;
461 info->bmiHeader.biXPelsPerMeter = 0;
462 info->bmiHeader.biYPelsPerMeter = 0;
463 info->bmiHeader.biClrUsed = 0;
464 info->bmiHeader.biClrImportant = 0;
465 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
466 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
467 info->bmiHeader.biSizeImage = 0;
468 dev = GET_DC_PHYSDEV( dc, pPutImage );
469 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
470 if (err && err != ERROR_BAD_FORMAT) goto done;
472 info->bmiHeader.biSizeImage = get_dib_image_size( info );
473 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
474 goto done;
475 bits.is_copy = TRUE;
476 bits.free = free_heap_bits;
478 /* make src and points relative to the bitmap */
479 src = dst;
480 src.x -= dst.visrect.left;
481 src.y -= dst.visrect.top;
482 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
483 for (i = 0; i < nvert; i++)
485 pts[i].x -= dst.visrect.left;
486 pts[i].y -= dst.visrect.top;
489 rgn = CreateRectRgn( 0, 0, 0, 0 );
490 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
491 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
492 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
494 if (bits.free) bits.free( &bits );
495 DeleteObject( rgn );
497 done:
498 HeapFree( GetProcessHeap(), 0, pts );
499 return ret;
502 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
504 DC *dc = get_nulldrv_dc( dev );
505 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
506 BITMAPINFO *info = (BITMAPINFO *)buffer;
507 struct bitblt_coords src;
508 struct gdi_image_bits bits;
509 COLORREF ret;
511 src.visrect.left = x;
512 src.visrect.top = y;
513 lp_to_dp( dc, (POINT *)&src.visrect, 1 );
514 src.visrect.right = src.visrect.left + 1;
515 src.visrect.bottom = src.visrect.top + 1;
516 src.x = src.visrect.left;
517 src.y = src.visrect.top;
518 src.width = src.height = 1;
520 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
522 dev = GET_DC_PHYSDEV( dc, pGetImage );
523 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
525 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
526 if (bits.free) bits.free( &bits );
527 return ret;
531 /***********************************************************************
532 * PatBlt (GDI32.@)
534 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
536 DC * dc;
537 BOOL ret = FALSE;
539 if (rop_uses_src( rop )) return FALSE;
540 if ((dc = get_dc_ptr( hdc )))
542 struct bitblt_coords dst;
544 update_dc( dc );
546 dst.log_x = left;
547 dst.log_y = top;
548 dst.log_width = width;
549 dst.log_height = height;
550 dst.layout = dc->layout;
551 if (rop & NOMIRRORBITMAP)
553 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
554 rop &= ~NOMIRRORBITMAP;
556 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
558 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
559 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
560 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
562 if (!ret)
564 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
565 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
567 release_dc_ptr( dc );
569 return ret;
573 /***********************************************************************
574 * BitBlt (GDI32.@)
576 BOOL WINAPI DECLSPEC_HOTPATCH BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
577 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
579 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
580 else return StretchBlt( hdcDst, xDst, yDst, width, height,
581 hdcSrc, xSrc, ySrc, width, height, rop );
585 /***********************************************************************
586 * StretchBlt (GDI32.@)
588 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
589 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
591 BOOL ret = FALSE;
592 DC *dcDst, *dcSrc;
594 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
596 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
598 if ((dcSrc = get_dc_ptr( hdcSrc )))
600 struct bitblt_coords src, dst;
602 update_dc( dcSrc );
603 update_dc( dcDst );
605 src.log_x = xSrc;
606 src.log_y = ySrc;
607 src.log_width = widthSrc;
608 src.log_height = heightSrc;
609 src.layout = dcSrc->layout;
610 dst.log_x = xDst;
611 dst.log_y = yDst;
612 dst.log_width = widthDst;
613 dst.log_height = heightDst;
614 dst.layout = dcDst->layout;
615 if (rop & NOMIRRORBITMAP)
617 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
618 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
619 rop &= ~NOMIRRORBITMAP;
621 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
623 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",
624 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
625 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
626 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
627 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
629 if (!ret)
631 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
632 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
633 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
635 release_dc_ptr( dcSrc );
637 release_dc_ptr( dcDst );
638 return ret;
641 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
642 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
644 /***********************************************************************
645 * MaskBlt [GDI32.@]
647 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
648 INT nWidth, INT nHeight, HDC hdcSrc,
649 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
650 INT xMask, INT yMask, DWORD dwRop)
652 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
653 HDC hDC1, hDC2;
654 HBRUSH hbrMask, hbrDst, hbrTmp;
656 static const DWORD ROP3Table[256] =
658 0x00000042, 0x00010289,
659 0x00020C89, 0x000300AA,
660 0x00040C88, 0x000500A9,
661 0x00060865, 0x000702C5,
662 0x00080F08, 0x00090245,
663 0x000A0329, 0x000B0B2A,
664 0x000C0324, 0x000D0B25,
665 0x000E08A5, 0x000F0001,
666 0x00100C85, 0x001100A6,
667 0x00120868, 0x001302C8,
668 0x00140869, 0x001502C9,
669 0x00165CCA, 0x00171D54,
670 0x00180D59, 0x00191CC8,
671 0x001A06C5, 0x001B0768,
672 0x001C06CA, 0x001D0766,
673 0x001E01A5, 0x001F0385,
674 0x00200F09, 0x00210248,
675 0x00220326, 0x00230B24,
676 0x00240D55, 0x00251CC5,
677 0x002606C8, 0x00271868,
678 0x00280369, 0x002916CA,
679 0x002A0CC9, 0x002B1D58,
680 0x002C0784, 0x002D060A,
681 0x002E064A, 0x002F0E2A,
682 0x0030032A, 0x00310B28,
683 0x00320688, 0x00330008,
684 0x003406C4, 0x00351864,
685 0x003601A8, 0x00370388,
686 0x0038078A, 0x00390604,
687 0x003A0644, 0x003B0E24,
688 0x003C004A, 0x003D18A4,
689 0x003E1B24, 0x003F00EA,
690 0x00400F0A, 0x00410249,
691 0x00420D5D, 0x00431CC4,
692 0x00440328, 0x00450B29,
693 0x004606C6, 0x0047076A,
694 0x00480368, 0x004916C5,
695 0x004A0789, 0x004B0605,
696 0x004C0CC8, 0x004D1954,
697 0x004E0645, 0x004F0E25,
698 0x00500325, 0x00510B26,
699 0x005206C9, 0x00530764,
700 0x005408A9, 0x00550009,
701 0x005601A9, 0x00570389,
702 0x00580785, 0x00590609,
703 0x005A0049, 0x005B18A9,
704 0x005C0649, 0x005D0E29,
705 0x005E1B29, 0x005F00E9,
706 0x00600365, 0x006116C6,
707 0x00620786, 0x00630608,
708 0x00640788, 0x00650606,
709 0x00660046, 0x006718A8,
710 0x006858A6, 0x00690145,
711 0x006A01E9, 0x006B178A,
712 0x006C01E8, 0x006D1785,
713 0x006E1E28, 0x006F0C65,
714 0x00700CC5, 0x00711D5C,
715 0x00720648, 0x00730E28,
716 0x00740646, 0x00750E26,
717 0x00761B28, 0x007700E6,
718 0x007801E5, 0x00791786,
719 0x007A1E29, 0x007B0C68,
720 0x007C1E24, 0x007D0C69,
721 0x007E0955, 0x007F03C9,
722 0x008003E9, 0x00810975,
723 0x00820C49, 0x00831E04,
724 0x00840C48, 0x00851E05,
725 0x008617A6, 0x008701C5,
726 0x008800C6, 0x00891B08,
727 0x008A0E06, 0x008B0666,
728 0x008C0E08, 0x008D0668,
729 0x008E1D7C, 0x008F0CE5,
730 0x00900C45, 0x00911E08,
731 0x009217A9, 0x009301C4,
732 0x009417AA, 0x009501C9,
733 0x00960169, 0x0097588A,
734 0x00981888, 0x00990066,
735 0x009A0709, 0x009B07A8,
736 0x009C0704, 0x009D07A6,
737 0x009E16E6, 0x009F0345,
738 0x00A000C9, 0x00A11B05,
739 0x00A20E09, 0x00A30669,
740 0x00A41885, 0x00A50065,
741 0x00A60706, 0x00A707A5,
742 0x00A803A9, 0x00A90189,
743 0x00AA0029, 0x00AB0889,
744 0x00AC0744, 0x00AD06E9,
745 0x00AE0B06, 0x00AF0229,
746 0x00B00E05, 0x00B10665,
747 0x00B21974, 0x00B30CE8,
748 0x00B4070A, 0x00B507A9,
749 0x00B616E9, 0x00B70348,
750 0x00B8074A, 0x00B906E6,
751 0x00BA0B09, 0x00BB0226,
752 0x00BC1CE4, 0x00BD0D7D,
753 0x00BE0269, 0x00BF08C9,
754 0x00C000CA, 0x00C11B04,
755 0x00C21884, 0x00C3006A,
756 0x00C40E04, 0x00C50664,
757 0x00C60708, 0x00C707AA,
758 0x00C803A8, 0x00C90184,
759 0x00CA0749, 0x00CB06E4,
760 0x00CC0020, 0x00CD0888,
761 0x00CE0B08, 0x00CF0224,
762 0x00D00E0A, 0x00D1066A,
763 0x00D20705, 0x00D307A4,
764 0x00D41D78, 0x00D50CE9,
765 0x00D616EA, 0x00D70349,
766 0x00D80745, 0x00D906E8,
767 0x00DA1CE9, 0x00DB0D75,
768 0x00DC0B04, 0x00DD0228,
769 0x00DE0268, 0x00DF08C8,
770 0x00E003A5, 0x00E10185,
771 0x00E20746, 0x00E306EA,
772 0x00E40748, 0x00E506E5,
773 0x00E61CE8, 0x00E70D79,
774 0x00E81D74, 0x00E95CE6,
775 0x00EA02E9, 0x00EB0849,
776 0x00EC02E8, 0x00ED0848,
777 0x00EE0086, 0x00EF0A08,
778 0x00F00021, 0x00F10885,
779 0x00F20B05, 0x00F3022A,
780 0x00F40B0A, 0x00F50225,
781 0x00F60265, 0x00F708C5,
782 0x00F802E5, 0x00F90845,
783 0x00FA0089, 0x00FB0A09,
784 0x00FC008A, 0x00FD0A0A,
785 0x00FE02A9, 0x00FF0062,
788 if (!hbmMask)
789 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
791 hbrMask = CreatePatternBrush(hbmMask);
792 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
794 /* make bitmap */
795 hDC1 = CreateCompatibleDC(hdcDest);
796 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
797 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
799 /* draw using bkgnd rop */
800 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
801 hbrTmp = SelectObject(hDC1, hbrDst);
802 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
803 SelectObject(hDC1, hbrTmp);
805 /* make bitmap */
806 hDC2 = CreateCompatibleDC(hdcDest);
807 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
808 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
810 /* draw using foregnd rop */
811 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
812 hbrTmp = SelectObject(hDC2, hbrDst);
813 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
815 /* combine both using the mask as a pattern brush */
816 SelectObject(hDC2, hbrMask);
817 SetBrushOrgEx(hDC2, -xMask, -yMask, NULL);
818 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
819 SelectObject(hDC2, hbrTmp);
821 /* blit to dst */
822 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
824 /* restore all objects */
825 SelectObject(hdcDest, hbrDst);
826 SelectObject(hDC1, hOldBitmap1);
827 SelectObject(hDC2, hOldBitmap2);
829 /* delete all temp objects */
830 DeleteObject(hBitmap1);
831 DeleteObject(hBitmap2);
832 DeleteObject(hbrMask);
834 DeleteDC(hDC1);
835 DeleteDC(hDC2);
837 return TRUE;
840 /******************************************************************************
841 * GdiTransparentBlt [GDI32.@]
843 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
844 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
845 UINT crTransparent )
847 BOOL ret = FALSE;
848 HDC hdcWork;
849 HBITMAP bmpWork;
850 HGDIOBJ oldWork;
851 HDC hdcMask = NULL;
852 HBITMAP bmpMask = NULL;
853 HBITMAP oldMask = NULL;
854 COLORREF oldBackground;
855 COLORREF oldForeground;
856 int oldStretchMode;
857 DIBSECTION dib;
859 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
860 TRACE("Cannot mirror\n");
861 return FALSE;
864 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
865 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
867 /* Stretch bitmap */
868 oldStretchMode = GetStretchBltMode(hdcSrc);
869 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
870 SetStretchBltMode(hdcSrc, COLORONCOLOR);
871 hdcWork = CreateCompatibleDC(hdcDest);
872 if ((GetObjectType( hdcDest ) != OBJ_MEMDC ||
873 GetObjectW( GetCurrentObject( hdcDest, OBJ_BITMAP ), sizeof(dib), &dib ) == sizeof(BITMAP)) &&
874 GetDeviceCaps( hdcDest, BITSPIXEL ) == 32)
876 /* screen DCs or DDBs are not supposed to have an alpha channel, so use a 24-bpp bitmap as copy */
877 BITMAPINFO info;
878 info.bmiHeader.biSize = sizeof(info.bmiHeader);
879 info.bmiHeader.biWidth = widthDest;
880 info.bmiHeader.biHeight = heightDest;
881 info.bmiHeader.biPlanes = 1;
882 info.bmiHeader.biBitCount = 24;
883 info.bmiHeader.biCompression = BI_RGB;
884 bmpWork = CreateDIBSection( 0, &info, DIB_RGB_COLORS, NULL, NULL, 0 );
886 else bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
887 oldWork = SelectObject(hdcWork, bmpWork);
888 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
889 TRACE("Failed to stretch\n");
890 goto error;
892 SetBkColor(hdcWork, crTransparent);
894 /* Create mask */
895 hdcMask = CreateCompatibleDC(hdcDest);
896 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
897 oldMask = SelectObject(hdcMask, bmpMask);
898 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
899 TRACE("Failed to create mask\n");
900 goto error;
903 /* Replace transparent color with black */
904 SetBkColor(hdcWork, RGB(0,0,0));
905 SetTextColor(hdcWork, RGB(255,255,255));
906 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
907 TRACE("Failed to mask out background\n");
908 goto error;
911 /* Replace non-transparent area on destination with black */
912 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
913 TRACE("Failed to clear destination area\n");
914 goto error;
917 /* Draw the image */
918 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
919 TRACE("Failed to paint image\n");
920 goto error;
923 ret = TRUE;
924 error:
925 SetStretchBltMode(hdcSrc, oldStretchMode);
926 SetBkColor(hdcDest, oldBackground);
927 SetTextColor(hdcDest, oldForeground);
928 if(hdcWork) {
929 SelectObject(hdcWork, oldWork);
930 DeleteDC(hdcWork);
932 if(bmpWork) DeleteObject(bmpWork);
933 if(hdcMask) {
934 SelectObject(hdcMask, oldMask);
935 DeleteDC(hdcMask);
937 if(bmpMask) DeleteObject(bmpMask);
938 return ret;
941 /******************************************************************************
942 * GdiAlphaBlend [GDI32.@]
944 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
945 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
946 BLENDFUNCTION blendFunction)
948 BOOL ret = FALSE;
949 DC *dcDst, *dcSrc;
951 dcSrc = get_dc_ptr( hdcSrc );
952 if (!dcSrc) return FALSE;
954 if ((dcDst = get_dc_ptr( hdcDst )))
956 struct bitblt_coords src, dst;
958 update_dc( dcSrc );
959 update_dc( dcDst );
961 src.log_x = xSrc;
962 src.log_y = ySrc;
963 src.log_width = widthSrc;
964 src.log_height = heightSrc;
965 src.layout = dcSrc->layout;
966 dst.log_x = xDst;
967 dst.log_y = yDst;
968 dst.log_width = widthDst;
969 dst.log_height = heightDst;
970 dst.layout = dcDst->layout;
971 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
973 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",
974 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
975 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
976 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
977 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
978 blendFunction.BlendOp, blendFunction.BlendFlags,
979 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
981 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
982 src.log_width < 0 || src.log_height < 0 ||
983 (!is_rect_empty( &dcSrc->device_rect ) &&
984 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
985 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
987 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
988 SetLastError( ERROR_INVALID_PARAMETER );
989 ret = FALSE;
991 else if (dst.log_width < 0 || dst.log_height < 0)
993 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
994 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
995 SetLastError( ERROR_INVALID_PARAMETER );
996 ret = FALSE;
998 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
999 src.y + src.height > dst.y && src.y < dst.y + dst.height)
1001 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
1002 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
1003 SetLastError( ERROR_INVALID_PARAMETER );
1004 ret = FALSE;
1006 else if (!ret)
1008 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
1009 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
1010 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
1012 release_dc_ptr( dcDst );
1014 release_dc_ptr( dcSrc );
1015 return ret;
1018 /*********************************************************************
1019 * PlgBlt [GDI32.@]
1022 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
1023 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
1024 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
1026 int oldgMode;
1027 /* parallelogram coords */
1028 POINT plg[3];
1029 /* rect coords */
1030 POINT rect[3];
1031 XFORM xf;
1032 XFORM SrcXf;
1033 XFORM oldDestXf;
1034 double det;
1036 /* save actual mode, set GM_ADVANCED */
1037 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1038 if (oldgMode == 0)
1039 return FALSE;
1041 memcpy(plg,lpPoint,sizeof(POINT)*3);
1042 rect[0].x = nXSrc;
1043 rect[0].y = nYSrc;
1044 rect[1].x = nXSrc + nWidth;
1045 rect[1].y = nYSrc;
1046 rect[2].x = nXSrc;
1047 rect[2].y = nYSrc + nHeight;
1048 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1049 /* determinant */
1050 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);
1052 if (fabs(det) < 1e-5)
1054 SetGraphicsMode(hdcDest,oldgMode);
1055 return FALSE;
1058 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1059 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1061 /* X components */
1062 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;
1063 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;
1064 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1065 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1066 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1067 ) / det;
1069 /* Y components */
1070 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;
1071 xf.eM22 = (rect[1].x*(plg[2].y - plg[0].y) - rect[2].x*(plg[1].y - plg[0].y) - rect[0].x*(plg[2].y - plg[1].y)) / det;
1072 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1073 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1074 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1075 ) / det;
1077 GetWorldTransform(hdcSrc,&SrcXf);
1078 CombineTransform(&xf,&xf,&SrcXf);
1080 /* save actual dest transform */
1081 GetWorldTransform(hdcDest,&oldDestXf);
1083 SetWorldTransform(hdcDest,&xf);
1084 /* now destination and source DCs use same coords */
1085 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1086 hdcSrc, nXSrc,nYSrc,
1087 hbmMask,xMask,yMask,
1088 SRCCOPY);
1089 /* restore dest DC */
1090 SetWorldTransform(hdcDest,&oldDestXf);
1091 SetGraphicsMode(hdcDest,oldgMode);
1093 return TRUE;