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 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
260 release_dc_ptr( dc_src );
261 if (err) return FALSE;
263 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
264 copy_bitmapinfo( dst_info, src_info );
265 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
266 if (err == ERROR_BAD_FORMAT)
268 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
270 /* 1-bpp source without a color table uses the destination DC colors */
271 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
272 get_mono_dc_colors( dst_dev->hdc, src_info, 2 );
274 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
276 /* 1-bpp destination without a color table requires a fake 1-entry table
277 * that contains only the background color; except with a 1-bpp source,
278 * in which case it uses the source colors */
279 if (src_info->bmiHeader.biBitCount > 1)
280 get_mono_dc_colors( src_dev->hdc, dst_info, 1 );
282 get_mono_dc_colors( src_dev->hdc, dst_info, 2 );
285 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
287 /* get rid of the fake destination table */
288 dst_info->bmiHeader.biClrUsed = dst_colors;
289 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
293 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
294 ((src->width != dst->width) || (src->height != dst->height)))
296 copy_bitmapinfo( src_info, dst_info );
297 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
298 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
301 if (bits.free) bits.free( &bits );
306 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
307 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
309 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
310 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
311 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
312 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
313 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
315 struct gdi_image_bits bits;
317 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
318 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
319 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
320 release_dc_ptr( dc_src );
323 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
324 copy_bitmapinfo( dst_info, src_info );
325 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
326 if (err == ERROR_BAD_FORMAT)
328 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
329 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
332 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
333 ((src->width != dst->width) || (src->height != dst->height)))
335 copy_bitmapinfo( src_info, dst_info );
336 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
337 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
340 if (bits.free) bits.free( &bits );
342 if (err) SetLastError( err );
347 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
348 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
350 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
351 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
352 struct gdi_image_bits dst_bits;
353 struct bitblt_coords orig_dst;
354 DC *dc = get_nulldrv_dc( dev );
357 if (info->bmiHeader.biPlanes != 1) goto update_format;
358 if (info->bmiHeader.biBitCount != 32) goto update_format;
359 if (info->bmiHeader.biCompression == BI_BITFIELDS)
361 DWORD *masks = (DWORD *)info->bmiColors;
362 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
366 if (!bits) return ERROR_SUCCESS;
367 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
369 dev = GET_DC_PHYSDEV( dc, pGetImage );
371 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
374 dev = GET_DC_PHYSDEV( dc, pPutImage );
375 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
376 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
378 if (dst_bits.free) dst_bits.free( &dst_bits );
382 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
383 return ERROR_INVALID_PARAMETER;
385 info->bmiHeader.biPlanes = 1;
386 info->bmiHeader.biBitCount = 32;
387 info->bmiHeader.biCompression = BI_RGB;
388 info->bmiHeader.biClrUsed = 0;
389 return ERROR_BAD_FORMAT;
392 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
393 void * grad_array, ULONG ngrad, ULONG mode )
395 DC *dc = get_nulldrv_dc( dev );
396 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
397 BITMAPINFO *info = (BITMAPINFO *)buffer;
398 struct bitblt_coords src, dst;
399 struct gdi_image_bits bits;
406 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
407 for (i = 0; i < nvert; i++)
409 pts[i].x = vert_array[i].x;
410 pts[i].y = vert_array[i].y;
412 LPtoDP( dev->hdc, pts, nvert );
414 /* compute bounding rect of all the rectangles/triangles */
415 reset_bounds( &dst.visrect );
416 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
418 ULONG v = ((ULONG *)grad_array)[i];
419 dst.visrect.left = min( dst.visrect.left, pts[v].x );
420 dst.visrect.top = min( dst.visrect.top, pts[v].y );
421 dst.visrect.right = max( dst.visrect.right, pts[v].x );
422 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
425 dst.x = dst.visrect.left;
426 dst.y = dst.visrect.top;
427 dst.width = dst.visrect.right - dst.visrect.left;
428 dst.height = dst.visrect.bottom - dst.visrect.top;
429 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
431 /* query the bitmap format */
432 info->bmiHeader.biSize = sizeof(info->bmiHeader);
433 info->bmiHeader.biPlanes = 1;
434 info->bmiHeader.biBitCount = 0;
435 info->bmiHeader.biCompression = BI_RGB;
436 info->bmiHeader.biXPelsPerMeter = 0;
437 info->bmiHeader.biYPelsPerMeter = 0;
438 info->bmiHeader.biClrUsed = 0;
439 info->bmiHeader.biClrImportant = 0;
440 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
441 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
442 info->bmiHeader.biSizeImage = 0;
443 dev = GET_DC_PHYSDEV( dc, pPutImage );
444 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
445 if (err && err != ERROR_BAD_FORMAT) goto done;
447 info->bmiHeader.biSizeImage = get_dib_image_size( info );
448 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
451 bits.free = free_heap_bits;
453 /* make src and points relative to the bitmap */
455 src.x -= dst.visrect.left;
456 src.y -= dst.visrect.top;
457 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
458 for (i = 0; i < nvert; i++)
460 pts[i].x -= dst.visrect.left;
461 pts[i].y -= dst.visrect.top;
464 rgn = CreateRectRgn( 0, 0, 0, 0 );
465 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
466 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
467 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
469 if (bits.free) bits.free( &bits );
473 HeapFree( GetProcessHeap(), 0, pts );
477 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
479 DC *dc = get_nulldrv_dc( dev );
480 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
481 BITMAPINFO *info = (BITMAPINFO *)buffer;
482 struct bitblt_coords src;
483 struct gdi_image_bits bits;
486 src.visrect.left = x;
488 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
489 src.visrect.right = src.visrect.left + 1;
490 src.visrect.bottom = src.visrect.top + 1;
491 src.x = src.visrect.left;
492 src.y = src.visrect.top;
493 src.width = src.height = 1;
495 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
497 dev = GET_DC_PHYSDEV( dc, pGetImage );
498 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
500 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
501 if (bits.free) bits.free( &bits );
506 /***********************************************************************
509 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
514 if (rop_uses_src( rop )) return FALSE;
515 if ((dc = get_dc_ptr( hdc )))
517 struct bitblt_coords dst;
518 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
524 dst.log_width = width;
525 dst.log_height = height;
526 dst.layout = dc->layout;
527 if (rop & NOMIRRORBITMAP)
529 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
530 rop &= ~NOMIRRORBITMAP;
532 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
534 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
535 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
536 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
538 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
540 release_dc_ptr( dc );
546 /***********************************************************************
549 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
550 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
552 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
553 else return StretchBlt( hdcDst, xDst, yDst, width, height,
554 hdcSrc, xSrc, ySrc, width, height, rop );
558 /***********************************************************************
559 * StretchBlt (GDI32.@)
561 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
562 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
567 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
569 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
571 if ((dcSrc = get_dc_ptr( hdcSrc )))
573 struct bitblt_coords src, dst;
574 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
575 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
582 src.log_width = widthSrc;
583 src.log_height = heightSrc;
584 src.layout = dcSrc->layout;
587 dst.log_width = widthDst;
588 dst.log_height = heightDst;
589 dst.layout = dcDst->layout;
590 if (rop & NOMIRRORBITMAP)
592 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
593 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
594 rop &= ~NOMIRRORBITMAP;
596 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
598 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",
599 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
600 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
601 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
602 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
604 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
605 release_dc_ptr( dcSrc );
607 release_dc_ptr( dcDst );
611 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
612 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
614 /***********************************************************************
617 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
618 INT nWidth, INT nHeight, HDC hdcSrc,
619 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
620 INT xMask, INT yMask, DWORD dwRop)
622 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
624 HBRUSH hbrMask, hbrDst, hbrTmp;
626 static const DWORD ROP3Table[256] =
628 0x00000042, 0x00010289,
629 0x00020C89, 0x000300AA,
630 0x00040C88, 0x000500A9,
631 0x00060865, 0x000702C5,
632 0x00080F08, 0x00090245,
633 0x000A0329, 0x000B0B2A,
634 0x000C0324, 0x000D0B25,
635 0x000E08A5, 0x000F0001,
636 0x00100C85, 0x001100A6,
637 0x00120868, 0x001302C8,
638 0x00140869, 0x001502C9,
639 0x00165CCA, 0x00171D54,
640 0x00180D59, 0x00191CC8,
641 0x001A06C5, 0x001B0768,
642 0x001C06CA, 0x001D0766,
643 0x001E01A5, 0x001F0385,
644 0x00200F09, 0x00210248,
645 0x00220326, 0x00230B24,
646 0x00240D55, 0x00251CC5,
647 0x002606C8, 0x00271868,
648 0x00280369, 0x002916CA,
649 0x002A0CC9, 0x002B1D58,
650 0x002C0784, 0x002D060A,
651 0x002E064A, 0x002F0E2A,
652 0x0030032A, 0x00310B28,
653 0x00320688, 0x00330008,
654 0x003406C4, 0x00351864,
655 0x003601A8, 0x00370388,
656 0x0038078A, 0x00390604,
657 0x003A0644, 0x003B0E24,
658 0x003C004A, 0x003D18A4,
659 0x003E1B24, 0x003F00EA,
660 0x00400F0A, 0x00410249,
661 0x00420D5D, 0x00431CC4,
662 0x00440328, 0x00450B29,
663 0x004606C6, 0x0047076A,
664 0x00480368, 0x004916C5,
665 0x004A0789, 0x004B0605,
666 0x004C0CC8, 0x004D1954,
667 0x004E0645, 0x004F0E25,
668 0x00500325, 0x00510B26,
669 0x005206C9, 0x00530764,
670 0x005408A9, 0x00550009,
671 0x005601A9, 0x00570389,
672 0x00580785, 0x00590609,
673 0x005A0049, 0x005B18A9,
674 0x005C0649, 0x005D0E29,
675 0x005E1B29, 0x005F00E9,
676 0x00600365, 0x006116C6,
677 0x00620786, 0x00630608,
678 0x00640788, 0x00650606,
679 0x00660046, 0x006718A8,
680 0x006858A6, 0x00690145,
681 0x006A01E9, 0x006B178A,
682 0x006C01E8, 0x006D1785,
683 0x006E1E28, 0x006F0C65,
684 0x00700CC5, 0x00711D5C,
685 0x00720648, 0x00730E28,
686 0x00740646, 0x00750E26,
687 0x00761B28, 0x007700E6,
688 0x007801E5, 0x00791786,
689 0x007A1E29, 0x007B0C68,
690 0x007C1E24, 0x007D0C69,
691 0x007E0955, 0x007F03C9,
692 0x008003E9, 0x00810975,
693 0x00820C49, 0x00831E04,
694 0x00840C48, 0x00851E05,
695 0x008617A6, 0x008701C5,
696 0x008800C6, 0x00891B08,
697 0x008A0E06, 0x008B0666,
698 0x008C0E08, 0x008D0668,
699 0x008E1D7C, 0x008F0CE5,
700 0x00900C45, 0x00911E08,
701 0x009217A9, 0x009301C4,
702 0x009417AA, 0x009501C9,
703 0x00960169, 0x0097588A,
704 0x00981888, 0x00990066,
705 0x009A0709, 0x009B07A8,
706 0x009C0704, 0x009D07A6,
707 0x009E16E6, 0x009F0345,
708 0x00A000C9, 0x00A11B05,
709 0x00A20E09, 0x00A30669,
710 0x00A41885, 0x00A50065,
711 0x00A60706, 0x00A707A5,
712 0x00A803A9, 0x00A90189,
713 0x00AA0029, 0x00AB0889,
714 0x00AC0744, 0x00AD06E9,
715 0x00AE0B06, 0x00AF0229,
716 0x00B00E05, 0x00B10665,
717 0x00B21974, 0x00B30CE8,
718 0x00B4070A, 0x00B507A9,
719 0x00B616E9, 0x00B70348,
720 0x00B8074A, 0x00B906E6,
721 0x00BA0B09, 0x00BB0226,
722 0x00BC1CE4, 0x00BD0D7D,
723 0x00BE0269, 0x00BF08C9,
724 0x00C000CA, 0x00C11B04,
725 0x00C21884, 0x00C3006A,
726 0x00C40E04, 0x00C50664,
727 0x00C60708, 0x00C707AA,
728 0x00C803A8, 0x00C90184,
729 0x00CA0749, 0x00CB06E4,
730 0x00CC0020, 0x00CD0888,
731 0x00CE0B08, 0x00CF0224,
732 0x00D00E0A, 0x00D1066A,
733 0x00D20705, 0x00D307A4,
734 0x00D41D78, 0x00D50CE9,
735 0x00D616EA, 0x00D70349,
736 0x00D80745, 0x00D906E8,
737 0x00DA1CE9, 0x00DB0D75,
738 0x00DC0B04, 0x00DD0228,
739 0x00DE0268, 0x00DF08C8,
740 0x00E003A5, 0x00E10185,
741 0x00E20746, 0x00E306EA,
742 0x00E40748, 0x00E506E5,
743 0x00E61CE8, 0x00E70D79,
744 0x00E81D74, 0x00E95CE6,
745 0x00EA02E9, 0x00EB0849,
746 0x00EC02E8, 0x00ED0848,
747 0x00EE0086, 0x00EF0A08,
748 0x00F00021, 0x00F10885,
749 0x00F20B05, 0x00F3022A,
750 0x00F40B0A, 0x00F50225,
751 0x00F60265, 0x00F708C5,
752 0x00F802E5, 0x00F90845,
753 0x00FA0089, 0x00FB0A09,
754 0x00FC008A, 0x00FD0A0A,
755 0x00FE02A9, 0x00FF0062,
759 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
761 hbrMask = CreatePatternBrush(hbmMask);
762 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
765 hDC1 = CreateCompatibleDC(hdcDest);
766 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
767 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
769 /* draw using bkgnd rop */
770 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
771 hbrTmp = SelectObject(hDC1, hbrDst);
772 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
773 SelectObject(hDC1, hbrTmp);
776 hDC2 = CreateCompatibleDC(hdcDest);
777 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
778 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
780 /* draw using foregnd rop */
781 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
782 hbrTmp = SelectObject(hDC2, hbrDst);
783 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
785 /* combine both using the mask as a pattern brush */
786 SelectObject(hDC2, hbrMask);
787 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
788 SelectObject(hDC2, hbrTmp);
791 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
793 /* restore all objects */
794 SelectObject(hdcDest, hbrDst);
795 SelectObject(hDC1, hOldBitmap1);
796 SelectObject(hDC2, hOldBitmap2);
798 /* delete all temp objects */
799 DeleteObject(hBitmap1);
800 DeleteObject(hBitmap2);
801 DeleteObject(hbrMask);
809 /******************************************************************************
810 * GdiTransparentBlt [GDI32.@]
812 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
813 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
821 HBITMAP bmpMask = NULL;
822 HBITMAP oldMask = NULL;
823 COLORREF oldBackground;
824 COLORREF oldForeground;
827 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
828 TRACE("Cannot mirror\n");
832 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
833 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
836 oldStretchMode = GetStretchBltMode(hdcSrc);
837 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
838 SetStretchBltMode(hdcSrc, COLORONCOLOR);
839 hdcWork = CreateCompatibleDC(hdcDest);
840 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
841 oldWork = SelectObject(hdcWork, bmpWork);
842 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
843 TRACE("Failed to stretch\n");
846 SetBkColor(hdcWork, crTransparent);
849 hdcMask = CreateCompatibleDC(hdcDest);
850 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
851 oldMask = SelectObject(hdcMask, bmpMask);
852 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
853 TRACE("Failed to create mask\n");
857 /* Replace transparent color with black */
858 SetBkColor(hdcWork, RGB(0,0,0));
859 SetTextColor(hdcWork, RGB(255,255,255));
860 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
861 TRACE("Failed to mask out background\n");
865 /* Replace non-transparent area on destination with black */
866 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
867 TRACE("Failed to clear destination area\n");
872 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
873 TRACE("Failed to paint image\n");
879 SetStretchBltMode(hdcSrc, oldStretchMode);
880 SetBkColor(hdcDest, oldBackground);
881 SetTextColor(hdcDest, oldForeground);
883 SelectObject(hdcWork, oldWork);
886 if(bmpWork) DeleteObject(bmpWork);
888 SelectObject(hdcMask, oldMask);
891 if(bmpMask) DeleteObject(bmpMask);
895 /******************************************************************************
896 * GdiAlphaBlend [GDI32.@]
898 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
899 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
900 BLENDFUNCTION blendFunction)
905 dcSrc = get_dc_ptr( hdcSrc );
906 if (!dcSrc) return FALSE;
908 if ((dcDst = get_dc_ptr( hdcDst )))
910 struct bitblt_coords src, dst;
911 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
912 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
919 src.log_width = widthSrc;
920 src.log_height = heightSrc;
921 src.layout = GetLayout( src_dev->hdc );
924 dst.log_width = widthDst;
925 dst.log_height = heightDst;
926 dst.layout = GetLayout( dst_dev->hdc );
927 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
929 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",
930 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
931 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
932 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
933 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
934 blendFunction.BlendOp, blendFunction.BlendFlags,
935 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
937 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
938 src.log_width < 0 || src.log_height < 0 ||
939 (!is_rect_empty( &dcSrc->device_rect ) &&
940 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
941 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
943 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
944 SetLastError( ERROR_INVALID_PARAMETER );
947 else if (dst.log_width < 0 || dst.log_height < 0)
949 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
950 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
951 SetLastError( ERROR_INVALID_PARAMETER );
954 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
955 src.y + src.height > dst.y && src.y < dst.y + dst.height)
957 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
958 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
959 SetLastError( ERROR_INVALID_PARAMETER );
962 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
964 release_dc_ptr( dcDst );
966 release_dc_ptr( dcSrc );
970 /*********************************************************************
974 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
975 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
976 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
979 /* parallelogram coords */
988 /* save actual mode, set GM_ADVANCED */
989 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
993 memcpy(plg,lpPoint,sizeof(POINT)*3);
996 rect[1].x = nXSrc + nWidth;
999 rect[2].y = nYSrc + nHeight;
1000 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1002 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);
1004 if (fabs(det) < 1e-5)
1006 SetGraphicsMode(hdcDest,oldgMode);
1010 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1011 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1014 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;
1015 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;
1016 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1017 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1018 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1022 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;
1023 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;
1024 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1025 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1026 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1029 GetWorldTransform(hdcSrc,&SrcXf);
1030 CombineTransform(&xf,&xf,&SrcXf);
1032 /* save actual dest transform */
1033 GetWorldTransform(hdcDest,&oldDestXf);
1035 SetWorldTransform(hdcDest,&xf);
1036 /* now destination and source DCs use same coords */
1037 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1038 hdcSrc, nXSrc,nYSrc,
1039 hbmMask,xMask,yMask,
1041 /* restore dest DC */
1042 SetWorldTransform(hdcDest,&oldDestXf);
1043 SetGraphicsMode(hdcDest,oldgMode);