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 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, BOOL add_alpha )
166 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
167 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
169 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
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 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 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
191 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
192 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
193 return ERROR_OUTOFMEMORY;
195 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
196 if (bits->free) bits->free( bits );
198 bits->is_copy = TRUE;
199 bits->free = free_heap_bits;
203 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
204 struct bitblt_coords *src, BITMAPINFO *dst_info,
205 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
207 if (!dst_bits->is_copy)
209 int size = dst_info->bmiHeader.biSizeImage;
210 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
211 if (!ptr) return ERROR_OUTOFMEMORY;
212 memcpy( ptr, dst_bits->ptr, size );
213 if (dst_bits->free) dst_bits->free( dst_bits );
215 dst_bits->is_copy = TRUE;
216 dst_bits->free = free_heap_bits;
218 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
221 /* helper to retrieve either both colors or only the background color for monochrome blits */
222 static void get_mono_dc_colors( HDC hdc, BITMAPINFO *info, int count )
224 COLORREF color = GetBkColor( hdc );
226 info->bmiColors[count - 1].rgbRed = GetRValue( color );
227 info->bmiColors[count - 1].rgbGreen = GetGValue( color );
228 info->bmiColors[count - 1].rgbBlue = GetBValue( color );
229 info->bmiColors[count - 1].rgbReserved = 0;
233 color = GetTextColor( hdc );
234 info->bmiColors[0].rgbRed = GetRValue( color );
235 info->bmiColors[0].rgbGreen = GetGValue( color );
236 info->bmiColors[0].rgbBlue = GetBValue( color );
237 info->bmiColors[0].rgbReserved = 0;
239 info->bmiHeader.biClrUsed = count;
242 /***********************************************************************
243 * null driver fallback implementations
246 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
247 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
249 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
250 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
251 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
252 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
253 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
255 struct gdi_image_bits bits;
257 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
258 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
259 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
261 release_dc_ptr( dc_src );
265 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
266 copy_bitmapinfo( dst_info, src_info );
267 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
268 if (err == ERROR_BAD_FORMAT)
270 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
272 /* 1-bpp source without a color table uses the destination DC colors */
273 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
274 get_mono_dc_colors( dst_dev->hdc, src_info, 2 );
276 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
278 /* 1-bpp destination without a color table requires a fake 1-entry table
279 * that contains only the background color; except with a 1-bpp source,
280 * in which case it uses the source colors */
281 if (src_info->bmiHeader.biBitCount > 1)
282 get_mono_dc_colors( src_dev->hdc, dst_info, 1 );
284 get_mono_dc_colors( src_dev->hdc, dst_info, 2 );
287 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
289 /* get rid of the fake destination table */
290 dst_info->bmiHeader.biClrUsed = dst_colors;
291 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
295 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
296 ((src->width != dst->width) || (src->height != dst->height)))
298 copy_bitmapinfo( src_info, dst_info );
299 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
300 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
303 if (bits.free) bits.free( &bits );
304 release_dc_ptr( dc_src );
309 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
310 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
312 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
313 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
314 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
315 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
316 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
318 struct gdi_image_bits bits;
320 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
321 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
322 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
325 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
326 copy_bitmapinfo( dst_info, src_info );
327 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
328 if (err == ERROR_BAD_FORMAT)
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 copy_bitmapinfo( src_info, dst_info );
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 release_dc_ptr( dc_src );
345 if (err) SetLastError( err );
350 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
351 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
353 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
354 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
355 struct gdi_image_bits dst_bits;
356 struct bitblt_coords orig_dst;
357 DC *dc = get_nulldrv_dc( dev );
360 if (info->bmiHeader.biPlanes != 1) goto update_format;
361 if (info->bmiHeader.biBitCount != 32) goto update_format;
362 if (info->bmiHeader.biCompression == BI_BITFIELDS)
364 DWORD *masks = (DWORD *)info->bmiColors;
365 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
369 if (!bits) return ERROR_SUCCESS;
370 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
372 dev = GET_DC_PHYSDEV( dc, pGetImage );
374 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
377 dev = GET_DC_PHYSDEV( dc, pPutImage );
378 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
379 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
381 if (dst_bits.free) dst_bits.free( &dst_bits );
385 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
386 return ERROR_INVALID_PARAMETER;
388 info->bmiHeader.biPlanes = 1;
389 info->bmiHeader.biBitCount = 32;
390 info->bmiHeader.biCompression = BI_RGB;
391 info->bmiHeader.biClrUsed = 0;
392 return ERROR_BAD_FORMAT;
395 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
396 void * grad_array, ULONG ngrad, ULONG mode )
398 DC *dc = get_nulldrv_dc( dev );
399 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
400 BITMAPINFO *info = (BITMAPINFO *)buffer;
401 struct bitblt_coords src, dst;
402 struct gdi_image_bits bits;
409 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
410 for (i = 0; i < nvert; i++)
412 pts[i].x = vert_array[i].x;
413 pts[i].y = vert_array[i].y;
415 LPtoDP( dev->hdc, pts, nvert );
417 /* compute bounding rect of all the rectangles/triangles */
418 reset_bounds( &dst.visrect );
419 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
421 ULONG v = ((ULONG *)grad_array)[i];
422 dst.visrect.left = min( dst.visrect.left, pts[v].x );
423 dst.visrect.top = min( dst.visrect.top, pts[v].y );
424 dst.visrect.right = max( dst.visrect.right, pts[v].x );
425 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
428 dst.x = dst.visrect.left;
429 dst.y = dst.visrect.top;
430 dst.width = dst.visrect.right - dst.visrect.left;
431 dst.height = dst.visrect.bottom - dst.visrect.top;
432 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
434 /* query the bitmap format */
435 info->bmiHeader.biSize = sizeof(info->bmiHeader);
436 info->bmiHeader.biPlanes = 1;
437 info->bmiHeader.biBitCount = 0;
438 info->bmiHeader.biCompression = BI_RGB;
439 info->bmiHeader.biXPelsPerMeter = 0;
440 info->bmiHeader.biYPelsPerMeter = 0;
441 info->bmiHeader.biClrUsed = 0;
442 info->bmiHeader.biClrImportant = 0;
443 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
444 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
445 info->bmiHeader.biSizeImage = 0;
446 dev = GET_DC_PHYSDEV( dc, pPutImage );
447 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
448 if (err && err != ERROR_BAD_FORMAT) goto done;
450 info->bmiHeader.biSizeImage = get_dib_image_size( info );
451 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
454 bits.free = free_heap_bits;
456 /* make src and points relative to the bitmap */
458 src.x -= dst.visrect.left;
459 src.y -= dst.visrect.top;
460 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
461 for (i = 0; i < nvert; i++)
463 pts[i].x -= dst.visrect.left;
464 pts[i].y -= dst.visrect.top;
467 rgn = CreateRectRgn( 0, 0, 0, 0 );
468 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
469 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
470 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
472 if (bits.free) bits.free( &bits );
476 HeapFree( GetProcessHeap(), 0, pts );
480 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
482 DC *dc = get_nulldrv_dc( dev );
483 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
484 BITMAPINFO *info = (BITMAPINFO *)buffer;
485 struct bitblt_coords src;
486 struct gdi_image_bits bits;
489 src.visrect.left = x;
491 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
492 src.visrect.right = src.visrect.left + 1;
493 src.visrect.bottom = src.visrect.top + 1;
494 src.x = src.visrect.left;
495 src.y = src.visrect.top;
496 src.width = src.height = 1;
498 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
500 dev = GET_DC_PHYSDEV( dc, pGetImage );
501 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
503 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
504 if (bits.free) bits.free( &bits );
509 /***********************************************************************
512 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
517 if (rop_uses_src( rop )) return FALSE;
518 if ((dc = get_dc_ptr( hdc )))
520 struct bitblt_coords dst;
526 dst.log_width = width;
527 dst.log_height = height;
528 dst.layout = dc->layout;
529 if (rop & NOMIRRORBITMAP)
531 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
532 rop &= ~NOMIRRORBITMAP;
534 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
536 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
537 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
538 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
542 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
543 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
545 release_dc_ptr( dc );
551 /***********************************************************************
554 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
555 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
557 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
558 else return StretchBlt( hdcDst, xDst, yDst, width, height,
559 hdcSrc, xSrc, ySrc, width, height, rop );
563 /***********************************************************************
564 * StretchBlt (GDI32.@)
566 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
567 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
572 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
574 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
576 if ((dcSrc = get_dc_ptr( hdcSrc )))
578 struct bitblt_coords src, dst;
585 src.log_width = widthSrc;
586 src.log_height = heightSrc;
587 src.layout = dcSrc->layout;
590 dst.log_width = widthDst;
591 dst.log_height = heightDst;
592 dst.layout = dcDst->layout;
593 if (rop & NOMIRRORBITMAP)
595 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
596 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
597 rop &= ~NOMIRRORBITMAP;
599 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
601 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",
602 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
603 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
604 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
605 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
609 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
610 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
611 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
613 release_dc_ptr( dcSrc );
615 release_dc_ptr( dcDst );
619 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
620 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
622 /***********************************************************************
625 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
626 INT nWidth, INT nHeight, HDC hdcSrc,
627 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
628 INT xMask, INT yMask, DWORD dwRop)
630 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
632 HBRUSH hbrMask, hbrDst, hbrTmp;
634 static const DWORD ROP3Table[256] =
636 0x00000042, 0x00010289,
637 0x00020C89, 0x000300AA,
638 0x00040C88, 0x000500A9,
639 0x00060865, 0x000702C5,
640 0x00080F08, 0x00090245,
641 0x000A0329, 0x000B0B2A,
642 0x000C0324, 0x000D0B25,
643 0x000E08A5, 0x000F0001,
644 0x00100C85, 0x001100A6,
645 0x00120868, 0x001302C8,
646 0x00140869, 0x001502C9,
647 0x00165CCA, 0x00171D54,
648 0x00180D59, 0x00191CC8,
649 0x001A06C5, 0x001B0768,
650 0x001C06CA, 0x001D0766,
651 0x001E01A5, 0x001F0385,
652 0x00200F09, 0x00210248,
653 0x00220326, 0x00230B24,
654 0x00240D55, 0x00251CC5,
655 0x002606C8, 0x00271868,
656 0x00280369, 0x002916CA,
657 0x002A0CC9, 0x002B1D58,
658 0x002C0784, 0x002D060A,
659 0x002E064A, 0x002F0E2A,
660 0x0030032A, 0x00310B28,
661 0x00320688, 0x00330008,
662 0x003406C4, 0x00351864,
663 0x003601A8, 0x00370388,
664 0x0038078A, 0x00390604,
665 0x003A0644, 0x003B0E24,
666 0x003C004A, 0x003D18A4,
667 0x003E1B24, 0x003F00EA,
668 0x00400F0A, 0x00410249,
669 0x00420D5D, 0x00431CC4,
670 0x00440328, 0x00450B29,
671 0x004606C6, 0x0047076A,
672 0x00480368, 0x004916C5,
673 0x004A0789, 0x004B0605,
674 0x004C0CC8, 0x004D1954,
675 0x004E0645, 0x004F0E25,
676 0x00500325, 0x00510B26,
677 0x005206C9, 0x00530764,
678 0x005408A9, 0x00550009,
679 0x005601A9, 0x00570389,
680 0x00580785, 0x00590609,
681 0x005A0049, 0x005B18A9,
682 0x005C0649, 0x005D0E29,
683 0x005E1B29, 0x005F00E9,
684 0x00600365, 0x006116C6,
685 0x00620786, 0x00630608,
686 0x00640788, 0x00650606,
687 0x00660046, 0x006718A8,
688 0x006858A6, 0x00690145,
689 0x006A01E9, 0x006B178A,
690 0x006C01E8, 0x006D1785,
691 0x006E1E28, 0x006F0C65,
692 0x00700CC5, 0x00711D5C,
693 0x00720648, 0x00730E28,
694 0x00740646, 0x00750E26,
695 0x00761B28, 0x007700E6,
696 0x007801E5, 0x00791786,
697 0x007A1E29, 0x007B0C68,
698 0x007C1E24, 0x007D0C69,
699 0x007E0955, 0x007F03C9,
700 0x008003E9, 0x00810975,
701 0x00820C49, 0x00831E04,
702 0x00840C48, 0x00851E05,
703 0x008617A6, 0x008701C5,
704 0x008800C6, 0x00891B08,
705 0x008A0E06, 0x008B0666,
706 0x008C0E08, 0x008D0668,
707 0x008E1D7C, 0x008F0CE5,
708 0x00900C45, 0x00911E08,
709 0x009217A9, 0x009301C4,
710 0x009417AA, 0x009501C9,
711 0x00960169, 0x0097588A,
712 0x00981888, 0x00990066,
713 0x009A0709, 0x009B07A8,
714 0x009C0704, 0x009D07A6,
715 0x009E16E6, 0x009F0345,
716 0x00A000C9, 0x00A11B05,
717 0x00A20E09, 0x00A30669,
718 0x00A41885, 0x00A50065,
719 0x00A60706, 0x00A707A5,
720 0x00A803A9, 0x00A90189,
721 0x00AA0029, 0x00AB0889,
722 0x00AC0744, 0x00AD06E9,
723 0x00AE0B06, 0x00AF0229,
724 0x00B00E05, 0x00B10665,
725 0x00B21974, 0x00B30CE8,
726 0x00B4070A, 0x00B507A9,
727 0x00B616E9, 0x00B70348,
728 0x00B8074A, 0x00B906E6,
729 0x00BA0B09, 0x00BB0226,
730 0x00BC1CE4, 0x00BD0D7D,
731 0x00BE0269, 0x00BF08C9,
732 0x00C000CA, 0x00C11B04,
733 0x00C21884, 0x00C3006A,
734 0x00C40E04, 0x00C50664,
735 0x00C60708, 0x00C707AA,
736 0x00C803A8, 0x00C90184,
737 0x00CA0749, 0x00CB06E4,
738 0x00CC0020, 0x00CD0888,
739 0x00CE0B08, 0x00CF0224,
740 0x00D00E0A, 0x00D1066A,
741 0x00D20705, 0x00D307A4,
742 0x00D41D78, 0x00D50CE9,
743 0x00D616EA, 0x00D70349,
744 0x00D80745, 0x00D906E8,
745 0x00DA1CE9, 0x00DB0D75,
746 0x00DC0B04, 0x00DD0228,
747 0x00DE0268, 0x00DF08C8,
748 0x00E003A5, 0x00E10185,
749 0x00E20746, 0x00E306EA,
750 0x00E40748, 0x00E506E5,
751 0x00E61CE8, 0x00E70D79,
752 0x00E81D74, 0x00E95CE6,
753 0x00EA02E9, 0x00EB0849,
754 0x00EC02E8, 0x00ED0848,
755 0x00EE0086, 0x00EF0A08,
756 0x00F00021, 0x00F10885,
757 0x00F20B05, 0x00F3022A,
758 0x00F40B0A, 0x00F50225,
759 0x00F60265, 0x00F708C5,
760 0x00F802E5, 0x00F90845,
761 0x00FA0089, 0x00FB0A09,
762 0x00FC008A, 0x00FD0A0A,
763 0x00FE02A9, 0x00FF0062,
767 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
769 hbrMask = CreatePatternBrush(hbmMask);
770 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
773 hDC1 = CreateCompatibleDC(hdcDest);
774 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
775 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
777 /* draw using bkgnd rop */
778 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
779 hbrTmp = SelectObject(hDC1, hbrDst);
780 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
781 SelectObject(hDC1, hbrTmp);
784 hDC2 = CreateCompatibleDC(hdcDest);
785 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
786 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
788 /* draw using foregnd rop */
789 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
790 hbrTmp = SelectObject(hDC2, hbrDst);
791 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
793 /* combine both using the mask as a pattern brush */
794 SelectObject(hDC2, hbrMask);
795 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
796 SelectObject(hDC2, hbrTmp);
799 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
801 /* restore all objects */
802 SelectObject(hdcDest, hbrDst);
803 SelectObject(hDC1, hOldBitmap1);
804 SelectObject(hDC2, hOldBitmap2);
806 /* delete all temp objects */
807 DeleteObject(hBitmap1);
808 DeleteObject(hBitmap2);
809 DeleteObject(hbrMask);
817 /******************************************************************************
818 * GdiTransparentBlt [GDI32.@]
820 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
821 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
829 HBITMAP bmpMask = NULL;
830 HBITMAP oldMask = NULL;
831 COLORREF oldBackground;
832 COLORREF oldForeground;
835 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
836 TRACE("Cannot mirror\n");
840 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
841 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
844 oldStretchMode = GetStretchBltMode(hdcSrc);
845 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
846 SetStretchBltMode(hdcSrc, COLORONCOLOR);
847 hdcWork = CreateCompatibleDC(hdcDest);
848 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
849 oldWork = SelectObject(hdcWork, bmpWork);
850 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
851 TRACE("Failed to stretch\n");
854 SetBkColor(hdcWork, crTransparent);
857 hdcMask = CreateCompatibleDC(hdcDest);
858 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
859 oldMask = SelectObject(hdcMask, bmpMask);
860 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
861 TRACE("Failed to create mask\n");
865 /* Replace transparent color with black */
866 SetBkColor(hdcWork, RGB(0,0,0));
867 SetTextColor(hdcWork, RGB(255,255,255));
868 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
869 TRACE("Failed to mask out background\n");
873 /* Replace non-transparent area on destination with black */
874 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
875 TRACE("Failed to clear destination area\n");
880 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
881 TRACE("Failed to paint image\n");
887 SetStretchBltMode(hdcSrc, oldStretchMode);
888 SetBkColor(hdcDest, oldBackground);
889 SetTextColor(hdcDest, oldForeground);
891 SelectObject(hdcWork, oldWork);
894 if(bmpWork) DeleteObject(bmpWork);
896 SelectObject(hdcMask, oldMask);
899 if(bmpMask) DeleteObject(bmpMask);
903 /******************************************************************************
904 * GdiAlphaBlend [GDI32.@]
906 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
907 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
908 BLENDFUNCTION blendFunction)
913 dcSrc = get_dc_ptr( hdcSrc );
914 if (!dcSrc) return FALSE;
916 if ((dcDst = get_dc_ptr( hdcDst )))
918 struct bitblt_coords src, dst;
925 src.log_width = widthSrc;
926 src.log_height = heightSrc;
927 src.layout = GetLayout( hdcSrc );
930 dst.log_width = widthDst;
931 dst.log_height = heightDst;
932 dst.layout = GetLayout( hdcDst );
933 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
935 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",
936 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
937 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
938 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
939 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
940 blendFunction.BlendOp, blendFunction.BlendFlags,
941 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
943 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
944 src.log_width < 0 || src.log_height < 0 ||
945 (!is_rect_empty( &dcSrc->device_rect ) &&
946 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
947 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
949 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
950 SetLastError( ERROR_INVALID_PARAMETER );
953 else if (dst.log_width < 0 || dst.log_height < 0)
955 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
956 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
957 SetLastError( ERROR_INVALID_PARAMETER );
960 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
961 src.y + src.height > dst.y && src.y < dst.y + dst.height)
963 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
964 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
965 SetLastError( ERROR_INVALID_PARAMETER );
970 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
971 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
972 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
974 release_dc_ptr( dcDst );
976 release_dc_ptr( dcSrc );
980 /*********************************************************************
984 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
985 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
986 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
989 /* parallelogram coords */
998 /* save actual mode, set GM_ADVANCED */
999 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1003 memcpy(plg,lpPoint,sizeof(POINT)*3);
1006 rect[1].x = nXSrc + nWidth;
1009 rect[2].y = nYSrc + nHeight;
1010 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1012 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);
1014 if (fabs(det) < 1e-5)
1016 SetGraphicsMode(hdcDest,oldgMode);
1020 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1021 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1024 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;
1025 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;
1026 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1027 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1028 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1032 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;
1033 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;
1034 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1035 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1036 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1039 GetWorldTransform(hdcSrc,&SrcXf);
1040 CombineTransform(&xf,&xf,&SrcXf);
1042 /* save actual dest transform */
1043 GetWorldTransform(hdcDest,&oldDestXf);
1045 SetWorldTransform(hdcDest,&xf);
1046 /* now destination and source DCs use same coords */
1047 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1048 hdcSrc, nXSrc,nYSrc,
1049 hbmMask,xMask,yMask,
1051 /* restore dest DC */
1052 SetWorldTransform(hdcDest,&oldDestXf);
1053 SetGraphicsMode(hdcDest,oldgMode);