gdi32: Simplify computation of the DIB header size for internal BITMAPINFO structures.
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
blob7167c4a105871828b16a3aeb46ece7e9902bd7e1
1 /*
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
21 #include "config.h"
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <math.h>
26 #ifdef HAVE_FLOAT_H
27 #include <float.h>
28 #endif
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
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 )
45 int tmp = *i;
46 *i = *j;
47 *j = tmp;
50 BOOL intersect_vis_rectangles( struct bitblt_coords *dst, struct bitblt_coords *src )
52 RECT rect;
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 );
63 else /* stretching */
65 /* map source rectangle into destination coordinates */
66 rect = src->visrect;
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 */
77 rect.left--;
78 rect.top--;
79 rect.right++;
80 rect.bottom++;
81 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
83 /* map destination rectangle back to source coordinates */
84 rect = dst->visrect;
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 */
95 rect.left--;
96 rect.top--;
97 rect.right++;
98 rect.bottom++;
99 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
101 return TRUE;
104 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
105 DC *dc_src, struct bitblt_coords *src )
107 RECT rect;
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 );
116 dst->x = rect.left;
117 dst->y = rect.top;
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 );
138 src->x = rect.left;
139 src->y = rect.top;
140 src->width = rect.right - rect.left;
141 src->height = rect.bottom - rect.top;
142 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
144 src->x += src->width;
145 src->width = -src->width;
147 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
149 /* source is not clipped */
150 if (dc_src->header.type == OBJ_MEMDC)
151 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
152 else
153 src->visrect = rect; /* FIXME: clip to device size */
155 if (is_rect_empty( &src->visrect )) return FALSE;
156 if (is_rect_empty( &dst->visrect )) return FALSE;
158 return intersect_vis_rectangles( dst, src );
161 void free_heap_bits( struct gdi_image_bits *bits )
163 HeapFree( GetProcessHeap(), 0, bits->ptr );
166 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
167 BITMAPINFO *dst_info, struct gdi_image_bits *bits, BOOL add_alpha )
169 void *ptr;
170 DWORD err;
172 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
173 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
175 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
176 return ERROR_OUTOFMEMORY;
178 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
179 if (bits->free) bits->free( bits );
180 bits->ptr = ptr;
181 bits->is_copy = TRUE;
182 bits->free = free_heap_bits;
183 return err;
186 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
187 BITMAPINFO *dst_info, struct bitblt_coords *dst,
188 struct gdi_image_bits *bits, int mode )
190 void *ptr;
191 DWORD err;
193 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
194 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
195 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
197 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
198 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
199 return ERROR_OUTOFMEMORY;
201 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
202 if (bits->free) bits->free( bits );
203 bits->ptr = ptr;
204 bits->is_copy = TRUE;
205 bits->free = free_heap_bits;
206 return err;
209 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
210 struct bitblt_coords *src, BITMAPINFO *dst_info,
211 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
213 if (!dst_bits->is_copy)
215 int size = dst_info->bmiHeader.biSizeImage;
216 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
217 if (!ptr) return ERROR_OUTOFMEMORY;
218 memcpy( ptr, dst_bits->ptr, size );
219 if (dst_bits->free) dst_bits->free( dst_bits );
220 dst_bits->ptr = ptr;
221 dst_bits->is_copy = TRUE;
222 dst_bits->free = free_heap_bits;
224 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
227 /***********************************************************************
228 * null driver fallback implementations
231 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
232 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
234 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
235 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
236 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
237 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
238 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
239 DWORD err;
240 struct gdi_image_bits bits;
242 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
243 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
244 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
245 release_dc_ptr( dc_src );
246 if (err) return FALSE;
248 /* 1-bpp source without a color table uses the destination DC colors */
249 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
251 COLORREF color = GetTextColor( dst_dev->hdc );
252 src_info->bmiColors[0].rgbRed = GetRValue( color );
253 src_info->bmiColors[0].rgbGreen = GetGValue( color );
254 src_info->bmiColors[0].rgbBlue = GetBValue( color );
255 src_info->bmiColors[0].rgbReserved = 0;
256 color = GetBkColor( dst_dev->hdc );
257 src_info->bmiColors[1].rgbRed = GetRValue( color );
258 src_info->bmiColors[1].rgbGreen = GetGValue( color );
259 src_info->bmiColors[1].rgbBlue = GetBValue( color );
260 src_info->bmiColors[1].rgbReserved = 0;
261 src_info->bmiHeader.biClrUsed = 2;
264 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
265 copy_bitmapinfo( dst_info, src_info );
266 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
267 if (err == ERROR_BAD_FORMAT)
269 /* 1-bpp destination without a color table requires a fake 1-entry table
270 * that contains only the background color */
271 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
273 COLORREF color = GetBkColor( src_dev->hdc );
274 dst_info->bmiColors[0].rgbRed = GetRValue( color );
275 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
276 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
277 dst_info->bmiColors[0].rgbReserved = 0;
278 dst_info->bmiHeader.biClrUsed = 1;
281 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
283 /* get rid of the fake 1-bpp table */
284 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
285 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
289 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
290 ((src->width != dst->width) || (src->height != dst->height)))
292 copy_bitmapinfo( src_info, dst_info );
293 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
294 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
297 if (bits.free) bits.free( &bits );
298 return !err;
302 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
303 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
305 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
306 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
307 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
308 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
309 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
310 DWORD err;
311 struct gdi_image_bits bits;
313 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
314 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
315 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
316 release_dc_ptr( dc_src );
317 if (err) goto done;
319 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
320 copy_bitmapinfo( dst_info, src_info );
321 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
322 if (err == ERROR_BAD_FORMAT)
324 /* 1-bpp source without a color table uses black & white */
325 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
327 src_info->bmiColors[0].rgbRed = 0;
328 src_info->bmiColors[0].rgbGreen = 0;
329 src_info->bmiColors[0].rgbBlue = 0;
330 src_info->bmiColors[0].rgbReserved = 0;
331 src_info->bmiColors[1].rgbRed = 0xff;
332 src_info->bmiColors[1].rgbGreen = 0xff;
333 src_info->bmiColors[1].rgbBlue = 0xff;
334 src_info->bmiColors[1].rgbReserved = 0;
335 src_info->bmiHeader.biClrUsed = 2;
338 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
339 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
342 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
343 ((src->width != dst->width) || (src->height != dst->height)))
345 copy_bitmapinfo( src_info, dst_info );
346 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
347 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
350 if (bits.free) bits.free( &bits );
351 done:
352 if (err) SetLastError( err );
353 return !err;
357 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
358 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
360 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
361 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
362 struct gdi_image_bits dst_bits;
363 struct bitblt_coords orig_dst;
364 DC *dc = get_nulldrv_dc( dev );
365 DWORD err;
367 if (info->bmiHeader.biPlanes != 1) goto update_format;
368 if (info->bmiHeader.biBitCount != 32) goto update_format;
369 if (info->bmiHeader.biCompression == BI_BITFIELDS)
371 DWORD *masks = (DWORD *)info->bmiColors;
372 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
373 goto update_format;
376 if (!bits) return ERROR_SUCCESS;
377 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
379 dev = GET_DC_PHYSDEV( dc, pGetImage );
380 orig_dst = *dst;
381 err = dev->funcs->pGetImage( dev, 0, dst_info, &dst_bits, dst );
382 if (err) return err;
384 dev = GET_DC_PHYSDEV( dc, pPutImage );
385 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
386 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
388 if (dst_bits.free) dst_bits.free( &dst_bits );
389 return err;
391 update_format:
392 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
393 return ERROR_INVALID_PARAMETER;
395 info->bmiHeader.biPlanes = 1;
396 info->bmiHeader.biBitCount = 32;
397 info->bmiHeader.biCompression = BI_RGB;
398 info->bmiHeader.biClrUsed = 0;
399 return ERROR_BAD_FORMAT;
402 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
403 void * grad_array, ULONG ngrad, ULONG mode )
405 DC *dc = get_nulldrv_dc( dev );
406 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
407 BITMAPINFO *info = (BITMAPINFO *)buffer;
408 struct bitblt_coords src, dst;
409 struct gdi_image_bits bits;
410 unsigned int i;
411 POINT *pts;
412 BOOL ret = TRUE;
413 DWORD err;
414 HRGN rgn;
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;
440 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
442 /* query the bitmap format */
443 info->bmiHeader.biSize = sizeof(info->bmiHeader);
444 info->bmiHeader.biPlanes = 1;
445 info->bmiHeader.biBitCount = 0;
446 info->bmiHeader.biCompression = BI_RGB;
447 info->bmiHeader.biXPelsPerMeter = 0;
448 info->bmiHeader.biYPelsPerMeter = 0;
449 info->bmiHeader.biClrUsed = 0;
450 info->bmiHeader.biClrImportant = 0;
451 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
452 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
453 info->bmiHeader.biSizeImage = get_dib_image_size( info );
454 dev = GET_DC_PHYSDEV( dc, pPutImage );
455 err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
456 if ((err && err != ERROR_BAD_FORMAT) ||
457 !(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
459 ret = FALSE;
460 goto done;
462 bits.is_copy = TRUE;
463 bits.free = free_heap_bits;
465 /* make src and points relative to the bitmap */
466 src = dst;
467 src.x -= dst.visrect.left;
468 src.y -= dst.visrect.top;
469 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
470 for (i = 0; i < nvert; i++)
472 pts[i].x -= dst.visrect.left;
473 pts[i].y -= dst.visrect.top;
476 rgn = CreateRectRgn( 0, 0, 0, 0 );
477 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
478 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
479 if (dev->funcs->pPutImage( dev, 0, rgn, info, &bits, &src, &dst, SRCCOPY )) ret = FALSE;
481 if (bits.free) bits.free( &bits );
482 DeleteObject( rgn );
484 done:
485 HeapFree( GetProcessHeap(), 0, pts );
486 return ret;
489 /***********************************************************************
490 * PatBlt (GDI32.@)
492 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
494 DC * dc;
495 BOOL ret = FALSE;
497 if (rop_uses_src( rop )) return FALSE;
498 if ((dc = get_dc_ptr( hdc )))
500 struct bitblt_coords dst;
501 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
503 update_dc( dc );
505 dst.log_x = left;
506 dst.log_y = top;
507 dst.log_width = width;
508 dst.log_height = height;
509 dst.layout = dc->layout;
510 if (rop & NOMIRRORBITMAP)
512 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
513 rop &= ~NOMIRRORBITMAP;
515 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
517 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
518 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
519 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
521 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
523 release_dc_ptr( dc );
525 return ret;
529 /***********************************************************************
530 * BitBlt (GDI32.@)
532 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
533 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
535 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
536 else return StretchBlt( hdcDst, xDst, yDst, width, height,
537 hdcSrc, xSrc, ySrc, width, height, rop );
541 /***********************************************************************
542 * StretchBlt (GDI32.@)
544 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
545 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
547 BOOL ret = FALSE;
548 DC *dcDst, *dcSrc;
550 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
552 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
554 if ((dcSrc = get_dc_ptr( hdcSrc )))
556 struct bitblt_coords src, dst;
557 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
558 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
560 update_dc( dcSrc );
561 update_dc( dcDst );
563 src.log_x = xSrc;
564 src.log_y = ySrc;
565 src.log_width = widthSrc;
566 src.log_height = heightSrc;
567 src.layout = dcSrc->layout;
568 dst.log_x = xDst;
569 dst.log_y = yDst;
570 dst.log_width = widthDst;
571 dst.log_height = heightDst;
572 dst.layout = dcDst->layout;
573 if (rop & NOMIRRORBITMAP)
575 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
576 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
577 rop &= ~NOMIRRORBITMAP;
579 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
581 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",
582 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
583 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
584 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
585 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
587 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
588 release_dc_ptr( dcSrc );
590 release_dc_ptr( dcDst );
591 return ret;
594 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
595 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
597 /***********************************************************************
598 * MaskBlt [GDI32.@]
600 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
601 INT nWidth, INT nHeight, HDC hdcSrc,
602 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
603 INT xMask, INT yMask, DWORD dwRop)
605 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
606 HDC hDC1, hDC2;
607 HBRUSH hbrMask, hbrDst, hbrTmp;
609 static const DWORD ROP3Table[256] =
611 0x00000042, 0x00010289,
612 0x00020C89, 0x000300AA,
613 0x00040C88, 0x000500A9,
614 0x00060865, 0x000702C5,
615 0x00080F08, 0x00090245,
616 0x000A0329, 0x000B0B2A,
617 0x000C0324, 0x000D0B25,
618 0x000E08A5, 0x000F0001,
619 0x00100C85, 0x001100A6,
620 0x00120868, 0x001302C8,
621 0x00140869, 0x001502C9,
622 0x00165CCA, 0x00171D54,
623 0x00180D59, 0x00191CC8,
624 0x001A06C5, 0x001B0768,
625 0x001C06CA, 0x001D0766,
626 0x001E01A5, 0x001F0385,
627 0x00200F09, 0x00210248,
628 0x00220326, 0x00230B24,
629 0x00240D55, 0x00251CC5,
630 0x002606C8, 0x00271868,
631 0x00280369, 0x002916CA,
632 0x002A0CC9, 0x002B1D58,
633 0x002C0784, 0x002D060A,
634 0x002E064A, 0x002F0E2A,
635 0x0030032A, 0x00310B28,
636 0x00320688, 0x00330008,
637 0x003406C4, 0x00351864,
638 0x003601A8, 0x00370388,
639 0x0038078A, 0x00390604,
640 0x003A0644, 0x003B0E24,
641 0x003C004A, 0x003D18A4,
642 0x003E1B24, 0x003F00EA,
643 0x00400F0A, 0x00410249,
644 0x00420D5D, 0x00431CC4,
645 0x00440328, 0x00450B29,
646 0x004606C6, 0x0047076A,
647 0x00480368, 0x004916C5,
648 0x004A0789, 0x004B0605,
649 0x004C0CC8, 0x004D1954,
650 0x004E0645, 0x004F0E25,
651 0x00500325, 0x00510B26,
652 0x005206C9, 0x00530764,
653 0x005408A9, 0x00550009,
654 0x005601A9, 0x00570389,
655 0x00580785, 0x00590609,
656 0x005A0049, 0x005B18A9,
657 0x005C0649, 0x005D0E29,
658 0x005E1B29, 0x005F00E9,
659 0x00600365, 0x006116C6,
660 0x00620786, 0x00630608,
661 0x00640788, 0x00650606,
662 0x00660046, 0x006718A8,
663 0x006858A6, 0x00690145,
664 0x006A01E9, 0x006B178A,
665 0x006C01E8, 0x006D1785,
666 0x006E1E28, 0x006F0C65,
667 0x00700CC5, 0x00711D5C,
668 0x00720648, 0x00730E28,
669 0x00740646, 0x00750E26,
670 0x00761B28, 0x007700E6,
671 0x007801E5, 0x00791786,
672 0x007A1E29, 0x007B0C68,
673 0x007C1E24, 0x007D0C69,
674 0x007E0955, 0x007F03C9,
675 0x008003E9, 0x00810975,
676 0x00820C49, 0x00831E04,
677 0x00840C48, 0x00851E05,
678 0x008617A6, 0x008701C5,
679 0x008800C6, 0x00891B08,
680 0x008A0E06, 0x008B0666,
681 0x008C0E08, 0x008D0668,
682 0x008E1D7C, 0x008F0CE5,
683 0x00900C45, 0x00911E08,
684 0x009217A9, 0x009301C4,
685 0x009417AA, 0x009501C9,
686 0x00960169, 0x0097588A,
687 0x00981888, 0x00990066,
688 0x009A0709, 0x009B07A8,
689 0x009C0704, 0x009D07A6,
690 0x009E16E6, 0x009F0345,
691 0x00A000C9, 0x00A11B05,
692 0x00A20E09, 0x00A30669,
693 0x00A41885, 0x00A50065,
694 0x00A60706, 0x00A707A5,
695 0x00A803A9, 0x00A90189,
696 0x00AA0029, 0x00AB0889,
697 0x00AC0744, 0x00AD06E9,
698 0x00AE0B06, 0x00AF0229,
699 0x00B00E05, 0x00B10665,
700 0x00B21974, 0x00B30CE8,
701 0x00B4070A, 0x00B507A9,
702 0x00B616E9, 0x00B70348,
703 0x00B8074A, 0x00B906E6,
704 0x00BA0B09, 0x00BB0226,
705 0x00BC1CE4, 0x00BD0D7D,
706 0x00BE0269, 0x00BF08C9,
707 0x00C000CA, 0x00C11B04,
708 0x00C21884, 0x00C3006A,
709 0x00C40E04, 0x00C50664,
710 0x00C60708, 0x00C707AA,
711 0x00C803A8, 0x00C90184,
712 0x00CA0749, 0x00CB06E4,
713 0x00CC0020, 0x00CD0888,
714 0x00CE0B08, 0x00CF0224,
715 0x00D00E0A, 0x00D1066A,
716 0x00D20705, 0x00D307A4,
717 0x00D41D78, 0x00D50CE9,
718 0x00D616EA, 0x00D70349,
719 0x00D80745, 0x00D906E8,
720 0x00DA1CE9, 0x00DB0D75,
721 0x00DC0B04, 0x00DD0228,
722 0x00DE0268, 0x00DF08C8,
723 0x00E003A5, 0x00E10185,
724 0x00E20746, 0x00E306EA,
725 0x00E40748, 0x00E506E5,
726 0x00E61CE8, 0x00E70D79,
727 0x00E81D74, 0x00E95CE6,
728 0x00EA02E9, 0x00EB0849,
729 0x00EC02E8, 0x00ED0848,
730 0x00EE0086, 0x00EF0A08,
731 0x00F00021, 0x00F10885,
732 0x00F20B05, 0x00F3022A,
733 0x00F40B0A, 0x00F50225,
734 0x00F60265, 0x00F708C5,
735 0x00F802E5, 0x00F90845,
736 0x00FA0089, 0x00FB0A09,
737 0x00FC008A, 0x00FD0A0A,
738 0x00FE02A9, 0x00FF0062,
741 if (!hbmMask)
742 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
744 hbrMask = CreatePatternBrush(hbmMask);
745 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
747 /* make bitmap */
748 hDC1 = CreateCompatibleDC(hdcDest);
749 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
750 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
752 /* draw using bkgnd rop */
753 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
754 hbrTmp = SelectObject(hDC1, hbrDst);
755 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
756 SelectObject(hDC1, hbrTmp);
758 /* make bitmap */
759 hDC2 = CreateCompatibleDC(hdcDest);
760 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
761 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
763 /* draw using foregnd rop */
764 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
765 hbrTmp = SelectObject(hDC2, hbrDst);
766 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
768 /* combine both using the mask as a pattern brush */
769 SelectObject(hDC2, hbrMask);
770 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
771 SelectObject(hDC2, hbrTmp);
773 /* blit to dst */
774 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
776 /* restore all objects */
777 SelectObject(hdcDest, hbrDst);
778 SelectObject(hDC1, hOldBitmap1);
779 SelectObject(hDC2, hOldBitmap2);
781 /* delete all temp objects */
782 DeleteObject(hBitmap1);
783 DeleteObject(hBitmap2);
784 DeleteObject(hbrMask);
786 DeleteDC(hDC1);
787 DeleteDC(hDC2);
789 return TRUE;
792 /******************************************************************************
793 * GdiTransparentBlt [GDI32.@]
795 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
796 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
797 UINT crTransparent )
799 BOOL ret = FALSE;
800 HDC hdcWork;
801 HBITMAP bmpWork;
802 HGDIOBJ oldWork;
803 HDC hdcMask = NULL;
804 HBITMAP bmpMask = NULL;
805 HBITMAP oldMask = NULL;
806 COLORREF oldBackground;
807 COLORREF oldForeground;
808 int oldStretchMode;
810 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
811 TRACE("Cannot mirror\n");
812 return FALSE;
815 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
816 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
818 /* Stretch bitmap */
819 oldStretchMode = GetStretchBltMode(hdcSrc);
820 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
821 SetStretchBltMode(hdcSrc, COLORONCOLOR);
822 hdcWork = CreateCompatibleDC(hdcDest);
823 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
824 oldWork = SelectObject(hdcWork, bmpWork);
825 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
826 TRACE("Failed to stretch\n");
827 goto error;
829 SetBkColor(hdcWork, crTransparent);
831 /* Create mask */
832 hdcMask = CreateCompatibleDC(hdcDest);
833 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
834 oldMask = SelectObject(hdcMask, bmpMask);
835 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
836 TRACE("Failed to create mask\n");
837 goto error;
840 /* Replace transparent color with black */
841 SetBkColor(hdcWork, RGB(0,0,0));
842 SetTextColor(hdcWork, RGB(255,255,255));
843 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
844 TRACE("Failed to mask out background\n");
845 goto error;
848 /* Replace non-transparent area on destination with black */
849 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
850 TRACE("Failed to clear destination area\n");
851 goto error;
854 /* Draw the image */
855 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
856 TRACE("Failed to paint image\n");
857 goto error;
860 ret = TRUE;
861 error:
862 SetStretchBltMode(hdcSrc, oldStretchMode);
863 SetBkColor(hdcDest, oldBackground);
864 SetTextColor(hdcDest, oldForeground);
865 if(hdcWork) {
866 SelectObject(hdcWork, oldWork);
867 DeleteDC(hdcWork);
869 if(bmpWork) DeleteObject(bmpWork);
870 if(hdcMask) {
871 SelectObject(hdcMask, oldMask);
872 DeleteDC(hdcMask);
874 if(bmpMask) DeleteObject(bmpMask);
875 return ret;
878 /******************************************************************************
879 * GdiAlphaBlend [GDI32.@]
881 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
882 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
883 BLENDFUNCTION blendFunction)
885 BOOL ret = FALSE;
886 DC *dcDst, *dcSrc;
888 dcSrc = get_dc_ptr( hdcSrc );
889 if (!dcSrc) return FALSE;
891 if ((dcDst = get_dc_ptr( hdcDst )))
893 struct bitblt_coords src, dst;
894 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
895 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
897 update_dc( dcSrc );
898 update_dc( dcDst );
900 src.log_x = xSrc;
901 src.log_y = ySrc;
902 src.log_width = widthSrc;
903 src.log_height = heightSrc;
904 src.layout = GetLayout( src_dev->hdc );
905 dst.log_x = xDst;
906 dst.log_y = yDst;
907 dst.log_width = widthDst;
908 dst.log_height = heightDst;
909 dst.layout = GetLayout( dst_dev->hdc );
910 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
912 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",
913 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
914 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
915 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
916 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
917 blendFunction.BlendOp, blendFunction.BlendFlags,
918 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
920 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
921 (dcSrc->header.type == OBJ_MEMDC &&
922 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
923 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
925 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
926 SetLastError( ERROR_INVALID_PARAMETER );
927 ret = FALSE;
929 else if (dst.width < 0 || dst.height < 0)
931 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
932 SetLastError( ERROR_INVALID_PARAMETER );
933 ret = FALSE;
935 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
936 src.y + src.height > dst.y && src.y < dst.y + dst.height)
938 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
939 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
940 SetLastError( ERROR_INVALID_PARAMETER );
941 ret = FALSE;
943 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
945 release_dc_ptr( dcDst );
947 release_dc_ptr( dcSrc );
948 return ret;
951 /*********************************************************************
952 * PlgBlt [GDI32.@]
955 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
956 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
957 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
959 int oldgMode;
960 /* parallelogram coords */
961 POINT plg[3];
962 /* rect coords */
963 POINT rect[3];
964 XFORM xf;
965 XFORM SrcXf;
966 XFORM oldDestXf;
967 double det;
969 /* save actual mode, set GM_ADVANCED */
970 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
971 if (oldgMode == 0)
972 return FALSE;
974 memcpy(plg,lpPoint,sizeof(POINT)*3);
975 rect[0].x = nXSrc;
976 rect[0].y = nYSrc;
977 rect[1].x = nXSrc + nWidth;
978 rect[1].y = nYSrc;
979 rect[2].x = nXSrc;
980 rect[2].y = nYSrc + nHeight;
981 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
982 /* determinant */
983 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);
985 if (fabs(det) < 1e-5)
987 SetGraphicsMode(hdcDest,oldgMode);
988 return FALSE;
991 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
992 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
994 /* X components */
995 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;
996 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;
997 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
998 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
999 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1000 ) / det;
1002 /* Y components */
1003 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;
1004 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;
1005 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1006 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1007 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1008 ) / det;
1010 GetWorldTransform(hdcSrc,&SrcXf);
1011 CombineTransform(&xf,&xf,&SrcXf);
1013 /* save actual dest transform */
1014 GetWorldTransform(hdcDest,&oldDestXf);
1016 SetWorldTransform(hdcDest,&xf);
1017 /* now destination and source DCs use same coords */
1018 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1019 hdcSrc, nXSrc,nYSrc,
1020 hbmMask,xMask,yMask,
1021 SRCCOPY);
1022 /* restore dest DC */
1023 SetWorldTransform(hdcDest,&oldDestXf);
1024 SetGraphicsMode(hdcDest,oldgMode);
1026 return TRUE;