webservices: Return HRESULT from insert_string.
[wine.git] / dlls / gdi32 / bitblt.c
blob1b057f729de3fb083b77aea74333197b99e58e52
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 lp_to_dp( dc_dst, (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 lp_to_dp( dc_src, (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 static RGBQUAD get_dc_rgb_color( DC *dc, int color_table_size, COLORREF color )
226 RGBQUAD ret = { 0, 0, 0, 0 };
228 if (color & (1 << 24)) /* PALETTEINDEX */
230 PALETTEENTRY pal;
232 if (!GetPaletteEntries( dc->hPalette, LOWORD(color), 1, &pal ))
233 GetPaletteEntries( dc->hPalette, 0, 1, &pal );
234 ret.rgbRed = pal.peRed;
235 ret.rgbGreen = pal.peGreen;
236 ret.rgbBlue = pal.peBlue;
237 return ret;
239 if (color >> 16 == 0x10ff) /* DIBINDEX */
241 if (color_table_size)
243 if (LOWORD(color) >= color_table_size) color = 0x10ff0000; /* fallback to index 0 */
244 *(DWORD *)&ret = color;
246 return ret;
248 ret.rgbRed = GetRValue( color );
249 ret.rgbGreen = GetGValue( color );
250 ret.rgbBlue = GetBValue( color );
251 return ret;
254 /* helper to retrieve either both colors or only the background color for monochrome blits */
255 void get_mono_dc_colors( DC *dc, int color_table_size, BITMAPINFO *info, int count )
257 info->bmiColors[count - 1] = get_dc_rgb_color( dc, color_table_size, dc->backgroundColor );
258 if (count > 1) info->bmiColors[0] = get_dc_rgb_color( dc, color_table_size, dc->textColor );
259 info->bmiHeader.biClrUsed = count;
262 /***********************************************************************
263 * null driver fallback implementations
266 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
267 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
269 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
270 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
271 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
272 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
273 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
274 DWORD err;
275 struct gdi_image_bits bits;
277 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
278 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
279 return FALSE;
281 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
282 copy_bitmapinfo( dst_info, src_info );
283 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
284 if (err == ERROR_BAD_FORMAT)
286 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
288 /* 1-bpp source without a color table uses the destination DC colors */
289 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
290 get_mono_dc_colors( dc_dst, dst_info->bmiHeader.biClrUsed, src_info, 2 );
292 /* 1-bpp destination without a color table requires a fake 1-entry table
293 * that contains only the background color */
294 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
295 get_mono_dc_colors( dc_src, src_info->bmiHeader.biClrUsed, dst_info, 1 );
297 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
299 /* get rid of the fake destination table */
300 dst_info->bmiHeader.biClrUsed = dst_colors;
301 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
305 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
306 ((src->width != dst->width) || (src->height != dst->height)))
308 copy_bitmapinfo( src_info, dst_info );
309 err = stretch_bits( src_info, src, dst_info, dst, &bits, dc_dst->stretchBltMode );
310 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
313 if (bits.free) bits.free( &bits );
314 return !err;
318 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
319 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
321 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
322 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
323 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
324 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
325 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
326 DWORD err;
327 struct gdi_image_bits bits;
329 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
330 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
331 if (err) goto done;
333 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
334 copy_bitmapinfo( dst_info, src_info );
335 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
336 if (err == ERROR_BAD_FORMAT)
338 err = convert_bits( src_info, src, dst_info, &bits );
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 DWORD *masks = (DWORD *)info->bmiColors;
365 DC *dc = get_nulldrv_dc( dev );
366 DWORD err;
368 if (info->bmiHeader.biPlanes != 1) goto update_format;
369 if (info->bmiHeader.biBitCount != 32) goto update_format;
370 if (info->bmiHeader.biCompression == BI_BITFIELDS)
372 if (blend.AlphaFormat & AC_SRC_ALPHA) return ERROR_INVALID_PARAMETER;
373 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
374 goto update_format;
377 if (!bits) return ERROR_SUCCESS;
378 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
380 dev = GET_DC_PHYSDEV( dc, pGetImage );
381 orig_dst = *dst;
382 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
383 if (err) return err;
385 dev = GET_DC_PHYSDEV( dc, pPutImage );
386 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
387 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
389 if (dst_bits.free) dst_bits.free( &dst_bits );
390 return err;
392 update_format:
393 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
394 return ERROR_INVALID_PARAMETER;
396 info->bmiHeader.biPlanes = 1;
397 info->bmiHeader.biBitCount = 32;
398 info->bmiHeader.biCompression = BI_BITFIELDS;
399 info->bmiHeader.biClrUsed = 0;
400 masks[0] = 0xff0000;
401 masks[1] = 0x00ff00;
402 masks[2] = 0x0000ff;
403 return ERROR_BAD_FORMAT;
406 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
407 void * grad_array, ULONG ngrad, ULONG mode )
409 DC *dc = get_nulldrv_dc( dev );
410 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
411 BITMAPINFO *info = (BITMAPINFO *)buffer;
412 struct bitblt_coords src, dst;
413 struct gdi_image_bits bits;
414 unsigned int i;
415 POINT *pts;
416 BOOL ret = FALSE;
417 DWORD err;
418 HRGN rgn;
420 if (!(pts = HeapAlloc( GetProcessHeap(), 0, nvert * sizeof(*pts) ))) return FALSE;
421 for (i = 0; i < nvert; i++)
423 pts[i].x = vert_array[i].x;
424 pts[i].y = vert_array[i].y;
426 lp_to_dp( dc, pts, nvert );
428 /* compute bounding rect of all the rectangles/triangles */
429 reset_bounds( &dst.visrect );
430 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
432 ULONG v = ((ULONG *)grad_array)[i];
433 dst.visrect.left = min( dst.visrect.left, pts[v].x );
434 dst.visrect.top = min( dst.visrect.top, pts[v].y );
435 dst.visrect.right = max( dst.visrect.right, pts[v].x );
436 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
439 dst.x = dst.visrect.left;
440 dst.y = dst.visrect.top;
441 dst.width = dst.visrect.right - dst.visrect.left;
442 dst.height = dst.visrect.bottom - dst.visrect.top;
443 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
445 /* query the bitmap format */
446 info->bmiHeader.biSize = sizeof(info->bmiHeader);
447 info->bmiHeader.biPlanes = 1;
448 info->bmiHeader.biBitCount = 0;
449 info->bmiHeader.biCompression = BI_RGB;
450 info->bmiHeader.biXPelsPerMeter = 0;
451 info->bmiHeader.biYPelsPerMeter = 0;
452 info->bmiHeader.biClrUsed = 0;
453 info->bmiHeader.biClrImportant = 0;
454 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
455 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
456 info->bmiHeader.biSizeImage = 0;
457 dev = GET_DC_PHYSDEV( dc, pPutImage );
458 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
459 if (err && err != ERROR_BAD_FORMAT) goto done;
461 info->bmiHeader.biSizeImage = get_dib_image_size( info );
462 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage )))
463 goto done;
464 bits.is_copy = TRUE;
465 bits.free = free_heap_bits;
467 /* make src and points relative to the bitmap */
468 src = dst;
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 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
483 if (bits.free) bits.free( &bits );
484 DeleteObject( rgn );
486 done:
487 HeapFree( GetProcessHeap(), 0, pts );
488 return ret;
491 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
493 DC *dc = get_nulldrv_dc( dev );
494 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
495 BITMAPINFO *info = (BITMAPINFO *)buffer;
496 struct bitblt_coords src;
497 struct gdi_image_bits bits;
498 COLORREF ret;
500 src.visrect.left = x;
501 src.visrect.top = y;
502 lp_to_dp( dc, (POINT *)&src.visrect, 1 );
503 src.visrect.right = src.visrect.left + 1;
504 src.visrect.bottom = src.visrect.top + 1;
505 src.x = src.visrect.left;
506 src.y = src.visrect.top;
507 src.width = src.height = 1;
509 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
511 dev = GET_DC_PHYSDEV( dc, pGetImage );
512 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
514 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
515 if (bits.free) bits.free( &bits );
516 return ret;
520 /***********************************************************************
521 * PatBlt (GDI32.@)
523 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
525 DC * dc;
526 BOOL ret = FALSE;
528 if (rop_uses_src( rop )) return FALSE;
529 if ((dc = get_dc_ptr( hdc )))
531 struct bitblt_coords dst;
533 update_dc( dc );
535 dst.log_x = left;
536 dst.log_y = top;
537 dst.log_width = width;
538 dst.log_height = height;
539 dst.layout = dc->layout;
540 if (rop & NOMIRRORBITMAP)
542 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
543 rop &= ~NOMIRRORBITMAP;
545 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
547 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
548 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
549 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
551 if (!ret)
553 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
554 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
556 release_dc_ptr( dc );
558 return ret;
562 /***********************************************************************
563 * BitBlt (GDI32.@)
565 BOOL WINAPI DECLSPEC_HOTPATCH BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
566 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
568 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
569 else return StretchBlt( hdcDst, xDst, yDst, width, height,
570 hdcSrc, xSrc, ySrc, width, height, rop );
574 /***********************************************************************
575 * StretchBlt (GDI32.@)
577 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
578 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
580 BOOL ret = FALSE;
581 DC *dcDst, *dcSrc;
583 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
585 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
587 if ((dcSrc = get_dc_ptr( hdcSrc )))
589 struct bitblt_coords src, dst;
591 update_dc( dcSrc );
592 update_dc( dcDst );
594 src.log_x = xSrc;
595 src.log_y = ySrc;
596 src.log_width = widthSrc;
597 src.log_height = heightSrc;
598 src.layout = dcSrc->layout;
599 dst.log_x = xDst;
600 dst.log_y = yDst;
601 dst.log_width = widthDst;
602 dst.log_height = heightDst;
603 dst.layout = dcDst->layout;
604 if (rop & NOMIRRORBITMAP)
606 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
607 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
608 rop &= ~NOMIRRORBITMAP;
610 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
612 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",
613 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
614 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
615 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
616 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
618 if (!ret)
620 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
621 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
622 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
624 release_dc_ptr( dcSrc );
626 release_dc_ptr( dcDst );
627 return ret;
630 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
631 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
633 /***********************************************************************
634 * MaskBlt [GDI32.@]
636 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
637 INT nWidth, INT nHeight, HDC hdcSrc,
638 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
639 INT xMask, INT yMask, DWORD dwRop)
641 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
642 HDC hDC1, hDC2;
643 HBRUSH hbrMask, hbrDst, hbrTmp;
645 static const DWORD ROP3Table[256] =
647 0x00000042, 0x00010289,
648 0x00020C89, 0x000300AA,
649 0x00040C88, 0x000500A9,
650 0x00060865, 0x000702C5,
651 0x00080F08, 0x00090245,
652 0x000A0329, 0x000B0B2A,
653 0x000C0324, 0x000D0B25,
654 0x000E08A5, 0x000F0001,
655 0x00100C85, 0x001100A6,
656 0x00120868, 0x001302C8,
657 0x00140869, 0x001502C9,
658 0x00165CCA, 0x00171D54,
659 0x00180D59, 0x00191CC8,
660 0x001A06C5, 0x001B0768,
661 0x001C06CA, 0x001D0766,
662 0x001E01A5, 0x001F0385,
663 0x00200F09, 0x00210248,
664 0x00220326, 0x00230B24,
665 0x00240D55, 0x00251CC5,
666 0x002606C8, 0x00271868,
667 0x00280369, 0x002916CA,
668 0x002A0CC9, 0x002B1D58,
669 0x002C0784, 0x002D060A,
670 0x002E064A, 0x002F0E2A,
671 0x0030032A, 0x00310B28,
672 0x00320688, 0x00330008,
673 0x003406C4, 0x00351864,
674 0x003601A8, 0x00370388,
675 0x0038078A, 0x00390604,
676 0x003A0644, 0x003B0E24,
677 0x003C004A, 0x003D18A4,
678 0x003E1B24, 0x003F00EA,
679 0x00400F0A, 0x00410249,
680 0x00420D5D, 0x00431CC4,
681 0x00440328, 0x00450B29,
682 0x004606C6, 0x0047076A,
683 0x00480368, 0x004916C5,
684 0x004A0789, 0x004B0605,
685 0x004C0CC8, 0x004D1954,
686 0x004E0645, 0x004F0E25,
687 0x00500325, 0x00510B26,
688 0x005206C9, 0x00530764,
689 0x005408A9, 0x00550009,
690 0x005601A9, 0x00570389,
691 0x00580785, 0x00590609,
692 0x005A0049, 0x005B18A9,
693 0x005C0649, 0x005D0E29,
694 0x005E1B29, 0x005F00E9,
695 0x00600365, 0x006116C6,
696 0x00620786, 0x00630608,
697 0x00640788, 0x00650606,
698 0x00660046, 0x006718A8,
699 0x006858A6, 0x00690145,
700 0x006A01E9, 0x006B178A,
701 0x006C01E8, 0x006D1785,
702 0x006E1E28, 0x006F0C65,
703 0x00700CC5, 0x00711D5C,
704 0x00720648, 0x00730E28,
705 0x00740646, 0x00750E26,
706 0x00761B28, 0x007700E6,
707 0x007801E5, 0x00791786,
708 0x007A1E29, 0x007B0C68,
709 0x007C1E24, 0x007D0C69,
710 0x007E0955, 0x007F03C9,
711 0x008003E9, 0x00810975,
712 0x00820C49, 0x00831E04,
713 0x00840C48, 0x00851E05,
714 0x008617A6, 0x008701C5,
715 0x008800C6, 0x00891B08,
716 0x008A0E06, 0x008B0666,
717 0x008C0E08, 0x008D0668,
718 0x008E1D7C, 0x008F0CE5,
719 0x00900C45, 0x00911E08,
720 0x009217A9, 0x009301C4,
721 0x009417AA, 0x009501C9,
722 0x00960169, 0x0097588A,
723 0x00981888, 0x00990066,
724 0x009A0709, 0x009B07A8,
725 0x009C0704, 0x009D07A6,
726 0x009E16E6, 0x009F0345,
727 0x00A000C9, 0x00A11B05,
728 0x00A20E09, 0x00A30669,
729 0x00A41885, 0x00A50065,
730 0x00A60706, 0x00A707A5,
731 0x00A803A9, 0x00A90189,
732 0x00AA0029, 0x00AB0889,
733 0x00AC0744, 0x00AD06E9,
734 0x00AE0B06, 0x00AF0229,
735 0x00B00E05, 0x00B10665,
736 0x00B21974, 0x00B30CE8,
737 0x00B4070A, 0x00B507A9,
738 0x00B616E9, 0x00B70348,
739 0x00B8074A, 0x00B906E6,
740 0x00BA0B09, 0x00BB0226,
741 0x00BC1CE4, 0x00BD0D7D,
742 0x00BE0269, 0x00BF08C9,
743 0x00C000CA, 0x00C11B04,
744 0x00C21884, 0x00C3006A,
745 0x00C40E04, 0x00C50664,
746 0x00C60708, 0x00C707AA,
747 0x00C803A8, 0x00C90184,
748 0x00CA0749, 0x00CB06E4,
749 0x00CC0020, 0x00CD0888,
750 0x00CE0B08, 0x00CF0224,
751 0x00D00E0A, 0x00D1066A,
752 0x00D20705, 0x00D307A4,
753 0x00D41D78, 0x00D50CE9,
754 0x00D616EA, 0x00D70349,
755 0x00D80745, 0x00D906E8,
756 0x00DA1CE9, 0x00DB0D75,
757 0x00DC0B04, 0x00DD0228,
758 0x00DE0268, 0x00DF08C8,
759 0x00E003A5, 0x00E10185,
760 0x00E20746, 0x00E306EA,
761 0x00E40748, 0x00E506E5,
762 0x00E61CE8, 0x00E70D79,
763 0x00E81D74, 0x00E95CE6,
764 0x00EA02E9, 0x00EB0849,
765 0x00EC02E8, 0x00ED0848,
766 0x00EE0086, 0x00EF0A08,
767 0x00F00021, 0x00F10885,
768 0x00F20B05, 0x00F3022A,
769 0x00F40B0A, 0x00F50225,
770 0x00F60265, 0x00F708C5,
771 0x00F802E5, 0x00F90845,
772 0x00FA0089, 0x00FB0A09,
773 0x00FC008A, 0x00FD0A0A,
774 0x00FE02A9, 0x00FF0062,
777 if (!hbmMask)
778 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
780 hbrMask = CreatePatternBrush(hbmMask);
781 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
783 /* make bitmap */
784 hDC1 = CreateCompatibleDC(hdcDest);
785 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
786 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
788 /* draw using bkgnd rop */
789 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
790 hbrTmp = SelectObject(hDC1, hbrDst);
791 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
792 SelectObject(hDC1, hbrTmp);
794 /* make bitmap */
795 hDC2 = CreateCompatibleDC(hdcDest);
796 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
797 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
799 /* draw using foregnd rop */
800 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
801 hbrTmp = SelectObject(hDC2, hbrDst);
802 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
804 /* combine both using the mask as a pattern brush */
805 SelectObject(hDC2, hbrMask);
806 SetBrushOrgEx(hDC2, -xMask, -yMask, NULL);
807 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
808 SelectObject(hDC2, hbrTmp);
810 /* blit to dst */
811 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
813 /* restore all objects */
814 SelectObject(hdcDest, hbrDst);
815 SelectObject(hDC1, hOldBitmap1);
816 SelectObject(hDC2, hOldBitmap2);
818 /* delete all temp objects */
819 DeleteObject(hBitmap1);
820 DeleteObject(hBitmap2);
821 DeleteObject(hbrMask);
823 DeleteDC(hDC1);
824 DeleteDC(hDC2);
826 return TRUE;
829 /******************************************************************************
830 * GdiTransparentBlt [GDI32.@]
832 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
833 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
834 UINT crTransparent )
836 BOOL ret = FALSE;
837 HDC hdcWork;
838 HBITMAP bmpWork;
839 HGDIOBJ oldWork;
840 HDC hdcMask = NULL;
841 HBITMAP bmpMask = NULL;
842 HBITMAP oldMask = NULL;
843 COLORREF oldBackground;
844 COLORREF oldForeground;
845 int oldStretchMode;
847 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
848 TRACE("Cannot mirror\n");
849 return FALSE;
852 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
853 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
855 /* Stretch bitmap */
856 oldStretchMode = GetStretchBltMode(hdcSrc);
857 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
858 SetStretchBltMode(hdcSrc, COLORONCOLOR);
859 hdcWork = CreateCompatibleDC(hdcDest);
860 if (GetObjectType( hdcDest ) != OBJ_MEMDC && GetDeviceCaps( hdcDest, BITSPIXEL ) == 32)
862 /* screen DCs are not supposed to have an alpha channel, so use a 24-bpp bitmap as copy */
863 BITMAPINFO info;
864 info.bmiHeader.biSize = sizeof(info.bmiHeader);
865 info.bmiHeader.biWidth = widthDest;
866 info.bmiHeader.biHeight = heightDest;
867 info.bmiHeader.biPlanes = 1;
868 info.bmiHeader.biBitCount = 24;
869 info.bmiHeader.biCompression = BI_RGB;
870 bmpWork = CreateDIBSection( 0, &info, DIB_RGB_COLORS, NULL, NULL, 0 );
872 else bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
873 oldWork = SelectObject(hdcWork, bmpWork);
874 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
875 TRACE("Failed to stretch\n");
876 goto error;
878 SetBkColor(hdcWork, crTransparent);
880 /* Create mask */
881 hdcMask = CreateCompatibleDC(hdcDest);
882 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
883 oldMask = SelectObject(hdcMask, bmpMask);
884 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
885 TRACE("Failed to create mask\n");
886 goto error;
889 /* Replace transparent color with black */
890 SetBkColor(hdcWork, RGB(0,0,0));
891 SetTextColor(hdcWork, RGB(255,255,255));
892 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
893 TRACE("Failed to mask out background\n");
894 goto error;
897 /* Replace non-transparent area on destination with black */
898 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
899 TRACE("Failed to clear destination area\n");
900 goto error;
903 /* Draw the image */
904 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
905 TRACE("Failed to paint image\n");
906 goto error;
909 ret = TRUE;
910 error:
911 SetStretchBltMode(hdcSrc, oldStretchMode);
912 SetBkColor(hdcDest, oldBackground);
913 SetTextColor(hdcDest, oldForeground);
914 if(hdcWork) {
915 SelectObject(hdcWork, oldWork);
916 DeleteDC(hdcWork);
918 if(bmpWork) DeleteObject(bmpWork);
919 if(hdcMask) {
920 SelectObject(hdcMask, oldMask);
921 DeleteDC(hdcMask);
923 if(bmpMask) DeleteObject(bmpMask);
924 return ret;
927 /******************************************************************************
928 * GdiAlphaBlend [GDI32.@]
930 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
931 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
932 BLENDFUNCTION blendFunction)
934 BOOL ret = FALSE;
935 DC *dcDst, *dcSrc;
937 dcSrc = get_dc_ptr( hdcSrc );
938 if (!dcSrc) return FALSE;
940 if ((dcDst = get_dc_ptr( hdcDst )))
942 struct bitblt_coords src, dst;
944 update_dc( dcSrc );
945 update_dc( dcDst );
947 src.log_x = xSrc;
948 src.log_y = ySrc;
949 src.log_width = widthSrc;
950 src.log_height = heightSrc;
951 src.layout = dcSrc->layout;
952 dst.log_x = xDst;
953 dst.log_y = yDst;
954 dst.log_width = widthDst;
955 dst.log_height = heightDst;
956 dst.layout = dcDst->layout;
957 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
959 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",
960 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
961 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
962 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
963 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
964 blendFunction.BlendOp, blendFunction.BlendFlags,
965 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
967 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
968 src.log_width < 0 || src.log_height < 0 ||
969 (!is_rect_empty( &dcSrc->device_rect ) &&
970 (src.width > dcSrc->device_rect.right - dcSrc->vis_rect.left - src.x ||
971 src.height > dcSrc->device_rect.bottom - dcSrc->vis_rect.top - src.y)))
973 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
974 SetLastError( ERROR_INVALID_PARAMETER );
975 ret = FALSE;
977 else if (dst.log_width < 0 || dst.log_height < 0)
979 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
980 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
981 SetLastError( ERROR_INVALID_PARAMETER );
982 ret = FALSE;
984 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
985 src.y + src.height > dst.y && src.y < dst.y + dst.height)
987 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
988 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
989 SetLastError( ERROR_INVALID_PARAMETER );
990 ret = FALSE;
992 else if (!ret)
994 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
995 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
996 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
998 release_dc_ptr( dcDst );
1000 release_dc_ptr( dcSrc );
1001 return ret;
1004 /*********************************************************************
1005 * PlgBlt [GDI32.@]
1008 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
1009 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
1010 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
1012 int oldgMode;
1013 /* parallelogram coords */
1014 POINT plg[3];
1015 /* rect coords */
1016 POINT rect[3];
1017 XFORM xf;
1018 XFORM SrcXf;
1019 XFORM oldDestXf;
1020 double det;
1022 /* save actual mode, set GM_ADVANCED */
1023 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1024 if (oldgMode == 0)
1025 return FALSE;
1027 memcpy(plg,lpPoint,sizeof(POINT)*3);
1028 rect[0].x = nXSrc;
1029 rect[0].y = nYSrc;
1030 rect[1].x = nXSrc + nWidth;
1031 rect[1].y = nYSrc;
1032 rect[2].x = nXSrc;
1033 rect[2].y = nYSrc + nHeight;
1034 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1035 /* determinant */
1036 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);
1038 if (fabs(det) < 1e-5)
1040 SetGraphicsMode(hdcDest,oldgMode);
1041 return FALSE;
1044 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1045 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1047 /* X components */
1048 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;
1049 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;
1050 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1051 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1052 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1053 ) / det;
1055 /* Y components */
1056 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;
1057 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;
1058 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1059 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1060 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1061 ) / det;
1063 GetWorldTransform(hdcSrc,&SrcXf);
1064 CombineTransform(&xf,&xf,&SrcXf);
1066 /* save actual dest transform */
1067 GetWorldTransform(hdcDest,&oldDestXf);
1069 SetWorldTransform(hdcDest,&xf);
1070 /* now destination and source DCs use same coords */
1071 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1072 hdcSrc, nXSrc,nYSrc,
1073 hbmMask,xMask,yMask,
1074 SRCCOPY);
1075 /* restore dest DC */
1076 SetWorldTransform(hdcDest,&oldDestXf);
1077 SetGraphicsMode(hdcDest,oldgMode);
1079 return TRUE;