wined3d: Use a separate STATE_VDECL state handler in the GLSL pipeline.
[wine/multimedia.git] / dlls / gdi32 / bitblt.c
blob762ca0f61807bcdc3ae647b58f72b1de168c73f9
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 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 )
163 void *ptr;
164 DWORD err;
165 BOOL top_down = dst_info->bmiHeader.biHeight < 0;
167 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
168 dst_info->bmiHeader.biHeight = src->visrect.bottom - src->visrect.top;
169 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
170 if (top_down) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
172 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
173 return ERROR_OUTOFMEMORY;
175 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
176 if (bits->free) bits->free( bits );
177 bits->ptr = ptr;
178 bits->is_copy = TRUE;
179 bits->free = free_heap_bits;
180 return err;
183 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
184 BITMAPINFO *dst_info, struct bitblt_coords *dst,
185 struct gdi_image_bits *bits, int mode )
187 void *ptr;
188 DWORD err;
190 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
191 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
192 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
194 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
195 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, dst_info->bmiHeader.biSizeImage )))
196 return ERROR_OUTOFMEMORY;
198 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
199 if (bits->free) bits->free( bits );
200 bits->ptr = ptr;
201 bits->is_copy = TRUE;
202 bits->free = free_heap_bits;
203 return err;
206 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
207 struct bitblt_coords *src, BITMAPINFO *dst_info,
208 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
210 if (!dst_bits->is_copy)
212 int size = dst_info->bmiHeader.biSizeImage;
213 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
214 if (!ptr) return ERROR_OUTOFMEMORY;
215 memcpy( ptr, dst_bits->ptr, size );
216 if (dst_bits->free) dst_bits->free( dst_bits );
217 dst_bits->ptr = ptr;
218 dst_bits->is_copy = TRUE;
219 dst_bits->free = free_heap_bits;
221 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
224 /* helper to retrieve either both colors or only the background color for monochrome blits */
225 static void get_mono_dc_colors( HDC hdc, BITMAPINFO *info, int count )
227 COLORREF color = GetBkColor( hdc );
229 info->bmiColors[count - 1].rgbRed = GetRValue( color );
230 info->bmiColors[count - 1].rgbGreen = GetGValue( color );
231 info->bmiColors[count - 1].rgbBlue = GetBValue( color );
232 info->bmiColors[count - 1].rgbReserved = 0;
234 if (count > 1)
236 color = GetTextColor( hdc );
237 info->bmiColors[0].rgbRed = GetRValue( color );
238 info->bmiColors[0].rgbGreen = GetGValue( color );
239 info->bmiColors[0].rgbBlue = GetBValue( color );
240 info->bmiColors[0].rgbReserved = 0;
242 info->bmiHeader.biClrUsed = count;
245 /***********************************************************************
246 * null driver fallback implementations
249 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
250 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
252 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
253 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
254 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
255 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
256 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
257 DWORD err;
258 struct gdi_image_bits bits;
260 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
261 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
262 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
264 release_dc_ptr( dc_src );
265 return FALSE;
268 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
269 copy_bitmapinfo( dst_info, src_info );
270 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
271 if (err == ERROR_BAD_FORMAT)
273 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
275 /* 1-bpp source without a color table uses the destination DC colors */
276 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
277 get_mono_dc_colors( dst_dev->hdc, src_info, 2 );
279 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
281 /* 1-bpp destination without a color table requires a fake 1-entry table
282 * that contains only the background color; except with a 1-bpp source,
283 * in which case it uses the source colors */
284 if (src_info->bmiHeader.biBitCount > 1)
285 get_mono_dc_colors( src_dev->hdc, dst_info, 1 );
286 else
287 get_mono_dc_colors( src_dev->hdc, dst_info, 2 );
290 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
292 /* get rid of the fake destination table */
293 dst_info->bmiHeader.biClrUsed = dst_colors;
294 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
298 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
299 ((src->width != dst->width) || (src->height != dst->height)))
301 copy_bitmapinfo( src_info, dst_info );
302 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
303 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
306 if (bits.free) bits.free( &bits );
307 release_dc_ptr( dc_src );
308 return !err;
312 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
313 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
315 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
316 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
317 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
318 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
319 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
320 DWORD err;
321 struct gdi_image_bits bits;
323 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
324 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
325 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
326 if (err) goto done;
328 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
329 copy_bitmapinfo( dst_info, src_info );
330 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
331 if (err == ERROR_BAD_FORMAT)
333 err = convert_bits( src_info, src, dst_info, &bits );
334 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
337 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
338 ((src->width != dst->width) || (src->height != dst->height)))
340 copy_bitmapinfo( src_info, dst_info );
341 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
342 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
345 if (bits.free) bits.free( &bits );
346 done:
347 release_dc_ptr( dc_src );
348 if (err) SetLastError( err );
349 return !err;
353 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
354 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
356 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
357 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
358 struct gdi_image_bits dst_bits;
359 struct bitblt_coords orig_dst;
360 DWORD *masks = (DWORD *)info->bmiColors;
361 DC *dc = get_nulldrv_dc( dev );
362 DWORD err;
364 if (info->bmiHeader.biPlanes != 1) goto update_format;
365 if (info->bmiHeader.biBitCount != 32) goto update_format;
366 if (info->bmiHeader.biCompression == BI_BITFIELDS)
368 if (blend.AlphaFormat & AC_SRC_ALPHA) return ERROR_INVALID_PARAMETER;
369 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
370 goto update_format;
373 if (!bits) return ERROR_SUCCESS;
374 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
376 dev = GET_DC_PHYSDEV( dc, pGetImage );
377 orig_dst = *dst;
378 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
379 if (err) return err;
381 dev = GET_DC_PHYSDEV( dc, pPutImage );
382 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
383 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
385 if (dst_bits.free) dst_bits.free( &dst_bits );
386 return err;
388 update_format:
389 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
390 return ERROR_INVALID_PARAMETER;
392 info->bmiHeader.biPlanes = 1;
393 info->bmiHeader.biBitCount = 32;
394 info->bmiHeader.biCompression = BI_BITFIELDS;
395 info->bmiHeader.biClrUsed = 0;
396 masks[0] = 0xff0000;
397 masks[1] = 0x00ff00;
398 masks[2] = 0x0000ff;
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 = FALSE;
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 reset_bounds( &dst.visrect );
426 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
428 ULONG v = ((ULONG *)grad_array)[i];
429 dst.visrect.left = min( dst.visrect.left, pts[v].x );
430 dst.visrect.top = min( dst.visrect.top, pts[v].y );
431 dst.visrect.right = max( dst.visrect.right, pts[v].x );
432 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
435 dst.x = dst.visrect.left;
436 dst.y = dst.visrect.top;
437 dst.width = dst.visrect.right - dst.visrect.left;
438 dst.height = dst.visrect.bottom - dst.visrect.top;
439 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
441 /* query the bitmap format */
442 info->bmiHeader.biSize = sizeof(info->bmiHeader);
443 info->bmiHeader.biPlanes = 1;
444 info->bmiHeader.biBitCount = 0;
445 info->bmiHeader.biCompression = BI_RGB;
446 info->bmiHeader.biXPelsPerMeter = 0;
447 info->bmiHeader.biYPelsPerMeter = 0;
448 info->bmiHeader.biClrUsed = 0;
449 info->bmiHeader.biClrImportant = 0;
450 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
451 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
452 info->bmiHeader.biSizeImage = 0;
453 dev = GET_DC_PHYSDEV( dc, pPutImage );
454 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
455 if (err && err != ERROR_BAD_FORMAT) goto done;
457 info->bmiHeader.biSizeImage = get_dib_image_size( info );
458 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
459 goto done;
460 bits.is_copy = TRUE;
461 bits.free = free_heap_bits;
463 /* make src and points relative to the bitmap */
464 src = dst;
465 src.x -= dst.visrect.left;
466 src.y -= dst.visrect.top;
467 offset_rect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
468 for (i = 0; i < nvert; i++)
470 pts[i].x -= dst.visrect.left;
471 pts[i].y -= dst.visrect.top;
474 rgn = CreateRectRgn( 0, 0, 0, 0 );
475 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
476 OffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
477 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
479 if (bits.free) bits.free( &bits );
480 DeleteObject( rgn );
482 done:
483 HeapFree( GetProcessHeap(), 0, pts );
484 return ret;
487 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
489 DC *dc = get_nulldrv_dc( dev );
490 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
491 BITMAPINFO *info = (BITMAPINFO *)buffer;
492 struct bitblt_coords src;
493 struct gdi_image_bits bits;
494 COLORREF ret;
496 src.visrect.left = x;
497 src.visrect.top = y;
498 LPtoDP( dev->hdc, (POINT *)&src.visrect, 1 );
499 src.visrect.right = src.visrect.left + 1;
500 src.visrect.bottom = src.visrect.top + 1;
501 src.x = src.visrect.left;
502 src.y = src.visrect.top;
503 src.width = src.height = 1;
505 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
507 dev = GET_DC_PHYSDEV( dc, pGetImage );
508 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
510 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
511 if (bits.free) bits.free( &bits );
512 return ret;
516 /***********************************************************************
517 * PatBlt (GDI32.@)
519 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
521 DC * dc;
522 BOOL ret = FALSE;
524 if (rop_uses_src( rop )) return FALSE;
525 if ((dc = get_dc_ptr( hdc )))
527 struct bitblt_coords dst;
529 update_dc( dc );
531 dst.log_x = left;
532 dst.log_y = top;
533 dst.log_width = width;
534 dst.log_height = height;
535 dst.layout = dc->layout;
536 if (rop & NOMIRRORBITMAP)
538 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
539 rop &= ~NOMIRRORBITMAP;
541 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
543 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
544 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
545 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
547 if (!ret)
549 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
550 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
552 release_dc_ptr( dc );
554 return ret;
558 /***********************************************************************
559 * BitBlt (GDI32.@)
561 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
562 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
564 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
565 else return StretchBlt( hdcDst, xDst, yDst, width, height,
566 hdcSrc, xSrc, ySrc, width, height, rop );
570 /***********************************************************************
571 * StretchBlt (GDI32.@)
573 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
574 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
576 BOOL ret = FALSE;
577 DC *dcDst, *dcSrc;
579 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
581 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
583 if ((dcSrc = get_dc_ptr( hdcSrc )))
585 struct bitblt_coords src, dst;
587 update_dc( dcSrc );
588 update_dc( dcDst );
590 src.log_x = xSrc;
591 src.log_y = ySrc;
592 src.log_width = widthSrc;
593 src.log_height = heightSrc;
594 src.layout = dcSrc->layout;
595 dst.log_x = xDst;
596 dst.log_y = yDst;
597 dst.log_width = widthDst;
598 dst.log_height = heightDst;
599 dst.layout = dcDst->layout;
600 if (rop & NOMIRRORBITMAP)
602 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
603 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
604 rop &= ~NOMIRRORBITMAP;
606 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
608 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",
609 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
610 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
611 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
612 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
614 if (!ret)
616 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
617 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
618 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
620 release_dc_ptr( dcSrc );
622 release_dc_ptr( dcDst );
623 return ret;
626 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
627 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
629 /***********************************************************************
630 * MaskBlt [GDI32.@]
632 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
633 INT nWidth, INT nHeight, HDC hdcSrc,
634 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
635 INT xMask, INT yMask, DWORD dwRop)
637 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
638 HDC hDC1, hDC2;
639 HBRUSH hbrMask, hbrDst, hbrTmp;
641 static const DWORD ROP3Table[256] =
643 0x00000042, 0x00010289,
644 0x00020C89, 0x000300AA,
645 0x00040C88, 0x000500A9,
646 0x00060865, 0x000702C5,
647 0x00080F08, 0x00090245,
648 0x000A0329, 0x000B0B2A,
649 0x000C0324, 0x000D0B25,
650 0x000E08A5, 0x000F0001,
651 0x00100C85, 0x001100A6,
652 0x00120868, 0x001302C8,
653 0x00140869, 0x001502C9,
654 0x00165CCA, 0x00171D54,
655 0x00180D59, 0x00191CC8,
656 0x001A06C5, 0x001B0768,
657 0x001C06CA, 0x001D0766,
658 0x001E01A5, 0x001F0385,
659 0x00200F09, 0x00210248,
660 0x00220326, 0x00230B24,
661 0x00240D55, 0x00251CC5,
662 0x002606C8, 0x00271868,
663 0x00280369, 0x002916CA,
664 0x002A0CC9, 0x002B1D58,
665 0x002C0784, 0x002D060A,
666 0x002E064A, 0x002F0E2A,
667 0x0030032A, 0x00310B28,
668 0x00320688, 0x00330008,
669 0x003406C4, 0x00351864,
670 0x003601A8, 0x00370388,
671 0x0038078A, 0x00390604,
672 0x003A0644, 0x003B0E24,
673 0x003C004A, 0x003D18A4,
674 0x003E1B24, 0x003F00EA,
675 0x00400F0A, 0x00410249,
676 0x00420D5D, 0x00431CC4,
677 0x00440328, 0x00450B29,
678 0x004606C6, 0x0047076A,
679 0x00480368, 0x004916C5,
680 0x004A0789, 0x004B0605,
681 0x004C0CC8, 0x004D1954,
682 0x004E0645, 0x004F0E25,
683 0x00500325, 0x00510B26,
684 0x005206C9, 0x00530764,
685 0x005408A9, 0x00550009,
686 0x005601A9, 0x00570389,
687 0x00580785, 0x00590609,
688 0x005A0049, 0x005B18A9,
689 0x005C0649, 0x005D0E29,
690 0x005E1B29, 0x005F00E9,
691 0x00600365, 0x006116C6,
692 0x00620786, 0x00630608,
693 0x00640788, 0x00650606,
694 0x00660046, 0x006718A8,
695 0x006858A6, 0x00690145,
696 0x006A01E9, 0x006B178A,
697 0x006C01E8, 0x006D1785,
698 0x006E1E28, 0x006F0C65,
699 0x00700CC5, 0x00711D5C,
700 0x00720648, 0x00730E28,
701 0x00740646, 0x00750E26,
702 0x00761B28, 0x007700E6,
703 0x007801E5, 0x00791786,
704 0x007A1E29, 0x007B0C68,
705 0x007C1E24, 0x007D0C69,
706 0x007E0955, 0x007F03C9,
707 0x008003E9, 0x00810975,
708 0x00820C49, 0x00831E04,
709 0x00840C48, 0x00851E05,
710 0x008617A6, 0x008701C5,
711 0x008800C6, 0x00891B08,
712 0x008A0E06, 0x008B0666,
713 0x008C0E08, 0x008D0668,
714 0x008E1D7C, 0x008F0CE5,
715 0x00900C45, 0x00911E08,
716 0x009217A9, 0x009301C4,
717 0x009417AA, 0x009501C9,
718 0x00960169, 0x0097588A,
719 0x00981888, 0x00990066,
720 0x009A0709, 0x009B07A8,
721 0x009C0704, 0x009D07A6,
722 0x009E16E6, 0x009F0345,
723 0x00A000C9, 0x00A11B05,
724 0x00A20E09, 0x00A30669,
725 0x00A41885, 0x00A50065,
726 0x00A60706, 0x00A707A5,
727 0x00A803A9, 0x00A90189,
728 0x00AA0029, 0x00AB0889,
729 0x00AC0744, 0x00AD06E9,
730 0x00AE0B06, 0x00AF0229,
731 0x00B00E05, 0x00B10665,
732 0x00B21974, 0x00B30CE8,
733 0x00B4070A, 0x00B507A9,
734 0x00B616E9, 0x00B70348,
735 0x00B8074A, 0x00B906E6,
736 0x00BA0B09, 0x00BB0226,
737 0x00BC1CE4, 0x00BD0D7D,
738 0x00BE0269, 0x00BF08C9,
739 0x00C000CA, 0x00C11B04,
740 0x00C21884, 0x00C3006A,
741 0x00C40E04, 0x00C50664,
742 0x00C60708, 0x00C707AA,
743 0x00C803A8, 0x00C90184,
744 0x00CA0749, 0x00CB06E4,
745 0x00CC0020, 0x00CD0888,
746 0x00CE0B08, 0x00CF0224,
747 0x00D00E0A, 0x00D1066A,
748 0x00D20705, 0x00D307A4,
749 0x00D41D78, 0x00D50CE9,
750 0x00D616EA, 0x00D70349,
751 0x00D80745, 0x00D906E8,
752 0x00DA1CE9, 0x00DB0D75,
753 0x00DC0B04, 0x00DD0228,
754 0x00DE0268, 0x00DF08C8,
755 0x00E003A5, 0x00E10185,
756 0x00E20746, 0x00E306EA,
757 0x00E40748, 0x00E506E5,
758 0x00E61CE8, 0x00E70D79,
759 0x00E81D74, 0x00E95CE6,
760 0x00EA02E9, 0x00EB0849,
761 0x00EC02E8, 0x00ED0848,
762 0x00EE0086, 0x00EF0A08,
763 0x00F00021, 0x00F10885,
764 0x00F20B05, 0x00F3022A,
765 0x00F40B0A, 0x00F50225,
766 0x00F60265, 0x00F708C5,
767 0x00F802E5, 0x00F90845,
768 0x00FA0089, 0x00FB0A09,
769 0x00FC008A, 0x00FD0A0A,
770 0x00FE02A9, 0x00FF0062,
773 if (!hbmMask)
774 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
776 hbrMask = CreatePatternBrush(hbmMask);
777 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
779 /* make bitmap */
780 hDC1 = CreateCompatibleDC(hdcDest);
781 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
782 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
784 /* draw using bkgnd rop */
785 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
786 hbrTmp = SelectObject(hDC1, hbrDst);
787 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
788 SelectObject(hDC1, hbrTmp);
790 /* make bitmap */
791 hDC2 = CreateCompatibleDC(hdcDest);
792 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
793 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
795 /* draw using foregnd rop */
796 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
797 hbrTmp = SelectObject(hDC2, hbrDst);
798 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
800 /* combine both using the mask as a pattern brush */
801 SelectObject(hDC2, hbrMask);
802 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
803 SelectObject(hDC2, hbrTmp);
805 /* blit to dst */
806 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
808 /* restore all objects */
809 SelectObject(hdcDest, hbrDst);
810 SelectObject(hDC1, hOldBitmap1);
811 SelectObject(hDC2, hOldBitmap2);
813 /* delete all temp objects */
814 DeleteObject(hBitmap1);
815 DeleteObject(hBitmap2);
816 DeleteObject(hbrMask);
818 DeleteDC(hDC1);
819 DeleteDC(hDC2);
821 return TRUE;
824 /******************************************************************************
825 * GdiTransparentBlt [GDI32.@]
827 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
828 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
829 UINT crTransparent )
831 BOOL ret = FALSE;
832 HDC hdcWork;
833 HBITMAP bmpWork;
834 HGDIOBJ oldWork;
835 HDC hdcMask = NULL;
836 HBITMAP bmpMask = NULL;
837 HBITMAP oldMask = NULL;
838 COLORREF oldBackground;
839 COLORREF oldForeground;
840 int oldStretchMode;
842 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
843 TRACE("Cannot mirror\n");
844 return FALSE;
847 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
848 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
850 /* Stretch bitmap */
851 oldStretchMode = GetStretchBltMode(hdcSrc);
852 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
853 SetStretchBltMode(hdcSrc, COLORONCOLOR);
854 hdcWork = CreateCompatibleDC(hdcDest);
855 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
856 oldWork = SelectObject(hdcWork, bmpWork);
857 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
858 TRACE("Failed to stretch\n");
859 goto error;
861 SetBkColor(hdcWork, crTransparent);
863 /* Create mask */
864 hdcMask = CreateCompatibleDC(hdcDest);
865 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
866 oldMask = SelectObject(hdcMask, bmpMask);
867 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
868 TRACE("Failed to create mask\n");
869 goto error;
872 /* Replace transparent color with black */
873 SetBkColor(hdcWork, RGB(0,0,0));
874 SetTextColor(hdcWork, RGB(255,255,255));
875 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
876 TRACE("Failed to mask out background\n");
877 goto error;
880 /* Replace non-transparent area on destination with black */
881 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
882 TRACE("Failed to clear destination area\n");
883 goto error;
886 /* Draw the image */
887 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
888 TRACE("Failed to paint image\n");
889 goto error;
892 ret = TRUE;
893 error:
894 SetStretchBltMode(hdcSrc, oldStretchMode);
895 SetBkColor(hdcDest, oldBackground);
896 SetTextColor(hdcDest, oldForeground);
897 if(hdcWork) {
898 SelectObject(hdcWork, oldWork);
899 DeleteDC(hdcWork);
901 if(bmpWork) DeleteObject(bmpWork);
902 if(hdcMask) {
903 SelectObject(hdcMask, oldMask);
904 DeleteDC(hdcMask);
906 if(bmpMask) DeleteObject(bmpMask);
907 return ret;
910 /******************************************************************************
911 * GdiAlphaBlend [GDI32.@]
913 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
914 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
915 BLENDFUNCTION blendFunction)
917 BOOL ret = FALSE;
918 DC *dcDst, *dcSrc;
920 dcSrc = get_dc_ptr( hdcSrc );
921 if (!dcSrc) return FALSE;
923 if ((dcDst = get_dc_ptr( hdcDst )))
925 struct bitblt_coords src, dst;
927 update_dc( dcSrc );
928 update_dc( dcDst );
930 src.log_x = xSrc;
931 src.log_y = ySrc;
932 src.log_width = widthSrc;
933 src.log_height = heightSrc;
934 src.layout = GetLayout( hdcSrc );
935 dst.log_x = xDst;
936 dst.log_y = yDst;
937 dst.log_width = widthDst;
938 dst.log_height = heightDst;
939 dst.layout = GetLayout( hdcDst );
940 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
942 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",
943 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
944 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
945 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
946 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
947 blendFunction.BlendOp, blendFunction.BlendFlags,
948 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
950 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
951 src.log_width < 0 || src.log_height < 0 ||
952 (!is_rect_empty( &dcSrc->device_rect ) &&
953 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
954 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
956 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
957 SetLastError( ERROR_INVALID_PARAMETER );
958 ret = FALSE;
960 else if (dst.log_width < 0 || dst.log_height < 0)
962 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
963 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
964 SetLastError( ERROR_INVALID_PARAMETER );
965 ret = FALSE;
967 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
968 src.y + src.height > dst.y && src.y < dst.y + dst.height)
970 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
971 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
972 SetLastError( ERROR_INVALID_PARAMETER );
973 ret = FALSE;
975 else if (!ret)
977 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
978 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
979 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
981 release_dc_ptr( dcDst );
983 release_dc_ptr( dcSrc );
984 return ret;
987 /*********************************************************************
988 * PlgBlt [GDI32.@]
991 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
992 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
993 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
995 int oldgMode;
996 /* parallelogram coords */
997 POINT plg[3];
998 /* rect coords */
999 POINT rect[3];
1000 XFORM xf;
1001 XFORM SrcXf;
1002 XFORM oldDestXf;
1003 double det;
1005 /* save actual mode, set GM_ADVANCED */
1006 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1007 if (oldgMode == 0)
1008 return FALSE;
1010 memcpy(plg,lpPoint,sizeof(POINT)*3);
1011 rect[0].x = nXSrc;
1012 rect[0].y = nYSrc;
1013 rect[1].x = nXSrc + nWidth;
1014 rect[1].y = nYSrc;
1015 rect[2].x = nXSrc;
1016 rect[2].y = nYSrc + nHeight;
1017 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1018 /* determinant */
1019 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);
1021 if (fabs(det) < 1e-5)
1023 SetGraphicsMode(hdcDest,oldgMode);
1024 return FALSE;
1027 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1028 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1030 /* X components */
1031 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;
1032 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;
1033 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1034 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1035 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1036 ) / det;
1038 /* Y components */
1039 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;
1040 xf.eM22 = (rect[1].x*(plg[2].y - plg[0].y) - rect[2].x*(plg[1].y - plg[0].y) - rect[0].x*(plg[2].y - plg[1].y)) / det;
1041 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1042 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1043 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1044 ) / det;
1046 GetWorldTransform(hdcSrc,&SrcXf);
1047 CombineTransform(&xf,&xf,&SrcXf);
1049 /* save actual dest transform */
1050 GetWorldTransform(hdcDest,&oldDestXf);
1052 SetWorldTransform(hdcDest,&xf);
1053 /* now destination and source DCs use same coords */
1054 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1055 hdcSrc, nXSrc,nYSrc,
1056 hbmMask,xMask,yMask,
1057 SRCCOPY);
1058 /* restore dest DC */
1059 SetWorldTransform(hdcDest,&oldDestXf);
1060 SetGraphicsMode(hdcDest,oldgMode);
1062 return TRUE;