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 static BOOL
get_vis_rectangles( DC
*dc_dst
, struct bitblt_coords
*dst
,
51 DC
*dc_src
, struct bitblt_coords
*src
)
55 /* get the destination visible rectangle */
57 rect
.left
= dst
->log_x
;
58 rect
.top
= dst
->log_y
;
59 rect
.right
= dst
->log_x
+ dst
->log_width
;
60 rect
.bottom
= dst
->log_y
+ dst
->log_height
;
61 LPtoDP( dc_dst
->hSelf
, (POINT
*)&rect
, 2 );
64 dst
->width
= rect
.right
- rect
.left
;
65 dst
->height
= rect
.bottom
- rect
.top
;
66 if (dst
->layout
& LAYOUT_RTL
&& dst
->layout
& LAYOUT_BITMAPORIENTATIONPRESERVED
)
69 dst
->width
= -dst
->width
;
71 get_bounding_rect( &rect
, dst
->x
, dst
->y
, dst
->width
, dst
->height
);
73 if (get_clip_box( dc_dst
, &clip
))
74 intersect_rect( &dst
->visrect
, &rect
, &clip
);
78 /* get the source visible rectangle */
80 if (!src
) return !is_rect_empty( &dst
->visrect
);
82 rect
.left
= src
->log_x
;
83 rect
.top
= src
->log_y
;
84 rect
.right
= src
->log_x
+ src
->log_width
;
85 rect
.bottom
= src
->log_y
+ src
->log_height
;
86 LPtoDP( dc_src
->hSelf
, (POINT
*)&rect
, 2 );
89 src
->width
= rect
.right
- rect
.left
;
90 src
->height
= rect
.bottom
- rect
.top
;
91 if (src
->layout
& LAYOUT_RTL
&& src
->layout
& LAYOUT_BITMAPORIENTATIONPRESERVED
)
94 src
->width
= -src
->width
;
96 get_bounding_rect( &rect
, src
->x
, src
->y
, src
->width
, src
->height
);
98 /* source is not clipped */
99 if (dc_src
->header
.type
== OBJ_MEMDC
)
100 intersect_rect( &src
->visrect
, &rect
, &dc_src
->vis_rect
);
102 src
->visrect
= rect
; /* FIXME: clip to device size */
104 if (is_rect_empty( &src
->visrect
)) return FALSE
;
105 if (is_rect_empty( &dst
->visrect
)) return FALSE
;
107 /* intersect the rectangles */
109 if ((src
->width
== dst
->width
) && (src
->height
== dst
->height
)) /* no stretching */
111 offset_rect( &src
->visrect
, dst
->x
- src
->x
, dst
->y
- src
->y
);
112 intersect_rect( &rect
, &src
->visrect
, &dst
->visrect
);
113 src
->visrect
= dst
->visrect
= rect
;
114 offset_rect( &src
->visrect
, src
->x
- dst
->x
, src
->y
- dst
->y
);
116 else /* stretching */
118 /* map source rectangle into destination coordinates */
120 offset_rect( &rect
, -min( src
->x
, src
->x
+ src
->width
+ 1),
121 -min( src
->y
, src
->y
+ src
->height
+ 1) );
122 rect
.left
= dst
->x
+ rect
.left
* dst
->width
/ abs(src
->width
);
123 rect
.top
= dst
->y
+ rect
.top
* dst
->height
/ abs(src
->height
);
124 rect
.right
= dst
->x
+ rect
.right
* dst
->width
/ abs(src
->width
);
125 rect
.bottom
= dst
->y
+ rect
.bottom
* dst
->height
/ abs(src
->height
);
126 if (rect
.left
> rect
.right
) swap_ints( &rect
.left
, &rect
.right
);
127 if (rect
.top
> rect
.bottom
) swap_ints( &rect
.top
, &rect
.bottom
);
129 /* avoid rounding errors */
134 if (!intersect_rect( &dst
->visrect
, &rect
, &dst
->visrect
)) return FALSE
;
136 /* map destination rectangle back to source coordinates */
138 offset_rect( &rect
, -min( dst
->x
, dst
->x
+ dst
->width
+ 1),
139 -min( dst
->y
, dst
->y
+ dst
->height
+ 1) );
140 rect
.left
= src
->x
+ rect
.left
* src
->width
/ abs(dst
->width
);
141 rect
.top
= src
->y
+ rect
.top
* src
->height
/ abs(dst
->height
);
142 rect
.right
= src
->x
+ rect
.right
* src
->width
/ abs(dst
->width
);
143 rect
.bottom
= src
->y
+ rect
.bottom
* src
->height
/ abs(dst
->height
);
144 if (rect
.left
> rect
.right
) swap_ints( &rect
.left
, &rect
.right
);
145 if (rect
.top
> rect
.bottom
) swap_ints( &rect
.top
, &rect
.bottom
);
147 /* avoid rounding errors */
152 if (!intersect_rect( &src
->visrect
, &rect
, &src
->visrect
)) return FALSE
;
157 void free_heap_bits( struct gdi_image_bits
*bits
)
159 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
162 static DWORD
convert_bits( const BITMAPINFO
*src_info
, struct bitblt_coords
*src
,
163 BITMAPINFO
*dst_info
, struct gdi_image_bits
*bits
, BOOL add_alpha
)
168 dst_info
->bmiHeader
.biWidth
= src
->visrect
.right
- src
->visrect
.left
;
169 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info
))))
170 return ERROR_OUTOFMEMORY
;
172 err
= convert_bitmapinfo( src_info
, bits
->ptr
, src
, dst_info
, ptr
, add_alpha
);
173 if (bits
->free
) bits
->free( bits
);
175 bits
->is_copy
= TRUE
;
176 bits
->free
= free_heap_bits
;
180 static DWORD
stretch_bits( const BITMAPINFO
*src_info
, struct bitblt_coords
*src
,
181 BITMAPINFO
*dst_info
, struct bitblt_coords
*dst
,
182 struct gdi_image_bits
*bits
, int mode
)
187 dst_info
->bmiHeader
.biWidth
= dst
->visrect
.right
- dst
->visrect
.left
;
188 dst_info
->bmiHeader
.biHeight
= dst
->visrect
.bottom
- dst
->visrect
.top
;
189 if (src_info
->bmiHeader
.biHeight
< 0) dst_info
->bmiHeader
.biHeight
= -dst_info
->bmiHeader
.biHeight
;
190 if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info
))))
191 return ERROR_OUTOFMEMORY
;
193 err
= stretch_bitmapinfo( src_info
, bits
->ptr
, src
, dst_info
, ptr
, dst
, mode
);
194 if (bits
->free
) bits
->free( bits
);
196 bits
->is_copy
= TRUE
;
197 bits
->free
= free_heap_bits
;
201 static DWORD
blend_bits( const BITMAPINFO
*src_info
, const struct gdi_image_bits
*src_bits
,
202 struct bitblt_coords
*src
, BITMAPINFO
*dst_info
,
203 struct gdi_image_bits
*dst_bits
, struct bitblt_coords
*dst
, BLENDFUNCTION blend
)
205 if (!dst_bits
->is_copy
)
207 int size
= get_dib_image_size( dst_info
);
208 void *ptr
= HeapAlloc( GetProcessHeap(), 0, size
);
209 if (!ptr
) return ERROR_OUTOFMEMORY
;
210 memcpy( ptr
, dst_bits
->ptr
, size
);
211 if (dst_bits
->free
) dst_bits
->free( dst_bits
);
213 dst_bits
->is_copy
= TRUE
;
214 dst_bits
->free
= free_heap_bits
;
216 return blend_bitmapinfo( src_info
, src_bits
->ptr
, src
, dst_info
, dst_bits
->ptr
, dst
, blend
);
219 /***********************************************************************
220 * null driver fallback implementations
223 BOOL
nulldrv_StretchBlt( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
224 PHYSDEV src_dev
, struct bitblt_coords
*src
, DWORD rop
)
226 DC
*dc_src
, *dc_dst
= get_nulldrv_dc( dst_dev
);
227 char src_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
228 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
229 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_buffer
;
230 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
232 struct gdi_image_bits bits
;
234 if (!(dc_src
= get_dc_ptr( src_dev
->hdc
))) return FALSE
;
235 src_dev
= GET_DC_PHYSDEV( dc_src
, pGetImage
);
236 err
= src_dev
->funcs
->pGetImage( src_dev
, 0, src_info
, &bits
, src
);
237 release_dc_ptr( dc_src
);
238 if (err
) return FALSE
;
240 dst_dev
= GET_DC_PHYSDEV( dc_dst
, pPutImage
);
241 memcpy( dst_info
, src_info
, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] ));
242 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, 0, dst_info
, &bits
, src
, dst
, rop
);
243 if (err
== ERROR_BAD_FORMAT
)
245 /* 1-bpp source without a color table uses the destination DC colors */
246 if (src_info
->bmiHeader
.biBitCount
== 1 && !src_info
->bmiHeader
.biClrUsed
)
248 COLORREF color
= GetTextColor( dst_dev
->hdc
);
249 src_info
->bmiColors
[0].rgbRed
= GetRValue( color
);
250 src_info
->bmiColors
[0].rgbGreen
= GetGValue( color
);
251 src_info
->bmiColors
[0].rgbBlue
= GetBValue( color
);
252 src_info
->bmiColors
[0].rgbReserved
= 0;
253 color
= GetBkColor( dst_dev
->hdc
);
254 src_info
->bmiColors
[1].rgbRed
= GetRValue( color
);
255 src_info
->bmiColors
[1].rgbGreen
= GetGValue( color
);
256 src_info
->bmiColors
[1].rgbBlue
= GetBValue( color
);
257 src_info
->bmiColors
[1].rgbReserved
= 0;
258 src_info
->bmiHeader
.biClrUsed
= 2;
261 /* 1-bpp destination without a color table requires a fake 1-entry table
262 * that contains only the background color */
263 if (dst_info
->bmiHeader
.biBitCount
== 1 && !dst_info
->bmiHeader
.biClrUsed
)
265 COLORREF color
= GetBkColor( src_dev
->hdc
);
266 dst_info
->bmiColors
[0].rgbRed
= GetRValue( color
);
267 dst_info
->bmiColors
[0].rgbGreen
= GetGValue( color
);
268 dst_info
->bmiColors
[0].rgbBlue
= GetBValue( color
);
269 dst_info
->bmiColors
[0].rgbReserved
= 0;
270 dst_info
->bmiHeader
.biClrUsed
= 1;
273 if (!(err
= convert_bits( src_info
, src
, dst_info
, &bits
, FALSE
)))
275 /* get rid of the fake 1-bpp table */
276 if (dst_info
->bmiHeader
.biClrUsed
== 1) dst_info
->bmiHeader
.biClrUsed
= 0;
277 err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, 0, dst_info
, &bits
, src
, dst
, rop
);
281 if (err
== ERROR_TRANSFORM_NOT_SUPPORTED
&&
282 ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)))
284 memcpy( src_info
, dst_info
, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] ));
285 err
= stretch_bits( src_info
, src
, dst_info
, dst
, &bits
, GetStretchBltMode( dst_dev
->hdc
));
286 if (!err
) err
= dst_dev
->funcs
->pPutImage( dst_dev
, 0, 0, dst_info
, &bits
, src
, dst
, rop
);
289 if (bits
.free
) bits
.free( &bits
);
294 BOOL
nulldrv_AlphaBlend( PHYSDEV dst_dev
, struct bitblt_coords
*dst
,
295 PHYSDEV src_dev
, struct bitblt_coords
*src
, BLENDFUNCTION func
)
297 DC
*dc_src
, *dc_dst
= get_nulldrv_dc( dst_dev
);
298 char src_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
299 char dst_buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
300 BITMAPINFO
*src_info
= (BITMAPINFO
*)src_buffer
;
301 BITMAPINFO
*dst_info
= (BITMAPINFO
*)dst_buffer
;
303 struct gdi_image_bits bits
;
305 if (!(dc_src
= get_dc_ptr( src_dev
->hdc
))) return FALSE
;
306 src_dev
= GET_DC_PHYSDEV( dc_src
, pGetImage
);
307 err
= src_dev
->funcs
->pGetImage( src_dev
, 0, src_info
, &bits
, src
);
308 release_dc_ptr( dc_src
);
311 dst_dev
= GET_DC_PHYSDEV( dc_dst
, pBlendImage
);
312 memcpy( dst_info
, src_info
, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] ));
313 err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
314 if (err
== ERROR_BAD_FORMAT
)
316 /* 1-bpp source without a color table uses black & white */
317 if (src_info
->bmiHeader
.biBitCount
== 1 && !src_info
->bmiHeader
.biClrUsed
)
319 src_info
->bmiColors
[0].rgbRed
= 0;
320 src_info
->bmiColors
[0].rgbGreen
= 0;
321 src_info
->bmiColors
[0].rgbBlue
= 0;
322 src_info
->bmiColors
[0].rgbReserved
= 0;
323 src_info
->bmiColors
[1].rgbRed
= 0xff;
324 src_info
->bmiColors
[1].rgbGreen
= 0xff;
325 src_info
->bmiColors
[1].rgbBlue
= 0xff;
326 src_info
->bmiColors
[1].rgbReserved
= 0;
327 src_info
->bmiHeader
.biClrUsed
= 2;
330 err
= convert_bits( src_info
, src
, dst_info
, &bits
, TRUE
);
331 if (!err
) err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
334 if (err
== ERROR_TRANSFORM_NOT_SUPPORTED
&&
335 ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)))
337 memcpy( src_info
, dst_info
, FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] ));
338 err
= stretch_bits( src_info
, src
, dst_info
, dst
, &bits
, COLORONCOLOR
);
339 if (!err
) err
= dst_dev
->funcs
->pBlendImage( dst_dev
, dst_info
, &bits
, src
, dst
, func
);
342 if (bits
.free
) bits
.free( &bits
);
344 if (err
) SetLastError( err
);
349 DWORD
nulldrv_BlendImage( PHYSDEV dev
, BITMAPINFO
*info
, const struct gdi_image_bits
*bits
,
350 struct bitblt_coords
*src
, struct bitblt_coords
*dst
, BLENDFUNCTION blend
)
352 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
353 BITMAPINFO
*dst_info
= (BITMAPINFO
*)buffer
;
354 struct gdi_image_bits dst_bits
;
355 struct bitblt_coords orig_dst
;
356 DC
*dc
= get_nulldrv_dc( dev
);
359 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
360 if (info
->bmiHeader
.biBitCount
!= 32) goto update_format
;
361 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
)
363 DWORD
*masks
= (DWORD
*)info
->bmiColors
;
364 if (masks
[0] != 0xff0000 || masks
[1] != 0x00ff00 || masks
[2] != 0x0000ff)
368 if (!bits
) return ERROR_SUCCESS
;
369 if ((src
->width
!= dst
->width
) || (src
->height
!= dst
->height
)) return ERROR_TRANSFORM_NOT_SUPPORTED
;
371 dev
= GET_DC_PHYSDEV( dc
, pGetImage
);
373 err
= dev
->funcs
->pGetImage( dev
, 0, dst_info
, &dst_bits
, dst
);
376 dev
= GET_DC_PHYSDEV( dc
, pPutImage
);
377 err
= blend_bits( info
, bits
, src
, dst_info
, &dst_bits
, dst
, blend
);
378 if (!err
) err
= dev
->funcs
->pPutImage( dev
, 0, 0, dst_info
, &dst_bits
, dst
, &orig_dst
, SRCCOPY
);
380 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
384 if (blend
.AlphaFormat
& AC_SRC_ALPHA
) /* source alpha requires A8R8G8B8 format */
385 return ERROR_INVALID_PARAMETER
;
387 info
->bmiHeader
.biPlanes
= 1;
388 info
->bmiHeader
.biBitCount
= 32;
389 info
->bmiHeader
.biCompression
= BI_RGB
;
390 info
->bmiHeader
.biClrUsed
= 0;
391 return ERROR_BAD_FORMAT
;
394 /***********************************************************************
397 BOOL WINAPI
PatBlt( HDC hdc
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
402 if (rop_uses_src( rop
)) return FALSE
;
403 if ((dc
= get_dc_ptr( hdc
)))
405 struct bitblt_coords dst
;
406 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPatBlt
);
412 dst
.log_width
= width
;
413 dst
.log_height
= height
;
414 dst
.layout
= dc
->layout
;
415 if (rop
& NOMIRRORBITMAP
)
417 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
418 rop
&= ~NOMIRRORBITMAP
;
420 ret
= !get_vis_rectangles( dc
, &dst
, NULL
, NULL
);
422 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
423 hdc
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
424 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
), rop
);
426 if (!ret
) ret
= physdev
->funcs
->pPatBlt( physdev
, &dst
, rop
);
428 release_dc_ptr( dc
);
434 /***********************************************************************
437 BOOL WINAPI
BitBlt( HDC hdcDst
, INT xDst
, INT yDst
, INT width
,
438 INT height
, HDC hdcSrc
, INT xSrc
, INT ySrc
, DWORD rop
)
440 if (!rop_uses_src( rop
)) return PatBlt( hdcDst
, xDst
, yDst
, width
, height
, rop
);
441 else return StretchBlt( hdcDst
, xDst
, yDst
, width
, height
,
442 hdcSrc
, xSrc
, ySrc
, width
, height
, rop
);
446 /***********************************************************************
447 * StretchBlt (GDI32.@)
449 BOOL WINAPI
StretchBlt( HDC hdcDst
, INT xDst
, INT yDst
, INT widthDst
, INT heightDst
,
450 HDC hdcSrc
, INT xSrc
, INT ySrc
, INT widthSrc
, INT heightSrc
, DWORD rop
)
455 if (!rop_uses_src( rop
)) return PatBlt( hdcDst
, xDst
, yDst
, widthDst
, heightDst
, rop
);
457 if (!(dcDst
= get_dc_ptr( hdcDst
))) return FALSE
;
459 if ((dcSrc
= get_dc_ptr( hdcSrc
)))
461 struct bitblt_coords src
, dst
;
462 PHYSDEV src_dev
= GET_DC_PHYSDEV( dcSrc
, pStretchBlt
);
463 PHYSDEV dst_dev
= GET_DC_PHYSDEV( dcDst
, pStretchBlt
);
470 src
.log_width
= widthSrc
;
471 src
.log_height
= heightSrc
;
472 src
.layout
= dcSrc
->layout
;
475 dst
.log_width
= widthDst
;
476 dst
.log_height
= heightDst
;
477 dst
.layout
= dcDst
->layout
;
478 if (rop
& NOMIRRORBITMAP
)
480 src
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
481 dst
.layout
|= LAYOUT_BITMAPORIENTATIONPRESERVED
;
482 rop
&= ~NOMIRRORBITMAP
;
484 ret
= !get_vis_rectangles( dcDst
, &dst
, dcSrc
, &src
);
486 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",
487 hdcSrc
, src
.log_x
, src
.log_y
, src
.log_width
, src
.log_height
,
488 src
.x
, src
.y
, src
.width
, src
.height
, wine_dbgstr_rect(&src
.visrect
),
489 hdcDst
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
490 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
), rop
);
492 if (!ret
) ret
= dst_dev
->funcs
->pStretchBlt( dst_dev
, &dst
, src_dev
, &src
, rop
);
493 release_dc_ptr( dcSrc
);
495 release_dc_ptr( dcDst
);
499 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
500 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
502 /***********************************************************************
505 BOOL WINAPI
MaskBlt(HDC hdcDest
, INT nXDest
, INT nYDest
,
506 INT nWidth
, INT nHeight
, HDC hdcSrc
,
507 INT nXSrc
, INT nYSrc
, HBITMAP hbmMask
,
508 INT xMask
, INT yMask
, DWORD dwRop
)
510 HBITMAP hBitmap1
, hOldBitmap1
, hBitmap2
, hOldBitmap2
;
512 HBRUSH hbrMask
, hbrDst
, hbrTmp
;
514 static const DWORD ROP3Table
[256] =
516 0x00000042, 0x00010289,
517 0x00020C89, 0x000300AA,
518 0x00040C88, 0x000500A9,
519 0x00060865, 0x000702C5,
520 0x00080F08, 0x00090245,
521 0x000A0329, 0x000B0B2A,
522 0x000C0324, 0x000D0B25,
523 0x000E08A5, 0x000F0001,
524 0x00100C85, 0x001100A6,
525 0x00120868, 0x001302C8,
526 0x00140869, 0x001502C9,
527 0x00165CCA, 0x00171D54,
528 0x00180D59, 0x00191CC8,
529 0x001A06C5, 0x001B0768,
530 0x001C06CA, 0x001D0766,
531 0x001E01A5, 0x001F0385,
532 0x00200F09, 0x00210248,
533 0x00220326, 0x00230B24,
534 0x00240D55, 0x00251CC5,
535 0x002606C8, 0x00271868,
536 0x00280369, 0x002916CA,
537 0x002A0CC9, 0x002B1D58,
538 0x002C0784, 0x002D060A,
539 0x002E064A, 0x002F0E2A,
540 0x0030032A, 0x00310B28,
541 0x00320688, 0x00330008,
542 0x003406C4, 0x00351864,
543 0x003601A8, 0x00370388,
544 0x0038078A, 0x00390604,
545 0x003A0644, 0x003B0E24,
546 0x003C004A, 0x003D18A4,
547 0x003E1B24, 0x003F00EA,
548 0x00400F0A, 0x00410249,
549 0x00420D5D, 0x00431CC4,
550 0x00440328, 0x00450B29,
551 0x004606C6, 0x0047076A,
552 0x00480368, 0x004916C5,
553 0x004A0789, 0x004B0605,
554 0x004C0CC8, 0x004D1954,
555 0x004E0645, 0x004F0E25,
556 0x00500325, 0x00510B26,
557 0x005206C9, 0x00530764,
558 0x005408A9, 0x00550009,
559 0x005601A9, 0x00570389,
560 0x00580785, 0x00590609,
561 0x005A0049, 0x005B18A9,
562 0x005C0649, 0x005D0E29,
563 0x005E1B29, 0x005F00E9,
564 0x00600365, 0x006116C6,
565 0x00620786, 0x00630608,
566 0x00640788, 0x00650606,
567 0x00660046, 0x006718A8,
568 0x006858A6, 0x00690145,
569 0x006A01E9, 0x006B178A,
570 0x006C01E8, 0x006D1785,
571 0x006E1E28, 0x006F0C65,
572 0x00700CC5, 0x00711D5C,
573 0x00720648, 0x00730E28,
574 0x00740646, 0x00750E26,
575 0x00761B28, 0x007700E6,
576 0x007801E5, 0x00791786,
577 0x007A1E29, 0x007B0C68,
578 0x007C1E24, 0x007D0C69,
579 0x007E0955, 0x007F03C9,
580 0x008003E9, 0x00810975,
581 0x00820C49, 0x00831E04,
582 0x00840C48, 0x00851E05,
583 0x008617A6, 0x008701C5,
584 0x008800C6, 0x00891B08,
585 0x008A0E06, 0x008B0666,
586 0x008C0E08, 0x008D0668,
587 0x008E1D7C, 0x008F0CE5,
588 0x00900C45, 0x00911E08,
589 0x009217A9, 0x009301C4,
590 0x009417AA, 0x009501C9,
591 0x00960169, 0x0097588A,
592 0x00981888, 0x00990066,
593 0x009A0709, 0x009B07A8,
594 0x009C0704, 0x009D07A6,
595 0x009E16E6, 0x009F0345,
596 0x00A000C9, 0x00A11B05,
597 0x00A20E09, 0x00A30669,
598 0x00A41885, 0x00A50065,
599 0x00A60706, 0x00A707A5,
600 0x00A803A9, 0x00A90189,
601 0x00AA0029, 0x00AB0889,
602 0x00AC0744, 0x00AD06E9,
603 0x00AE0B06, 0x00AF0229,
604 0x00B00E05, 0x00B10665,
605 0x00B21974, 0x00B30CE8,
606 0x00B4070A, 0x00B507A9,
607 0x00B616E9, 0x00B70348,
608 0x00B8074A, 0x00B906E6,
609 0x00BA0B09, 0x00BB0226,
610 0x00BC1CE4, 0x00BD0D7D,
611 0x00BE0269, 0x00BF08C9,
612 0x00C000CA, 0x00C11B04,
613 0x00C21884, 0x00C3006A,
614 0x00C40E04, 0x00C50664,
615 0x00C60708, 0x00C707AA,
616 0x00C803A8, 0x00C90184,
617 0x00CA0749, 0x00CB06E4,
618 0x00CC0020, 0x00CD0888,
619 0x00CE0B08, 0x00CF0224,
620 0x00D00E0A, 0x00D1066A,
621 0x00D20705, 0x00D307A4,
622 0x00D41D78, 0x00D50CE9,
623 0x00D616EA, 0x00D70349,
624 0x00D80745, 0x00D906E8,
625 0x00DA1CE9, 0x00DB0D75,
626 0x00DC0B04, 0x00DD0228,
627 0x00DE0268, 0x00DF08C8,
628 0x00E003A5, 0x00E10185,
629 0x00E20746, 0x00E306EA,
630 0x00E40748, 0x00E506E5,
631 0x00E61CE8, 0x00E70D79,
632 0x00E81D74, 0x00E95CE6,
633 0x00EA02E9, 0x00EB0849,
634 0x00EC02E8, 0x00ED0848,
635 0x00EE0086, 0x00EF0A08,
636 0x00F00021, 0x00F10885,
637 0x00F20B05, 0x00F3022A,
638 0x00F40B0A, 0x00F50225,
639 0x00F60265, 0x00F708C5,
640 0x00F802E5, 0x00F90845,
641 0x00FA0089, 0x00FB0A09,
642 0x00FC008A, 0x00FD0A0A,
643 0x00FE02A9, 0x00FF0062,
647 return BitBlt(hdcDest
, nXDest
, nYDest
, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, FRGND_ROP3(dwRop
));
649 hbrMask
= CreatePatternBrush(hbmMask
);
650 hbrDst
= SelectObject(hdcDest
, GetStockObject(NULL_BRUSH
));
653 hDC1
= CreateCompatibleDC(hdcDest
);
654 hBitmap1
= CreateCompatibleBitmap(hdcDest
, nWidth
, nHeight
);
655 hOldBitmap1
= SelectObject(hDC1
, hBitmap1
);
657 /* draw using bkgnd rop */
658 BitBlt(hDC1
, 0, 0, nWidth
, nHeight
, hdcDest
, nXDest
, nYDest
, SRCCOPY
);
659 hbrTmp
= SelectObject(hDC1
, hbrDst
);
660 BitBlt(hDC1
, 0, 0, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, BKGND_ROP3(dwRop
));
661 SelectObject(hDC1
, hbrTmp
);
664 hDC2
= CreateCompatibleDC(hdcDest
);
665 hBitmap2
= CreateCompatibleBitmap(hdcDest
, nWidth
, nHeight
);
666 hOldBitmap2
= SelectObject(hDC2
, hBitmap2
);
668 /* draw using foregnd rop */
669 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hdcDest
, nXDest
, nYDest
, SRCCOPY
);
670 hbrTmp
= SelectObject(hDC2
, hbrDst
);
671 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hdcSrc
, nXSrc
, nYSrc
, FRGND_ROP3(dwRop
));
673 /* combine both using the mask as a pattern brush */
674 SelectObject(hDC2
, hbrMask
);
675 BitBlt(hDC2
, 0, 0, nWidth
, nHeight
, hDC1
, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
676 SelectObject(hDC2
, hbrTmp
);
679 BitBlt(hdcDest
, nXDest
, nYDest
, nWidth
, nHeight
, hDC2
, 0, 0, SRCCOPY
);
681 /* restore all objects */
682 SelectObject(hdcDest
, hbrDst
);
683 SelectObject(hDC1
, hOldBitmap1
);
684 SelectObject(hDC2
, hOldBitmap2
);
686 /* delete all temp objects */
687 DeleteObject(hBitmap1
);
688 DeleteObject(hBitmap2
);
689 DeleteObject(hbrMask
);
697 /******************************************************************************
698 * GdiTransparentBlt [GDI32.@]
700 BOOL WINAPI
GdiTransparentBlt( HDC hdcDest
, int xDest
, int yDest
, int widthDest
, int heightDest
,
701 HDC hdcSrc
, int xSrc
, int ySrc
, int widthSrc
, int heightSrc
,
709 HBITMAP bmpMask
= NULL
;
710 HBITMAP oldMask
= NULL
;
711 COLORREF oldBackground
;
712 COLORREF oldForeground
;
715 if(widthDest
< 0 || heightDest
< 0 || widthSrc
< 0 || heightSrc
< 0) {
716 TRACE("Cannot mirror\n");
720 oldBackground
= SetBkColor(hdcDest
, RGB(255,255,255));
721 oldForeground
= SetTextColor(hdcDest
, RGB(0,0,0));
724 oldStretchMode
= GetStretchBltMode(hdcSrc
);
725 if(oldStretchMode
== BLACKONWHITE
|| oldStretchMode
== WHITEONBLACK
)
726 SetStretchBltMode(hdcSrc
, COLORONCOLOR
);
727 hdcWork
= CreateCompatibleDC(hdcDest
);
728 bmpWork
= CreateCompatibleBitmap(hdcDest
, widthDest
, heightDest
);
729 oldWork
= SelectObject(hdcWork
, bmpWork
);
730 if(!StretchBlt(hdcWork
, 0, 0, widthDest
, heightDest
, hdcSrc
, xSrc
, ySrc
, widthSrc
, heightSrc
, SRCCOPY
)) {
731 TRACE("Failed to stretch\n");
734 SetBkColor(hdcWork
, crTransparent
);
737 hdcMask
= CreateCompatibleDC(hdcDest
);
738 bmpMask
= CreateCompatibleBitmap(hdcMask
, widthDest
, heightDest
);
739 oldMask
= SelectObject(hdcMask
, bmpMask
);
740 if(!BitBlt(hdcMask
, 0, 0, widthDest
, heightDest
, hdcWork
, 0, 0, SRCCOPY
)) {
741 TRACE("Failed to create mask\n");
745 /* Replace transparent color with black */
746 SetBkColor(hdcWork
, RGB(0,0,0));
747 SetTextColor(hdcWork
, RGB(255,255,255));
748 if(!BitBlt(hdcWork
, 0, 0, widthDest
, heightDest
, hdcMask
, 0, 0, SRCAND
)) {
749 TRACE("Failed to mask out background\n");
753 /* Replace non-transparent area on destination with black */
754 if(!BitBlt(hdcDest
, xDest
, yDest
, widthDest
, heightDest
, hdcMask
, 0, 0, SRCAND
)) {
755 TRACE("Failed to clear destination area\n");
760 if(!BitBlt(hdcDest
, xDest
, yDest
, widthDest
, heightDest
, hdcWork
, 0, 0, SRCPAINT
)) {
761 TRACE("Failed to paint image\n");
767 SetStretchBltMode(hdcSrc
, oldStretchMode
);
768 SetBkColor(hdcDest
, oldBackground
);
769 SetTextColor(hdcDest
, oldForeground
);
771 SelectObject(hdcWork
, oldWork
);
774 if(bmpWork
) DeleteObject(bmpWork
);
776 SelectObject(hdcMask
, oldMask
);
779 if(bmpMask
) DeleteObject(bmpMask
);
783 /******************************************************************************
784 * GdiAlphaBlend [GDI32.@]
786 BOOL WINAPI
GdiAlphaBlend(HDC hdcDst
, int xDst
, int yDst
, int widthDst
, int heightDst
,
787 HDC hdcSrc
, int xSrc
, int ySrc
, int widthSrc
, int heightSrc
,
788 BLENDFUNCTION blendFunction
)
793 dcSrc
= get_dc_ptr( hdcSrc
);
794 if (!dcSrc
) return FALSE
;
796 if ((dcDst
= get_dc_ptr( hdcDst
)))
798 struct bitblt_coords src
, dst
;
799 PHYSDEV src_dev
= GET_DC_PHYSDEV( dcSrc
, pAlphaBlend
);
800 PHYSDEV dst_dev
= GET_DC_PHYSDEV( dcDst
, pAlphaBlend
);
807 src
.log_width
= widthSrc
;
808 src
.log_height
= heightSrc
;
809 src
.layout
= GetLayout( src_dev
->hdc
);
812 dst
.log_width
= widthDst
;
813 dst
.log_height
= heightDst
;
814 dst
.layout
= GetLayout( dst_dev
->hdc
);
815 ret
= !get_vis_rectangles( dcDst
, &dst
, dcSrc
, &src
);
817 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",
818 hdcSrc
, src
.log_x
, src
.log_y
, src
.log_width
, src
.log_height
,
819 src
.x
, src
.y
, src
.width
, src
.height
, wine_dbgstr_rect(&src
.visrect
),
820 hdcDst
, dst
.log_x
, dst
.log_y
, dst
.log_width
, dst
.log_height
,
821 dst
.x
, dst
.y
, dst
.width
, dst
.height
, wine_dbgstr_rect(&dst
.visrect
),
822 blendFunction
.BlendOp
, blendFunction
.BlendFlags
,
823 blendFunction
.SourceConstantAlpha
, blendFunction
.AlphaFormat
);
825 if (src
.x
< 0 || src
.y
< 0 || src
.width
< 0 || src
.height
< 0 ||
826 (dcSrc
->header
.type
== OBJ_MEMDC
&&
827 (src
.width
> dcSrc
->vis_rect
.right
- dcSrc
->vis_rect
.left
- src
.x
||
828 src
.height
> dcSrc
->vis_rect
.bottom
- dcSrc
->vis_rect
.top
- src
.y
)))
830 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src
.x
, src
.y
, src
.width
, src
.height
);
831 SetLastError( ERROR_INVALID_PARAMETER
);
834 else if (dst
.width
< 0 || dst
.height
< 0)
836 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst
.x
, dst
.y
, dst
.width
, dst
.height
);
837 SetLastError( ERROR_INVALID_PARAMETER
);
840 else if (dcSrc
== dcDst
&& src
.x
+ src
.width
> dst
.x
&& src
.x
< dst
.x
+ dst
.width
&&
841 src
.y
+ src
.height
> dst
.y
&& src
.y
< dst
.y
+ dst
.height
)
843 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
844 src
.x
, src
.y
, src
.width
, src
.height
, dst
.x
, dst
.y
, dst
.width
, dst
.height
);
845 SetLastError( ERROR_INVALID_PARAMETER
);
848 else if (!ret
) ret
= dst_dev
->funcs
->pAlphaBlend( dst_dev
, &dst
, src_dev
, &src
, blendFunction
);
850 release_dc_ptr( dcDst
);
852 release_dc_ptr( dcSrc
);
856 /*********************************************************************
860 BOOL WINAPI
PlgBlt( HDC hdcDest
, const POINT
*lpPoint
,
861 HDC hdcSrc
, INT nXSrc
, INT nYSrc
, INT nWidth
,
862 INT nHeight
, HBITMAP hbmMask
, INT xMask
, INT yMask
)
865 /* parallelogram coords */
874 /* save actual mode, set GM_ADVANCED */
875 oldgMode
= SetGraphicsMode(hdcDest
,GM_ADVANCED
);
879 memcpy(plg
,lpPoint
,sizeof(POINT
)*3);
882 rect
[1].x
= nXSrc
+ nWidth
;
885 rect
[2].y
= nYSrc
+ nHeight
;
886 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
888 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
);
890 if (fabs(det
) < 1e-5)
892 SetGraphicsMode(hdcDest
,oldgMode
);
896 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
897 hdcSrc
, nXSrc
, nYSrc
, nWidth
, nHeight
, hdcDest
, plg
[0].x
, plg
[0].y
, plg
[1].x
, plg
[1].y
, plg
[2].x
, plg
[2].y
);
900 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
;
901 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
;
902 xf
.eDx
= (rect
[0].x
*(rect
[1].y
*plg
[2].x
- rect
[2].y
*plg
[1].x
) -
903 rect
[1].x
*(rect
[0].y
*plg
[2].x
- rect
[2].y
*plg
[0].x
) +
904 rect
[2].x
*(rect
[0].y
*plg
[1].x
- rect
[1].y
*plg
[0].x
)
908 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
;
909 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
;
910 xf
.eDy
= (rect
[0].x
*(rect
[1].y
*plg
[2].y
- rect
[2].y
*plg
[1].y
) -
911 rect
[1].x
*(rect
[0].y
*plg
[2].y
- rect
[2].y
*plg
[0].y
) +
912 rect
[2].x
*(rect
[0].y
*plg
[1].y
- rect
[1].y
*plg
[0].y
)
915 GetWorldTransform(hdcSrc
,&SrcXf
);
916 CombineTransform(&xf
,&xf
,&SrcXf
);
918 /* save actual dest transform */
919 GetWorldTransform(hdcDest
,&oldDestXf
);
921 SetWorldTransform(hdcDest
,&xf
);
922 /* now destination and source DCs use same coords */
923 MaskBlt(hdcDest
,nXSrc
,nYSrc
,nWidth
,nHeight
,
927 /* restore dest DC */
928 SetWorldTransform(hdcDest
,&oldDestXf
);
929 SetGraphicsMode(hdcDest
,oldgMode
);