gdi32: Directly use ntgdi interface to select objects.
[wine.git] / dlls / gdi32 / bitblt.c
blob47b7c7152e5f203f4cc5e91c83b83d6d318f44d0
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 <stdarg.h>
22 #include <limits.h>
23 #include <math.h>
24 #include <float.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "gdi_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
34 static inline BOOL rop_uses_src( DWORD rop )
36 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
39 BOOL intersect_vis_rectangles( struct bitblt_coords *dst, struct bitblt_coords *src )
41 RECT rect;
43 /* intersect the rectangles */
45 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
47 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
48 if (!intersect_rect( &rect, &src->visrect, &dst->visrect )) return FALSE;
49 src->visrect = dst->visrect = rect;
50 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
52 else /* stretching */
54 /* map source rectangle into destination coordinates */
55 rect = src->visrect;
56 offset_rect( &rect,
57 -src->x - (src->width < 0 ? 1 : 0),
58 -src->y - (src->height < 0 ? 1 : 0));
59 rect.left = rect.left * dst->width / src->width;
60 rect.top = rect.top * dst->height / src->height;
61 rect.right = rect.right * dst->width / src->width;
62 rect.bottom = rect.bottom * dst->height / src->height;
63 order_rect( &rect );
65 /* when the source rectangle needs to flip and it doesn't fit in the source device
66 area, the destination area isn't flipped. So, adjust destination coordinates */
67 if (src->width < 0 && dst->width > 0 &&
68 (src->x + src->width + 1 < src->visrect.left || src->x > src->visrect.right))
69 dst->x += (dst->width - rect.right) - rect.left;
70 else if (src->width > 0 && dst->width < 0 &&
71 (src->x < src->visrect.left || src->x + src->width > src->visrect.right))
72 dst->x -= rect.right - (dst->width - rect.left);
74 if (src->height < 0 && dst->height > 0 &&
75 (src->y + src->height + 1 < src->visrect.top || src->y > src->visrect.bottom))
76 dst->y += (dst->height - rect.bottom) - rect.top;
77 else if (src->height > 0 && dst->height < 0 &&
78 (src->y < src->visrect.top || src->y + src->height > src->visrect.bottom))
79 dst->y -= rect.bottom - (dst->height - rect.top);
81 offset_rect( &rect, dst->x, dst->y );
83 /* avoid rounding errors */
84 rect.left--;
85 rect.top--;
86 rect.right++;
87 rect.bottom++;
88 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
90 /* map destination rectangle back to source coordinates */
91 rect = dst->visrect;
92 offset_rect( &rect,
93 -dst->x - (dst->width < 0 ? 1 : 0),
94 -dst->y - (dst->height < 0 ? 1 : 0));
95 rect.left = src->x + rect.left * src->width / dst->width;
96 rect.top = src->y + rect.top * src->height / dst->height;
97 rect.right = src->x + rect.right * src->width / dst->width;
98 rect.bottom = src->y + rect.bottom * src->height / dst->height;
99 order_rect( &rect );
101 /* avoid rounding errors */
102 rect.left--;
103 rect.top--;
104 rect.right++;
105 rect.bottom++;
106 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
108 return TRUE;
111 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
112 DC *dc_src, struct bitblt_coords *src )
114 RECT rect;
116 /* get the destination visible rectangle */
118 rect.left = dst->log_x;
119 rect.top = dst->log_y;
120 rect.right = dst->log_x + dst->log_width;
121 rect.bottom = dst->log_y + dst->log_height;
122 lp_to_dp( dc_dst, (POINT *)&rect, 2 );
123 dst->x = rect.left;
124 dst->y = rect.top;
125 dst->width = rect.right - rect.left;
126 dst->height = rect.bottom - rect.top;
127 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
129 dst->x += dst->width;
130 dst->width = -dst->width;
132 get_bounding_rect( &rect, dst->x, dst->y, dst->width, dst->height );
134 clip_visrect( dc_dst, &dst->visrect, &rect );
136 /* get the source visible rectangle */
138 if (!src) return !is_rect_empty( &dst->visrect );
140 rect.left = src->log_x;
141 rect.top = src->log_y;
142 rect.right = src->log_x + src->log_width;
143 rect.bottom = src->log_y + src->log_height;
144 lp_to_dp( dc_src, (POINT *)&rect, 2 );
145 src->x = rect.left;
146 src->y = rect.top;
147 src->width = rect.right - rect.left;
148 src->height = rect.bottom - rect.top;
149 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
151 src->x += src->width;
152 src->width = -src->width;
154 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
156 if (!clip_device_rect( dc_src, &src->visrect, &rect )) return FALSE;
157 if (is_rect_empty( &dst->visrect )) return FALSE;
159 return intersect_vis_rectangles( dst, src );
162 void CDECL free_heap_bits( struct gdi_image_bits *bits )
164 HeapFree( GetProcessHeap(), 0, bits->ptr );
167 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
168 BITMAPINFO *dst_info, struct gdi_image_bits *bits )
170 void *ptr;
171 DWORD err;
172 BOOL top_down = dst_info->bmiHeader.biHeight < 0;
174 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
175 dst_info->bmiHeader.biHeight = src->visrect.bottom - src->visrect.top;
176 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
177 if (top_down) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
179 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
180 return ERROR_OUTOFMEMORY;
182 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
183 if (bits->free) bits->free( bits );
184 bits->ptr = ptr;
185 bits->is_copy = TRUE;
186 bits->free = free_heap_bits;
187 return err;
190 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
191 BITMAPINFO *dst_info, struct bitblt_coords *dst,
192 struct gdi_image_bits *bits, int mode )
194 void *ptr;
195 DWORD err;
197 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
198 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
199 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
201 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
202 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
203 return ERROR_OUTOFMEMORY;
205 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
206 if (bits->free) bits->free( bits );
207 bits->ptr = ptr;
208 bits->is_copy = TRUE;
209 bits->free = free_heap_bits;
210 return err;
213 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
214 struct bitblt_coords *src, BITMAPINFO *dst_info,
215 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
217 if (!dst_bits->is_copy)
219 int size = dst_info->bmiHeader.biSizeImage;
220 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
221 if (!ptr) return ERROR_OUTOFMEMORY;
222 memcpy( ptr, dst_bits->ptr, size );
223 if (dst_bits->free) dst_bits->free( dst_bits );
224 dst_bits->ptr = ptr;
225 dst_bits->is_copy = TRUE;
226 dst_bits->free = free_heap_bits;
228 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
231 static RGBQUAD get_dc_rgb_color( DC *dc, int color_table_size, COLORREF color )
233 RGBQUAD ret = { 0, 0, 0, 0 };
235 if (color & (1 << 24)) /* PALETTEINDEX */
237 PALETTEENTRY pal;
239 if (!GetPaletteEntries( dc->hPalette, LOWORD(color), 1, &pal ))
240 GetPaletteEntries( dc->hPalette, 0, 1, &pal );
241 ret.rgbRed = pal.peRed;
242 ret.rgbGreen = pal.peGreen;
243 ret.rgbBlue = pal.peBlue;
244 return ret;
246 if (color >> 16 == 0x10ff) /* DIBINDEX */
248 if (color_table_size)
250 if (LOWORD(color) >= color_table_size) color = 0x10ff0000; /* fallback to index 0 */
251 *(DWORD *)&ret = color;
253 return ret;
255 ret.rgbRed = GetRValue( color );
256 ret.rgbGreen = GetGValue( color );
257 ret.rgbBlue = GetBValue( color );
258 return ret;
261 /* helper to retrieve either both colors or only the background color for monochrome blits */
262 void get_mono_dc_colors( DC *dc, int color_table_size, BITMAPINFO *info, int count )
264 info->bmiColors[count - 1] = get_dc_rgb_color( dc, color_table_size, dc->backgroundColor );
265 if (count > 1) info->bmiColors[0] = get_dc_rgb_color( dc, color_table_size, dc->textColor );
266 info->bmiHeader.biClrUsed = count;
269 /***********************************************************************
270 * null driver fallback implementations
273 BOOL CDECL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
274 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
276 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
277 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
278 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
279 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
280 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
281 DWORD err;
282 struct gdi_image_bits bits;
284 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
285 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
286 return FALSE;
288 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
289 copy_bitmapinfo( dst_info, src_info );
290 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
291 if (err == ERROR_BAD_FORMAT)
293 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
295 /* 1-bpp source without a color table uses the destination DC colors */
296 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
297 get_mono_dc_colors( dc_dst, dst_info->bmiHeader.biClrUsed, src_info, 2 );
299 /* 1-bpp destination without a color table requires a fake 1-entry table
300 * that contains only the background color */
301 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
302 get_mono_dc_colors( dc_src, src_info->bmiHeader.biClrUsed, dst_info, 1 );
304 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
306 /* get rid of the fake destination table */
307 dst_info->bmiHeader.biClrUsed = dst_colors;
308 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
312 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
313 ((src->width != dst->width) || (src->height != dst->height)))
315 copy_bitmapinfo( src_info, dst_info );
316 err = stretch_bits( src_info, src, dst_info, dst, &bits, dc_dst->stretchBltMode );
317 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
320 if (bits.free) bits.free( &bits );
321 return !err;
325 BOOL CDECL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
326 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
328 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
329 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
330 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
331 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
332 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
333 DWORD err;
334 struct gdi_image_bits bits;
336 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
337 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
338 if (err) goto done;
340 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
341 copy_bitmapinfo( dst_info, src_info );
342 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
343 if (err == ERROR_BAD_FORMAT)
345 err = convert_bits( src_info, src, dst_info, &bits );
346 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
349 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
350 ((src->width != dst->width) || (src->height != dst->height)))
352 copy_bitmapinfo( src_info, dst_info );
353 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
354 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
357 if (bits.free) bits.free( &bits );
358 done:
359 if (err) SetLastError( err );
360 return !err;
364 DWORD CDECL nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
365 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
367 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
368 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
369 struct gdi_image_bits dst_bits;
370 struct bitblt_coords orig_dst;
371 DWORD *masks = (DWORD *)info->bmiColors;
372 DC *dc = get_nulldrv_dc( dev );
373 DWORD err;
375 if (info->bmiHeader.biPlanes != 1) goto update_format;
376 if (info->bmiHeader.biBitCount != 32) goto update_format;
377 if (info->bmiHeader.biCompression == BI_BITFIELDS)
379 if (blend.AlphaFormat & AC_SRC_ALPHA) return ERROR_INVALID_PARAMETER;
380 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
381 goto update_format;
384 if (!bits) return ERROR_SUCCESS;
385 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
387 dev = GET_DC_PHYSDEV( dc, pGetImage );
388 orig_dst = *dst;
389 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
390 if (err) return err;
392 dev = GET_DC_PHYSDEV( dc, pPutImage );
393 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
394 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
396 if (dst_bits.free) dst_bits.free( &dst_bits );
397 return err;
399 update_format:
400 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
401 return ERROR_INVALID_PARAMETER;
403 info->bmiHeader.biPlanes = 1;
404 info->bmiHeader.biBitCount = 32;
405 info->bmiHeader.biCompression = BI_BITFIELDS;
406 info->bmiHeader.biClrUsed = 0;
407 masks[0] = 0xff0000;
408 masks[1] = 0x00ff00;
409 masks[2] = 0x0000ff;
410 return ERROR_BAD_FORMAT;
413 BOOL CDECL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
414 void * grad_array, ULONG ngrad, ULONG mode )
416 DC *dc = get_nulldrv_dc( dev );
417 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
418 BITMAPINFO *info = (BITMAPINFO *)buffer;
419 struct bitblt_coords src, dst;
420 struct gdi_image_bits bits;
421 unsigned int i;
422 POINT *pts;
423 BOOL ret = FALSE;
424 DWORD err;
425 HRGN rgn;
427 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
428 for (i = 0; i < nvert; i++)
430 pts[i].x = vert_array[i].x;
431 pts[i].y = vert_array[i].y;
433 lp_to_dp( dc, pts, nvert );
435 /* compute bounding rect of all the rectangles/triangles */
436 reset_bounds( &dst.visrect );
437 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
439 ULONG v = ((ULONG *)grad_array)[i];
440 dst.visrect.left = min( dst.visrect.left, pts[v].x );
441 dst.visrect.top = min( dst.visrect.top, pts[v].y );
442 dst.visrect.right = max( dst.visrect.right, pts[v].x );
443 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
446 dst.x = dst.visrect.left;
447 dst.y = dst.visrect.top;
448 dst.width = dst.visrect.right - dst.visrect.left;
449 dst.height = dst.visrect.bottom - dst.visrect.top;
450 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
452 /* query the bitmap format */
453 info->bmiHeader.biSize = sizeof(info->bmiHeader);
454 info->bmiHeader.biPlanes = 1;
455 info->bmiHeader.biBitCount = 0;
456 info->bmiHeader.biCompression = BI_RGB;
457 info->bmiHeader.biXPelsPerMeter = 0;
458 info->bmiHeader.biYPelsPerMeter = 0;
459 info->bmiHeader.biClrUsed = 0;
460 info->bmiHeader.biClrImportant = 0;
461 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
462 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
463 info->bmiHeader.biSizeImage = 0;
464 dev = GET_DC_PHYSDEV( dc, pPutImage );
465 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
466 if (err && err != ERROR_BAD_FORMAT) goto done;
468 info->bmiHeader.biSizeImage = get_dib_image_size( info );
469 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
470 goto done;
471 bits.is_copy = TRUE;
472 bits.free = free_heap_bits;
474 /* make src and points relative to the bitmap */
475 src = dst;
476 src.x -= dst.visrect.left;
477 src.y -= dst.visrect.top;
478 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
479 for (i = 0; i < nvert; i++)
481 pts[i].x -= dst.visrect.left;
482 pts[i].y -= dst.visrect.top;
485 rgn = CreateRectRgn( 0, 0, 0, 0 );
486 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
487 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
488 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
490 if (bits.free) bits.free( &bits );
491 DeleteObject( rgn );
493 done:
494 HeapFree( GetProcessHeap(), 0, pts );
495 return ret;
498 COLORREF CDECL nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
500 DC *dc = get_nulldrv_dc( dev );
501 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
502 BITMAPINFO *info = (BITMAPINFO *)buffer;
503 struct bitblt_coords src;
504 struct gdi_image_bits bits;
505 COLORREF ret;
507 src.visrect.left = x;
508 src.visrect.top = y;
509 lp_to_dp( dc, (POINT *)&src.visrect, 1 );
510 src.visrect.right = src.visrect.left + 1;
511 src.visrect.bottom = src.visrect.top + 1;
512 src.x = src.visrect.left;
513 src.y = src.visrect.top;
514 src.width = src.height = 1;
516 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
518 dev = GET_DC_PHYSDEV( dc, pGetImage );
519 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
521 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
522 if (bits.free) bits.free( &bits );
523 return ret;
527 /***********************************************************************
528 * PatBlt (GDI32.@)
530 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
532 DC * dc;
533 BOOL ret = FALSE;
535 if (rop_uses_src( rop )) return FALSE;
536 if ((dc = get_dc_ptr( hdc )))
538 struct bitblt_coords dst;
540 update_dc( dc );
542 dst.log_x = left;
543 dst.log_y = top;
544 dst.log_width = width;
545 dst.log_height = height;
546 dst.layout = dc->layout;
547 if (rop & NOMIRRORBITMAP)
549 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
550 rop &= ~NOMIRRORBITMAP;
552 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
554 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
555 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
556 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
558 if (!ret)
560 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
561 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
563 release_dc_ptr( dc );
565 return ret;
569 /***********************************************************************
570 * BitBlt (GDI32.@)
572 BOOL WINAPI DECLSPEC_HOTPATCH BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
573 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
575 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
576 else return StretchBlt( hdcDst, xDst, yDst, width, height,
577 hdcSrc, xSrc, ySrc, width, height, rop );
581 /***********************************************************************
582 * StretchBlt (GDI32.@)
584 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
585 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
587 BOOL ret = FALSE;
588 DC *dcDst, *dcSrc;
590 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
592 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
594 if ((dcSrc = get_dc_ptr( hdcSrc )))
596 struct bitblt_coords src, dst;
598 update_dc( dcSrc );
599 update_dc( dcDst );
601 src.log_x = xSrc;
602 src.log_y = ySrc;
603 src.log_width = widthSrc;
604 src.log_height = heightSrc;
605 src.layout = dcSrc->layout;
606 dst.log_x = xDst;
607 dst.log_y = yDst;
608 dst.log_width = widthDst;
609 dst.log_height = heightDst;
610 dst.layout = dcDst->layout;
611 if (rop & NOMIRRORBITMAP)
613 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
614 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
615 rop &= ~NOMIRRORBITMAP;
617 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
619 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",
620 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
621 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
622 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
623 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
625 if (!ret)
627 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
628 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
629 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
631 release_dc_ptr( dcSrc );
633 release_dc_ptr( dcDst );
634 return ret;
637 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
638 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
640 /***********************************************************************
641 * MaskBlt [GDI32.@]
643 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
644 INT nWidth, INT nHeight, HDC hdcSrc,
645 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
646 INT xMask, INT yMask, DWORD dwRop)
648 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
649 HDC hDC1, hDC2;
650 HBRUSH hbrMask, hbrDst, hbrTmp;
652 static const DWORD ROP3Table[256] =
654 0x00000042, 0x00010289,
655 0x00020C89, 0x000300AA,
656 0x00040C88, 0x000500A9,
657 0x00060865, 0x000702C5,
658 0x00080F08, 0x00090245,
659 0x000A0329, 0x000B0B2A,
660 0x000C0324, 0x000D0B25,
661 0x000E08A5, 0x000F0001,
662 0x00100C85, 0x001100A6,
663 0x00120868, 0x001302C8,
664 0x00140869, 0x001502C9,
665 0x00165CCA, 0x00171D54,
666 0x00180D59, 0x00191CC8,
667 0x001A06C5, 0x001B0768,
668 0x001C06CA, 0x001D0766,
669 0x001E01A5, 0x001F0385,
670 0x00200F09, 0x00210248,
671 0x00220326, 0x00230B24,
672 0x00240D55, 0x00251CC5,
673 0x002606C8, 0x00271868,
674 0x00280369, 0x002916CA,
675 0x002A0CC9, 0x002B1D58,
676 0x002C0784, 0x002D060A,
677 0x002E064A, 0x002F0E2A,
678 0x0030032A, 0x00310B28,
679 0x00320688, 0x00330008,
680 0x003406C4, 0x00351864,
681 0x003601A8, 0x00370388,
682 0x0038078A, 0x00390604,
683 0x003A0644, 0x003B0E24,
684 0x003C004A, 0x003D18A4,
685 0x003E1B24, 0x003F00EA,
686 0x00400F0A, 0x00410249,
687 0x00420D5D, 0x00431CC4,
688 0x00440328, 0x00450B29,
689 0x004606C6, 0x0047076A,
690 0x00480368, 0x004916C5,
691 0x004A0789, 0x004B0605,
692 0x004C0CC8, 0x004D1954,
693 0x004E0645, 0x004F0E25,
694 0x00500325, 0x00510B26,
695 0x005206C9, 0x00530764,
696 0x005408A9, 0x00550009,
697 0x005601A9, 0x00570389,
698 0x00580785, 0x00590609,
699 0x005A0049, 0x005B18A9,
700 0x005C0649, 0x005D0E29,
701 0x005E1B29, 0x005F00E9,
702 0x00600365, 0x006116C6,
703 0x00620786, 0x00630608,
704 0x00640788, 0x00650606,
705 0x00660046, 0x006718A8,
706 0x006858A6, 0x00690145,
707 0x006A01E9, 0x006B178A,
708 0x006C01E8, 0x006D1785,
709 0x006E1E28, 0x006F0C65,
710 0x00700CC5, 0x00711D5C,
711 0x00720648, 0x00730E28,
712 0x00740646, 0x00750E26,
713 0x00761B28, 0x007700E6,
714 0x007801E5, 0x00791786,
715 0x007A1E29, 0x007B0C68,
716 0x007C1E24, 0x007D0C69,
717 0x007E0955, 0x007F03C9,
718 0x008003E9, 0x00810975,
719 0x00820C49, 0x00831E04,
720 0x00840C48, 0x00851E05,
721 0x008617A6, 0x008701C5,
722 0x008800C6, 0x00891B08,
723 0x008A0E06, 0x008B0666,
724 0x008C0E08, 0x008D0668,
725 0x008E1D7C, 0x008F0CE5,
726 0x00900C45, 0x00911E08,
727 0x009217A9, 0x009301C4,
728 0x009417AA, 0x009501C9,
729 0x00960169, 0x0097588A,
730 0x00981888, 0x00990066,
731 0x009A0709, 0x009B07A8,
732 0x009C0704, 0x009D07A6,
733 0x009E16E6, 0x009F0345,
734 0x00A000C9, 0x00A11B05,
735 0x00A20E09, 0x00A30669,
736 0x00A41885, 0x00A50065,
737 0x00A60706, 0x00A707A5,
738 0x00A803A9, 0x00A90189,
739 0x00AA0029, 0x00AB0889,
740 0x00AC0744, 0x00AD06E9,
741 0x00AE0B06, 0x00AF0229,
742 0x00B00E05, 0x00B10665,
743 0x00B21974, 0x00B30CE8,
744 0x00B4070A, 0x00B507A9,
745 0x00B616E9, 0x00B70348,
746 0x00B8074A, 0x00B906E6,
747 0x00BA0B09, 0x00BB0226,
748 0x00BC1CE4, 0x00BD0D7D,
749 0x00BE0269, 0x00BF08C9,
750 0x00C000CA, 0x00C11B04,
751 0x00C21884, 0x00C3006A,
752 0x00C40E04, 0x00C50664,
753 0x00C60708, 0x00C707AA,
754 0x00C803A8, 0x00C90184,
755 0x00CA0749, 0x00CB06E4,
756 0x00CC0020, 0x00CD0888,
757 0x00CE0B08, 0x00CF0224,
758 0x00D00E0A, 0x00D1066A,
759 0x00D20705, 0x00D307A4,
760 0x00D41D78, 0x00D50CE9,
761 0x00D616EA, 0x00D70349,
762 0x00D80745, 0x00D906E8,
763 0x00DA1CE9, 0x00DB0D75,
764 0x00DC0B04, 0x00DD0228,
765 0x00DE0268, 0x00DF08C8,
766 0x00E003A5, 0x00E10185,
767 0x00E20746, 0x00E306EA,
768 0x00E40748, 0x00E506E5,
769 0x00E61CE8, 0x00E70D79,
770 0x00E81D74, 0x00E95CE6,
771 0x00EA02E9, 0x00EB0849,
772 0x00EC02E8, 0x00ED0848,
773 0x00EE0086, 0x00EF0A08,
774 0x00F00021, 0x00F10885,
775 0x00F20B05, 0x00F3022A,
776 0x00F40B0A, 0x00F50225,
777 0x00F60265, 0x00F708C5,
778 0x00F802E5, 0x00F90845,
779 0x00FA0089, 0x00FB0A09,
780 0x00FC008A, 0x00FD0A0A,
781 0x00FE02A9, 0x00FF0062,
784 if (!hbmMask)
785 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
787 hbrMask = CreatePatternBrush(hbmMask);
788 hbrDst = NtGdiSelectBrush(hdcDest, GetStockObject(NULL_BRUSH));
790 /* make bitmap */
791 hDC1 = CreateCompatibleDC(hdcDest);
792 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
793 hOldBitmap1 = NtGdiSelectBitmap(hDC1, hBitmap1);
795 /* draw using bkgnd rop */
796 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
797 hbrTmp = NtGdiSelectBrush(hDC1, hbrDst);
798 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
799 NtGdiSelectBrush(hDC1, hbrTmp);
801 /* make bitmap */
802 hDC2 = CreateCompatibleDC(hdcDest);
803 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
804 hOldBitmap2 = NtGdiSelectBitmap(hDC2, hBitmap2);
806 /* draw using foregnd rop */
807 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
808 hbrTmp = NtGdiSelectBrush(hDC2, hbrDst);
809 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
811 /* combine both using the mask as a pattern brush */
812 NtGdiSelectBrush(hDC2, hbrMask);
813 SetBrushOrgEx(hDC2, -xMask, -yMask, NULL);
814 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
815 NtGdiSelectBrush(hDC2, hbrTmp);
817 /* blit to dst */
818 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
820 /* restore all objects */
821 NtGdiSelectBrush(hdcDest, hbrDst);
822 NtGdiSelectBitmap(hDC1, hOldBitmap1);
823 NtGdiSelectBitmap(hDC2, hOldBitmap2);
825 /* delete all temp objects */
826 DeleteObject(hBitmap1);
827 DeleteObject(hBitmap2);
828 DeleteObject(hbrMask);
830 DeleteDC(hDC1);
831 DeleteDC(hDC2);
833 return TRUE;
836 /******************************************************************************
837 * GdiTransparentBlt [GDI32.@]
839 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
840 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
841 UINT crTransparent )
843 BOOL ret = FALSE;
844 HDC hdcWork;
845 HBITMAP bmpWork;
846 HGDIOBJ oldWork;
847 HDC hdcMask = NULL;
848 HBITMAP bmpMask = NULL;
849 HBITMAP oldMask = NULL;
850 COLORREF oldBackground;
851 COLORREF oldForeground;
852 int oldStretchMode;
853 DIBSECTION dib;
855 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
856 TRACE("Cannot mirror\n");
857 return FALSE;
860 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
861 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
863 /* Stretch bitmap */
864 oldStretchMode = GetStretchBltMode(hdcSrc);
865 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
866 SetStretchBltMode(hdcSrc, COLORONCOLOR);
867 hdcWork = CreateCompatibleDC(hdcDest);
868 if ((GetObjectType( hdcDest ) != OBJ_MEMDC ||
869 GetObjectW( GetCurrentObject( hdcDest, OBJ_BITMAP ), sizeof(dib), &dib ) == sizeof(BITMAP)) &&
870 GetDeviceCaps( hdcDest, BITSPIXEL ) == 32)
872 /* screen DCs or DDBs are not supposed to have an alpha channel, so use a 24-bpp bitmap as copy */
873 BITMAPINFO info;
874 info.bmiHeader.biSize = sizeof(info.bmiHeader);
875 info.bmiHeader.biWidth = widthDest;
876 info.bmiHeader.biHeight = heightDest;
877 info.bmiHeader.biPlanes = 1;
878 info.bmiHeader.biBitCount = 24;
879 info.bmiHeader.biCompression = BI_RGB;
880 bmpWork = CreateDIBSection( 0, &info, DIB_RGB_COLORS, NULL, NULL, 0 );
882 else bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
883 oldWork = NtGdiSelectBitmap(hdcWork, bmpWork);
884 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
885 TRACE("Failed to stretch\n");
886 goto error;
888 SetBkColor(hdcWork, crTransparent);
890 /* Create mask */
891 hdcMask = CreateCompatibleDC(hdcDest);
892 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
893 oldMask = NtGdiSelectBitmap(hdcMask, bmpMask);
894 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
895 TRACE("Failed to create mask\n");
896 goto error;
899 /* Replace transparent color with black */
900 SetBkColor(hdcWork, RGB(0,0,0));
901 SetTextColor(hdcWork, RGB(255,255,255));
902 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
903 TRACE("Failed to mask out background\n");
904 goto error;
907 /* Replace non-transparent area on destination with black */
908 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
909 TRACE("Failed to clear destination area\n");
910 goto error;
913 /* Draw the image */
914 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
915 TRACE("Failed to paint image\n");
916 goto error;
919 ret = TRUE;
920 error:
921 SetStretchBltMode(hdcSrc, oldStretchMode);
922 SetBkColor(hdcDest, oldBackground);
923 SetTextColor(hdcDest, oldForeground);
924 if(hdcWork) {
925 NtGdiSelectBitmap(hdcWork, oldWork);
926 DeleteDC(hdcWork);
928 if(bmpWork) DeleteObject(bmpWork);
929 if(hdcMask) {
930 NtGdiSelectBitmap(hdcMask, oldMask);
931 DeleteDC(hdcMask);
933 if(bmpMask) DeleteObject(bmpMask);
934 return ret;
937 /******************************************************************************
938 * GdiAlphaBlend [GDI32.@]
940 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
941 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
942 BLENDFUNCTION blendFunction)
944 BOOL ret = FALSE;
945 DC *dcDst, *dcSrc;
947 dcSrc = get_dc_ptr( hdcSrc );
948 if (!dcSrc) return FALSE;
950 if ((dcDst = get_dc_ptr( hdcDst )))
952 struct bitblt_coords src, dst;
954 update_dc( dcSrc );
955 update_dc( dcDst );
957 src.log_x = xSrc;
958 src.log_y = ySrc;
959 src.log_width = widthSrc;
960 src.log_height = heightSrc;
961 src.layout = dcSrc->layout;
962 dst.log_x = xDst;
963 dst.log_y = yDst;
964 dst.log_width = widthDst;
965 dst.log_height = heightDst;
966 dst.layout = dcDst->layout;
967 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
969 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",
970 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
971 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
972 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
973 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
974 blendFunction.BlendOp, blendFunction.BlendFlags,
975 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
977 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
978 src.log_width < 0 || src.log_height < 0 ||
979 (!is_rect_empty( &dcSrc->device_rect ) &&
980 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
981 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
983 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
984 SetLastError( ERROR_INVALID_PARAMETER );
985 ret = FALSE;
987 else if (dst.log_width < 0 || dst.log_height < 0)
989 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
990 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
991 SetLastError( ERROR_INVALID_PARAMETER );
992 ret = FALSE;
994 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
995 src.y + src.height > dst.y && src.y < dst.y + dst.height)
997 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
998 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
999 SetLastError( ERROR_INVALID_PARAMETER );
1000 ret = FALSE;
1002 else if (!ret)
1004 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
1005 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
1006 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
1008 release_dc_ptr( dcDst );
1010 release_dc_ptr( dcSrc );
1011 return ret;
1014 /*********************************************************************
1015 * PlgBlt [GDI32.@]
1018 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
1019 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
1020 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
1022 int oldgMode;
1023 /* parallelogram coords */
1024 POINT plg[3];
1025 /* rect coords */
1026 POINT rect[3];
1027 XFORM xf;
1028 XFORM SrcXf;
1029 XFORM oldDestXf;
1030 double det;
1032 /* save actual mode, set GM_ADVANCED */
1033 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1034 if (oldgMode == 0)
1035 return FALSE;
1037 memcpy(plg,lpPoint,sizeof(POINT)*3);
1038 rect[0].x = nXSrc;
1039 rect[0].y = nYSrc;
1040 rect[1].x = nXSrc + nWidth;
1041 rect[1].y = nYSrc;
1042 rect[2].x = nXSrc;
1043 rect[2].y = nYSrc + nHeight;
1044 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1045 /* determinant */
1046 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);
1048 if (fabs(det) < 1e-5)
1050 SetGraphicsMode(hdcDest,oldgMode);
1051 return FALSE;
1054 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1055 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1057 /* X components */
1058 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;
1059 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;
1060 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1061 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1062 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1063 ) / det;
1065 /* Y components */
1066 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;
1067 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;
1068 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1069 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1070 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1071 ) / det;
1073 GetWorldTransform(hdcSrc,&SrcXf);
1074 CombineTransform(&xf,&xf,&SrcXf);
1076 /* save actual dest transform */
1077 GetWorldTransform(hdcDest,&oldDestXf);
1079 SetWorldTransform(hdcDest,&xf);
1080 /* now destination and source DCs use same coords */
1081 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1082 hdcSrc, nXSrc,nYSrc,
1083 hbmMask,xMask,yMask,
1084 SRCCOPY);
1085 /* restore dest DC */
1086 SetWorldTransform(hdcDest,&oldDestXf);
1087 SetGraphicsMode(hdcDest,oldgMode);
1089 return TRUE;