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 LPtoDP( dc_dst
->hSelf
, (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 LPtoDP( dc_src
->hSelf
, (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 /* source is not clipped */
150 if (dc_src
->header
.type
== OBJ_MEMDC
)
151 intersect_rect( &src
->visrect
, &rect
, &dc_src
->vis_rect
);
153 src
->visrect
= rect
; /* FIXME: clip to device size */
155 if (is_rect_empty( &src
->visrect
)) return FALSE
;
156 if (is_rect_empty( &dst
->visrect
)) return FALSE
;
158 return intersect_vis_rectangles( dst
, src
);
161 void free_heap_bits( struct gdi_image_bits
*bits
)
163 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
166 DWORD
convert_bits( const BITMAPINFO
*src_info
, struct bitblt_coords
*src
,
167 BITMAPINFO
*dst_info
, struct gdi_image_bits
*bits
, BOOL add_alpha
)
172 dst_info
->bmiHeader
.biWidth
= src
->visrect
.right
- src
->visrect
.left
;
173 dst_info
->bmiHeader
.biSizeImage
= get_dib_image_size( dst_info
);
175 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, dst_info
->bmiHeader
.biSizeImage
)))
176 return ERROR_OUTOFMEMORY
;
178 err
= convert_bitmapinfo( src_info
, bits
->ptr
, src
, dst_info
, ptr
, add_alpha
);
179 if (bits
->free
) bits
->free( bits
);
181 bits
->is_copy
= TRUE
;
182 bits
->free
= free_heap_bits
;
186 DWORD
stretch_bits( const BITMAPINFO
*src_info
, struct bitblt_coords
*src
,
187 BITMAPINFO
*dst_info
, struct bitblt_coords
*dst
,
188 struct gdi_image_bits
*bits
, int mode
)
193 dst_info
->bmiHeader
.biWidth
= dst
->visrect
.right
- dst
->visrect
.left
;
194 dst_info
->bmiHeader
.biHeight
= dst
->visrect
.bottom
- dst
->visrect
.top
;
195 dst_info
->bmiHeader
.biSizeImage
= get_dib_image_size( dst_info
);
197 if (src_info
->bmiHeader
.biHeight
< 0) dst_info
->bmiHeader
.biHeight
= -dst_info
->bmiHeader
.biHeight
;
198 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, dst_info
->bmiHeader
.biSizeImage
)))
199 return ERROR_OUTOFMEMORY
;
201 err
= stretch_bitmapinfo( src_info
, bits
->ptr
, src
, dst_info
, ptr
, dst
, mode
);
202 if (bits
->free
) bits
->free( bits
);
204 bits
->is_copy
= TRUE
;
205 bits
->free
= free_heap_bits
;
209 static DWORD
blend_bits( const BITMAPINFO
*src_info
, const struct gdi_image_bits
*src_bits
,
210 struct bitblt_coords
*src
, BITMAPINFO
*dst_info
,
211 struct gdi_image_bits
*dst_bits
, struct bitblt_coords
*dst
, BLENDFUNCTION blend
)
213 if (!dst_bits
->is_copy
)
215 int size
= dst_info
->bmiHeader
.biSizeImage
;
216 void *ptr
= HeapAlloc( GetProcessHeap(), 0, size
);
217 if (!ptr
) return ERROR_OUTOFMEMORY
;
218 memcpy( ptr
, dst_bits
->ptr
, size
);
219 if (dst_bits
->free
) dst_bits
->free( dst_bits
);
221 dst_bits
->is_copy
= TRUE
;
222 dst_bits
->free
= free_heap_bits
;
224 return blend_bitmapinfo( src_info
, src_bits
->ptr
, src
, dst_info
, dst_bits
->ptr
, dst
, blend
);
227 /***********************************************************************
228 * null driver fallback implementations
231 BOOL
nulldrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
232 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
234 DC
*dc_src
, *dc_dst
= get_nulldrv_dc( dst_dev
);
235 char src_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
236 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
237 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_buffer
;
238 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
240 struct gdi_image_bits bits
;
242 if (!(dc_src
= get_dc_ptr( src_dev
->hdc
))) return FALSE
;
243 src_dev
= GET_DC_PHYSDEV( dc_src
, pGetImage
);
244 err
= src_dev
->funcs
->pGetImage( src_dev
, 0, src_info
, &bits
, src
);
245 release_dc_ptr( dc_src
);
246 if (err
) return FALSE
;
248 /* 1-bpp source without a color table uses the destination DC colors */
249 if (src_info
->bmiHeader
.biBitCount
== 1 && !src_info
->bmiHeader
.biClrUsed
)
251 COLORREF color
= GetTextColor( dst_dev
->hdc
);
252 src_info
->bmiColors
[0].rgbRed
= GetRValue( color
);
253 src_info
->bmiColors
[0].rgbGreen
= GetGValue( color
);
254 src_info
->bmiColors
[0].rgbBlue
= GetBValue( color
);
255 src_info
->bmiColors
[0].rgbReserved
= 0;
256 color
= GetBkColor( dst_dev
->hdc
);
257 src_info
->bmiColors
[1].rgbRed
= GetRValue( color
);
258 src_info
->bmiColors
[1].rgbGreen
= GetGValue( color
);
259 src_info
->bmiColors
[1].rgbBlue
= GetBValue( color
);
260 src_info
->bmiColors
[1].rgbReserved
= 0;
261 src_info
->bmiHeader
.biClrUsed
= 2;
264 dst_dev
= GET_DC_PHYSDEV( dc_dst
, pPutImage
);
265 copy_bitmapinfo( dst_info
, src_info
);
266 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, 0, dst_info
, &bits
, src
, dst
, rop
);
267 if (err
== ERROR_BAD_FORMAT
)
269 /* 1-bpp destination without a color table requires a fake 1-entry table
270 * that contains only the background color */
271 if (dst_info
->bmiHeader
.biBitCount
== 1 && !dst_info
->bmiHeader
.biClrUsed
)
273 COLORREF color
= GetBkColor( src_dev
->hdc
);
274 dst_info
->bmiColors
[0].rgbRed
= GetRValue( color
);
275 dst_info
->bmiColors
[0].rgbGreen
= GetGValue( color
);
276 dst_info
->bmiColors
[0].rgbBlue
= GetBValue( color
);
277 dst_info
->bmiColors
[0].rgbReserved
= 0;
278 dst_info
->bmiHeader
.biClrUsed
= 1;
281 if (!(err
= convert_bits( src_info
, src
, dst_info
, &bits
, FALSE
)))
283 /* get rid of the fake 1-bpp table */
284 if (dst_info
->bmiHeader
.biClrUsed
== 1) dst_info
->bmiHeader
.biClrUsed
= 0;
285 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, 0, dst_info
, &bits
, src
, dst
, rop
);
289 if (err
== ERROR_TRANSFORM_NOT_SUPPORTED
&&
290 ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)))
292 copy_bitmapinfo( src_info
, dst_info
);
293 err
= stretch_bits( src_info
, src
, dst_info
, dst
, &bits
, GetStretchBltMode( dst_dev
->hdc
));
294 if (!err
) err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, 0, dst_info
, &bits
, src
, dst
, rop
);
297 if (bits
.free
) bits
.free( &bits
);
302 BOOL
nulldrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
303 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION func
)
305 DC
*dc_src
, *dc_dst
= get_nulldrv_dc( dst_dev
);
306 char src_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
307 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
308 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_buffer
;
309 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
311 struct gdi_image_bits bits
;
313 if (!(dc_src
= get_dc_ptr( src_dev
->hdc
))) return FALSE
;
314 src_dev
= GET_DC_PHYSDEV( dc_src
, pGetImage
);
315 err
= src_dev
->funcs
->pGetImage( src_dev
, 0, src_info
, &bits
, src
);
316 release_dc_ptr( dc_src
);
319 dst_dev
= GET_DC_PHYSDEV( dc_dst
, pBlendImage
);
320 copy_bitmapinfo( dst_info
, src_info
);
321 err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
322 if (err
== ERROR_BAD_FORMAT
)
324 err
= convert_bits( src_info
, src
, dst_info
, &bits
, TRUE
);
325 if (!err
) err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
328 if (err
== ERROR_TRANSFORM_NOT_SUPPORTED
&&
329 ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)))
331 copy_bitmapinfo( src_info
, dst_info
);
332 err
= stretch_bits( src_info
, src
, dst_info
, dst
, &bits
, COLORONCOLOR
);
333 if (!err
) err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
336 if (bits
.free
) bits
.free( &bits
);
338 if (err
) SetLastError( err
);
343 DWORD
nulldrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
344 struct bitblt_coords
*src
, struct bitblt_coords
*dst
, BLENDFUNCTION blend
)
346 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
347 BITMAPINFO
*dst_info
= (BITMAPINFO
*)buffer
;
348 struct gdi_image_bits dst_bits
;
349 struct bitblt_coords orig_dst
;
350 DC
*dc
= get_nulldrv_dc( dev
);
353 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
354 if (info
->bmiHeader
.biBitCount
!= 32) goto update_format
;
355 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
357 DWORD
*masks
= (DWORD
*)info
->bmiColors
;
358 if (masks
[0] != 0xff0000 || masks
[1] != 0x00ff00 || masks
[2] != 0x0000ff)
362 if (!bits
) return ERROR_SUCCESS
;
363 if ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)) return ERROR_TRANSFORM_NOT_SUPPORTED
;
365 dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
367 err
= dev
->funcs
->pGetImage( dev
, 0, dst_info
, &dst_bits
, dst
);
370 dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
371 err
= blend_bits( info
, bits
, src
, dst_info
, &dst_bits
, dst
, blend
);
372 if (!err
) err
= dev
->funcs
->pPutImage( dev
, 0, 0, dst_info
, &dst_bits
, dst
, &orig_dst
, SRCCOPY
);
374 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
378 if (blend
.AlphaFormat
& AC_SRC_ALPHA
) /* source alpha requires A8R8G8B8 format */
379 return ERROR_INVALID_PARAMETER
;
381 info
->bmiHeader
.biPlanes
= 1;
382 info
->bmiHeader
.biBitCount
= 32;
383 info
->bmiHeader
.biCompression
= BI_RGB
;
384 info
->bmiHeader
.biClrUsed
= 0;
385 return ERROR_BAD_FORMAT
;
388 BOOL
nulldrv_GradientFill( PHYSDEV dev
, TRIVERTEX
*vert_array
, ULONG nvert
,
389 void * grad_array
, ULONG ngrad
, ULONG mode
)
391 DC
*dc
= get_nulldrv_dc( dev
);
392 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
393 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
394 struct bitblt_coords src
, dst
;
395 struct gdi_image_bits bits
;
402 if (!(pts
= HeapAlloc( GetProcessHeap(), 0, nvert
* sizeof(*pts
) ))) return FALSE
;
403 for (i
= 0; i
< nvert
; i
++)
405 pts
[i
].x
= vert_array
[i
].x
;
406 pts
[i
].y
= vert_array
[i
].y
;
408 LPtoDP( dev
->hdc
, pts
, nvert
);
410 /* compute bounding rect of all the rectangles/triangles */
411 dst
.visrect
.left
= dst
.visrect
.top
= INT_MAX
;
412 dst
.visrect
.right
= dst
.visrect
.bottom
= INT_MIN
;
413 for (i
= 0; i
< ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2); i
++)
415 ULONG v
= ((ULONG
*)grad_array
)[i
];
416 dst
.visrect
.left
= min( dst
.visrect
.left
, pts
[v
].x
);
417 dst
.visrect
.top
= min( dst
.visrect
.top
, pts
[v
].y
);
418 dst
.visrect
.right
= max( dst
.visrect
.right
, pts
[v
].x
);
419 dst
.visrect
.bottom
= max( dst
.visrect
.bottom
, pts
[v
].y
);
422 dst
.x
= dst
.visrect
.left
;
423 dst
.y
= dst
.visrect
.top
;
424 dst
.width
= dst
.visrect
.right
- dst
.visrect
.left
;
425 dst
.height
= dst
.visrect
.bottom
- dst
.visrect
.top
;
426 if (!clip_visrect( dc
, &dst
.visrect
, &dst
.visrect
)) goto done
;
428 /* query the bitmap format */
429 info
->bmiHeader
.biSize
= sizeof(info
->bmiHeader
);
430 info
->bmiHeader
.biPlanes
= 1;
431 info
->bmiHeader
.biBitCount
= 0;
432 info
->bmiHeader
.biCompression
= BI_RGB
;
433 info
->bmiHeader
.biXPelsPerMeter
= 0;
434 info
->bmiHeader
.biYPelsPerMeter
= 0;
435 info
->bmiHeader
.biClrUsed
= 0;
436 info
->bmiHeader
.biClrImportant
= 0;
437 info
->bmiHeader
.biWidth
= dst
.visrect
.right
- dst
.visrect
.left
;
438 info
->bmiHeader
.biHeight
= dst
.visrect
.bottom
- dst
.visrect
.top
;
439 info
->bmiHeader
.biSizeImage
= 0;
440 dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
441 err
= dev
->funcs
->pPutImage( dev
, 0, 0, info
, NULL
, NULL
, NULL
, 0 );
442 if (err
&& err
!= ERROR_BAD_FORMAT
) goto done
;
444 info
->bmiHeader
.biSizeImage
= get_dib_image_size( info
);
445 if (!(bits
.ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, info
->bmiHeader
.biSizeImage
)))
448 bits
.free
= free_heap_bits
;
450 /* make src and points relative to the bitmap */
452 src
.x
-= dst
.visrect
.left
;
453 src
.y
-= dst
.visrect
.top
;
454 offset_rect( &src
.visrect
, -dst
.visrect
.left
, -dst
.visrect
.top
);
455 for (i
= 0; i
< nvert
; i
++)
457 pts
[i
].x
-= dst
.visrect
.left
;
458 pts
[i
].y
-= dst
.visrect
.top
;
461 rgn
= CreateRectRgn( 0, 0, 0, 0 );
462 gradient_bitmapinfo( info
, bits
.ptr
, vert_array
, nvert
, grad_array
, ngrad
, mode
, pts
, rgn
);
463 OffsetRgn( rgn
, dst
.visrect
.left
, dst
.visrect
.top
);
464 ret
= !dev
->funcs
->pPutImage( dev
, 0, rgn
, info
, &bits
, &src
, &dst
, SRCCOPY
);
466 if (bits
.free
) bits
.free( &bits
);
470 HeapFree( GetProcessHeap(), 0, pts
);
474 COLORREF
nulldrv_GetPixel( PHYSDEV dev
, INT x
, INT y
)
476 DC
*dc
= get_nulldrv_dc( dev
);
477 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
478 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
479 struct bitblt_coords src
;
480 struct gdi_image_bits bits
;
483 src
.visrect
.left
= x
;
485 LPtoDP( dev
->hdc
, (POINT
*)&src
.visrect
, 1 );
486 src
.visrect
.right
= src
.visrect
.left
+ 1;
487 src
.visrect
.bottom
= src
.visrect
.top
+ 1;
488 src
.x
= src
.visrect
.left
;
489 src
.y
= src
.visrect
.top
;
490 src
.width
= src
.height
= 1;
492 if (!clip_visrect( dc
, &src
.visrect
, &src
.visrect
)) return CLR_INVALID
;
494 dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
495 if (dev
->funcs
->pGetImage( dev
, 0, info
, &bits
, &src
)) return CLR_INVALID
;
497 ret
= get_pixel_bitmapinfo( info
, bits
.ptr
, &src
);
498 if (bits
.free
) bits
.free( &bits
);
503 /***********************************************************************
506 BOOL WINAPI
PatBlt( HDC hdc
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
511 if (rop_uses_src( rop
)) return FALSE
;
512 if ((dc
= get_dc_ptr( hdc
)))
514 struct bitblt_coords dst
;
515 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPatBlt
);
521 dst
.log_width
= width
;
522 dst
.log_height
= height
;
523 dst
.layout
= dc
->layout
;
524 if (rop
& NOMIRRORBITMAP
)
526 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
527 rop
&= ~NOMIRRORBITMAP
;
529 ret
= !get_vis_rectangles( dc
, &dst
, NULL
, NULL
);
531 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
532 hdc
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
533 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
), rop
);
535 if (!ret
) ret
= physdev
->funcs
->pPatBlt( physdev
, &dst
, rop
);
537 release_dc_ptr( dc
);
543 /***********************************************************************
546 BOOL WINAPI
BitBlt( HDC hdcDst
, INT xDst
, INT yDst
, INT width
,
547 INT height
, HDC hdcSrc
, INT xSrc
, INT ySrc
, DWORD rop
)
549 if (!rop_uses_src( rop
)) return PatBlt( hdcDst
, xDst
, yDst
, width
, height
, rop
);
550 else return StretchBlt( hdcDst
, xDst
, yDst
, width
, height
,
551 hdcSrc
, xSrc
, ySrc
, width
, height
, rop
);
555 /***********************************************************************
556 * StretchBlt (GDI32.@)
558 BOOL WINAPI
StretchBlt( HDC hdcDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
559 HDC hdcSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
, DWORD rop
)
564 if (!rop_uses_src( rop
)) return PatBlt( hdcDst
, xDst
, yDst
, widthDst
, heightDst
, rop
);
566 if (!(dcDst
= get_dc_ptr( hdcDst
))) return FALSE
;
568 if ((dcSrc
= get_dc_ptr( hdcSrc
)))
570 struct bitblt_coords src
, dst
;
571 PHYSDEV src_dev
= GET_DC_PHYSDEV( dcSrc
, pStretchBlt
);
572 PHYSDEV dst_dev
= GET_DC_PHYSDEV( dcDst
, pStretchBlt
);
579 src
.log_width
= widthSrc
;
580 src
.log_height
= heightSrc
;
581 src
.layout
= dcSrc
->layout
;
584 dst
.log_width
= widthDst
;
585 dst
.log_height
= heightDst
;
586 dst
.layout
= dcDst
->layout
;
587 if (rop
& NOMIRRORBITMAP
)
589 src
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
590 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
591 rop
&= ~NOMIRRORBITMAP
;
593 ret
= !get_vis_rectangles( dcDst
, &dst
, dcSrc
, &src
);
595 TRACE("src %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
596 hdcSrc
, src
.log_x
, src
.log_y
, src
.log_width
, src
.log_height
,
597 src
.x
, src
.y
, src
.width
, src
.height
, wine_dbgstr_rect(&src
.visrect
),
598 hdcDst
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
599 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
), rop
);
601 if (!ret
) ret
= dst_dev
->funcs
->pStretchBlt( dst_dev
, &dst
, src_dev
, &src
, rop
);
602 release_dc_ptr( dcSrc
);
604 release_dc_ptr( dcDst
);
608 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
609 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
611 /***********************************************************************
614 BOOL WINAPI
MaskBlt(HDC hdcDest
, INT nXDest
, INT nYDest
,
615 INT nWidth
, INT nHeight
, HDC hdcSrc
,
616 INT nXSrc
, INT nYSrc
, HBITMAP hbmMask
,
617 INT xMask
, INT yMask
, DWORD dwRop
)
619 HBITMAP hBitmap1
, hOldBitmap1
, hBitmap2
, hOldBitmap2
;
621 HBRUSH hbrMask
, hbrDst
, hbrTmp
;
623 static const DWORD ROP3Table
[256] =
625 0x00000042, 0x00010289,
626 0x00020C89, 0x000300AA,
627 0x00040C88, 0x000500A9,
628 0x00060865, 0x000702C5,
629 0x00080F08, 0x00090245,
630 0x000A0329, 0x000B0B2A,
631 0x000C0324, 0x000D0B25,
632 0x000E08A5, 0x000F0001,
633 0x00100C85, 0x001100A6,
634 0x00120868, 0x001302C8,
635 0x00140869, 0x001502C9,
636 0x00165CCA, 0x00171D54,
637 0x00180D59, 0x00191CC8,
638 0x001A06C5, 0x001B0768,
639 0x001C06CA, 0x001D0766,
640 0x001E01A5, 0x001F0385,
641 0x00200F09, 0x00210248,
642 0x00220326, 0x00230B24,
643 0x00240D55, 0x00251CC5,
644 0x002606C8, 0x00271868,
645 0x00280369, 0x002916CA,
646 0x002A0CC9, 0x002B1D58,
647 0x002C0784, 0x002D060A,
648 0x002E064A, 0x002F0E2A,
649 0x0030032A, 0x00310B28,
650 0x00320688, 0x00330008,
651 0x003406C4, 0x00351864,
652 0x003601A8, 0x00370388,
653 0x0038078A, 0x00390604,
654 0x003A0644, 0x003B0E24,
655 0x003C004A, 0x003D18A4,
656 0x003E1B24, 0x003F00EA,
657 0x00400F0A, 0x00410249,
658 0x00420D5D, 0x00431CC4,
659 0x00440328, 0x00450B29,
660 0x004606C6, 0x0047076A,
661 0x00480368, 0x004916C5,
662 0x004A0789, 0x004B0605,
663 0x004C0CC8, 0x004D1954,
664 0x004E0645, 0x004F0E25,
665 0x00500325, 0x00510B26,
666 0x005206C9, 0x00530764,
667 0x005408A9, 0x00550009,
668 0x005601A9, 0x00570389,
669 0x00580785, 0x00590609,
670 0x005A0049, 0x005B18A9,
671 0x005C0649, 0x005D0E29,
672 0x005E1B29, 0x005F00E9,
673 0x00600365, 0x006116C6,
674 0x00620786, 0x00630608,
675 0x00640788, 0x00650606,
676 0x00660046, 0x006718A8,
677 0x006858A6, 0x00690145,
678 0x006A01E9, 0x006B178A,
679 0x006C01E8, 0x006D1785,
680 0x006E1E28, 0x006F0C65,
681 0x00700CC5, 0x00711D5C,
682 0x00720648, 0x00730E28,
683 0x00740646, 0x00750E26,
684 0x00761B28, 0x007700E6,
685 0x007801E5, 0x00791786,
686 0x007A1E29, 0x007B0C68,
687 0x007C1E24, 0x007D0C69,
688 0x007E0955, 0x007F03C9,
689 0x008003E9, 0x00810975,
690 0x00820C49, 0x00831E04,
691 0x00840C48, 0x00851E05,
692 0x008617A6, 0x008701C5,
693 0x008800C6, 0x00891B08,
694 0x008A0E06, 0x008B0666,
695 0x008C0E08, 0x008D0668,
696 0x008E1D7C, 0x008F0CE5,
697 0x00900C45, 0x00911E08,
698 0x009217A9, 0x009301C4,
699 0x009417AA, 0x009501C9,
700 0x00960169, 0x0097588A,
701 0x00981888, 0x00990066,
702 0x009A0709, 0x009B07A8,
703 0x009C0704, 0x009D07A6,
704 0x009E16E6, 0x009F0345,
705 0x00A000C9, 0x00A11B05,
706 0x00A20E09, 0x00A30669,
707 0x00A41885, 0x00A50065,
708 0x00A60706, 0x00A707A5,
709 0x00A803A9, 0x00A90189,
710 0x00AA0029, 0x00AB0889,
711 0x00AC0744, 0x00AD06E9,
712 0x00AE0B06, 0x00AF0229,
713 0x00B00E05, 0x00B10665,
714 0x00B21974, 0x00B30CE8,
715 0x00B4070A, 0x00B507A9,
716 0x00B616E9, 0x00B70348,
717 0x00B8074A, 0x00B906E6,
718 0x00BA0B09, 0x00BB0226,
719 0x00BC1CE4, 0x00BD0D7D,
720 0x00BE0269, 0x00BF08C9,
721 0x00C000CA, 0x00C11B04,
722 0x00C21884, 0x00C3006A,
723 0x00C40E04, 0x00C50664,
724 0x00C60708, 0x00C707AA,
725 0x00C803A8, 0x00C90184,
726 0x00CA0749, 0x00CB06E4,
727 0x00CC0020, 0x00CD0888,
728 0x00CE0B08, 0x00CF0224,
729 0x00D00E0A, 0x00D1066A,
730 0x00D20705, 0x00D307A4,
731 0x00D41D78, 0x00D50CE9,
732 0x00D616EA, 0x00D70349,
733 0x00D80745, 0x00D906E8,
734 0x00DA1CE9, 0x00DB0D75,
735 0x00DC0B04, 0x00DD0228,
736 0x00DE0268, 0x00DF08C8,
737 0x00E003A5, 0x00E10185,
738 0x00E20746, 0x00E306EA,
739 0x00E40748, 0x00E506E5,
740 0x00E61CE8, 0x00E70D79,
741 0x00E81D74, 0x00E95CE6,
742 0x00EA02E9, 0x00EB0849,
743 0x00EC02E8, 0x00ED0848,
744 0x00EE0086, 0x00EF0A08,
745 0x00F00021, 0x00F10885,
746 0x00F20B05, 0x00F3022A,
747 0x00F40B0A, 0x00F50225,
748 0x00F60265, 0x00F708C5,
749 0x00F802E5, 0x00F90845,
750 0x00FA0089, 0x00FB0A09,
751 0x00FC008A, 0x00FD0A0A,
752 0x00FE02A9, 0x00FF0062,
756 return BitBlt(hdcDest
, nXDest
, nYDest
, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, FRGND_ROP3(dwRop
));
758 hbrMask
= CreatePatternBrush(hbmMask
);
759 hbrDst
= SelectObject(hdcDest
, GetStockObject(NULL_BRUSH
));
762 hDC1
= CreateCompatibleDC(hdcDest
);
763 hBitmap1
= CreateCompatibleBitmap(hdcDest
, nWidth
, nHeight
);
764 hOldBitmap1
= SelectObject(hDC1
, hBitmap1
);
766 /* draw using bkgnd rop */
767 BitBlt(hDC1
, 0, 0, nWidth
, nHeight
, hdcDest
, nXDest
, nYDest
, SRCCOPY
);
768 hbrTmp
= SelectObject(hDC1
, hbrDst
);
769 BitBlt(hDC1
, 0, 0, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, BKGND_ROP3(dwRop
));
770 SelectObject(hDC1
, hbrTmp
);
773 hDC2
= CreateCompatibleDC(hdcDest
);
774 hBitmap2
= CreateCompatibleBitmap(hdcDest
, nWidth
, nHeight
);
775 hOldBitmap2
= SelectObject(hDC2
, hBitmap2
);
777 /* draw using foregnd rop */
778 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hdcDest
, nXDest
, nYDest
, SRCCOPY
);
779 hbrTmp
= SelectObject(hDC2
, hbrDst
);
780 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, FRGND_ROP3(dwRop
));
782 /* combine both using the mask as a pattern brush */
783 SelectObject(hDC2
, hbrMask
);
784 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hDC1
, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
785 SelectObject(hDC2
, hbrTmp
);
788 BitBlt(hdcDest
, nXDest
, nYDest
, nWidth
, nHeight
, hDC2
, 0, 0, SRCCOPY
);
790 /* restore all objects */
791 SelectObject(hdcDest
, hbrDst
);
792 SelectObject(hDC1
, hOldBitmap1
);
793 SelectObject(hDC2
, hOldBitmap2
);
795 /* delete all temp objects */
796 DeleteObject(hBitmap1
);
797 DeleteObject(hBitmap2
);
798 DeleteObject(hbrMask
);
806 /******************************************************************************
807 * GdiTransparentBlt [GDI32.@]
809 BOOL WINAPI
GdiTransparentBlt( HDC hdcDest
, int xDest
, int yDest
, int widthDest
, int heightDest
,
810 HDC hdcSrc
, int xSrc
, int ySrc
, int widthSrc
, int heightSrc
,
818 HBITMAP bmpMask
= NULL
;
819 HBITMAP oldMask
= NULL
;
820 COLORREF oldBackground
;
821 COLORREF oldForeground
;
824 if(widthDest
< 0 || heightDest
< 0 || widthSrc
< 0 || heightSrc
< 0) {
825 TRACE("Cannot mirror\n");
829 oldBackground
= SetBkColor(hdcDest
, RGB(255,255,255));
830 oldForeground
= SetTextColor(hdcDest
, RGB(0,0,0));
833 oldStretchMode
= GetStretchBltMode(hdcSrc
);
834 if(oldStretchMode
== BLACKONWHITE
|| oldStretchMode
== WHITEONBLACK
)
835 SetStretchBltMode(hdcSrc
, COLORONCOLOR
);
836 hdcWork
= CreateCompatibleDC(hdcDest
);
837 bmpWork
= CreateCompatibleBitmap(hdcDest
, widthDest
, heightDest
);
838 oldWork
= SelectObject(hdcWork
, bmpWork
);
839 if(!StretchBlt(hdcWork
, 0, 0, widthDest
, heightDest
, hdcSrc
, xSrc
, ySrc
, widthSrc
, heightSrc
, SRCCOPY
)) {
840 TRACE("Failed to stretch\n");
843 SetBkColor(hdcWork
, crTransparent
);
846 hdcMask
= CreateCompatibleDC(hdcDest
);
847 bmpMask
= CreateCompatibleBitmap(hdcMask
, widthDest
, heightDest
);
848 oldMask
= SelectObject(hdcMask
, bmpMask
);
849 if(!BitBlt(hdcMask
, 0, 0, widthDest
, heightDest
, hdcWork
, 0, 0, SRCCOPY
)) {
850 TRACE("Failed to create mask\n");
854 /* Replace transparent color with black */
855 SetBkColor(hdcWork
, RGB(0,0,0));
856 SetTextColor(hdcWork
, RGB(255,255,255));
857 if(!BitBlt(hdcWork
, 0, 0, widthDest
, heightDest
, hdcMask
, 0, 0, SRCAND
)) {
858 TRACE("Failed to mask out background\n");
862 /* Replace non-transparent area on destination with black */
863 if(!BitBlt(hdcDest
, xDest
, yDest
, widthDest
, heightDest
, hdcMask
, 0, 0, SRCAND
)) {
864 TRACE("Failed to clear destination area\n");
869 if(!BitBlt(hdcDest
, xDest
, yDest
, widthDest
, heightDest
, hdcWork
, 0, 0, SRCPAINT
)) {
870 TRACE("Failed to paint image\n");
876 SetStretchBltMode(hdcSrc
, oldStretchMode
);
877 SetBkColor(hdcDest
, oldBackground
);
878 SetTextColor(hdcDest
, oldForeground
);
880 SelectObject(hdcWork
, oldWork
);
883 if(bmpWork
) DeleteObject(bmpWork
);
885 SelectObject(hdcMask
, oldMask
);
888 if(bmpMask
) DeleteObject(bmpMask
);
892 /******************************************************************************
893 * GdiAlphaBlend [GDI32.@]
895 BOOL WINAPI
GdiAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int widthDst
, int heightDst
,
896 HDC hdcSrc
, int xSrc
, int ySrc
, int widthSrc
, int heightSrc
,
897 BLENDFUNCTION blendFunction
)
902 dcSrc
= get_dc_ptr( hdcSrc
);
903 if (!dcSrc
) return FALSE
;
905 if ((dcDst
= get_dc_ptr( hdcDst
)))
907 struct bitblt_coords src
, dst
;
908 PHYSDEV src_dev
= GET_DC_PHYSDEV( dcSrc
, pAlphaBlend
);
909 PHYSDEV dst_dev
= GET_DC_PHYSDEV( dcDst
, pAlphaBlend
);
916 src
.log_width
= widthSrc
;
917 src
.log_height
= heightSrc
;
918 src
.layout
= GetLayout( src_dev
->hdc
);
921 dst
.log_width
= widthDst
;
922 dst
.log_height
= heightDst
;
923 dst
.layout
= GetLayout( dst_dev
->hdc
);
924 ret
= !get_vis_rectangles( dcDst
, &dst
, dcSrc
, &src
);
926 TRACE("src %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s blend=%02x/%02x/%02x/%02x\n",
927 hdcSrc
, src
.log_x
, src
.log_y
, src
.log_width
, src
.log_height
,
928 src
.x
, src
.y
, src
.width
, src
.height
, wine_dbgstr_rect(&src
.visrect
),
929 hdcDst
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
930 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
),
931 blendFunction
.BlendOp
, blendFunction
.BlendFlags
,
932 blendFunction
.SourceConstantAlpha
, blendFunction
.AlphaFormat
);
934 if (src
.x
< 0 || src
.y
< 0 || src
.width
< 0 || src
.height
< 0 ||
935 src
.log_width
< 0 || src
.log_height
< 0 ||
936 (dcSrc
->header
.type
== OBJ_MEMDC
&&
937 (src
.width
> dcSrc
->vis_rect
.right
- dcSrc
->vis_rect
.left
- src
.x
||
938 src
.height
> dcSrc
->vis_rect
.bottom
- dcSrc
->vis_rect
.top
- src
.y
)))
940 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src
.x
, src
.y
, src
.width
, src
.height
);
941 SetLastError( ERROR_INVALID_PARAMETER
);
944 else if (dst
.log_width
< 0 || dst
.log_height
< 0)
946 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
947 dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
);
948 SetLastError( ERROR_INVALID_PARAMETER
);
951 else if (dcSrc
== dcDst
&& src
.x
+ src
.width
> dst
.x
&& src
.x
< dst
.x
+ dst
.width
&&
952 src
.y
+ src
.height
> dst
.y
&& src
.y
< dst
.y
+ dst
.height
)
954 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
955 src
.x
, src
.y
, src
.width
, src
.height
, dst
.x
, dst
.y
, dst
.width
, dst
.height
);
956 SetLastError( ERROR_INVALID_PARAMETER
);
959 else if (!ret
) ret
= dst_dev
->funcs
->pAlphaBlend( dst_dev
, &dst
, src_dev
, &src
, blendFunction
);
961 release_dc_ptr( dcDst
);
963 release_dc_ptr( dcSrc
);
967 /*********************************************************************
971 BOOL WINAPI
PlgBlt( HDC hdcDest
, const POINT
*lpPoint
,
972 HDC hdcSrc
, INT nXSrc
, INT nYSrc
, INT nWidth
,
973 INT nHeight
, HBITMAP hbmMask
, INT xMask
, INT yMask
)
976 /* parallelogram coords */
985 /* save actual mode, set GM_ADVANCED */
986 oldgMode
= SetGraphicsMode(hdcDest
,GM_ADVANCED
);
990 memcpy(plg
,lpPoint
,sizeof(POINT
)*3);
993 rect
[1].x
= nXSrc
+ nWidth
;
996 rect
[2].y
= nYSrc
+ nHeight
;
997 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
999 det
= rect
[1].x
*(rect
[2].y
- rect
[0].y
) - rect
[2].x
*(rect
[1].y
- rect
[0].y
) - rect
[0].x
*(rect
[2].y
- rect
[1].y
);
1001 if (fabs(det
) < 1e-5)
1003 SetGraphicsMode(hdcDest
,oldgMode
);
1007 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1008 hdcSrc
, nXSrc
, nYSrc
, nWidth
, nHeight
, hdcDest
, plg
[0].x
, plg
[0].y
, plg
[1].x
, plg
[1].y
, plg
[2].x
, plg
[2].y
);
1011 xf
.eM11
= (plg
[1].x
*(rect
[2].y
- rect
[0].y
) - plg
[2].x
*(rect
[1].y
- rect
[0].y
) - plg
[0].x
*(rect
[2].y
- rect
[1].y
)) / det
;
1012 xf
.eM21
= (rect
[1].x
*(plg
[2].x
- plg
[0].x
) - rect
[2].x
*(plg
[1].x
- plg
[0].x
) - rect
[0].x
*(plg
[2].x
- plg
[1].x
)) / det
;
1013 xf
.eDx
= (rect
[0].x
*(rect
[1].y
*plg
[2].x
- rect
[2].y
*plg
[1].x
) -
1014 rect
[1].x
*(rect
[0].y
*plg
[2].x
- rect
[2].y
*plg
[0].x
) +
1015 rect
[2].x
*(rect
[0].y
*plg
[1].x
- rect
[1].y
*plg
[0].x
)
1019 xf
.eM12
= (plg
[1].y
*(rect
[2].y
- rect
[0].y
) - plg
[2].y
*(rect
[1].y
- rect
[0].y
) - plg
[0].y
*(rect
[2].y
- rect
[1].y
)) / det
;
1020 xf
.eM22
= (plg
[1].x
*(rect
[2].y
- rect
[0].y
) - plg
[2].x
*(rect
[1].y
- rect
[0].y
) - plg
[0].x
*(rect
[2].y
- rect
[1].y
)) / det
;
1021 xf
.eDy
= (rect
[0].x
*(rect
[1].y
*plg
[2].y
- rect
[2].y
*plg
[1].y
) -
1022 rect
[1].x
*(rect
[0].y
*plg
[2].y
- rect
[2].y
*plg
[0].y
) +
1023 rect
[2].x
*(rect
[0].y
*plg
[1].y
- rect
[1].y
*plg
[0].y
)
1026 GetWorldTransform(hdcSrc
,&SrcXf
);
1027 CombineTransform(&xf
,&xf
,&SrcXf
);
1029 /* save actual dest transform */
1030 GetWorldTransform(hdcDest
,&oldDestXf
);
1032 SetWorldTransform(hdcDest
,&xf
);
1033 /* now destination and source DCs use same coords */
1034 MaskBlt(hdcDest
,nXSrc
,nYSrc
,nWidth
,nHeight
,
1035 hdcSrc
, nXSrc
,nYSrc
,
1036 hbmMask
,xMask
,yMask
,
1038 /* restore dest DC */
1039 SetWorldTransform(hdcDest
,&oldDestXf
);
1040 SetGraphicsMode(hdcDest
,oldgMode
);