2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "gdi_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
38 static inline BOOL rop_uses_src( DWORD rop )
40 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
43 static inline void swap_ints( int *i, int *j )
50 BOOL intersect_vis_rectangles( struct bitblt_coords *dst, struct bitblt_coords *src )
54 /* intersect the rectangles */
56 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
58 offset_rect( &src->visrect, dst->x - src->x, dst->y - src->y );
59 intersect_rect( &rect, &src->visrect, &dst->visrect );
60 src->visrect = dst->visrect = rect;
61 offset_rect( &src->visrect, src->x - dst->x, src->y - dst->y );
65 /* map source rectangle into destination coordinates */
67 offset_rect( &rect, -min( src->x, src->x + src->width + 1),
68 -min( src->y, src->y + src->height + 1) );
69 rect.left = dst->x + rect.left * dst->width / abs(src->width);
70 rect.top = dst->y + rect.top * dst->height / abs(src->height);
71 rect.right = dst->x + rect.right * dst->width / abs(src->width);
72 rect.bottom = dst->y + rect.bottom * dst->height / abs(src->height);
73 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
74 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
76 /* avoid rounding errors */
81 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
83 /* map destination rectangle back to source coordinates */
85 offset_rect( &rect, -min( dst->x, dst->x + dst->width + 1),
86 -min( dst->y, dst->y + dst->height + 1) );
87 rect.left = src->x + rect.left * src->width / abs(dst->width);
88 rect.top = src->y + rect.top * src->height / abs(dst->height);
89 rect.right = src->x + rect.right * src->width / abs(dst->width);
90 rect.bottom = src->y + rect.bottom * src->height / abs(dst->height);
91 if (rect.left > rect.right) swap_ints( &rect.left, &rect.right );
92 if (rect.top > rect.bottom) swap_ints( &rect.top, &rect.bottom );
94 /* avoid rounding errors */
99 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
104 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
105 DC *dc_src, struct bitblt_coords *src )
109 /* get the destination visible rectangle */
111 rect.left = dst->log_x;
112 rect.top = dst->log_y;
113 rect.right = dst->log_x + dst->log_width;
114 rect.bottom = dst->log_y + dst->log_height;
115 LPtoDP( dc_dst->hSelf, (POINT *)&rect, 2 );
118 dst->width = rect.right - rect.left;
119 dst->height = rect.bottom - rect.top;
120 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
122 dst->x += dst->width;
123 dst->width = -dst->width;
125 get_bounding_rect( &rect, dst->x, dst->y, dst->width, dst->height );
127 if (get_clip_box( dc_dst, &clip ))
128 intersect_rect( &dst->visrect, &rect, &clip );
132 /* get the source visible rectangle */
134 if (!src) return !is_rect_empty( &dst->visrect );
136 rect.left = src->log_x;
137 rect.top = src->log_y;
138 rect.right = src->log_x + src->log_width;
139 rect.bottom = src->log_y + src->log_height;
140 LPtoDP( dc_src->hSelf, (POINT *)&rect, 2 );
143 src->width = rect.right - rect.left;
144 src->height = rect.bottom - rect.top;
145 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
147 src->x += src->width;
148 src->width = -src->width;
150 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
152 /* source is not clipped */
153 if (dc_src->header.type == OBJ_MEMDC)
154 intersect_rect( &src->visrect, &rect, &dc_src->vis_rect );
156 src->visrect = rect; /* FIXME: clip to device size */
158 if (is_rect_empty( &src->visrect )) return FALSE;
159 if (is_rect_empty( &dst->visrect )) return FALSE;
161 return intersect_vis_rectangles( dst, src );
164 void free_heap_bits( struct gdi_image_bits *bits )
166 HeapFree( GetProcessHeap(), 0, bits->ptr );
169 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
170 BITMAPINFO *dst_info, struct gdi_image_bits *bits, BOOL add_alpha )
175 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
176 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
177 return ERROR_OUTOFMEMORY;
179 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, add_alpha );
180 if (bits->free) bits->free( bits );
182 bits->is_copy = TRUE;
183 bits->free = free_heap_bits;
187 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
188 BITMAPINFO *dst_info, struct bitblt_coords *dst,
189 struct gdi_image_bits *bits, int mode )
194 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
195 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
196 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
197 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( dst_info ))))
198 return ERROR_OUTOFMEMORY;
200 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
201 if (bits->free) bits->free( bits );
203 bits->is_copy = TRUE;
204 bits->free = free_heap_bits;
208 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
209 struct bitblt_coords *src, BITMAPINFO *dst_info,
210 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
212 if (!dst_bits->is_copy)
214 int size = get_dib_image_size( dst_info );
215 void *ptr = HeapAlloc( GetProcessHeap(), 0, size );
216 if (!ptr) return ERROR_OUTOFMEMORY;
217 memcpy( ptr, dst_bits->ptr, size );
218 if (dst_bits->free) dst_bits->free( dst_bits );
220 dst_bits->is_copy = TRUE;
221 dst_bits->free = free_heap_bits;
223 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
226 /***********************************************************************
227 * null driver fallback implementations
230 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
231 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
233 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
234 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
235 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
236 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
237 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
239 struct gdi_image_bits bits;
241 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
242 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
243 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
244 release_dc_ptr( dc_src );
245 if (err) return FALSE;
247 /* 1-bpp source without a color table uses the destination DC colors */
248 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
250 COLORREF color = GetTextColor( dst_dev->hdc );
251 src_info->bmiColors[0].rgbRed = GetRValue( color );
252 src_info->bmiColors[0].rgbGreen = GetGValue( color );
253 src_info->bmiColors[0].rgbBlue = GetBValue( color );
254 src_info->bmiColors[0].rgbReserved = 0;
255 color = GetBkColor( dst_dev->hdc );
256 src_info->bmiColors[1].rgbRed = GetRValue( color );
257 src_info->bmiColors[1].rgbGreen = GetGValue( color );
258 src_info->bmiColors[1].rgbBlue = GetBValue( color );
259 src_info->bmiColors[1].rgbReserved = 0;
260 src_info->bmiHeader.biClrUsed = 2;
263 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
264 copy_bitmapinfo( dst_info, src_info );
265 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
266 if (err == ERROR_BAD_FORMAT)
268 /* 1-bpp destination without a color table requires a fake 1-entry table
269 * that contains only the background color */
270 if (dst_info->bmiHeader.biBitCount == 1 && !dst_info->bmiHeader.biClrUsed)
272 COLORREF color = GetBkColor( src_dev->hdc );
273 dst_info->bmiColors[0].rgbRed = GetRValue( color );
274 dst_info->bmiColors[0].rgbGreen = GetGValue( color );
275 dst_info->bmiColors[0].rgbBlue = GetBValue( color );
276 dst_info->bmiColors[0].rgbReserved = 0;
277 dst_info->bmiHeader.biClrUsed = 1;
280 if (!(err = convert_bits( src_info, src, dst_info, &bits, FALSE )))
282 /* get rid of the fake 1-bpp table */
283 if (dst_info->bmiHeader.biClrUsed == 1) dst_info->bmiHeader.biClrUsed = 0;
284 err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
288 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
289 ((src->width != dst->width) || (src->height != dst->height)))
291 copy_bitmapinfo( src_info, dst_info );
292 err = stretch_bits( src_info, src, dst_info, dst, &bits, GetStretchBltMode( dst_dev->hdc ));
293 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, 0, dst_info, &bits, src, dst, rop );
296 if (bits.free) bits.free( &bits );
301 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
302 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
304 DC *dc_src, *dc_dst = get_nulldrv_dc( dst_dev );
305 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
306 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
307 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
308 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
310 struct gdi_image_bits bits;
312 if (!(dc_src = get_dc_ptr( src_dev->hdc ))) return FALSE;
313 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
314 err = src_dev->funcs->pGetImage( src_dev, 0, src_info, &bits, src );
315 release_dc_ptr( dc_src );
318 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
319 copy_bitmapinfo( dst_info, src_info );
320 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
321 if (err == ERROR_BAD_FORMAT)
323 /* 1-bpp source without a color table uses black & white */
324 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
326 src_info->bmiColors[0].rgbRed = 0;
327 src_info->bmiColors[0].rgbGreen = 0;
328 src_info->bmiColors[0].rgbBlue = 0;
329 src_info->bmiColors[0].rgbReserved = 0;
330 src_info->bmiColors[1].rgbRed = 0xff;
331 src_info->bmiColors[1].rgbGreen = 0xff;
332 src_info->bmiColors[1].rgbBlue = 0xff;
333 src_info->bmiColors[1].rgbReserved = 0;
334 src_info->bmiHeader.biClrUsed = 2;
337 err = convert_bits( src_info, src, dst_info, &bits, TRUE );
338 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
341 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
342 ((src->width != dst->width) || (src->height != dst->height)))
344 copy_bitmapinfo( src_info, dst_info );
345 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
346 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
349 if (bits.free) bits.free( &bits );
351 if (err) SetLastError( err );
356 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
357 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
359 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
360 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
361 struct gdi_image_bits dst_bits;
362 struct bitblt_coords orig_dst;
363 DC *dc = get_nulldrv_dc( dev );
366 if (info->bmiHeader.biPlanes != 1) goto update_format;
367 if (info->bmiHeader.biBitCount != 32) goto update_format;
368 if (info->bmiHeader.biCompression == BI_BITFIELDS)
370 DWORD *masks = (DWORD *)info->bmiColors;
371 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
375 if (!bits) return ERROR_SUCCESS;
376 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
378 dev = GET_DC_PHYSDEV( dc, pGetImage );
380 err = dev->funcs->pGetImage( dev, 0, dst_info, &dst_bits, dst );
383 dev = GET_DC_PHYSDEV( dc, pPutImage );
384 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
385 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
387 if (dst_bits.free) dst_bits.free( &dst_bits );
391 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
392 return ERROR_INVALID_PARAMETER;
394 info->bmiHeader.biPlanes = 1;
395 info->bmiHeader.biBitCount = 32;
396 info->bmiHeader.biCompression = BI_RGB;
397 info->bmiHeader.biClrUsed = 0;
398 return ERROR_BAD_FORMAT;
401 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
402 void * grad_array, ULONG ngrad, ULONG mode )
404 DC *dc = get_nulldrv_dc( dev );
405 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
406 BITMAPINFO *info = (BITMAPINFO *)buffer;
407 struct bitblt_coords src, dst;
408 struct gdi_image_bits bits;
414 case GRADIENT_FILL_RECT_H:
415 case GRADIENT_FILL_RECT_V:
417 const GRADIENT_RECT *rect = grad_array;
420 for (i = 0; i < ngrad; i++, rect++)
422 v[0] = vert_array[rect->UpperLeft];
423 v[1] = vert_array[rect->LowerRight];
427 dst.log_width = v[1].x - v[0].x;
428 dst.log_height = v[1].y - v[0].y;
429 dst.layout = dc->layout;
430 if (!get_vis_rectangles( dc, &dst, NULL, NULL )) continue;
434 if (mode == GRADIENT_FILL_RECT_H) /* swap the colors */
436 v[0] = vert_array[rect->LowerRight];
437 v[1] = vert_array[rect->UpperLeft];
439 dst.x += dst.width + 1;
440 dst.width = -dst.width;
444 if (mode == GRADIENT_FILL_RECT_V) /* swap the colors */
446 v[0] = vert_array[rect->LowerRight];
447 v[1] = vert_array[rect->UpperLeft];
449 dst.y += dst.height + 1;
450 dst.height = -dst.height;
453 /* query the bitmap format */
454 info->bmiHeader.biSize = sizeof(info->bmiHeader);
455 info->bmiHeader.biPlanes = 1;
456 info->bmiHeader.biBitCount = 0;
457 info->bmiHeader.biCompression = BI_RGB;
458 info->bmiHeader.biXPelsPerMeter = 0;
459 info->bmiHeader.biYPelsPerMeter = 0;
460 info->bmiHeader.biClrUsed = 0;
461 info->bmiHeader.biClrImportant = 0;
462 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
463 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
464 info->bmiHeader.biSizeImage = 0;
465 dev = GET_DC_PHYSDEV( dc, pPutImage );
466 err = dev->funcs->pPutImage( dev, 0, 0, info, NULL, NULL, NULL, 0 );
467 if (!err || err == ERROR_BAD_FORMAT)
469 if (!(bits.ptr = HeapAlloc( GetProcessHeap(), 0, get_dib_image_size( info ))))
472 bits.free = free_heap_bits;
474 /* make src relative to the bitmap */
476 src.x -= src.visrect.left;
477 src.y -= src.visrect.top;
478 offset_rect( &src.visrect, -src.visrect.left, -src.visrect.top );
481 v[1].x = src.x + src.width;
482 v[1].y = src.y + src.height;
483 err = gradient_bitmapinfo( info, bits.ptr, v, mode );
485 if (!err) err = dev->funcs->pPutImage( dev, 0, 0, info, &bits, &src, &dst, SRCCOPY );
486 if (bits.free) bits.free( &bits );
488 if (err) return FALSE;
492 case GRADIENT_FILL_TRIANGLE:
493 for (i = 0; i < ngrad; i++)
495 GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
496 TRIVERTEX *v1 = vert_array + tri->Vertex1;
497 TRIVERTEX *v2 = vert_array + tri->Vertex2;
498 TRIVERTEX *v3 = vert_array + tri->Vertex3;
502 { TRIVERTEX *t = v1; v1 = v2; v2 = t; }
505 TRIVERTEX *t = v2; v2 = v3; v3 = t;
507 { t = v1; v1 = v2; v2 = t; }
509 /* v1->y <= v2->y <= v3->y */
512 for (y = 0; y < dy; y++)
514 /* v1->y <= y < v3->y */
515 TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
516 /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
517 int dy2 = v2->y - v->y;
518 int y2 = y + v1->y - v->y;
520 int x1 = (v3->x * y + v1->x * (dy - y )) / dy;
521 int x2 = (v2->x * y2 + v-> x * (dy2 - y2)) / dy2;
522 int r1 = (v3->Red * y + v1->Red * (dy - y )) / dy;
523 int r2 = (v2->Red * y2 + v-> Red * (dy2 - y2)) / dy2;
524 int g1 = (v3->Green * y + v1->Green * (dy - y )) / dy;
525 int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
526 int b1 = (v3->Blue * y + v1->Blue * (dy - y )) / dy;
527 int b2 = (v2->Blue * y2 + v-> Blue * (dy2 - y2)) / dy2;
533 for (x = 0; x < dx; x++)
534 SetPixel (dev->hdc, x + x1, y + v1->y, RGB(
535 (r1 * (dx - x) + r2 * x) / dx >> 8,
536 (g1 * (dx - x) + g2 * x) / dx >> 8,
537 (b1 * (dx - x) + b2 * x) / dx >> 8));
542 for (x = 0; x < dx; x++)
543 SetPixel (dev->hdc, x + x2, y + v1->y, RGB(
544 (r2 * (dx - x) + r1 * x) / dx >> 8,
545 (g2 * (dx - x) + g1 * x) / dx >> 8,
546 (b2 * (dx - x) + b1 * x) / dx >> 8));
558 /***********************************************************************
561 BOOL WINAPI PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop)
566 if (rop_uses_src( rop )) return FALSE;
567 if ((dc = get_dc_ptr( hdc )))
569 struct bitblt_coords dst;
570 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
576 dst.log_width = width;
577 dst.log_height = height;
578 dst.layout = dc->layout;
579 if (rop & NOMIRRORBITMAP)
581 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
582 rop &= ~NOMIRRORBITMAP;
584 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
586 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
587 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
588 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
590 if (!ret) ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
592 release_dc_ptr( dc );
598 /***********************************************************************
601 BOOL WINAPI BitBlt( HDC hdcDst, INT xDst, INT yDst, INT width,
602 INT height, HDC hdcSrc, INT xSrc, INT ySrc, DWORD rop )
604 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, width, height, rop );
605 else return StretchBlt( hdcDst, xDst, yDst, width, height,
606 hdcSrc, xSrc, ySrc, width, height, rop );
610 /***********************************************************************
611 * StretchBlt (GDI32.@)
613 BOOL WINAPI StretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
614 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, DWORD rop )
619 if (!rop_uses_src( rop )) return PatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
621 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
623 if ((dcSrc = get_dc_ptr( hdcSrc )))
625 struct bitblt_coords src, dst;
626 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
627 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
634 src.log_width = widthSrc;
635 src.log_height = heightSrc;
636 src.layout = dcSrc->layout;
639 dst.log_width = widthDst;
640 dst.log_height = heightDst;
641 dst.layout = dcDst->layout;
642 if (rop & NOMIRRORBITMAP)
644 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
645 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
646 rop &= ~NOMIRRORBITMAP;
648 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
650 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",
651 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
652 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
653 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
654 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), rop );
656 if (!ret) ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
657 release_dc_ptr( dcSrc );
659 release_dc_ptr( dcDst );
663 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
664 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
666 /***********************************************************************
669 BOOL WINAPI MaskBlt(HDC hdcDest, INT nXDest, INT nYDest,
670 INT nWidth, INT nHeight, HDC hdcSrc,
671 INT nXSrc, INT nYSrc, HBITMAP hbmMask,
672 INT xMask, INT yMask, DWORD dwRop)
674 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
676 HBRUSH hbrMask, hbrDst, hbrTmp;
678 static const DWORD ROP3Table[256] =
680 0x00000042, 0x00010289,
681 0x00020C89, 0x000300AA,
682 0x00040C88, 0x000500A9,
683 0x00060865, 0x000702C5,
684 0x00080F08, 0x00090245,
685 0x000A0329, 0x000B0B2A,
686 0x000C0324, 0x000D0B25,
687 0x000E08A5, 0x000F0001,
688 0x00100C85, 0x001100A6,
689 0x00120868, 0x001302C8,
690 0x00140869, 0x001502C9,
691 0x00165CCA, 0x00171D54,
692 0x00180D59, 0x00191CC8,
693 0x001A06C5, 0x001B0768,
694 0x001C06CA, 0x001D0766,
695 0x001E01A5, 0x001F0385,
696 0x00200F09, 0x00210248,
697 0x00220326, 0x00230B24,
698 0x00240D55, 0x00251CC5,
699 0x002606C8, 0x00271868,
700 0x00280369, 0x002916CA,
701 0x002A0CC9, 0x002B1D58,
702 0x002C0784, 0x002D060A,
703 0x002E064A, 0x002F0E2A,
704 0x0030032A, 0x00310B28,
705 0x00320688, 0x00330008,
706 0x003406C4, 0x00351864,
707 0x003601A8, 0x00370388,
708 0x0038078A, 0x00390604,
709 0x003A0644, 0x003B0E24,
710 0x003C004A, 0x003D18A4,
711 0x003E1B24, 0x003F00EA,
712 0x00400F0A, 0x00410249,
713 0x00420D5D, 0x00431CC4,
714 0x00440328, 0x00450B29,
715 0x004606C6, 0x0047076A,
716 0x00480368, 0x004916C5,
717 0x004A0789, 0x004B0605,
718 0x004C0CC8, 0x004D1954,
719 0x004E0645, 0x004F0E25,
720 0x00500325, 0x00510B26,
721 0x005206C9, 0x00530764,
722 0x005408A9, 0x00550009,
723 0x005601A9, 0x00570389,
724 0x00580785, 0x00590609,
725 0x005A0049, 0x005B18A9,
726 0x005C0649, 0x005D0E29,
727 0x005E1B29, 0x005F00E9,
728 0x00600365, 0x006116C6,
729 0x00620786, 0x00630608,
730 0x00640788, 0x00650606,
731 0x00660046, 0x006718A8,
732 0x006858A6, 0x00690145,
733 0x006A01E9, 0x006B178A,
734 0x006C01E8, 0x006D1785,
735 0x006E1E28, 0x006F0C65,
736 0x00700CC5, 0x00711D5C,
737 0x00720648, 0x00730E28,
738 0x00740646, 0x00750E26,
739 0x00761B28, 0x007700E6,
740 0x007801E5, 0x00791786,
741 0x007A1E29, 0x007B0C68,
742 0x007C1E24, 0x007D0C69,
743 0x007E0955, 0x007F03C9,
744 0x008003E9, 0x00810975,
745 0x00820C49, 0x00831E04,
746 0x00840C48, 0x00851E05,
747 0x008617A6, 0x008701C5,
748 0x008800C6, 0x00891B08,
749 0x008A0E06, 0x008B0666,
750 0x008C0E08, 0x008D0668,
751 0x008E1D7C, 0x008F0CE5,
752 0x00900C45, 0x00911E08,
753 0x009217A9, 0x009301C4,
754 0x009417AA, 0x009501C9,
755 0x00960169, 0x0097588A,
756 0x00981888, 0x00990066,
757 0x009A0709, 0x009B07A8,
758 0x009C0704, 0x009D07A6,
759 0x009E16E6, 0x009F0345,
760 0x00A000C9, 0x00A11B05,
761 0x00A20E09, 0x00A30669,
762 0x00A41885, 0x00A50065,
763 0x00A60706, 0x00A707A5,
764 0x00A803A9, 0x00A90189,
765 0x00AA0029, 0x00AB0889,
766 0x00AC0744, 0x00AD06E9,
767 0x00AE0B06, 0x00AF0229,
768 0x00B00E05, 0x00B10665,
769 0x00B21974, 0x00B30CE8,
770 0x00B4070A, 0x00B507A9,
771 0x00B616E9, 0x00B70348,
772 0x00B8074A, 0x00B906E6,
773 0x00BA0B09, 0x00BB0226,
774 0x00BC1CE4, 0x00BD0D7D,
775 0x00BE0269, 0x00BF08C9,
776 0x00C000CA, 0x00C11B04,
777 0x00C21884, 0x00C3006A,
778 0x00C40E04, 0x00C50664,
779 0x00C60708, 0x00C707AA,
780 0x00C803A8, 0x00C90184,
781 0x00CA0749, 0x00CB06E4,
782 0x00CC0020, 0x00CD0888,
783 0x00CE0B08, 0x00CF0224,
784 0x00D00E0A, 0x00D1066A,
785 0x00D20705, 0x00D307A4,
786 0x00D41D78, 0x00D50CE9,
787 0x00D616EA, 0x00D70349,
788 0x00D80745, 0x00D906E8,
789 0x00DA1CE9, 0x00DB0D75,
790 0x00DC0B04, 0x00DD0228,
791 0x00DE0268, 0x00DF08C8,
792 0x00E003A5, 0x00E10185,
793 0x00E20746, 0x00E306EA,
794 0x00E40748, 0x00E506E5,
795 0x00E61CE8, 0x00E70D79,
796 0x00E81D74, 0x00E95CE6,
797 0x00EA02E9, 0x00EB0849,
798 0x00EC02E8, 0x00ED0848,
799 0x00EE0086, 0x00EF0A08,
800 0x00F00021, 0x00F10885,
801 0x00F20B05, 0x00F3022A,
802 0x00F40B0A, 0x00F50225,
803 0x00F60265, 0x00F708C5,
804 0x00F802E5, 0x00F90845,
805 0x00FA0089, 0x00FB0A09,
806 0x00FC008A, 0x00FD0A0A,
807 0x00FE02A9, 0x00FF0062,
811 return BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
813 hbrMask = CreatePatternBrush(hbmMask);
814 hbrDst = SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
817 hDC1 = CreateCompatibleDC(hdcDest);
818 hBitmap1 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
819 hOldBitmap1 = SelectObject(hDC1, hBitmap1);
821 /* draw using bkgnd rop */
822 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
823 hbrTmp = SelectObject(hDC1, hbrDst);
824 BitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop));
825 SelectObject(hDC1, hbrTmp);
828 hDC2 = CreateCompatibleDC(hdcDest);
829 hBitmap2 = CreateCompatibleBitmap(hdcDest, nWidth, nHeight);
830 hOldBitmap2 = SelectObject(hDC2, hBitmap2);
832 /* draw using foregnd rop */
833 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY);
834 hbrTmp = SelectObject(hDC2, hbrDst);
835 BitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop));
837 /* combine both using the mask as a pattern brush */
838 SelectObject(hDC2, hbrMask);
839 BitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744 ); /* (D & P) | (S & ~P) */
840 SelectObject(hDC2, hbrTmp);
843 BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY);
845 /* restore all objects */
846 SelectObject(hdcDest, hbrDst);
847 SelectObject(hDC1, hOldBitmap1);
848 SelectObject(hDC2, hOldBitmap2);
850 /* delete all temp objects */
851 DeleteObject(hBitmap1);
852 DeleteObject(hBitmap2);
853 DeleteObject(hbrMask);
861 /******************************************************************************
862 * GdiTransparentBlt [GDI32.@]
864 BOOL WINAPI GdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
865 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
873 HBITMAP bmpMask = NULL;
874 HBITMAP oldMask = NULL;
875 COLORREF oldBackground;
876 COLORREF oldForeground;
879 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
880 TRACE("Cannot mirror\n");
884 oldBackground = SetBkColor(hdcDest, RGB(255,255,255));
885 oldForeground = SetTextColor(hdcDest, RGB(0,0,0));
888 oldStretchMode = GetStretchBltMode(hdcSrc);
889 if(oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
890 SetStretchBltMode(hdcSrc, COLORONCOLOR);
891 hdcWork = CreateCompatibleDC(hdcDest);
892 bmpWork = CreateCompatibleBitmap(hdcDest, widthDest, heightDest);
893 oldWork = SelectObject(hdcWork, bmpWork);
894 if(!StretchBlt(hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc, widthSrc, heightSrc, SRCCOPY)) {
895 TRACE("Failed to stretch\n");
898 SetBkColor(hdcWork, crTransparent);
901 hdcMask = CreateCompatibleDC(hdcDest);
902 bmpMask = CreateCompatibleBitmap(hdcMask, widthDest, heightDest);
903 oldMask = SelectObject(hdcMask, bmpMask);
904 if(!BitBlt(hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY)) {
905 TRACE("Failed to create mask\n");
909 /* Replace transparent color with black */
910 SetBkColor(hdcWork, RGB(0,0,0));
911 SetTextColor(hdcWork, RGB(255,255,255));
912 if(!BitBlt(hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
913 TRACE("Failed to mask out background\n");
917 /* Replace non-transparent area on destination with black */
918 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND)) {
919 TRACE("Failed to clear destination area\n");
924 if(!BitBlt(hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT)) {
925 TRACE("Failed to paint image\n");
931 SetStretchBltMode(hdcSrc, oldStretchMode);
932 SetBkColor(hdcDest, oldBackground);
933 SetTextColor(hdcDest, oldForeground);
935 SelectObject(hdcWork, oldWork);
938 if(bmpWork) DeleteObject(bmpWork);
940 SelectObject(hdcMask, oldMask);
943 if(bmpMask) DeleteObject(bmpMask);
947 /******************************************************************************
948 * GdiAlphaBlend [GDI32.@]
950 BOOL WINAPI GdiAlphaBlend(HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
951 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
952 BLENDFUNCTION blendFunction)
957 dcSrc = get_dc_ptr( hdcSrc );
958 if (!dcSrc) return FALSE;
960 if ((dcDst = get_dc_ptr( hdcDst )))
962 struct bitblt_coords src, dst;
963 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
964 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
971 src.log_width = widthSrc;
972 src.log_height = heightSrc;
973 src.layout = GetLayout( src_dev->hdc );
976 dst.log_width = widthDst;
977 dst.log_height = heightDst;
978 dst.layout = GetLayout( dst_dev->hdc );
979 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
981 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",
982 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
983 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
984 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
985 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
986 blendFunction.BlendOp, blendFunction.BlendFlags,
987 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
989 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
990 (dcSrc->header.type == OBJ_MEMDC &&
991 (src.width > dcSrc->vis_rect.right - dcSrc->vis_rect.left - src.x ||
992 src.height > dcSrc->vis_rect.bottom - dcSrc->vis_rect.top - src.y)))
994 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
995 SetLastError( ERROR_INVALID_PARAMETER );
998 else if (dst.width < 0 || dst.height < 0)
1000 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n", dst.x, dst.y, dst.width, dst.height );
1001 SetLastError( ERROR_INVALID_PARAMETER );
1004 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
1005 src.y + src.height > dst.y && src.y < dst.y + dst.height)
1007 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
1008 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
1009 SetLastError( ERROR_INVALID_PARAMETER );
1012 else if (!ret) ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
1014 release_dc_ptr( dcDst );
1016 release_dc_ptr( dcSrc );
1020 /*********************************************************************
1024 BOOL WINAPI PlgBlt( HDC hdcDest, const POINT *lpPoint,
1025 HDC hdcSrc, INT nXSrc, INT nYSrc, INT nWidth,
1026 INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask)
1029 /* parallelogram coords */
1038 /* save actual mode, set GM_ADVANCED */
1039 oldgMode = SetGraphicsMode(hdcDest,GM_ADVANCED);
1043 memcpy(plg,lpPoint,sizeof(POINT)*3);
1046 rect[1].x = nXSrc + nWidth;
1049 rect[2].y = nYSrc + nHeight;
1050 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1052 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);
1054 if (fabs(det) < 1e-5)
1056 SetGraphicsMode(hdcDest,oldgMode);
1060 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1061 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest, plg[0].x, plg[0].y, plg[1].x, plg[1].y, plg[2].x, plg[2].y);
1064 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;
1065 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;
1066 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1067 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1068 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1072 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;
1073 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;
1074 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1075 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1076 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1079 GetWorldTransform(hdcSrc,&SrcXf);
1080 CombineTransform(&xf,&xf,&SrcXf);
1082 /* save actual dest transform */
1083 GetWorldTransform(hdcDest,&oldDestXf);
1085 SetWorldTransform(hdcDest,&xf);
1086 /* now destination and source DCs use same coords */
1087 MaskBlt(hdcDest,nXSrc,nYSrc,nWidth,nHeight,
1088 hdcSrc, nXSrc,nYSrc,
1089 hbmMask,xMask,yMask,
1091 /* restore dest DC */
1092 SetWorldTransform(hdcDest,&oldDestXf);
1093 SetGraphicsMode(hdcDest,oldgMode);