cmd: DIR command outputs free space for the path.
[wine.git] / dlls / win32u / bitblt.c
blob48c76bac676a813cb9ea55e24033c240b56eaa29
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 #if 0
22 #pragma makedep unix
23 #endif
25 #include <stdarg.h>
26 #include <limits.h>
27 #include <math.h>
28 #include <float.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "ntgdi_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 BOOL intersect_vis_rectangles( struct bitblt_coords *dst, struct bitblt_coords *src )
45 RECT rect;
47 /* intersect the rectangles */
49 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
51 OffsetRect( &src->visrect, dst->x - src->x, dst->y - src->y );
52 if (!intersect_rect( &rect, &src->visrect, &dst->visrect )) return FALSE;
53 src->visrect = dst->visrect = rect;
54 OffsetRect( &src->visrect, src->x - dst->x, src->y - dst->y );
56 else /* stretching */
58 /* map source rectangle into destination coordinates */
59 rect = src->visrect;
60 OffsetRect( &rect,
61 -src->x - (src->width < 0 ? 1 : 0),
62 -src->y - (src->height < 0 ? 1 : 0) );
63 rect.left = rect.left * dst->width / src->width;
64 rect.top = rect.top * dst->height / src->height;
65 rect.right = rect.right * dst->width / src->width;
66 rect.bottom = rect.bottom * dst->height / src->height;
67 order_rect( &rect );
69 /* when the source rectangle needs to flip and it doesn't fit in the source device
70 area, the destination area isn't flipped. So, adjust destination coordinates */
71 if (src->width < 0 && dst->width > 0 &&
72 (src->x + src->width + 1 < src->visrect.left || src->x > src->visrect.right))
73 dst->x += (dst->width - rect.right) - rect.left;
74 else if (src->width > 0 && dst->width < 0 &&
75 (src->x < src->visrect.left || src->x + src->width > src->visrect.right))
76 dst->x -= rect.right - (dst->width - rect.left);
78 if (src->height < 0 && dst->height > 0 &&
79 (src->y + src->height + 1 < src->visrect.top || src->y > src->visrect.bottom))
80 dst->y += (dst->height - rect.bottom) - rect.top;
81 else if (src->height > 0 && dst->height < 0 &&
82 (src->y < src->visrect.top || src->y + src->height > src->visrect.bottom))
83 dst->y -= rect.bottom - (dst->height - rect.top);
85 OffsetRect( &rect, dst->x, dst->y );
87 /* avoid rounding errors */
88 rect.left--;
89 rect.top--;
90 rect.right++;
91 rect.bottom++;
92 if (!intersect_rect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
94 /* map destination rectangle back to source coordinates */
95 rect = dst->visrect;
96 OffsetRect( &rect,
97 -dst->x - (dst->width < 0 ? 1 : 0),
98 -dst->y - (dst->height < 0 ? 1 : 0) );
99 rect.left = src->x + rect.left * src->width / dst->width;
100 rect.top = src->y + rect.top * src->height / dst->height;
101 rect.right = src->x + rect.right * src->width / dst->width;
102 rect.bottom = src->y + rect.bottom * src->height / dst->height;
103 order_rect( &rect );
105 /* avoid rounding errors */
106 rect.left--;
107 rect.top--;
108 rect.right++;
109 rect.bottom++;
110 if (!intersect_rect( &src->visrect, &rect, &src->visrect )) return FALSE;
112 return TRUE;
115 static BOOL get_vis_rectangles( DC *dc_dst, struct bitblt_coords *dst,
116 DC *dc_src, struct bitblt_coords *src )
118 RECT rect;
120 /* get the destination visible rectangle */
122 rect.left = dst->log_x;
123 rect.top = dst->log_y;
124 rect.right = dst->log_x + dst->log_width;
125 rect.bottom = dst->log_y + dst->log_height;
126 lp_to_dp( dc_dst, (POINT *)&rect, 2 );
127 dst->x = rect.left;
128 dst->y = rect.top;
129 dst->width = rect.right - rect.left;
130 dst->height = rect.bottom - rect.top;
131 if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
133 dst->x += dst->width;
134 dst->width = -dst->width;
136 get_bounding_rect( &rect, dst->x, dst->y, dst->width, dst->height );
138 clip_visrect( dc_dst, &dst->visrect, &rect );
140 /* get the source visible rectangle */
142 if (!src) return !IsRectEmpty( &dst->visrect );
144 rect.left = src->log_x;
145 rect.top = src->log_y;
146 rect.right = src->log_x + src->log_width;
147 rect.bottom = src->log_y + src->log_height;
148 lp_to_dp( dc_src, (POINT *)&rect, 2 );
149 src->x = rect.left;
150 src->y = rect.top;
151 src->width = rect.right - rect.left;
152 src->height = rect.bottom - rect.top;
153 if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED)
155 src->x += src->width;
156 src->width = -src->width;
158 get_bounding_rect( &rect, src->x, src->y, src->width, src->height );
160 if (!clip_device_rect( dc_src, &src->visrect, &rect )) return FALSE;
161 if (IsRectEmpty( &dst->visrect )) return FALSE;
163 return intersect_vis_rectangles( dst, src );
166 void free_heap_bits( struct gdi_image_bits *bits )
168 free( bits->ptr );
171 DWORD convert_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
172 BITMAPINFO *dst_info, struct gdi_image_bits *bits )
174 void *ptr;
175 DWORD err;
176 BOOL top_down = dst_info->bmiHeader.biHeight < 0;
178 dst_info->bmiHeader.biWidth = src->visrect.right - src->visrect.left;
179 dst_info->bmiHeader.biHeight = src->visrect.bottom - src->visrect.top;
180 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
181 if (top_down) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
183 if (!(ptr = malloc( dst_info->bmiHeader.biSizeImage )))
184 return ERROR_OUTOFMEMORY;
186 err = convert_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr );
187 if (bits->free) bits->free( bits );
188 bits->ptr = ptr;
189 bits->is_copy = TRUE;
190 bits->free = free_heap_bits;
191 return err;
194 DWORD stretch_bits( const BITMAPINFO *src_info, struct bitblt_coords *src,
195 BITMAPINFO *dst_info, struct bitblt_coords *dst,
196 struct gdi_image_bits *bits, int mode )
198 void *ptr;
199 DWORD err;
201 dst_info->bmiHeader.biWidth = dst->visrect.right - dst->visrect.left;
202 dst_info->bmiHeader.biHeight = dst->visrect.bottom - dst->visrect.top;
203 dst_info->bmiHeader.biSizeImage = get_dib_image_size( dst_info );
205 if (src_info->bmiHeader.biHeight < 0) dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
206 if (!(ptr = malloc( dst_info->bmiHeader.biSizeImage )))
207 return ERROR_OUTOFMEMORY;
209 err = stretch_bitmapinfo( src_info, bits->ptr, src, dst_info, ptr, dst, mode );
210 if (bits->free) bits->free( bits );
211 bits->ptr = ptr;
212 bits->is_copy = TRUE;
213 bits->free = free_heap_bits;
214 return err;
217 static DWORD blend_bits( const BITMAPINFO *src_info, const struct gdi_image_bits *src_bits,
218 struct bitblt_coords *src, BITMAPINFO *dst_info,
219 struct gdi_image_bits *dst_bits, struct bitblt_coords *dst, BLENDFUNCTION blend )
221 if (!dst_bits->is_copy)
223 int size = dst_info->bmiHeader.biSizeImage;
224 void *ptr = malloc( size );
225 if (!ptr) return ERROR_OUTOFMEMORY;
226 memcpy( ptr, dst_bits->ptr, size );
227 if (dst_bits->free) dst_bits->free( dst_bits );
228 dst_bits->ptr = ptr;
229 dst_bits->is_copy = TRUE;
230 dst_bits->free = free_heap_bits;
232 return blend_bitmapinfo( src_info, src_bits->ptr, src, dst_info, dst_bits->ptr, dst, blend );
235 static RGBQUAD get_dc_rgb_color( DC *dc, int color_table_size, COLORREF color )
237 RGBQUAD ret = { 0, 0, 0, 0 };
239 if (color & (1 << 24)) /* PALETTEINDEX */
241 PALETTEENTRY pal;
243 if (!get_palette_entries( dc->hPalette, LOWORD(color), 1, &pal ))
244 get_palette_entries( dc->hPalette, 0, 1, &pal );
245 ret.rgbRed = pal.peRed;
246 ret.rgbGreen = pal.peGreen;
247 ret.rgbBlue = pal.peBlue;
248 return ret;
250 if (color >> 16 == 0x10ff) /* DIBINDEX */
252 if (color_table_size)
254 if (LOWORD(color) >= color_table_size) color = 0x10ff0000; /* fallback to index 0 */
255 *(DWORD *)&ret = color;
257 return ret;
259 ret.rgbRed = GetRValue( color );
260 ret.rgbGreen = GetGValue( color );
261 ret.rgbBlue = GetBValue( color );
262 return ret;
265 /* helper to retrieve either both colors or only the background color for monochrome blits */
266 void get_mono_dc_colors( DC *dc, int color_table_size, BITMAPINFO *info, int count )
268 info->bmiColors[count - 1] = get_dc_rgb_color( dc, color_table_size, dc->attr->background_color );
269 if (count > 1) info->bmiColors[0] = get_dc_rgb_color( dc, color_table_size, dc->attr->text_color );
270 info->bmiHeader.biClrUsed = count;
273 /***********************************************************************
274 * null driver fallback implementations
277 BOOL nulldrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
278 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
280 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
281 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
282 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
283 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
284 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
285 DWORD err;
286 struct gdi_image_bits bits;
288 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
289 if (src_dev->funcs->pGetImage( src_dev, src_info, &bits, src ))
290 return FALSE;
292 dst_dev = GET_DC_PHYSDEV( dc_dst, pPutImage );
293 copy_bitmapinfo( dst_info, src_info );
294 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
295 if (err == ERROR_BAD_FORMAT)
297 DWORD dst_colors = dst_info->bmiHeader.biClrUsed;
299 /* 1-bpp source without a color table uses the destination DC colors */
300 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
301 get_mono_dc_colors( dc_dst, dst_info->bmiHeader.biClrUsed, src_info, 2 );
303 /* 1-bpp destination without a color table requires a fake 1-entry table
304 * that contains only the background color */
305 if (dst_info->bmiHeader.biBitCount == 1 && !dst_colors)
306 get_mono_dc_colors( dc_src, src_info->bmiHeader.biClrUsed, dst_info, 1 );
308 if (!(err = convert_bits( src_info, src, dst_info, &bits )))
310 /* get rid of the fake destination table */
311 dst_info->bmiHeader.biClrUsed = dst_colors;
312 err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
316 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
317 ((src->width != dst->width) || (src->height != dst->height)))
319 copy_bitmapinfo( src_info, dst_info );
320 err = stretch_bits( src_info, src, dst_info, dst, &bits, dc_dst->attr->stretch_blt_mode );
321 if (!err) err = dst_dev->funcs->pPutImage( dst_dev, 0, dst_info, &bits, src, dst, rop );
324 if (bits.free) bits.free( &bits );
325 return !err;
329 BOOL nulldrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
330 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION func )
332 DC *dc_src = get_physdev_dc( src_dev ), *dc_dst = get_nulldrv_dc( dst_dev );
333 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
334 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
335 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
336 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
337 DWORD err;
338 struct gdi_image_bits bits;
340 src_dev = GET_DC_PHYSDEV( dc_src, pGetImage );
341 err = src_dev->funcs->pGetImage( src_dev, src_info, &bits, src );
342 if (err) goto done;
344 dst_dev = GET_DC_PHYSDEV( dc_dst, pBlendImage );
345 copy_bitmapinfo( dst_info, src_info );
346 err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
347 if (err == ERROR_BAD_FORMAT)
349 err = convert_bits( src_info, src, dst_info, &bits );
350 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
353 if (err == ERROR_TRANSFORM_NOT_SUPPORTED &&
354 ((src->width != dst->width) || (src->height != dst->height)))
356 copy_bitmapinfo( src_info, dst_info );
357 err = stretch_bits( src_info, src, dst_info, dst, &bits, COLORONCOLOR );
358 if (!err) err = dst_dev->funcs->pBlendImage( dst_dev, dst_info, &bits, src, dst, func );
361 if (bits.free) bits.free( &bits );
362 done:
363 if (err) RtlSetLastWin32Error( err );
364 return !err;
368 DWORD nulldrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const struct gdi_image_bits *bits,
369 struct bitblt_coords *src, struct bitblt_coords *dst, BLENDFUNCTION blend )
371 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
372 BITMAPINFO *dst_info = (BITMAPINFO *)buffer;
373 struct gdi_image_bits dst_bits;
374 struct bitblt_coords orig_dst;
375 DWORD *masks = (DWORD *)info->bmiColors;
376 DC *dc = get_nulldrv_dc( dev );
377 DWORD err;
379 if (info->bmiHeader.biPlanes != 1) goto update_format;
380 if (info->bmiHeader.biBitCount != 32) goto update_format;
381 if (info->bmiHeader.biCompression == BI_BITFIELDS)
383 if (blend.AlphaFormat & AC_SRC_ALPHA) return ERROR_INVALID_PARAMETER;
384 if (masks[0] != 0xff0000 || masks[1] != 0x00ff00 || masks[2] != 0x0000ff)
385 goto update_format;
388 if (!bits) return ERROR_SUCCESS;
389 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
391 dev = GET_DC_PHYSDEV( dc, pGetImage );
392 orig_dst = *dst;
393 err = dev->funcs->pGetImage( dev, dst_info, &dst_bits, dst );
394 if (err) return err;
396 dev = GET_DC_PHYSDEV( dc, pPutImage );
397 err = blend_bits( info, bits, src, dst_info, &dst_bits, dst, blend );
398 if (!err) err = dev->funcs->pPutImage( dev, 0, dst_info, &dst_bits, dst, &orig_dst, SRCCOPY );
400 if (dst_bits.free) dst_bits.free( &dst_bits );
401 return err;
403 update_format:
404 if (blend.AlphaFormat & AC_SRC_ALPHA) /* source alpha requires A8R8G8B8 format */
405 return ERROR_INVALID_PARAMETER;
407 info->bmiHeader.biPlanes = 1;
408 info->bmiHeader.biBitCount = 32;
409 info->bmiHeader.biCompression = BI_BITFIELDS;
410 info->bmiHeader.biClrUsed = 0;
411 masks[0] = 0xff0000;
412 masks[1] = 0x00ff00;
413 masks[2] = 0x0000ff;
414 return ERROR_BAD_FORMAT;
417 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
418 void * grad_array, ULONG ngrad, ULONG mode )
420 DC *dc = get_nulldrv_dc( dev );
421 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
422 BITMAPINFO *info = (BITMAPINFO *)buffer;
423 struct bitblt_coords src, dst;
424 struct gdi_image_bits bits;
425 unsigned int i;
426 POINT *pts;
427 BOOL ret = FALSE;
428 DWORD err;
429 HRGN rgn;
431 if (!(pts = malloc( nvert * sizeof(*pts) ))) return FALSE;
432 for (i = 0; i < nvert; i++)
434 pts[i].x = vert_array[i].x;
435 pts[i].y = vert_array[i].y;
437 lp_to_dp( dc, pts, nvert );
439 /* compute bounding rect of all the rectangles/triangles */
440 reset_bounds( &dst.visrect );
441 for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
443 ULONG v = ((ULONG *)grad_array)[i];
444 dst.visrect.left = min( dst.visrect.left, pts[v].x );
445 dst.visrect.top = min( dst.visrect.top, pts[v].y );
446 dst.visrect.right = max( dst.visrect.right, pts[v].x );
447 dst.visrect.bottom = max( dst.visrect.bottom, pts[v].y );
450 dst.x = dst.visrect.left;
451 dst.y = dst.visrect.top;
452 dst.width = dst.visrect.right - dst.visrect.left;
453 dst.height = dst.visrect.bottom - dst.visrect.top;
454 if (!clip_visrect( dc, &dst.visrect, &dst.visrect )) goto done;
456 /* query the bitmap format */
457 info->bmiHeader.biSize = sizeof(info->bmiHeader);
458 info->bmiHeader.biPlanes = 1;
459 info->bmiHeader.biBitCount = 0;
460 info->bmiHeader.biCompression = BI_RGB;
461 info->bmiHeader.biXPelsPerMeter = 0;
462 info->bmiHeader.biYPelsPerMeter = 0;
463 info->bmiHeader.biClrUsed = 0;
464 info->bmiHeader.biClrImportant = 0;
465 info->bmiHeader.biWidth = dst.visrect.right - dst.visrect.left;
466 info->bmiHeader.biHeight = dst.visrect.bottom - dst.visrect.top;
467 info->bmiHeader.biSizeImage = 0;
468 dev = GET_DC_PHYSDEV( dc, pPutImage );
469 err = dev->funcs->pPutImage( dev, 0, info, NULL, NULL, NULL, 0 );
470 if (err && err != ERROR_BAD_FORMAT) goto done;
472 info->bmiHeader.biSizeImage = get_dib_image_size( info );
473 if (!(bits.ptr = calloc( 1, info->bmiHeader.biSizeImage )))
474 goto done;
475 bits.is_copy = TRUE;
476 bits.free = free_heap_bits;
478 /* make src and points relative to the bitmap */
479 src = dst;
480 src.x -= dst.visrect.left;
481 src.y -= dst.visrect.top;
482 OffsetRect( &src.visrect, -dst.visrect.left, -dst.visrect.top );
483 for (i = 0; i < nvert; i++)
485 pts[i].x -= dst.visrect.left;
486 pts[i].y -= dst.visrect.top;
489 rgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
490 gradient_bitmapinfo( info, bits.ptr, vert_array, nvert, grad_array, ngrad, mode, pts, rgn );
491 NtGdiOffsetRgn( rgn, dst.visrect.left, dst.visrect.top );
492 ret = !dev->funcs->pPutImage( dev, rgn, info, &bits, &src, &dst, SRCCOPY );
494 if (bits.free) bits.free( &bits );
495 NtGdiDeleteObjectApp( rgn );
497 done:
498 free( pts );
499 return ret;
502 COLORREF nulldrv_GetPixel( PHYSDEV dev, INT x, INT y )
504 DC *dc = get_nulldrv_dc( dev );
505 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
506 BITMAPINFO *info = (BITMAPINFO *)buffer;
507 struct bitblt_coords src;
508 struct gdi_image_bits bits;
509 COLORREF ret;
511 src.visrect.left = x;
512 src.visrect.top = y;
513 lp_to_dp( dc, (POINT *)&src.visrect, 1 );
514 src.visrect.right = src.visrect.left + 1;
515 src.visrect.bottom = src.visrect.top + 1;
516 src.x = src.visrect.left;
517 src.y = src.visrect.top;
518 src.width = src.height = 1;
520 if (!clip_visrect( dc, &src.visrect, &src.visrect )) return CLR_INVALID;
522 dev = GET_DC_PHYSDEV( dc, pGetImage );
523 if (dev->funcs->pGetImage( dev, info, &bits, &src )) return CLR_INVALID;
525 ret = get_pixel_bitmapinfo( info, bits.ptr, &src );
526 if (bits.free) bits.free( &bits );
527 return ret;
531 /***********************************************************************
532 * NtGdiPatBlt (win32u.@)
534 BOOL WINAPI NtGdiPatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop )
536 DC * dc;
537 BOOL ret = FALSE;
539 if (rop_uses_src( rop )) return FALSE;
540 if ((dc = get_dc_ptr( hdc )))
542 struct bitblt_coords dst;
544 update_dc( dc );
546 dst.log_x = left;
547 dst.log_y = top;
548 dst.log_width = width;
549 dst.log_height = height;
550 dst.layout = dc->attr->layout;
551 if (rop & NOMIRRORBITMAP)
553 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
554 rop &= ~NOMIRRORBITMAP;
556 ret = !get_vis_rectangles( dc, &dst, NULL, NULL );
558 TRACE("dst %p log=%d,%d %dx%d phys=%d,%d %dx%d vis=%s rop=%06x\n",
559 hdc, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
560 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), (int)rop );
562 if (!ret)
564 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPatBlt );
565 ret = physdev->funcs->pPatBlt( physdev, &dst, rop );
567 release_dc_ptr( dc );
569 return ret;
573 /***********************************************************************
574 * NtGdiBitBlt (win32u.@)
576 BOOL WINAPI NtGdiBitBlt( HDC hdc_dst, INT x_dst, INT y_dst, INT width, INT height,
577 HDC hdc_src, INT x_src, INT y_src, DWORD rop, DWORD bk_color, FLONG fl )
579 return NtGdiStretchBlt( hdc_dst, x_dst, y_dst, width, height,
580 hdc_src, x_src, y_src, width, height, rop, bk_color );
584 /***********************************************************************
585 * NtGdiStretchBlt (win32u.@)
587 BOOL WINAPI NtGdiStretchBlt( HDC hdcDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
588 HDC hdcSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
589 DWORD rop, COLORREF bk_color )
591 BOOL ret = FALSE;
592 DC *dcDst, *dcSrc;
594 if (!rop_uses_src( rop )) return NtGdiPatBlt( hdcDst, xDst, yDst, widthDst, heightDst, rop );
596 if (!(dcDst = get_dc_ptr( hdcDst ))) return FALSE;
598 if ((dcSrc = get_dc_ptr( hdcSrc )))
600 struct bitblt_coords src, dst;
602 update_dc( dcSrc );
603 update_dc( dcDst );
605 src.log_x = xSrc;
606 src.log_y = ySrc;
607 src.log_width = widthSrc;
608 src.log_height = heightSrc;
609 src.layout = dcSrc->attr->layout;
610 dst.log_x = xDst;
611 dst.log_y = yDst;
612 dst.log_width = widthDst;
613 dst.log_height = heightDst;
614 dst.layout = dcDst->attr->layout;
615 if (rop & NOMIRRORBITMAP)
617 src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
618 dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED;
619 rop &= ~NOMIRRORBITMAP;
621 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
623 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",
624 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
625 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
626 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
627 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect), (int)rop );
629 if (!ret)
631 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pStretchBlt );
632 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pStretchBlt );
633 ret = dst_dev->funcs->pStretchBlt( dst_dev, &dst, src_dev, &src, rop );
635 release_dc_ptr( dcSrc );
637 release_dc_ptr( dcDst );
638 return ret;
641 #define FRGND_ROP3(ROP4) ((ROP4) & 0x00FFFFFF)
642 #define BKGND_ROP3(ROP4) (ROP3Table[((ROP4)>>24) & 0xFF])
644 /***********************************************************************
645 * NtGdiMaskBlt (win32u.@)
647 BOOL WINAPI NtGdiMaskBlt( HDC hdcDest, INT nXDest, INT nYDest, INT nWidth, INT nHeight,
648 HDC hdcSrc, INT nXSrc, INT nYSrc, HBITMAP hbmMask,
649 INT xMask, INT yMask, DWORD dwRop, DWORD bk_color )
651 HBITMAP hBitmap1, hOldBitmap1, hBitmap2, hOldBitmap2;
652 HDC hDC1, hDC2;
653 HBRUSH hbrMask, hbrDst, hbrTmp;
655 static const DWORD ROP3Table[256] =
657 0x00000042, 0x00010289,
658 0x00020C89, 0x000300AA,
659 0x00040C88, 0x000500A9,
660 0x00060865, 0x000702C5,
661 0x00080F08, 0x00090245,
662 0x000A0329, 0x000B0B2A,
663 0x000C0324, 0x000D0B25,
664 0x000E08A5, 0x000F0001,
665 0x00100C85, 0x001100A6,
666 0x00120868, 0x001302C8,
667 0x00140869, 0x001502C9,
668 0x00165CCA, 0x00171D54,
669 0x00180D59, 0x00191CC8,
670 0x001A06C5, 0x001B0768,
671 0x001C06CA, 0x001D0766,
672 0x001E01A5, 0x001F0385,
673 0x00200F09, 0x00210248,
674 0x00220326, 0x00230B24,
675 0x00240D55, 0x00251CC5,
676 0x002606C8, 0x00271868,
677 0x00280369, 0x002916CA,
678 0x002A0CC9, 0x002B1D58,
679 0x002C0784, 0x002D060A,
680 0x002E064A, 0x002F0E2A,
681 0x0030032A, 0x00310B28,
682 0x00320688, 0x00330008,
683 0x003406C4, 0x00351864,
684 0x003601A8, 0x00370388,
685 0x0038078A, 0x00390604,
686 0x003A0644, 0x003B0E24,
687 0x003C004A, 0x003D18A4,
688 0x003E1B24, 0x003F00EA,
689 0x00400F0A, 0x00410249,
690 0x00420D5D, 0x00431CC4,
691 0x00440328, 0x00450B29,
692 0x004606C6, 0x0047076A,
693 0x00480368, 0x004916C5,
694 0x004A0789, 0x004B0605,
695 0x004C0CC8, 0x004D1954,
696 0x004E0645, 0x004F0E25,
697 0x00500325, 0x00510B26,
698 0x005206C9, 0x00530764,
699 0x005408A9, 0x00550009,
700 0x005601A9, 0x00570389,
701 0x00580785, 0x00590609,
702 0x005A0049, 0x005B18A9,
703 0x005C0649, 0x005D0E29,
704 0x005E1B29, 0x005F00E9,
705 0x00600365, 0x006116C6,
706 0x00620786, 0x00630608,
707 0x00640788, 0x00650606,
708 0x00660046, 0x006718A8,
709 0x006858A6, 0x00690145,
710 0x006A01E9, 0x006B178A,
711 0x006C01E8, 0x006D1785,
712 0x006E1E28, 0x006F0C65,
713 0x00700CC5, 0x00711D5C,
714 0x00720648, 0x00730E28,
715 0x00740646, 0x00750E26,
716 0x00761B28, 0x007700E6,
717 0x007801E5, 0x00791786,
718 0x007A1E29, 0x007B0C68,
719 0x007C1E24, 0x007D0C69,
720 0x007E0955, 0x007F03C9,
721 0x008003E9, 0x00810975,
722 0x00820C49, 0x00831E04,
723 0x00840C48, 0x00851E05,
724 0x008617A6, 0x008701C5,
725 0x008800C6, 0x00891B08,
726 0x008A0E06, 0x008B0666,
727 0x008C0E08, 0x008D0668,
728 0x008E1D7C, 0x008F0CE5,
729 0x00900C45, 0x00911E08,
730 0x009217A9, 0x009301C4,
731 0x009417AA, 0x009501C9,
732 0x00960169, 0x0097588A,
733 0x00981888, 0x00990066,
734 0x009A0709, 0x009B07A8,
735 0x009C0704, 0x009D07A6,
736 0x009E16E6, 0x009F0345,
737 0x00A000C9, 0x00A11B05,
738 0x00A20E09, 0x00A30669,
739 0x00A41885, 0x00A50065,
740 0x00A60706, 0x00A707A5,
741 0x00A803A9, 0x00A90189,
742 0x00AA0029, 0x00AB0889,
743 0x00AC0744, 0x00AD06E9,
744 0x00AE0B06, 0x00AF0229,
745 0x00B00E05, 0x00B10665,
746 0x00B21974, 0x00B30CE8,
747 0x00B4070A, 0x00B507A9,
748 0x00B616E9, 0x00B70348,
749 0x00B8074A, 0x00B906E6,
750 0x00BA0B09, 0x00BB0226,
751 0x00BC1CE4, 0x00BD0D7D,
752 0x00BE0269, 0x00BF08C9,
753 0x00C000CA, 0x00C11B04,
754 0x00C21884, 0x00C3006A,
755 0x00C40E04, 0x00C50664,
756 0x00C60708, 0x00C707AA,
757 0x00C803A8, 0x00C90184,
758 0x00CA0749, 0x00CB06E4,
759 0x00CC0020, 0x00CD0888,
760 0x00CE0B08, 0x00CF0224,
761 0x00D00E0A, 0x00D1066A,
762 0x00D20705, 0x00D307A4,
763 0x00D41D78, 0x00D50CE9,
764 0x00D616EA, 0x00D70349,
765 0x00D80745, 0x00D906E8,
766 0x00DA1CE9, 0x00DB0D75,
767 0x00DC0B04, 0x00DD0228,
768 0x00DE0268, 0x00DF08C8,
769 0x00E003A5, 0x00E10185,
770 0x00E20746, 0x00E306EA,
771 0x00E40748, 0x00E506E5,
772 0x00E61CE8, 0x00E70D79,
773 0x00E81D74, 0x00E95CE6,
774 0x00EA02E9, 0x00EB0849,
775 0x00EC02E8, 0x00ED0848,
776 0x00EE0086, 0x00EF0A08,
777 0x00F00021, 0x00F10885,
778 0x00F20B05, 0x00F3022A,
779 0x00F40B0A, 0x00F50225,
780 0x00F60265, 0x00F708C5,
781 0x00F802E5, 0x00F90845,
782 0x00FA0089, 0x00FB0A09,
783 0x00FC008A, 0x00FD0A0A,
784 0x00FE02A9, 0x00FF0062,
787 if (!hbmMask)
788 return NtGdiBitBlt( hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc,
789 nXSrc, nYSrc, FRGND_ROP3(dwRop), bk_color, 0 );
791 hbrMask = NtGdiCreatePatternBrushInternal( hbmMask, FALSE, FALSE );
792 hbrDst = NtGdiSelectBrush( hdcDest, GetStockObject(NULL_BRUSH) );
794 /* make bitmap */
795 hDC1 = NtGdiCreateCompatibleDC( hdcDest );
796 hBitmap1 = NtGdiCreateCompatibleBitmap( hdcDest, nWidth, nHeight );
797 hOldBitmap1 = NtGdiSelectBitmap(hDC1, hBitmap1);
799 /* draw using bkgnd rop */
800 NtGdiBitBlt( hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0 );
801 hbrTmp = NtGdiSelectBrush(hDC1, hbrDst);
802 NtGdiBitBlt( hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, BKGND_ROP3(dwRop), 0, 0 );
803 NtGdiSelectBrush(hDC1, hbrTmp);
805 /* make bitmap */
806 hDC2 = NtGdiCreateCompatibleDC( hdcDest );
807 hBitmap2 = NtGdiCreateCompatibleBitmap( hdcDest, nWidth, nHeight );
808 hOldBitmap2 = NtGdiSelectBitmap(hDC2, hBitmap2);
810 /* draw using foregnd rop */
811 NtGdiBitBlt( hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0 );
812 hbrTmp = NtGdiSelectBrush(hDC2, hbrDst);
813 NtGdiBitBlt( hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0, 0 );
815 /* combine both using the mask as a pattern brush */
816 NtGdiSelectBrush(hDC2, hbrMask);
817 NtGdiSetBrushOrg( hDC2, -xMask, -yMask, NULL );
818 /* (D & P) | (S & ~P) */
819 NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDC1, 0, 0, 0xac0744, 0, 0 );
820 NtGdiSelectBrush(hDC2, hbrTmp);
822 /* blit to dst */
823 NtGdiBitBlt( hdcDest, nXDest, nYDest, nWidth, nHeight, hDC2, 0, 0, SRCCOPY, bk_color, 0 );
825 /* restore all objects */
826 NtGdiSelectBrush(hdcDest, hbrDst);
827 NtGdiSelectBitmap(hDC1, hOldBitmap1);
828 NtGdiSelectBitmap(hDC2, hOldBitmap2);
830 /* delete all temp objects */
831 NtGdiDeleteObjectApp( hBitmap1 );
832 NtGdiDeleteObjectApp( hBitmap2 );
833 NtGdiDeleteObjectApp( hbrMask );
835 NtGdiDeleteObjectApp( hDC1 );
836 NtGdiDeleteObjectApp( hDC2 );
838 return TRUE;
841 /******************************************************************************
842 * NtGdiTransparentBlt (win32u.@)
844 BOOL WINAPI NtGdiTransparentBlt( HDC hdcDest, int xDest, int yDest, int widthDest, int heightDest,
845 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
846 UINT crTransparent )
848 BOOL ret = FALSE;
849 HDC hdcWork;
850 HBITMAP bmpWork;
851 HGDIOBJ oldWork;
852 HDC hdcMask = NULL;
853 HBITMAP bmpMask = NULL;
854 HBITMAP oldMask = NULL;
855 COLORREF oldBackground;
856 COLORREF oldForeground;
857 int oldStretchMode;
858 DIBSECTION dib;
859 DC *dc_src;
861 if(widthDest < 0 || heightDest < 0 || widthSrc < 0 || heightSrc < 0) {
862 TRACE("Cannot mirror\n");
863 return FALSE;
866 if (!(dc_src = get_dc_ptr( hdcSrc ))) return FALSE;
868 NtGdiGetAndSetDCDword( hdcDest, NtGdiSetBkColor, RGB(255,255,255), &oldBackground );
869 NtGdiGetAndSetDCDword( hdcDest, NtGdiSetTextColor, RGB(0,0,0), &oldForeground );
871 /* Stretch bitmap */
872 oldStretchMode = dc_src->attr->stretch_blt_mode;
873 if (oldStretchMode == BLACKONWHITE || oldStretchMode == WHITEONBLACK)
874 dc_src->attr->stretch_blt_mode = COLORONCOLOR;
875 hdcWork = NtGdiCreateCompatibleDC( hdcDest );
876 if ((get_gdi_object_type( hdcDest ) != NTGDI_OBJ_MEMDC ||
877 NtGdiExtGetObjectW( NtGdiGetDCObject( hdcDest, NTGDI_OBJ_SURF ),
878 sizeof(dib), &dib ) == sizeof(BITMAP)) &&
879 NtGdiGetDeviceCaps( hdcDest, BITSPIXEL ) == 32)
881 /* screen DCs or DDBs are not supposed to have an alpha channel, so use a 24-bpp bitmap as copy */
882 BITMAPINFO info;
883 info.bmiHeader.biSize = sizeof(info.bmiHeader);
884 info.bmiHeader.biWidth = widthDest;
885 info.bmiHeader.biHeight = heightDest;
886 info.bmiHeader.biPlanes = 1;
887 info.bmiHeader.biBitCount = 24;
888 info.bmiHeader.biCompression = BI_RGB;
889 bmpWork = NtGdiCreateDIBSection( 0, NULL, 0, &info, DIB_RGB_COLORS, 0, 0, 0, NULL );
891 else bmpWork = NtGdiCreateCompatibleBitmap( hdcDest, widthDest, heightDest );
892 oldWork = NtGdiSelectBitmap(hdcWork, bmpWork);
893 if (!NtGdiStretchBlt( hdcWork, 0, 0, widthDest, heightDest, hdcSrc, xSrc, ySrc,
894 widthSrc, heightSrc, SRCCOPY, 0 ))
896 TRACE("Failed to stretch\n");
897 goto error;
899 NtGdiGetAndSetDCDword( hdcWork, NtGdiSetBkColor, crTransparent, NULL );
901 /* Create mask */
902 hdcMask = NtGdiCreateCompatibleDC( hdcDest );
903 bmpMask = NtGdiCreateCompatibleBitmap( hdcMask, widthDest, heightDest );
904 oldMask = NtGdiSelectBitmap(hdcMask, bmpMask);
905 if (!NtGdiBitBlt( hdcMask, 0, 0, widthDest, heightDest, hdcWork, 0, 0, SRCCOPY, 0, 0 ))
907 TRACE("Failed to create mask\n");
908 goto error;
911 /* Replace transparent color with black */
912 NtGdiGetAndSetDCDword( hdcWork, NtGdiSetBkColor, RGB(0,0,0), NULL );
913 NtGdiGetAndSetDCDword( hdcWork, NtGdiSetTextColor, RGB(255,255,255), NULL );
914 if (!NtGdiBitBlt( hdcWork, 0, 0, widthDest, heightDest, hdcMask, 0, 0, SRCAND, 0, 0 ))
916 TRACE("Failed to mask out background\n");
917 goto error;
920 /* Replace non-transparent area on destination with black */
921 if (!NtGdiBitBlt( hdcDest, xDest, yDest, widthDest, heightDest, hdcMask, 0, 0, SRCAND, 0, 0 ))
923 TRACE("Failed to clear destination area\n");
924 goto error;
927 /* Draw the image */
928 if (!NtGdiBitBlt( hdcDest, xDest, yDest, widthDest, heightDest, hdcWork, 0, 0, SRCPAINT, 0, 0 ))
930 TRACE("Failed to paint image\n");
931 goto error;
934 ret = TRUE;
935 error:
936 dc_src->attr->stretch_blt_mode = oldStretchMode;
937 release_dc_ptr( dc_src );
938 NtGdiGetAndSetDCDword( hdcDest, NtGdiSetBkColor, oldBackground, NULL );
939 NtGdiGetAndSetDCDword( hdcDest, NtGdiSetTextColor, oldForeground, NULL );
940 if(hdcWork) {
941 NtGdiSelectBitmap(hdcWork, oldWork);
942 NtGdiDeleteObjectApp( hdcWork );
944 if(bmpWork) NtGdiDeleteObjectApp( bmpWork );
945 if(hdcMask) {
946 NtGdiSelectBitmap(hdcMask, oldMask);
947 NtGdiDeleteObjectApp( hdcMask );
949 if(bmpMask) NtGdiDeleteObjectApp( bmpMask );
950 return ret;
953 /******************************************************************************
954 * NtGdiAlphaBlend (win32u.@)
956 BOOL WINAPI NtGdiAlphaBlend( HDC hdcDst, int xDst, int yDst, int widthDst, int heightDst,
957 HDC hdcSrc, int xSrc, int ySrc, int widthSrc, int heightSrc,
958 DWORD blend_func, HANDLE xform )
960 BLENDFUNCTION blendFunction = *(BLENDFUNCTION *)&blend_func;
961 BOOL ret = FALSE;
962 DC *dcDst, *dcSrc;
964 dcSrc = get_dc_ptr( hdcSrc );
965 if (!dcSrc) return FALSE;
967 if ((dcDst = get_dc_ptr( hdcDst )))
969 struct bitblt_coords src, dst;
971 update_dc( dcSrc );
972 update_dc( dcDst );
974 src.log_x = xSrc;
975 src.log_y = ySrc;
976 src.log_width = widthSrc;
977 src.log_height = heightSrc;
978 src.layout = dcSrc->attr->layout;
979 dst.log_x = xDst;
980 dst.log_y = yDst;
981 dst.log_width = widthDst;
982 dst.log_height = heightDst;
983 dst.layout = dcDst->attr->layout;
984 ret = !get_vis_rectangles( dcDst, &dst, dcSrc, &src );
986 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",
987 hdcSrc, src.log_x, src.log_y, src.log_width, src.log_height,
988 src.x, src.y, src.width, src.height, wine_dbgstr_rect(&src.visrect),
989 hdcDst, dst.log_x, dst.log_y, dst.log_width, dst.log_height,
990 dst.x, dst.y, dst.width, dst.height, wine_dbgstr_rect(&dst.visrect),
991 blendFunction.BlendOp, blendFunction.BlendFlags,
992 blendFunction.SourceConstantAlpha, blendFunction.AlphaFormat );
994 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
995 src.log_width < 0 || src.log_height < 0 ||
996 (!IsRectEmpty( &dcSrc->device_rect ) &&
997 (src.width > dcSrc->device_rect.right - dcSrc->attr->vis_rect.left - src.x ||
998 src.height > dcSrc->device_rect.bottom - dcSrc->attr->vis_rect.top - src.y)))
1000 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
1001 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1002 ret = FALSE;
1004 else if (dst.log_width < 0 || dst.log_height < 0)
1006 WARN( "Invalid dst coords: (%d,%d), size %dx%d\n",
1007 dst.log_x, dst.log_y, dst.log_width, dst.log_height );
1008 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1009 ret = FALSE;
1011 else if (dcSrc == dcDst && src.x + src.width > dst.x && src.x < dst.x + dst.width &&
1012 src.y + src.height > dst.y && src.y < dst.y + dst.height)
1014 WARN( "Overlapping coords: (%d,%d), %dx%d and (%d,%d), %dx%d\n",
1015 src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height );
1016 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
1017 ret = FALSE;
1019 else if (!ret)
1021 PHYSDEV src_dev = GET_DC_PHYSDEV( dcSrc, pAlphaBlend );
1022 PHYSDEV dst_dev = GET_DC_PHYSDEV( dcDst, pAlphaBlend );
1023 ret = dst_dev->funcs->pAlphaBlend( dst_dev, &dst, src_dev, &src, blendFunction );
1025 release_dc_ptr( dcDst );
1027 release_dc_ptr( dcSrc );
1028 return ret;
1031 /*********************************************************************
1032 * NtGdiPlgBlt (win32u.@)
1034 BOOL WINAPI NtGdiPlgBlt( HDC hdcDest, const POINT *lpPoint, HDC hdcSrc, INT nXSrc, INT nYSrc,
1035 INT nWidth, INT nHeight, HBITMAP hbmMask, INT xMask, INT yMask,
1036 DWORD bk_color )
1038 DWORD prev_mode;
1039 /* parallelogram coords */
1040 POINT plg[3];
1041 /* rect coords */
1042 POINT rect[3];
1043 XFORM xf;
1044 XFORM SrcXf;
1045 XFORM oldDestXf;
1046 double det;
1048 /* save actual mode, set GM_ADVANCED */
1049 if (!NtGdiGetAndSetDCDword( hdcDest, NtGdiSetGraphicsMode, GM_ADVANCED, &prev_mode ))
1050 return FALSE;
1052 memcpy(plg,lpPoint,sizeof(POINT)*3);
1053 rect[0].x = nXSrc;
1054 rect[0].y = nYSrc;
1055 rect[1].x = nXSrc + nWidth;
1056 rect[1].y = nYSrc;
1057 rect[2].x = nXSrc;
1058 rect[2].y = nYSrc + nHeight;
1059 /* calc XFORM matrix to transform hdcDest -> hdcSrc (parallelogram to rectangle) */
1060 /* determinant */
1061 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);
1063 if (fabs(det) < 1e-5)
1065 NtGdiGetAndSetDCDword( hdcDest, NtGdiSetGraphicsMode, prev_mode, NULL );
1066 return FALSE;
1069 TRACE("hdcSrc=%p %d,%d,%dx%d -> hdcDest=%p %d,%d,%d,%d,%d,%d\n",
1070 hdcSrc, nXSrc, nYSrc, nWidth, nHeight, hdcDest,
1071 (int)plg[0].x, (int)plg[0].y, (int)plg[1].x, (int)plg[1].y, (int)plg[2].x, (int)plg[2].y);
1073 /* X components */
1074 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;
1075 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;
1076 xf.eDx = (rect[0].x*(rect[1].y*plg[2].x - rect[2].y*plg[1].x) -
1077 rect[1].x*(rect[0].y*plg[2].x - rect[2].y*plg[0].x) +
1078 rect[2].x*(rect[0].y*plg[1].x - rect[1].y*plg[0].x)
1079 ) / det;
1081 /* Y components */
1082 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;
1083 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;
1084 xf.eDy = (rect[0].x*(rect[1].y*plg[2].y - rect[2].y*plg[1].y) -
1085 rect[1].x*(rect[0].y*plg[2].y - rect[2].y*plg[0].y) +
1086 rect[2].x*(rect[0].y*plg[1].y - rect[1].y*plg[0].y)
1087 ) / det;
1089 NtGdiGetTransform( hdcSrc, 0x203, &SrcXf );
1090 combine_transform( &xf, &xf, &SrcXf );
1092 /* save actual dest transform */
1093 NtGdiGetTransform( hdcDest, 0x203, &oldDestXf );
1095 NtGdiModifyWorldTransform( hdcDest, &xf, MWT_SET );
1096 /* now destination and source DCs use same coords */
1097 NtGdiMaskBlt( hdcDest, nXSrc, nYSrc, nWidth, nHeight, hdcSrc, nXSrc, nYSrc,
1098 hbmMask, xMask, yMask, SRCCOPY, 0 );
1099 /* restore dest DC */
1100 NtGdiModifyWorldTransform( hdcDest, &oldDestXf, MWT_SET );
1101 NtGdiGetAndSetDCDword( hdcDest, NtGdiSetGraphicsMode, prev_mode, NULL );
1103 return TRUE;