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 intersect_rect( &rect, &src->visrect, &dst->visrect );
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 if (get_clip_box( dc_dst, &clip ))
128 intersect_rect( &dst->visrect, &rect, &clip );
132 /* get the source visible rectangle */
134 if (!src) return !is_rect_empty( &dst->visrect );
136 rect.left = src->log_x;
137 rect.top = src->log_y;
138 rect.right = src->log_x + src->log_width;
139 rect.bottom = src->log_y + src->log_height;
140 LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
143 src->width = rect.right - rect.left;
144 src->height = rect.bottom - rect.top;
145 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
147 src->x += src->width;
148 src->width = -src->width;
150 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
152 /* source is not clipped */
153 if (dc_src->header.type == OBJ_MEMDC)
154 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
156 src->visrect = rect; /* FIXME: clip to device size */
158 if (is_rect_empty( &src->visrect )) return FALSE;
159 if (is_rect_empty( &dst->visrect )) return FALSE;
161 return intersect_vis_rectangles( dst, src );
164 void free_heap_bits( struct gdi_image_bits *bits )
166 HeapFree( GetProcessHeap(), 0, bits->ptr );
169 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
170 BITMAPINFO *dst_info, struct gdi_image_bits *bits, BOOL add_alpha )
175 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
176 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
177 return ERROR_OUTOFMEMORY;
179 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
180 if (bits->free) bits->free( bits );
182 bits->is_copy = TRUE;
183 bits->free = free_heap_bits;
187 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
188 BITMAPINFO *dst_info, struct bitblt_coords *dst,
189 struct gdi_image_bits *bits, int mode )
194 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
195 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
196 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
197 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
198 return ERROR_OUTOFMEMORY;
200 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
201 if (bits->free) bits->free( bits );
203 bits->is_copy = TRUE;
204 bits->free = free_heap_bits;
208 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
209 struct bitblt_coords *src, BITMAPINFO *dst_info,
210 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
212 if (!dst_bits->is_copy)
214 int size = get_dib_image_size( dst_info );
215 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
216 if (!ptr) return ERROR_OUTOFMEMORY;
217 memcpy( ptr, dst_bits->ptr, size );
218 if (dst_bits->free) dst_bits->free( dst_bits );
220 dst_bits->is_copy = TRUE;
221 dst_bits->free = free_heap_bits;
223 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
226 /***********************************************************************
227 * null driver fallback implementations
230 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
231 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
233 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
234 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
235 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
236 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
237 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
239 struct gdi_image_bits bits;
241 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
242 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
243 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
244 release_dc_ptr( dc_src );
245 if (err) return FALSE;
247 /* 1-bpp source without a color table uses the destination DC colors */
248 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
250 COLORREF color = GetTextColor( dst_dev->hdc );
251 src_info->bmiColors[0].rgbRed = GetRValue( color );
252 src_info->bmiColors[0].rgbGreen = GetGValue( color );
253 src_info->bmiColors[0].rgbBlue = GetBValue( color );
254 src_info->bmiColors[0].rgbReserved = 0;
255 color = GetBkColor( dst_dev->hdc );
256 src_info->bmiColors[1].rgbRed = GetRValue( color );
257 src_info->bmiColors[1].rgbGreen = GetGValue( color );
258 src_info->bmiColors[1].rgbBlue = GetBValue( color );
259 src_info->bmiColors[1].rgbReserved = 0;
260 src_info->bmiHeader.biClrUsed = 2;
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, 0, dst_info, &bits, src, dst, rop );
266 if (err == ERROR_BAD_FORMAT)
268 /* 1-bpp destination without a color table requires a fake 1-entry table
269 * that contains only the background color */
270 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
272 COLORREF color = GetBkColor( src_dev->hdc );
273 dst_info->bmiColors[0].rgbRed = GetRValue( color );
274 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
275 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
276 dst_info->bmiColors[0].rgbReserved = 0;
277 dst_info->bmiHeader.biClrUsed = 1;
280 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
282 /* get rid of the fake 1-bpp table */
283 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
284 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
288 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
289 ((src->width != dst->width) || (src->height != dst->height)))
291 copy_bitmapinfo( src_info, dst_info );
292 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
293 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
296 if (bits.free) bits.free( &bits );
301 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
302 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
304 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
305 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
306 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
307 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
308 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
310 struct gdi_image_bits bits;
312 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
313 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
314 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
315 release_dc_ptr( dc_src );
318 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
319 copy_bitmapinfo( dst_info, src_info );
320 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
321 if (err == ERROR_BAD_FORMAT)
323 /* 1-bpp source without a color table uses black & white */
324 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
326 src_info->bmiColors[0].rgbRed = 0;
327 src_info->bmiColors[0].rgbGreen = 0;
328 src_info->bmiColors[0].rgbBlue = 0;
329 src_info->bmiColors[0].rgbReserved = 0;
330 src_info->bmiColors[1].rgbRed = 0xff;
331 src_info->bmiColors[1].rgbGreen = 0xff;
332 src_info->bmiColors[1].rgbBlue = 0xff;
333 src_info->bmiColors[1].rgbReserved = 0;
334 src_info->bmiHeader.biClrUsed = 2;
337 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
338 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
341 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
342 ((src->width != dst->width) || (src->height != dst->height)))
344 copy_bitmapinfo( src_info, dst_info );
345 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
346 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
349 if (bits.free) bits.free( &bits );
351 if (err) SetLastError( err );
356 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
357 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
359 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
360 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
361 struct gdi_image_bits dst_bits;
362 struct bitblt_coords orig_dst;
363 DC *dc = get_nulldrv_dc( dev );
366 if (info->bmiHeader.biPlanes != 1) goto update_format;
367 if (info->bmiHeader.biBitCount != 32) goto update_format;
368 if (info->bmiHeader.biCompression == BI_BITFIELDS)
370 DWORD *masks = (DWORD *)info->bmiColors;
371 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
375 if (!bits) return ERROR_SUCCESS;
376 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
378 dev = GET_DC_PHYSDEV( dc, pGetImage );
380 err = dev->funcs->pGetImage( dev, 0, dst_info, &dst_bits, dst );
383 dev = GET_DC_PHYSDEV( dc, pPutImage );
384 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
385 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
387 if (dst_bits.free) dst_bits.free( &dst_bits );
391 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
392 return ERROR_INVALID_PARAMETER;
394 info->bmiHeader.biPlanes = 1;
395 info->bmiHeader.biBitCount = 32;
396 info->bmiHeader.biCompression = BI_RGB;
397 info->bmiHeader.biClrUsed = 0;
398 return ERROR_BAD_FORMAT;
401 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
402 void * grad_array, ULONG ngrad, ULONG mode )
404 DC *dc = get_nulldrv_dc( dev );
405 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
406 BITMAPINFO *info = (BITMAPINFO *)buffer;
407 struct bitblt_coords src, dst;
408 struct gdi_image_bits bits;
416 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
417 for (i = 0; i < nvert; i++)
419 pts[i].x = vert_array[i].x;
420 pts[i].y = vert_array[i].y;
422 LPtoDP( dev->hdc, pts, nvert );
424 /* compute bounding rect of all the rectangles/triangles */
425 dst.visrect.left = dst.visrect.top = INT_MAX;
426 dst.visrect.right = dst.visrect.bottom = INT_MIN;
427 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
429 ULONG v = ((ULONG *)grad_array)[i];
430 dst.visrect.left = min( dst.visrect.left, pts[v].x );
431 dst.visrect.top = min( dst.visrect.top, pts[v].y );
432 dst.visrect.right = max( dst.visrect.right, pts[v].x );
433 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
436 dst.x = dst.visrect.left;
437 dst.y = dst.visrect.top;
438 dst.width = dst.visrect.right - dst.visrect.left;
439 dst.height = dst.visrect.bottom - dst.visrect.top;
441 if (get_clip_box( dc, &clip )) intersect_rect( &dst.visrect, &dst.visrect, &clip );
442 if (is_rect_empty( &dst.visrect )) goto done;
444 /* query the bitmap format */
445 info->bmiHeader.biSize = sizeof(info->bmiHeader);
446 info->bmiHeader.biPlanes = 1;
447 info->bmiHeader.biBitCount = 0;
448 info->bmiHeader.biCompression = BI_RGB;
449 info->bmiHeader.biXPelsPerMeter = 0;
450 info->bmiHeader.biYPelsPerMeter = 0;
451 info->bmiHeader.biClrUsed = 0;
452 info->bmiHeader.biClrImportant = 0;
453 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
454 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
455 info->bmiHeader.biSizeImage = 0;
456 dev = GET_DC_PHYSDEV( dc, pPutImage );
457 err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
458 if ((err && err != ERROR_BAD_FORMAT) ||
459 !(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, get_dib_image_size( info ))))
465 bits.free = free_heap_bits;
467 /* make src and points relative to the bitmap */
469 src.x -= dst.visrect.left;
470 src.y -= dst.visrect.top;
471 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
472 for (i = 0; i < nvert; i++)
474 pts[i].x -= dst.visrect.left;
475 pts[i].y -= dst.visrect.top;
478 rgn = CreateRectRgn( 0, 0, 0, 0 );
479 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
480 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
481 if (dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY )) ret = FALSE;
483 if (bits.free) bits.free( &bits );
487 HeapFree( GetProcessHeap(), 0, pts );
491 /***********************************************************************
494 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
499 if (rop_uses_src( rop )) return FALSE;
500 if ((dc = get_dc_ptr( hdc )))
502 struct bitblt_coords dst;
503 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
509 dst.log_width = width;
510 dst.log_height = height;
511 dst.layout = dc->layout;
512 if (rop & NOMIRRORBITMAP)
514 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
515 rop &= ~NOMIRRORBITMAP;
517 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
519 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
520 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
521 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
523 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
525 release_dc_ptr( dc );
531 /***********************************************************************
534 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
535 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
537 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
538 else return StretchBlt( hdcDst, xDst, yDst, width, height,
539 hdcSrc, xSrc, ySrc, width, height, rop );
543 /***********************************************************************
544 * StretchBlt (GDI32.@)
546 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
547 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
552 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
554 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
556 if ((dcSrc = get_dc_ptr( hdcSrc )))
558 struct bitblt_coords src, dst;
559 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
560 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
567 src.log_width = widthSrc;
568 src.log_height = heightSrc;
569 src.layout = dcSrc->layout;
572 dst.log_width = widthDst;
573 dst.log_height = heightDst;
574 dst.layout = dcDst->layout;
575 if (rop & NOMIRRORBITMAP)
577 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
578 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
579 rop &= ~NOMIRRORBITMAP;
581 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
583 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",
584 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
585 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
586 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
587 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
589 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
590 release_dc_ptr( dcSrc );
592 release_dc_ptr( dcDst );
596 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
597 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
599 /***********************************************************************
602 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
603 INT nWidth, INT nHeight, HDC hdcSrc,
604 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
605 INT xMask, INT yMask, DWORD dwRop)
607 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
609 HBRUSH hbrMask, hbrDst, hbrTmp;
611 static const DWORD ROP3Table[256] =
613 0x00000042, 0x00010289,
614 0x00020C89, 0x000300AA,
615 0x00040C88, 0x000500A9,
616 0x00060865, 0x000702C5,
617 0x00080F08, 0x00090245,
618 0x000A0329, 0x000B0B2A,
619 0x000C0324, 0x000D0B25,
620 0x000E08A5, 0x000F0001,
621 0x00100C85, 0x001100A6,
622 0x00120868, 0x001302C8,
623 0x00140869, 0x001502C9,
624 0x00165CCA, 0x00171D54,
625 0x00180D59, 0x00191CC8,
626 0x001A06C5, 0x001B0768,
627 0x001C06CA, 0x001D0766,
628 0x001E01A5, 0x001F0385,
629 0x00200F09, 0x00210248,
630 0x00220326, 0x00230B24,
631 0x00240D55, 0x00251CC5,
632 0x002606C8, 0x00271868,
633 0x00280369, 0x002916CA,
634 0x002A0CC9, 0x002B1D58,
635 0x002C0784, 0x002D060A,
636 0x002E064A, 0x002F0E2A,
637 0x0030032A, 0x00310B28,
638 0x00320688, 0x00330008,
639 0x003406C4, 0x00351864,
640 0x003601A8, 0x00370388,
641 0x0038078A, 0x00390604,
642 0x003A0644, 0x003B0E24,
643 0x003C004A, 0x003D18A4,
644 0x003E1B24, 0x003F00EA,
645 0x00400F0A, 0x00410249,
646 0x00420D5D, 0x00431CC4,
647 0x00440328, 0x00450B29,
648 0x004606C6, 0x0047076A,
649 0x00480368, 0x004916C5,
650 0x004A0789, 0x004B0605,
651 0x004C0CC8, 0x004D1954,
652 0x004E0645, 0x004F0E25,
653 0x00500325, 0x00510B26,
654 0x005206C9, 0x00530764,
655 0x005408A9, 0x00550009,
656 0x005601A9, 0x00570389,
657 0x00580785, 0x00590609,
658 0x005A0049, 0x005B18A9,
659 0x005C0649, 0x005D0E29,
660 0x005E1B29, 0x005F00E9,
661 0x00600365, 0x006116C6,
662 0x00620786, 0x00630608,
663 0x00640788, 0x00650606,
664 0x00660046, 0x006718A8,
665 0x006858A6, 0x00690145,
666 0x006A01E9, 0x006B178A,
667 0x006C01E8, 0x006D1785,
668 0x006E1E28, 0x006F0C65,
669 0x00700CC5, 0x00711D5C,
670 0x00720648, 0x00730E28,
671 0x00740646, 0x00750E26,
672 0x00761B28, 0x007700E6,
673 0x007801E5, 0x00791786,
674 0x007A1E29, 0x007B0C68,
675 0x007C1E24, 0x007D0C69,
676 0x007E0955, 0x007F03C9,
677 0x008003E9, 0x00810975,
678 0x00820C49, 0x00831E04,
679 0x00840C48, 0x00851E05,
680 0x008617A6, 0x008701C5,
681 0x008800C6, 0x00891B08,
682 0x008A0E06, 0x008B0666,
683 0x008C0E08, 0x008D0668,
684 0x008E1D7C, 0x008F0CE5,
685 0x00900C45, 0x00911E08,
686 0x009217A9, 0x009301C4,
687 0x009417AA, 0x009501C9,
688 0x00960169, 0x0097588A,
689 0x00981888, 0x00990066,
690 0x009A0709, 0x009B07A8,
691 0x009C0704, 0x009D07A6,
692 0x009E16E6, 0x009F0345,
693 0x00A000C9, 0x00A11B05,
694 0x00A20E09, 0x00A30669,
695 0x00A41885, 0x00A50065,
696 0x00A60706, 0x00A707A5,
697 0x00A803A9, 0x00A90189,
698 0x00AA0029, 0x00AB0889,
699 0x00AC0744, 0x00AD06E9,
700 0x00AE0B06, 0x00AF0229,
701 0x00B00E05, 0x00B10665,
702 0x00B21974, 0x00B30CE8,
703 0x00B4070A, 0x00B507A9,
704 0x00B616E9, 0x00B70348,
705 0x00B8074A, 0x00B906E6,
706 0x00BA0B09, 0x00BB0226,
707 0x00BC1CE4, 0x00BD0D7D,
708 0x00BE0269, 0x00BF08C9,
709 0x00C000CA, 0x00C11B04,
710 0x00C21884, 0x00C3006A,
711 0x00C40E04, 0x00C50664,
712 0x00C60708, 0x00C707AA,
713 0x00C803A8, 0x00C90184,
714 0x00CA0749, 0x00CB06E4,
715 0x00CC0020, 0x00CD0888,
716 0x00CE0B08, 0x00CF0224,
717 0x00D00E0A, 0x00D1066A,
718 0x00D20705, 0x00D307A4,
719 0x00D41D78, 0x00D50CE9,
720 0x00D616EA, 0x00D70349,
721 0x00D80745, 0x00D906E8,
722 0x00DA1CE9, 0x00DB0D75,
723 0x00DC0B04, 0x00DD0228,
724 0x00DE0268, 0x00DF08C8,
725 0x00E003A5, 0x00E10185,
726 0x00E20746, 0x00E306EA,
727 0x00E40748, 0x00E506E5,
728 0x00E61CE8, 0x00E70D79,
729 0x00E81D74, 0x00E95CE6,
730 0x00EA02E9, 0x00EB0849,
731 0x00EC02E8, 0x00ED0848,
732 0x00EE0086, 0x00EF0A08,
733 0x00F00021, 0x00F10885,
734 0x00F20B05, 0x00F3022A,
735 0x00F40B0A, 0x00F50225,
736 0x00F60265, 0x00F708C5,
737 0x00F802E5, 0x00F90845,
738 0x00FA0089, 0x00FB0A09,
739 0x00FC008A, 0x00FD0A0A,
740 0x00FE02A9, 0x00FF0062,
744 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
746 hbrMask = CreatePatternBrush(hbmMask);
747 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
750 hDC1 = CreateCompatibleDC(hdcDest);
751 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
752 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
754 /* draw using bkgnd rop */
755 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
756 hbrTmp = SelectObject(hDC1, hbrDst);
757 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
758 SelectObject(hDC1, hbrTmp);
761 hDC2 = CreateCompatibleDC(hdcDest);
762 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
763 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
765 /* draw using foregnd rop */
766 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
767 hbrTmp = SelectObject(hDC2, hbrDst);
768 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
770 /* combine both using the mask as a pattern brush */
771 SelectObject(hDC2, hbrMask);
772 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
773 SelectObject(hDC2, hbrTmp);
776 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
778 /* restore all objects */
779 SelectObject(hdcDest, hbrDst);
780 SelectObject(hDC1, hOldBitmap1);
781 SelectObject(hDC2, hOldBitmap2);
783 /* delete all temp objects */
784 DeleteObject(hBitmap1);
785 DeleteObject(hBitmap2);
786 DeleteObject(hbrMask);
794 /******************************************************************************
795 * GdiTransparentBlt [GDI32.@]
797 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
798 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
806 HBITMAP bmpMask = NULL;
807 HBITMAP oldMask = NULL;
808 COLORREF oldBackground;
809 COLORREF oldForeground;
812 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
813 TRACE("Cannot mirror\n");
817 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
818 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
821 oldStretchMode = GetStretchBltMode(hdcSrc);
822 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
823 SetStretchBltMode(hdcSrc, COLORONCOLOR);
824 hdcWork = CreateCompatibleDC(hdcDest);
825 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
826 oldWork = SelectObject(hdcWork, bmpWork);
827 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
828 TRACE("Failed to stretch\n");
831 SetBkColor(hdcWork, crTransparent);
834 hdcMask = CreateCompatibleDC(hdcDest);
835 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
836 oldMask = SelectObject(hdcMask, bmpMask);
837 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
838 TRACE("Failed to create mask\n");
842 /* Replace transparent color with black */
843 SetBkColor(hdcWork, RGB(0,0,0));
844 SetTextColor(hdcWork, RGB(255,255,255));
845 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
846 TRACE("Failed to mask out background\n");
850 /* Replace non-transparent area on destination with black */
851 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
852 TRACE("Failed to clear destination area\n");
857 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
858 TRACE("Failed to paint image\n");
864 SetStretchBltMode(hdcSrc, oldStretchMode);
865 SetBkColor(hdcDest, oldBackground);
866 SetTextColor(hdcDest, oldForeground);
868 SelectObject(hdcWork, oldWork);
871 if(bmpWork) DeleteObject(bmpWork);
873 SelectObject(hdcMask, oldMask);
876 if(bmpMask) DeleteObject(bmpMask);
880 /******************************************************************************
881 * GdiAlphaBlend [GDI32.@]
883 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
884 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
885 BLENDFUNCTION blendFunction)
890 dcSrc = get_dc_ptr( hdcSrc );
891 if (!dcSrc) return FALSE;
893 if ((dcDst = get_dc_ptr( hdcDst )))
895 struct bitblt_coords src, dst;
896 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
897 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
904 src.log_width = widthSrc;
905 src.log_height = heightSrc;
906 src.layout = GetLayout( src_dev->hdc );
909 dst.log_width = widthDst;
910 dst.log_height = heightDst;
911 dst.layout = GetLayout( dst_dev->hdc );
912 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
914 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",
915 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
916 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
917 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
918 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
919 blendFunction.BlendOp, blendFunction.BlendFlags,
920 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
922 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
923 (dcSrc->header.type == OBJ_MEMDC &&
924 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
925 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
927 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
928 SetLastError( ERROR_INVALID_PARAMETER );
931 else if (dst.width < 0 || dst.height < 0)
933 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
934 SetLastError( ERROR_INVALID_PARAMETER );
937 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
938 src.y + src.height > dst.y && src.y < dst.y + dst.height)
940 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
941 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
942 SetLastError( ERROR_INVALID_PARAMETER );
945 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
947 release_dc_ptr( dcDst );
949 release_dc_ptr( dcSrc );
953 /*********************************************************************
957 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
958 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
959 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
962 /* parallelogram coords */
971 /* save actual mode, set GM_ADVANCED */
972 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
976 memcpy(plg,lpPoint,sizeof(POINT)*3);
979 rect[1].x = nXSrc + nWidth;
982 rect[2].y = nYSrc + nHeight;
983 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
985 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);
987 if (fabs(det) < 1e-5)
989 SetGraphicsMode(hdcDest,oldgMode);
993 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
994 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
997 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;
998 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;
999 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1000 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1001 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1005 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;
1006 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;
1007 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1008 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1009 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1012 GetWorldTransform(hdcSrc,&SrcXf);
1013 CombineTransform(&xf,&xf,&SrcXf);
1015 /* save actual dest transform */
1016 GetWorldTransform(hdcDest,&oldDestXf);
1018 SetWorldTransform(hdcDest,&xf);
1019 /* now destination and source DCs use same coords */
1020 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1021 hdcSrc, nXSrc,nYSrc,
1022 hbmMask,xMask,yMask,
1024 /* restore dest DC */
1025 SetWorldTransform(hdcDest,&oldDestXf);
1026 SetGraphicsMode(hdcDest,oldgMode);