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
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 static inline void swap_ints( int *i
, int *j
)
50 BOOL
intersect_vis_rectangles( struct bitblt_coords
*dst
, struct bitblt_coords
*src
)
54 /* intersect the rectangles */
56 if ((src
->width
== dst
->width
) && (src
->height
== dst
->height
)) /* no stretching */
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
);
65 /* map source rectangle into destination coordinates */
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
);
76 /* avoid rounding errors */
81 if (!intersect_rect( &dst
->visrect
, &rect
, &dst
->visrect
)) return FALSE
;
83 /* map destination rectangle back to source coordinates */
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
);
94 /* avoid rounding errors */
99 if (!intersect_rect( &src
->visrect
, &rect
, &src
->visrect
)) return FALSE
;
104 static BOOL
get_vis_rectangles( DC
*dc_dst
, struct bitblt_coords
*dst
,
105 DC
*dc_src
, struct bitblt_coords
*src
)
109 /* get the destination visible rectangle */
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 lp_to_dp( dc_dst
, (POINT
*)&rect
, 2 );
118 dst
->width
= rect
.right
- rect
.left
;
119 dst
->height
= rect
.bottom
- rect
.top
;
120 if (dst
->layout
& LAYOUT_RTL
&& dst
->layout
& LAYOUT_BITMAPORIENTATIONPRESERVED
)
122 dst
->x
+= dst
->width
;
123 dst
->width
= -dst
->width
;
125 get_bounding_rect( &rect
, dst
->x
, dst
->y
, dst
->width
, dst
->height
);
127 clip_visrect( dc_dst
, &dst
->visrect
, &rect
);
129 /* get the source visible rectangle */
131 if (!src
) return !is_rect_empty( &dst
->visrect
);
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 lp_to_dp( dc_src
, (POINT
*)&rect
, 2 );
140 src
->width
= rect
.right
- rect
.left
;
141 src
->height
= rect
.bottom
- rect
.top
;
142 if (src
->layout
& LAYOUT_RTL
&& src
->layout
& LAYOUT_BITMAPORIENTATIONPRESERVED
)
144 src
->x
+= src
->width
;
145 src
->width
= -src
->width
;
147 get_bounding_rect( &rect
, src
->x
, src
->y
, src
->width
, src
->height
);
149 if (!clip_device_rect( dc_src
, &src
->visrect
, &rect
)) return FALSE
;
150 if (is_rect_empty( &dst
->visrect
)) return FALSE
;
152 return intersect_vis_rectangles( dst
, src
);
155 void free_heap_bits( struct gdi_image_bits
*bits
)
157 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
160 DWORD
convert_bits( const BITMAPINFO
*src_info
, struct bitblt_coords
*src
,
161 BITMAPINFO
*dst_info
, struct gdi_image_bits
*bits
)
165 BOOL top_down
= dst_info
->bmiHeader
.biHeight
< 0;
167 dst_info
->bmiHeader
.biWidth
= src
->visrect
.right
- src
->visrect
.left
;
168 dst_info
->bmiHeader
.biHeight
= src
->visrect
.bottom
- src
->visrect
.top
;
169 dst_info
->bmiHeader
.biSizeImage
= get_dib_image_size( dst_info
);
170 if (top_down
) dst_info
->bmiHeader
.biHeight
= -dst_info
->bmiHeader
.biHeight
;
172 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, dst_info
->bmiHeader
.biSizeImage
)))
173 return ERROR_OUTOFMEMORY
;
175 err
= convert_bitmapinfo( src_info
, bits
->ptr
, src
, dst_info
, ptr
);
176 if (bits
->free
) bits
->free( bits
);
178 bits
->is_copy
= TRUE
;
179 bits
->free
= free_heap_bits
;
183 DWORD
stretch_bits( const BITMAPINFO
*src_info
, struct bitblt_coords
*src
,
184 BITMAPINFO
*dst_info
, struct bitblt_coords
*dst
,
185 struct gdi_image_bits
*bits
, int mode
)
190 dst_info
->bmiHeader
.biWidth
= dst
->visrect
.right
- dst
->visrect
.left
;
191 dst_info
->bmiHeader
.biHeight
= dst
->visrect
.bottom
- dst
->visrect
.top
;
192 dst_info
->bmiHeader
.biSizeImage
= get_dib_image_size( dst_info
);
194 if (src_info
->bmiHeader
.biHeight
< 0) dst_info
->bmiHeader
.biHeight
= -dst_info
->bmiHeader
.biHeight
;
195 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, dst_info
->bmiHeader
.biSizeImage
)))
196 return ERROR_OUTOFMEMORY
;
198 err
= stretch_bitmapinfo( src_info
, bits
->ptr
, src
, dst_info
, ptr
, dst
, mode
);
199 if (bits
->free
) bits
->free( bits
);
201 bits
->is_copy
= TRUE
;
202 bits
->free
= free_heap_bits
;
206 static DWORD
blend_bits( const BITMAPINFO
*src_info
, const struct gdi_image_bits
*src_bits
,
207 struct bitblt_coords
*src
, BITMAPINFO
*dst_info
,
208 struct gdi_image_bits
*dst_bits
, struct bitblt_coords
*dst
, BLENDFUNCTION blend
)
210 if (!dst_bits
->is_copy
)
212 int size
= dst_info
->bmiHeader
.biSizeImage
;
213 void *ptr
= HeapAlloc( GetProcessHeap(), 0, size
);
214 if (!ptr
) return ERROR_OUTOFMEMORY
;
215 memcpy( ptr
, dst_bits
->ptr
, size
);
216 if (dst_bits
->free
) dst_bits
->free( dst_bits
);
218 dst_bits
->is_copy
= TRUE
;
219 dst_bits
->free
= free_heap_bits
;
221 return blend_bitmapinfo( src_info
, src_bits
->ptr
, src
, dst_info
, dst_bits
->ptr
, dst
, blend
);
224 static RGBQUAD
get_dc_rgb_color( DC
*dc
, int color_table_size
, COLORREF color
)
226 RGBQUAD ret
= { 0, 0, 0, 0 };
228 if (color
& (1 << 24)) /* PALETTEINDEX */
232 if (!GetPaletteEntries( dc
->hPalette
, LOWORD(color
), 1, &pal
))
233 GetPaletteEntries( dc
->hPalette
, 0, 1, &pal
);
234 ret
.rgbRed
= pal
.peRed
;
235 ret
.rgbGreen
= pal
.peGreen
;
236 ret
.rgbBlue
= pal
.peBlue
;
239 if (color
>> 16 == 0x10ff) /* DIBINDEX */
241 if (color_table_size
)
243 if (LOWORD(color
) >= color_table_size
) color
= 0x10ff0000; /* fallback to index 0 */
244 *(DWORD
*)&ret
= color
;
248 ret
.rgbRed
= GetRValue( color
);
249 ret
.rgbGreen
= GetGValue( color
);
250 ret
.rgbBlue
= GetBValue( color
);
254 /* helper to retrieve either both colors or only the background color for monochrome blits */
255 void get_mono_dc_colors( DC
*dc
, int color_table_size
, BITMAPINFO
*info
, int count
)
257 info
->bmiColors
[count
- 1] = get_dc_rgb_color( dc
, color_table_size
, dc
->backgroundColor
);
258 if (count
> 1) info
->bmiColors
[0] = get_dc_rgb_color( dc
, color_table_size
, dc
->textColor
);
259 info
->bmiHeader
.biClrUsed
= count
;
262 /***********************************************************************
263 * null driver fallback implementations
266 BOOL
nulldrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
267 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
269 DC
*dc_src
= get_physdev_dc( src_dev
), *dc_dst
= get_nulldrv_dc( dst_dev
);
270 char src_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
271 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
272 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_buffer
;
273 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
275 struct gdi_image_bits bits
;
277 src_dev
= GET_DC_PHYSDEV( dc_src
, pGetImage
);
278 if (src_dev
->funcs
->pGetImage( src_dev
, src_info
, &bits
, src
))
281 dst_dev
= GET_DC_PHYSDEV( dc_dst
, pPutImage
);
282 copy_bitmapinfo( dst_info
, src_info
);
283 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, dst_info
, &bits
, src
, dst
, rop
);
284 if (err
== ERROR_BAD_FORMAT
)
286 DWORD dst_colors
= dst_info
->bmiHeader
.biClrUsed
;
288 /* 1-bpp source without a color table uses the destination DC colors */
289 if (src_info
->bmiHeader
.biBitCount
== 1 && !src_info
->bmiHeader
.biClrUsed
)
290 get_mono_dc_colors( dc_dst
, dst_info
->bmiHeader
.biClrUsed
, src_info
, 2 );
292 /* 1-bpp destination without a color table requires a fake 1-entry table
293 * that contains only the background color */
294 if (dst_info
->bmiHeader
.biBitCount
== 1 && !dst_colors
)
295 get_mono_dc_colors( dc_src
, src_info
->bmiHeader
.biClrUsed
, dst_info
, 1 );
297 if (!(err
= convert_bits( src_info
, src
, dst_info
, &bits
)))
299 /* get rid of the fake destination table */
300 dst_info
->bmiHeader
.biClrUsed
= dst_colors
;
301 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, dst_info
, &bits
, src
, dst
, rop
);
305 if (err
== ERROR_TRANSFORM_NOT_SUPPORTED
&&
306 ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)))
308 copy_bitmapinfo( src_info
, dst_info
);
309 err
= stretch_bits( src_info
, src
, dst_info
, dst
, &bits
, dc_dst
->stretchBltMode
);
310 if (!err
) err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, dst_info
, &bits
, src
, dst
, rop
);
313 if (bits
.free
) bits
.free( &bits
);
318 BOOL
nulldrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
319 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION func
)
321 DC
*dc_src
= get_physdev_dc( src_dev
), *dc_dst
= get_nulldrv_dc( dst_dev
);
322 char src_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
323 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
324 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_buffer
;
325 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
327 struct gdi_image_bits bits
;
329 src_dev
= GET_DC_PHYSDEV( dc_src
, pGetImage
);
330 err
= src_dev
->funcs
->pGetImage( src_dev
, src_info
, &bits
, src
);
333 dst_dev
= GET_DC_PHYSDEV( dc_dst
, pBlendImage
);
334 copy_bitmapinfo( dst_info
, src_info
);
335 err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
336 if (err
== ERROR_BAD_FORMAT
)
338 err
= convert_bits( src_info
, src
, dst_info
, &bits
);
339 if (!err
) err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
342 if (err
== ERROR_TRANSFORM_NOT_SUPPORTED
&&
343 ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)))
345 copy_bitmapinfo( src_info
, dst_info
);
346 err
= stretch_bits( src_info
, src
, dst_info
, dst
, &bits
, COLORONCOLOR
);
347 if (!err
) err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
350 if (bits
.free
) bits
.free( &bits
);
352 if (err
) SetLastError( err
);
357 DWORD
nulldrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
358 struct bitblt_coords
*src
, struct bitblt_coords
*dst
, BLENDFUNCTION blend
)
360 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
361 BITMAPINFO
*dst_info
= (BITMAPINFO
*)buffer
;
362 struct gdi_image_bits dst_bits
;
363 struct bitblt_coords orig_dst
;
364 DWORD
*masks
= (DWORD
*)info
->bmiColors
;
365 DC
*dc
= get_nulldrv_dc( dev
);
368 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
369 if (info
->bmiHeader
.biBitCount
!= 32) goto update_format
;
370 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
372 if (blend
.AlphaFormat
& AC_SRC_ALPHA
) return ERROR_INVALID_PARAMETER
;
373 if (masks
[0] != 0xff0000 || masks
[1] != 0x00ff00 || masks
[2] != 0x0000ff)
377 if (!bits
) return ERROR_SUCCESS
;
378 if ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)) return ERROR_TRANSFORM_NOT_SUPPORTED
;
380 dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
382 err
= dev
->funcs
->pGetImage( dev
, dst_info
, &dst_bits
, dst
);
385 dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
386 err
= blend_bits( info
, bits
, src
, dst_info
, &dst_bits
, dst
, blend
);
387 if (!err
) err
= dev
->funcs
->pPutImage( dev
, 0, dst_info
, &dst_bits
, dst
, &orig_dst
, SRCCOPY
);
389 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
393 if (blend
.AlphaFormat
& AC_SRC_ALPHA
) /* source alpha requires A8R8G8B8 format */
394 return ERROR_INVALID_PARAMETER
;
396 info
->bmiHeader
.biPlanes
= 1;
397 info
->bmiHeader
.biBitCount
= 32;
398 info
->bmiHeader
.biCompression
= BI_BITFIELDS
;
399 info
->bmiHeader
.biClrUsed
= 0;
403 return ERROR_BAD_FORMAT
;
406 BOOL
nulldrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
407 void * grad_array
, ULONG ngrad
, ULONG mode
)
409 DC
*dc
= get_nulldrv_dc( dev
);
410 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
411 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
412 struct bitblt_coords src
, dst
;
413 struct gdi_image_bits bits
;
420 if (!(pts
= HeapAlloc( GetProcessHeap(), 0, nvert
* sizeof(*pts
) ))) return FALSE
;
421 for (i
= 0; i
< nvert
; i
++)
423 pts
[i
].x
= vert_array
[i
].x
;
424 pts
[i
].y
= vert_array
[i
].y
;
426 lp_to_dp( dc
, pts
, nvert
);
428 /* compute bounding rect of all the rectangles/triangles */
429 reset_bounds( &dst
.visrect
);
430 for (i
= 0; i
< ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2); i
++)
432 ULONG v
= ((ULONG
*)grad_array
)[i
];
433 dst
.visrect
.left
= min( dst
.visrect
.left
, pts
[v
].x
);
434 dst
.visrect
.top
= min( dst
.visrect
.top
, pts
[v
].y
);
435 dst
.visrect
.right
= max( dst
.visrect
.right
, pts
[v
].x
);
436 dst
.visrect
.bottom
= max( dst
.visrect
.bottom
, pts
[v
].y
);
439 dst
.x
= dst
.visrect
.left
;
440 dst
.y
= dst
.visrect
.top
;
441 dst
.width
= dst
.visrect
.right
- dst
.visrect
.left
;
442 dst
.height
= dst
.visrect
.bottom
- dst
.visrect
.top
;
443 if (!clip_visrect( dc
, &dst
.visrect
, &dst
.visrect
)) goto done
;
445 /* query the bitmap format */
446 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
447 info
->bmiHeader
.biPlanes
= 1;
448 info
->bmiHeader
.biBitCount
= 0;
449 info
->bmiHeader
.biCompression
= BI_RGB
;
450 info
->bmiHeader
.biXPelsPerMeter
= 0;
451 info
->bmiHeader
.biYPelsPerMeter
= 0;
452 info
->bmiHeader
.biClrUsed
= 0;
453 info
->bmiHeader
.biClrImportant
= 0;
454 info
->bmiHeader
.biWidth
= dst
.visrect
.right
- dst
.visrect
.left
;
455 info
->bmiHeader
.biHeight
= dst
.visrect
.bottom
- dst
.visrect
.top
;
456 info
->bmiHeader
.biSizeImage
= 0;
457 dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
458 err
= dev
->funcs
->pPutImage( dev
, 0, info
, NULL
, NULL
, NULL
, 0 );
459 if (err
&& err
!= ERROR_BAD_FORMAT
) goto done
;
461 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
462 if (!(bits
.ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, info
->bmiHeader
.biSizeImage
)))
465 bits
.free
= free_heap_bits
;
467 /* make src and points relative to the bitmap */
469 src
.x
-= dst
.visrect
.left
;
470 src
.y
-= dst
.visrect
.top
;
471 offset_rect( &src
.visrect
, -dst
.visrect
.left
, -dst
.visrect
.top
);
472 for (i
= 0; i
< nvert
; i
++)
474 pts
[i
].x
-= dst
.visrect
.left
;
475 pts
[i
].y
-= dst
.visrect
.top
;
478 rgn
= CreateRectRgn( 0, 0, 0, 0 );
479 gradient_bitmapinfo( info
, bits
.ptr
, vert_array
, nvert
, grad_array
, ngrad
, mode
, pts
, rgn
);
480 OffsetRgn( rgn
, dst
.visrect
.left
, dst
.visrect
.top
);
481 ret
= !dev
->funcs
->pPutImage( dev
, rgn
, info
, &bits
, &src
, &dst
, SRCCOPY
);
483 if (bits
.free
) bits
.free( &bits
);
487 HeapFree( GetProcessHeap(), 0, pts
);
491 COLORREF
nulldrv_GetPixel( PHYSDEV dev
, INT x
, INT y
)
493 DC
*dc
= get_nulldrv_dc( dev
);
494 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
495 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
496 struct bitblt_coords src
;
497 struct gdi_image_bits bits
;
500 src
.visrect
.left
= x
;
502 lp_to_dp( dc
, (POINT
*)&src
.visrect
, 1 );
503 src
.visrect
.right
= src
.visrect
.left
+ 1;
504 src
.visrect
.bottom
= src
.visrect
.top
+ 1;
505 src
.x
= src
.visrect
.left
;
506 src
.y
= src
.visrect
.top
;
507 src
.width
= src
.height
= 1;
509 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return CLR_INVALID
;
511 dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
512 if (dev
->funcs
->pGetImage( dev
, info
, &bits
, &src
)) return CLR_INVALID
;
514 ret
= get_pixel_bitmapinfo( info
, bits
.ptr
, &src
);
515 if (bits
.free
) bits
.free( &bits
);
520 /***********************************************************************
523 BOOL WINAPI
PatBlt( HDC hdc
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
528 if (rop_uses_src( rop
)) return FALSE
;
529 if ((dc
= get_dc_ptr( hdc
)))
531 struct bitblt_coords dst
;
537 dst
.log_width
= width
;
538 dst
.log_height
= height
;
539 dst
.layout
= dc
->layout
;
540 if (rop
& NOMIRRORBITMAP
)
542 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
543 rop
&= ~NOMIRRORBITMAP
;
545 ret
= !get_vis_rectangles( dc
, &dst
, NULL
, NULL
);
547 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
548 hdc
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
549 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
), rop
);
553 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPatBlt
);
554 ret
= physdev
->funcs
->pPatBlt( physdev
, &dst
, rop
);
556 release_dc_ptr( dc
);
562 /***********************************************************************
565 BOOL WINAPI DECLSPEC_HOTPATCH
BitBlt( HDC hdcDst
, INT xDst
, INT yDst
, INT width
,
566 INT height
, HDC hdcSrc
, INT xSrc
, INT ySrc
, DWORD rop
)
568 if (!rop_uses_src( rop
)) return PatBlt( hdcDst
, xDst
, yDst
, width
, height
, rop
);
569 else return StretchBlt( hdcDst
, xDst
, yDst
, width
, height
,
570 hdcSrc
, xSrc
, ySrc
, width
, height
, rop
);
574 /***********************************************************************
575 * StretchBlt (GDI32.@)
577 BOOL WINAPI
StretchBlt( HDC hdcDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
578 HDC hdcSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
, DWORD rop
)
583 if (!rop_uses_src( rop
)) return PatBlt( hdcDst
, xDst
, yDst
, widthDst
, heightDst
, rop
);
585 if (!(dcDst
= get_dc_ptr( hdcDst
))) return FALSE
;
587 if ((dcSrc
= get_dc_ptr( hdcSrc
)))
589 struct bitblt_coords src
, dst
;
596 src
.log_width
= widthSrc
;
597 src
.log_height
= heightSrc
;
598 src
.layout
= dcSrc
->layout
;
601 dst
.log_width
= widthDst
;
602 dst
.log_height
= heightDst
;
603 dst
.layout
= dcDst
->layout
;
604 if (rop
& NOMIRRORBITMAP
)
606 src
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
607 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
608 rop
&= ~NOMIRRORBITMAP
;
610 ret
= !get_vis_rectangles( dcDst
, &dst
, dcSrc
, &src
);
612 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",
613 hdcSrc
, src
.log_x
, src
.log_y
, src
.log_width
, src
.log_height
,
614 src
.x
, src
.y
, src
.width
, src
.height
, wine_dbgstr_rect(&src
.visrect
),
615 hdcDst
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
616 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
), rop
);
620 PHYSDEV src_dev
= GET_DC_PHYSDEV( dcSrc
, pStretchBlt
);
621 PHYSDEV dst_dev
= GET_DC_PHYSDEV( dcDst
, pStretchBlt
);
622 ret
= dst_dev
->funcs
->pStretchBlt( dst_dev
, &dst
, src_dev
, &src
, rop
);
624 release_dc_ptr( dcSrc
);
626 release_dc_ptr( dcDst
);
630 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
631 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
633 /***********************************************************************
636 BOOL WINAPI
MaskBlt(HDC hdcDest
, INT nXDest
, INT nYDest
,
637 INT nWidth
, INT nHeight
, HDC hdcSrc
,
638 INT nXSrc
, INT nYSrc
, HBITMAP hbmMask
,
639 INT xMask
, INT yMask
, DWORD dwRop
)
641 HBITMAP hBitmap1
, hOldBitmap1
, hBitmap2
, hOldBitmap2
;
643 HBRUSH hbrMask
, hbrDst
, hbrTmp
;
645 static const DWORD ROP3Table
[256] =
647 0x00000042, 0x00010289,
648 0x00020C89, 0x000300AA,
649 0x00040C88, 0x000500A9,
650 0x00060865, 0x000702C5,
651 0x00080F08, 0x00090245,
652 0x000A0329, 0x000B0B2A,
653 0x000C0324, 0x000D0B25,
654 0x000E08A5, 0x000F0001,
655 0x00100C85, 0x001100A6,
656 0x00120868, 0x001302C8,
657 0x00140869, 0x001502C9,
658 0x00165CCA, 0x00171D54,
659 0x00180D59, 0x00191CC8,
660 0x001A06C5, 0x001B0768,
661 0x001C06CA, 0x001D0766,
662 0x001E01A5, 0x001F0385,
663 0x00200F09, 0x00210248,
664 0x00220326, 0x00230B24,
665 0x00240D55, 0x00251CC5,
666 0x002606C8, 0x00271868,
667 0x00280369, 0x002916CA,
668 0x002A0CC9, 0x002B1D58,
669 0x002C0784, 0x002D060A,
670 0x002E064A, 0x002F0E2A,
671 0x0030032A, 0x00310B28,
672 0x00320688, 0x00330008,
673 0x003406C4, 0x00351864,
674 0x003601A8, 0x00370388,
675 0x0038078A, 0x00390604,
676 0x003A0644, 0x003B0E24,
677 0x003C004A, 0x003D18A4,
678 0x003E1B24, 0x003F00EA,
679 0x00400F0A, 0x00410249,
680 0x00420D5D, 0x00431CC4,
681 0x00440328, 0x00450B29,
682 0x004606C6, 0x0047076A,
683 0x00480368, 0x004916C5,
684 0x004A0789, 0x004B0605,
685 0x004C0CC8, 0x004D1954,
686 0x004E0645, 0x004F0E25,
687 0x00500325, 0x00510B26,
688 0x005206C9, 0x00530764,
689 0x005408A9, 0x00550009,
690 0x005601A9, 0x00570389,
691 0x00580785, 0x00590609,
692 0x005A0049, 0x005B18A9,
693 0x005C0649, 0x005D0E29,
694 0x005E1B29, 0x005F00E9,
695 0x00600365, 0x006116C6,
696 0x00620786, 0x00630608,
697 0x00640788, 0x00650606,
698 0x00660046, 0x006718A8,
699 0x006858A6, 0x00690145,
700 0x006A01E9, 0x006B178A,
701 0x006C01E8, 0x006D1785,
702 0x006E1E28, 0x006F0C65,
703 0x00700CC5, 0x00711D5C,
704 0x00720648, 0x00730E28,
705 0x00740646, 0x00750E26,
706 0x00761B28, 0x007700E6,
707 0x007801E5, 0x00791786,
708 0x007A1E29, 0x007B0C68,
709 0x007C1E24, 0x007D0C69,
710 0x007E0955, 0x007F03C9,
711 0x008003E9, 0x00810975,
712 0x00820C49, 0x00831E04,
713 0x00840C48, 0x00851E05,
714 0x008617A6, 0x008701C5,
715 0x008800C6, 0x00891B08,
716 0x008A0E06, 0x008B0666,
717 0x008C0E08, 0x008D0668,
718 0x008E1D7C, 0x008F0CE5,
719 0x00900C45, 0x00911E08,
720 0x009217A9, 0x009301C4,
721 0x009417AA, 0x009501C9,
722 0x00960169, 0x0097588A,
723 0x00981888, 0x00990066,
724 0x009A0709, 0x009B07A8,
725 0x009C0704, 0x009D07A6,
726 0x009E16E6, 0x009F0345,
727 0x00A000C9, 0x00A11B05,
728 0x00A20E09, 0x00A30669,
729 0x00A41885, 0x00A50065,
730 0x00A60706, 0x00A707A5,
731 0x00A803A9, 0x00A90189,
732 0x00AA0029, 0x00AB0889,
733 0x00AC0744, 0x00AD06E9,
734 0x00AE0B06, 0x00AF0229,
735 0x00B00E05, 0x00B10665,
736 0x00B21974, 0x00B30CE8,
737 0x00B4070A, 0x00B507A9,
738 0x00B616E9, 0x00B70348,
739 0x00B8074A, 0x00B906E6,
740 0x00BA0B09, 0x00BB0226,
741 0x00BC1CE4, 0x00BD0D7D,
742 0x00BE0269, 0x00BF08C9,
743 0x00C000CA, 0x00C11B04,
744 0x00C21884, 0x00C3006A,
745 0x00C40E04, 0x00C50664,
746 0x00C60708, 0x00C707AA,
747 0x00C803A8, 0x00C90184,
748 0x00CA0749, 0x00CB06E4,
749 0x00CC0020, 0x00CD0888,
750 0x00CE0B08, 0x00CF0224,
751 0x00D00E0A, 0x00D1066A,
752 0x00D20705, 0x00D307A4,
753 0x00D41D78, 0x00D50CE9,
754 0x00D616EA, 0x00D70349,
755 0x00D80745, 0x00D906E8,
756 0x00DA1CE9, 0x00DB0D75,
757 0x00DC0B04, 0x00DD0228,
758 0x00DE0268, 0x00DF08C8,
759 0x00E003A5, 0x00E10185,
760 0x00E20746, 0x00E306EA,
761 0x00E40748, 0x00E506E5,
762 0x00E61CE8, 0x00E70D79,
763 0x00E81D74, 0x00E95CE6,
764 0x00EA02E9, 0x00EB0849,
765 0x00EC02E8, 0x00ED0848,
766 0x00EE0086, 0x00EF0A08,
767 0x00F00021, 0x00F10885,
768 0x00F20B05, 0x00F3022A,
769 0x00F40B0A, 0x00F50225,
770 0x00F60265, 0x00F708C5,
771 0x00F802E5, 0x00F90845,
772 0x00FA0089, 0x00FB0A09,
773 0x00FC008A, 0x00FD0A0A,
774 0x00FE02A9, 0x00FF0062,
778 return BitBlt(hdcDest
, nXDest
, nYDest
, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, FRGND_ROP3(dwRop
));
780 hbrMask
= CreatePatternBrush(hbmMask
);
781 hbrDst
= SelectObject(hdcDest
, GetStockObject(NULL_BRUSH
));
784 hDC1
= CreateCompatibleDC(hdcDest
);
785 hBitmap1
= CreateCompatibleBitmap(hdcDest
, nWidth
, nHeight
);
786 hOldBitmap1
= SelectObject(hDC1
, hBitmap1
);
788 /* draw using bkgnd rop */
789 BitBlt(hDC1
, 0, 0, nWidth
, nHeight
, hdcDest
, nXDest
, nYDest
, SRCCOPY
);
790 hbrTmp
= SelectObject(hDC1
, hbrDst
);
791 BitBlt(hDC1
, 0, 0, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, BKGND_ROP3(dwRop
));
792 SelectObject(hDC1
, hbrTmp
);
795 hDC2
= CreateCompatibleDC(hdcDest
);
796 hBitmap2
= CreateCompatibleBitmap(hdcDest
, nWidth
, nHeight
);
797 hOldBitmap2
= SelectObject(hDC2
, hBitmap2
);
799 /* draw using foregnd rop */
800 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hdcDest
, nXDest
, nYDest
, SRCCOPY
);
801 hbrTmp
= SelectObject(hDC2
, hbrDst
);
802 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, FRGND_ROP3(dwRop
));
804 /* combine both using the mask as a pattern brush */
805 SelectObject(hDC2
, hbrMask
);
806 SetBrushOrgEx(hDC2
, -xMask
, -yMask
, NULL
);
807 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hDC1
, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
808 SelectObject(hDC2
, hbrTmp
);
811 BitBlt(hdcDest
, nXDest
, nYDest
, nWidth
, nHeight
, hDC2
, 0, 0, SRCCOPY
);
813 /* restore all objects */
814 SelectObject(hdcDest
, hbrDst
);
815 SelectObject(hDC1
, hOldBitmap1
);
816 SelectObject(hDC2
, hOldBitmap2
);
818 /* delete all temp objects */
819 DeleteObject(hBitmap1
);
820 DeleteObject(hBitmap2
);
821 DeleteObject(hbrMask
);
829 /******************************************************************************
830 * GdiTransparentBlt [GDI32.@]
832 BOOL WINAPI
GdiTransparentBlt( HDC hdcDest
, int xDest
, int yDest
, int widthDest
, int heightDest
,
833 HDC hdcSrc
, int xSrc
, int ySrc
, int widthSrc
, int heightSrc
,
841 HBITMAP bmpMask
= NULL
;
842 HBITMAP oldMask
= NULL
;
843 COLORREF oldBackground
;
844 COLORREF oldForeground
;
847 if(widthDest
< 0 || heightDest
< 0 || widthSrc
< 0 || heightSrc
< 0) {
848 TRACE("Cannot mirror\n");
852 oldBackground
= SetBkColor(hdcDest
, RGB(255,255,255));
853 oldForeground
= SetTextColor(hdcDest
, RGB(0,0,0));
856 oldStretchMode
= GetStretchBltMode(hdcSrc
);
857 if(oldStretchMode
== BLACKONWHITE
|| oldStretchMode
== WHITEONBLACK
)
858 SetStretchBltMode(hdcSrc
, COLORONCOLOR
);
859 hdcWork
= CreateCompatibleDC(hdcDest
);
860 if (GetObjectType( hdcDest
) != OBJ_MEMDC
&& GetDeviceCaps( hdcDest
, BITSPIXEL
) == 32)
862 /* screen DCs are not supposed to have an alpha channel, so use a 24-bpp bitmap as copy */
864 info
.bmiHeader
.biSize
= sizeof(info
.bmiHeader
);
865 info
.bmiHeader
.biWidth
= widthDest
;
866 info
.bmiHeader
.biHeight
= heightDest
;
867 info
.bmiHeader
.biPlanes
= 1;
868 info
.bmiHeader
.biBitCount
= 24;
869 info
.bmiHeader
.biCompression
= BI_RGB
;
870 bmpWork
= CreateDIBSection( 0, &info
, DIB_RGB_COLORS
, NULL
, NULL
, 0 );
872 else bmpWork
= CreateCompatibleBitmap(hdcDest
, widthDest
, heightDest
);
873 oldWork
= SelectObject(hdcWork
, bmpWork
);
874 if(!StretchBlt(hdcWork
, 0, 0, widthDest
, heightDest
, hdcSrc
, xSrc
, ySrc
, widthSrc
, heightSrc
, SRCCOPY
)) {
875 TRACE("Failed to stretch\n");
878 SetBkColor(hdcWork
, crTransparent
);
881 hdcMask
= CreateCompatibleDC(hdcDest
);
882 bmpMask
= CreateCompatibleBitmap(hdcMask
, widthDest
, heightDest
);
883 oldMask
= SelectObject(hdcMask
, bmpMask
);
884 if(!BitBlt(hdcMask
, 0, 0, widthDest
, heightDest
, hdcWork
, 0, 0, SRCCOPY
)) {
885 TRACE("Failed to create mask\n");
889 /* Replace transparent color with black */
890 SetBkColor(hdcWork
, RGB(0,0,0));
891 SetTextColor(hdcWork
, RGB(255,255,255));
892 if(!BitBlt(hdcWork
, 0, 0, widthDest
, heightDest
, hdcMask
, 0, 0, SRCAND
)) {
893 TRACE("Failed to mask out background\n");
897 /* Replace non-transparent area on destination with black */
898 if(!BitBlt(hdcDest
, xDest
, yDest
, widthDest
, heightDest
, hdcMask
, 0, 0, SRCAND
)) {
899 TRACE("Failed to clear destination area\n");
904 if(!BitBlt(hdcDest
, xDest
, yDest
, widthDest
, heightDest
, hdcWork
, 0, 0, SRCPAINT
)) {
905 TRACE("Failed to paint image\n");
911 SetStretchBltMode(hdcSrc
, oldStretchMode
);
912 SetBkColor(hdcDest
, oldBackground
);
913 SetTextColor(hdcDest
, oldForeground
);
915 SelectObject(hdcWork
, oldWork
);
918 if(bmpWork
) DeleteObject(bmpWork
);
920 SelectObject(hdcMask
, oldMask
);
923 if(bmpMask
) DeleteObject(bmpMask
);
927 /******************************************************************************
928 * GdiAlphaBlend [GDI32.@]
930 BOOL WINAPI
GdiAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int widthDst
, int heightDst
,
931 HDC hdcSrc
, int xSrc
, int ySrc
, int widthSrc
, int heightSrc
,
932 BLENDFUNCTION blendFunction
)
937 dcSrc
= get_dc_ptr( hdcSrc
);
938 if (!dcSrc
) return FALSE
;
940 if ((dcDst
= get_dc_ptr( hdcDst
)))
942 struct bitblt_coords src
, dst
;
949 src
.log_width
= widthSrc
;
950 src
.log_height
= heightSrc
;
951 src
.layout
= dcSrc
->layout
;
954 dst
.log_width
= widthDst
;
955 dst
.log_height
= heightDst
;
956 dst
.layout
= dcDst
->layout
;
957 ret
= !get_vis_rectangles( dcDst
, &dst
, dcSrc
, &src
);
959 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",
960 hdcSrc
, src
.log_x
, src
.log_y
, src
.log_width
, src
.log_height
,
961 src
.x
, src
.y
, src
.width
, src
.height
, wine_dbgstr_rect(&src
.visrect
),
962 hdcDst
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
963 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
),
964 blendFunction
.BlendOp
, blendFunction
.BlendFlags
,
965 blendFunction
.SourceConstantAlpha
, blendFunction
.AlphaFormat
);
967 if (src
.x
< 0 || src
.y
< 0 || src
.width
< 0 || src
.height
< 0 ||
968 src
.log_width
< 0 || src
.log_height
< 0 ||
969 (!is_rect_empty( &dcSrc
->device_rect
) &&
970 (src
.width
> dcSrc
->device_rect
.right
- dcSrc
->vis_rect
.left
- src
.x
||
971 src
.height
> dcSrc
->device_rect
.bottom
- dcSrc
->vis_rect
.top
- src
.y
)))
973 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src
.x
, src
.y
, src
.width
, src
.height
);
974 SetLastError( ERROR_INVALID_PARAMETER
);
977 else if (dst
.log_width
< 0 || dst
.log_height
< 0)
979 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
980 dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
);
981 SetLastError( ERROR_INVALID_PARAMETER
);
984 else if (dcSrc
== dcDst
&& src
.x
+ src
.width
> dst
.x
&& src
.x
< dst
.x
+ dst
.width
&&
985 src
.y
+ src
.height
> dst
.y
&& src
.y
< dst
.y
+ dst
.height
)
987 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
988 src
.x
, src
.y
, src
.width
, src
.height
, dst
.x
, dst
.y
, dst
.width
, dst
.height
);
989 SetLastError( ERROR_INVALID_PARAMETER
);
994 PHYSDEV src_dev
= GET_DC_PHYSDEV( dcSrc
, pAlphaBlend
);
995 PHYSDEV dst_dev
= GET_DC_PHYSDEV( dcDst
, pAlphaBlend
);
996 ret
= dst_dev
->funcs
->pAlphaBlend( dst_dev
, &dst
, src_dev
, &src
, blendFunction
);
998 release_dc_ptr( dcDst
);
1000 release_dc_ptr( dcSrc
);
1004 /*********************************************************************
1008 BOOL WINAPI
PlgBlt( HDC hdcDest
, const POINT
*lpPoint
,
1009 HDC hdcSrc
, INT nXSrc
, INT nYSrc
, INT nWidth
,
1010 INT nHeight
, HBITMAP hbmMask
, INT xMask
, INT yMask
)
1013 /* parallelogram coords */
1022 /* save actual mode, set GM_ADVANCED */
1023 oldgMode
= SetGraphicsMode(hdcDest
,GM_ADVANCED
);
1027 memcpy(plg
,lpPoint
,sizeof(POINT
)*3);
1030 rect
[1].x
= nXSrc
+ nWidth
;
1033 rect
[2].y
= nYSrc
+ nHeight
;
1034 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1036 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
);
1038 if (fabs(det
) < 1e-5)
1040 SetGraphicsMode(hdcDest
,oldgMode
);
1044 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1045 hdcSrc
, nXSrc
, nYSrc
, nWidth
, nHeight
, hdcDest
, plg
[0].x
, plg
[0].y
, plg
[1].x
, plg
[1].y
, plg
[2].x
, plg
[2].y
);
1048 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
;
1049 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
;
1050 xf
.eDx
= (rect
[0].x
*(rect
[1].y
*plg
[2].x
- rect
[2].y
*plg
[1].x
) -
1051 rect
[1].x
*(rect
[0].y
*plg
[2].x
- rect
[2].y
*plg
[0].x
) +
1052 rect
[2].x
*(rect
[0].y
*plg
[1].x
- rect
[1].y
*plg
[0].x
)
1056 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
;
1057 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
;
1058 xf
.eDy
= (rect
[0].x
*(rect
[1].y
*plg
[2].y
- rect
[2].y
*plg
[1].y
) -
1059 rect
[1].x
*(rect
[0].y
*plg
[2].y
- rect
[2].y
*plg
[0].y
) +
1060 rect
[2].x
*(rect
[0].y
*plg
[1].y
- rect
[1].y
*plg
[0].y
)
1063 GetWorldTransform(hdcSrc
,&SrcXf
);
1064 CombineTransform(&xf
,&xf
,&SrcXf
);
1066 /* save actual dest transform */
1067 GetWorldTransform(hdcDest
,&oldDestXf
);
1069 SetWorldTransform(hdcDest
,&xf
);
1070 /* now destination and source DCs use same coords */
1071 MaskBlt(hdcDest
,nXSrc
,nYSrc
,nWidth
,nHeight
,
1072 hdcSrc
, nXSrc
,nYSrc
,
1073 hbmMask
,xMask
,yMask
,
1075 /* restore dest DC */
1076 SetWorldTransform(hdcDest
,&oldDestXf
);
1077 SetGraphicsMode(hdcDest
,oldgMode
);