mfmediaengine: Remove unnecessary import library.
[wine.git] / dlls / gdi32 / emfdc.c
blobd0b9033722c5c9f39ba2dc891d588b82c5e08228
1 /*
2 * Enhanced MetaFile recording functions
4 * Copyright 1999 Huw D M Davies
5 * Copyright 2016 Alexandre Julliard
6 * Copyright 2021 Jacek Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <assert.h>
24 #include <stdlib.h>
26 #include "gdi_private.h"
27 #include "winnls.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
34 struct emf
36 ENHMETAHEADER *emh;
37 DC_ATTR *dc_attr;
38 UINT handles_size, cur_handles;
39 HGDIOBJ *handles;
40 HANDLE file;
41 HBRUSH dc_brush;
42 HPEN dc_pen;
43 BOOL path;
46 #define HANDLE_LIST_INC 20
47 static const RECTL empty_bounds = { 0, 0, -1, -1 };
49 static BOOL emfdc_record( struct emf *emf, EMR *emr )
51 DWORD len, size;
52 ENHMETAHEADER *emh;
54 TRACE( "record %d, size %d\n", emr->iType, emr->nSize );
56 assert( !(emr->nSize & 3) );
58 emf->emh->nBytes += emr->nSize;
59 emf->emh->nRecords++;
61 size = HeapSize( GetProcessHeap(), 0, emf->emh );
62 len = emf->emh->nBytes;
63 if (len > size)
65 size += (size / 2) + emr->nSize;
66 emh = HeapReAlloc( GetProcessHeap(), 0, emf->emh, size );
67 if (!emh) return FALSE;
68 emf->emh = emh;
70 memcpy( (char *)emf->emh + emf->emh->nBytes - emr->nSize, emr, emr->nSize );
71 return TRUE;
74 static void emfdc_update_bounds( struct emf *emf, RECTL *rect )
76 RECTL *bounds = &emf->dc_attr->emf_bounds;
77 RECTL vport_rect = *rect;
79 LPtoDP( emf->dc_attr->hdc, (POINT *)&vport_rect, 2 );
81 /* The coordinate systems may be mirrored
82 (LPtoDP handles points, not rectangles) */
83 if (vport_rect.left > vport_rect.right)
85 LONG temp = vport_rect.right;
86 vport_rect.right = vport_rect.left;
87 vport_rect.left = temp;
89 if (vport_rect.top > vport_rect.bottom)
91 LONG temp = vport_rect.bottom;
92 vport_rect.bottom = vport_rect.top;
93 vport_rect.top = temp;
96 if (bounds->left > bounds->right)
98 /* first bounding rectangle */
99 *bounds = vport_rect;
101 else
103 bounds->left = min(bounds->left, vport_rect.left);
104 bounds->top = min(bounds->top, vport_rect.top);
105 bounds->right = max(bounds->right, vport_rect.right);
106 bounds->bottom = max(bounds->bottom, vport_rect.bottom);
110 static UINT get_bitmap_info( HDC *hdc, HBITMAP *bitmap, BITMAPINFO *info )
112 HBITMAP blit_bitmap;
113 HDC blit_dc;
114 UINT info_size, bpp;
115 DIBSECTION dib;
117 if (!(info_size = GetObjectW( *bitmap, sizeof(dib), &dib ))) return 0;
119 if (info_size == sizeof(dib))
121 blit_dc = *hdc;
122 blit_bitmap = *bitmap;
124 else
126 unsigned char dib_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
127 BITMAPINFO *dib_info = (BITMAPINFO *)dib_info_buffer;
128 BITMAP bmp = dib.dsBm;
129 HPALETTE palette;
130 void *bits;
132 assert( info_size == sizeof(BITMAP) );
134 dib_info->bmiHeader.biSize = sizeof(dib_info->bmiHeader);
135 dib_info->bmiHeader.biWidth = bmp.bmWidth;
136 dib_info->bmiHeader.biHeight = bmp.bmHeight;
137 dib_info->bmiHeader.biPlanes = 1;
138 dib_info->bmiHeader.biBitCount = bmp.bmBitsPixel;
139 dib_info->bmiHeader.biCompression = BI_RGB;
140 dib_info->bmiHeader.biSizeImage = 0;
141 dib_info->bmiHeader.biXPelsPerMeter = 0;
142 dib_info->bmiHeader.biYPelsPerMeter = 0;
143 dib_info->bmiHeader.biClrUsed = 0;
144 dib_info->bmiHeader.biClrImportant = 0;
145 switch (dib_info->bmiHeader.biBitCount)
147 case 16:
148 ((DWORD *)dib_info->bmiColors)[0] = 0xf800;
149 ((DWORD *)dib_info->bmiColors)[1] = 0x07e0;
150 ((DWORD *)dib_info->bmiColors)[2] = 0x001f;
151 break;
152 case 32:
153 ((DWORD *)dib_info->bmiColors)[0] = 0xff0000;
154 ((DWORD *)dib_info->bmiColors)[1] = 0x00ff00;
155 ((DWORD *)dib_info->bmiColors)[2] = 0x0000ff;
156 break;
157 default:
158 if (dib_info->bmiHeader.biBitCount > 8) break;
159 if (!(palette = GetCurrentObject( *hdc, OBJ_PAL ))) return FALSE;
160 if (!GetPaletteEntries( palette, 0, 256, (PALETTEENTRY *)dib_info->bmiColors ))
161 return FALSE;
164 if (!(blit_dc = NtGdiCreateCompatibleDC( *hdc ))) return FALSE;
165 if (!(blit_bitmap = CreateDIBSection( blit_dc, dib_info, DIB_RGB_COLORS, &bits, NULL, 0 )))
166 goto err;
167 if (!SelectObject( blit_dc, blit_bitmap )) goto err;
168 if (!BitBlt( blit_dc, 0, 0, bmp.bmWidth, bmp.bmHeight, *hdc, 0, 0, SRCCOPY ))
169 goto err;
171 if (!GetDIBits( blit_dc, blit_bitmap, 0, INT_MAX, NULL, info, DIB_RGB_COLORS ))
172 goto err;
174 bpp = info->bmiHeader.biBitCount;
175 if (bpp <= 8)
176 return sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD);
177 else if (bpp == 16 || bpp == 32)
178 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
180 return sizeof(BITMAPINFOHEADER);
182 err:
183 if (blit_dc && blit_dc != *hdc) DeleteDC( blit_dc );
184 if (blit_bitmap && blit_bitmap != *bitmap) DeleteObject( blit_bitmap );
185 return 0;
188 /*******************************************************************************************
189 * Verify that the DIB parameters are valid.
191 static BOOL is_valid_dib_format( const BITMAPINFOHEADER *info, BOOL allow_compression )
193 if (info->biWidth <= 0) return FALSE;
194 if (info->biHeight == 0) return FALSE;
196 if (allow_compression && (info->biCompression == BI_RLE4 || info->biCompression == BI_RLE8))
198 if (info->biHeight < 0) return FALSE;
199 if (!info->biSizeImage) return FALSE;
200 return info->biBitCount == (info->biCompression == BI_RLE4 ? 4 : 8);
203 if (!info->biPlanes) return FALSE;
205 /* check for size overflow */
206 if (!info->biBitCount) return FALSE;
207 if (UINT_MAX / info->biBitCount < info->biWidth) return FALSE;
208 if (UINT_MAX / get_dib_stride( info->biWidth, info->biBitCount ) < abs( info->biHeight )) return FALSE;
210 switch (info->biBitCount)
212 case 1:
213 case 4:
214 case 8:
215 case 24:
216 return (info->biCompression == BI_RGB);
217 case 16:
218 case 32:
219 return (info->biCompression == BI_BITFIELDS || info->biCompression == BI_RGB);
220 default:
221 return FALSE;
225 static BOOL emf_parse_user_bitmapinfo( BITMAPINFOHEADER *dst, const BITMAPINFOHEADER *info,
226 UINT coloruse, BOOL allow_compression,
227 UINT *bmi_size, UINT *img_size )
229 UINT colour_table_size;
231 if (coloruse > DIB_PAL_COLORS + 1) return FALSE; /* FIXME: handle DIB_PAL_COLORS+1 format */
232 if (!info) return FALSE;
234 memset(dst, 0, sizeof(*dst));
236 if (info->biSize == sizeof(BITMAPCOREHEADER))
238 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
239 dst->biWidth = core->bcWidth;
240 dst->biHeight = core->bcHeight;
241 dst->biPlanes = core->bcPlanes;
242 dst->biBitCount = core->bcBitCount;
243 dst->biCompression = BI_RGB;
244 dst->biXPelsPerMeter = 0;
245 dst->biYPelsPerMeter = 0;
246 dst->biClrUsed = 0;
247 dst->biClrImportant = 0;
249 else if (info->biSize >= sizeof(BITMAPINFOHEADER)) /* assume BITMAPINFOHEADER */
251 *dst = *info;
253 else
255 WARN( "(%u): unknown/wrong size for header\n", info->biSize );
256 return FALSE;
259 dst->biSize = sizeof(*dst);
261 if (!is_valid_dib_format( dst, allow_compression )) return FALSE;
263 colour_table_size = 0;
264 if (dst->biCompression == BI_BITFIELDS)
266 colour_table_size = 3 * sizeof(DWORD);
268 else if (dst->biBitCount <= 8)
270 UINT elm_size = coloruse == DIB_PAL_COLORS ? sizeof(WORD) : sizeof(DWORD);
271 UINT colours = dst->biClrUsed;
273 /* Windows never truncates colour tables, even if they are
274 * unnecessarily big (> 1<<bpp). We emulate this behaviour. */
276 if (colours > UINT_MAX / elm_size)
278 WARN( "too many colours in palette (%u > %u)\n",
279 colours, UINT_MAX / elm_size );
280 return FALSE;
283 colour_table_size = colours * elm_size;
286 *bmi_size = sizeof(BITMAPINFOHEADER) + colour_table_size;
287 if (*bmi_size < sizeof(BITMAPINFOHEADER))
288 return FALSE;
290 if (dst->biCompression == BI_RGB || dst->biCompression == BI_BITFIELDS)
291 *img_size = get_dib_stride( dst->biWidth, dst->biBitCount ) * abs( dst->biHeight );
292 else
293 *img_size = dst->biSizeImage;
295 return TRUE;
298 static void emf_copy_colours_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *info, UINT coloruse )
300 if (dst->bmiHeader.biCompression == BI_BITFIELDS)
302 /* bitfields are always at bmiColors even in larger structures */
303 memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) );
305 else if (dst->bmiHeader.biBitCount <= 8)
307 void *src_colors = (char *)info + info->bmiHeader.biSize;
308 unsigned int colors = dst->bmiHeader.biClrUsed;
310 if (!colors) colors = 1 << dst->bmiHeader.biBitCount;
312 if (coloruse == DIB_PAL_COLORS)
314 memcpy( dst->bmiColors, src_colors, colors * sizeof(WORD) );
316 else if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
318 memcpy( dst->bmiColors, src_colors, colors * sizeof(RGBQUAD) );
320 else
322 unsigned int i;
323 RGBTRIPLE *triple = (RGBTRIPLE *)src_colors;
324 for (i = 0; i < colors; i++)
326 dst->bmiColors[i].rgbRed = triple[i].rgbtRed;
327 dst->bmiColors[i].rgbGreen = triple[i].rgbtGreen;
328 dst->bmiColors[i].rgbBlue = triple[i].rgbtBlue;
329 dst->bmiColors[i].rgbReserved = 0;
335 static UINT emfdc_add_handle( struct emf *emf, HGDIOBJ obj )
337 UINT index;
339 for (index = 0; index < emf->handles_size; index++)
340 if (emf->handles[index] == 0) break;
342 if (index == emf->handles_size)
344 emf->handles_size += HANDLE_LIST_INC;
345 emf->handles = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
346 emf->handles,
347 emf->handles_size * sizeof(emf->handles[0]) );
349 emf->handles[index] = obj;
351 emf->cur_handles++;
352 if (emf->cur_handles > emf->emh->nHandles)
353 emf->emh->nHandles++;
355 return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
358 static UINT emfdc_find_object( struct emf *emf, HGDIOBJ obj )
360 UINT index;
362 for (index = 0; index < emf->handles_size; index++)
363 if (emf->handles[index] == obj) return index + 1;
365 return 0;
368 static void emfdc_delete_object( HDC hdc, HGDIOBJ obj )
370 DC_ATTR *dc_attr = get_dc_attr( hdc );
371 struct emf *emf = dc_attr->emf;
372 EMRDELETEOBJECT emr;
373 UINT index;
375 if(!(index = emfdc_find_object( emf, obj ))) return;
377 emr.emr.iType = EMR_DELETEOBJECT;
378 emr.emr.nSize = sizeof(emr);
379 emr.ihObject = index;
381 emfdc_record( emf, &emr.emr );
383 emf->handles[index - 1] = 0;
384 emf->cur_handles--;
387 static DWORD emfdc_create_brush( struct emf *emf, HBRUSH brush )
389 DWORD index = 0;
390 LOGBRUSH logbrush;
392 if (!GetObjectA( brush, sizeof(logbrush), &logbrush )) return 0;
394 switch (logbrush.lbStyle) {
395 case BS_SOLID:
396 case BS_HATCHED:
397 case BS_NULL:
399 EMRCREATEBRUSHINDIRECT emr;
400 emr.emr.iType = EMR_CREATEBRUSHINDIRECT;
401 emr.emr.nSize = sizeof(emr);
402 emr.ihBrush = index = emfdc_add_handle( emf, brush );
403 emr.lb.lbStyle = logbrush.lbStyle;
404 emr.lb.lbColor = logbrush.lbColor;
405 emr.lb.lbHatch = logbrush.lbHatch;
407 if(!emfdc_record( emf, &emr.emr ))
408 index = 0;
410 break;
411 case BS_PATTERN:
412 case BS_DIBPATTERN:
414 EMRCREATEDIBPATTERNBRUSHPT *emr;
415 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
416 BITMAPINFO *info = (BITMAPINFO *)buffer;
417 DWORD info_size;
418 UINT usage;
420 if (!__wine_get_brush_bitmap_info( brush, info, NULL, &usage )) break;
421 info_size = get_dib_info_size( info, usage );
423 emr = HeapAlloc( GetProcessHeap(), 0,
424 sizeof(EMRCREATEDIBPATTERNBRUSHPT) + sizeof(DWORD) +
425 info_size+info->bmiHeader.biSizeImage );
426 if(!emr) break;
428 /* FIXME: There is an extra DWORD written by native before the BMI.
429 * Not sure what it's meant to contain.
431 emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ) + sizeof(DWORD);
432 *(DWORD *)(emr + 1) = 0x20000000;
434 if (logbrush.lbStyle == BS_PATTERN && info->bmiHeader.biBitCount == 1)
436 /* Presumably to reduce the size of the written EMF, MS supports an
437 * undocumented iUsage value of 2, indicating a mono bitmap without the
438 * 8 byte 2 entry black/white palette. Stupidly, they could have saved
439 * over 20 bytes more by also ignoring the BITMAPINFO fields that are
440 * irrelevant/constant for monochrome bitmaps.
441 * FIXME: It may be that the DIB functions themselves accept this value.
443 emr->emr.iType = EMR_CREATEMONOBRUSH;
444 usage = DIB_PAL_MONO;
445 emr->cbBmi = sizeof( BITMAPINFOHEADER );
447 else
449 emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT;
450 emr->cbBmi = info_size;
452 emr->ihBrush = index = emfdc_add_handle( emf, brush );
453 emr->iUsage = usage;
454 emr->offBits = emr->offBmi + emr->cbBmi;
455 emr->cbBits = info->bmiHeader.biSizeImage;
456 emr->emr.nSize = emr->offBits + emr->cbBits;
458 if (info->bmiHeader.biClrUsed == 1 << info->bmiHeader.biBitCount)
459 info->bmiHeader.biClrUsed = 0;
460 memcpy( (BYTE *)emr + emr->offBmi, info, emr->cbBmi );
461 __wine_get_brush_bitmap_info( brush, NULL, (char *)emr + emr->offBits, NULL );
463 if (!emfdc_record( emf, &emr->emr )) index = 0;
464 HeapFree( GetProcessHeap(), 0, emr );
466 break;
468 default:
469 FIXME("Unknown style %x\n", logbrush.lbStyle);
470 break;
473 return index;
476 static BOOL emfdc_select_brush( DC_ATTR *dc_attr, HBRUSH brush )
478 struct emf *emf = dc_attr->emf;
479 EMRSELECTOBJECT emr;
480 DWORD index = 0;
481 int i;
483 /* If the object is a stock brush object, do not need to create it.
484 * See definitions in wingdi.h for range of stock brushes.
485 * We do however have to handle setting the higher order bit to
486 * designate that this is a stock object.
488 for (i = WHITE_BRUSH; i <= DC_BRUSH; i++)
490 if (brush == GetStockObject(i))
492 index = i | 0x80000000;
493 break;
497 if (!index && !(index = emfdc_find_object( emf, brush )))
499 if (!(index = emfdc_create_brush( emf, brush ))) return 0;
500 GDI_hdc_using_object( brush, dc_attr->hdc, emfdc_delete_object );
503 emr.emr.iType = EMR_SELECTOBJECT;
504 emr.emr.nSize = sizeof(emr);
505 emr.ihObject = index;
506 return emfdc_record( emf, &emr.emr );
509 static BOOL emfdc_create_font( struct emf *emf, HFONT font )
511 DWORD index = 0;
512 EMREXTCREATEFONTINDIRECTW emr;
513 int i;
515 if (!GetObjectW( font, sizeof(emr.elfw.elfLogFont), &emr.elfw.elfLogFont )) return FALSE;
517 emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW;
518 emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4;
519 emr.ihFont = index = emfdc_add_handle( emf, font );
520 emr.elfw.elfFullName[0] = '\0';
521 emr.elfw.elfStyle[0] = '\0';
522 emr.elfw.elfVersion = 0;
523 emr.elfw.elfStyleSize = 0;
524 emr.elfw.elfMatch = 0;
525 emr.elfw.elfReserved = 0;
526 for (i = 0; i < ELF_VENDOR_SIZE; i++)
527 emr.elfw.elfVendorId[i] = 0;
528 emr.elfw.elfCulture = PAN_CULTURE_LATIN;
529 emr.elfw.elfPanose.bFamilyType = PAN_NO_FIT;
530 emr.elfw.elfPanose.bSerifStyle = PAN_NO_FIT;
531 emr.elfw.elfPanose.bWeight = PAN_NO_FIT;
532 emr.elfw.elfPanose.bProportion = PAN_NO_FIT;
533 emr.elfw.elfPanose.bContrast = PAN_NO_FIT;
534 emr.elfw.elfPanose.bStrokeVariation = PAN_NO_FIT;
535 emr.elfw.elfPanose.bArmStyle = PAN_NO_FIT;
536 emr.elfw.elfPanose.bLetterform = PAN_NO_FIT;
537 emr.elfw.elfPanose.bMidline = PAN_NO_FIT;
538 emr.elfw.elfPanose.bXHeight = PAN_NO_FIT;
540 return emfdc_record( emf, &emr.emr ) ? index : 0;
543 static BOOL emfdc_select_font( DC_ATTR *dc_attr, HFONT font )
545 struct emf *emf = dc_attr->emf;
546 EMRSELECTOBJECT emr;
547 DWORD index;
548 int i;
550 /* If the object is a stock font object, do not need to create it.
551 * See definitions in wingdi.h for range of stock fonts.
552 * We do however have to handle setting the higher order bit to
553 * designate that this is a stock object.
556 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
558 if (i != DEFAULT_PALETTE && font == GetStockObject(i))
560 index = i | 0x80000000;
561 goto found;
565 if (!(index = emfdc_find_object( emf, font )))
567 if (!(index = emfdc_create_font( emf, font ))) return FALSE;
568 GDI_hdc_using_object( font, dc_attr->hdc, emfdc_delete_object );
571 found:
572 emr.emr.iType = EMR_SELECTOBJECT;
573 emr.emr.nSize = sizeof(emr);
574 emr.ihObject = index;
575 return emfdc_record( emf, &emr.emr );
578 static DWORD emfdc_create_pen( struct emf *emf, HPEN hPen )
580 EMRCREATEPEN emr;
581 DWORD index = 0;
583 if (!GetObjectW( hPen, sizeof(emr.lopn), &emr.lopn ))
585 /* must be an extended pen */
586 EXTLOGPEN *elp;
587 INT size = GetObjectW( hPen, 0, NULL );
589 if (!size) return 0;
591 elp = HeapAlloc( GetProcessHeap(), 0, size );
593 GetObjectW( hPen, size, elp );
594 /* FIXME: add support for user style pens */
595 emr.lopn.lopnStyle = elp->elpPenStyle;
596 emr.lopn.lopnWidth.x = elp->elpWidth;
597 emr.lopn.lopnWidth.y = 0;
598 emr.lopn.lopnColor = elp->elpColor;
600 HeapFree( GetProcessHeap(), 0, elp );
603 emr.emr.iType = EMR_CREATEPEN;
604 emr.emr.nSize = sizeof(emr);
605 emr.ihPen = index = emfdc_add_handle( emf, hPen );
606 return emfdc_record( emf, &emr.emr ) ? index : 0;
609 static BOOL emfdc_select_pen( DC_ATTR *dc_attr, HPEN pen )
611 struct emf *emf = dc_attr->emf;
612 EMRSELECTOBJECT emr;
613 DWORD index = 0;
614 int i;
616 /* If the object is a stock pen object, do not need to create it.
617 * See definitions in wingdi.h for range of stock pens.
618 * We do however have to handle setting the higher order bit to
619 * designate that this is a stock object.
622 for (i = WHITE_PEN; i <= DC_PEN; i++)
624 if (pen == GetStockObject(i))
626 index = i | 0x80000000;
627 break;
630 if (!index && !(index = emfdc_find_object( emf, pen )))
632 if (!(index = emfdc_create_pen( emf, pen ))) return FALSE;
633 GDI_hdc_using_object( pen, dc_attr->hdc, emfdc_delete_object );
636 emr.emr.iType = EMR_SELECTOBJECT;
637 emr.emr.nSize = sizeof(emr);
638 emr.ihObject = index;
639 return emfdc_record( emf, &emr.emr );
642 static DWORD emfdc_create_palette( struct emf *emf, HPALETTE hPal )
644 WORD i;
645 struct {
646 EMRCREATEPALETTE hdr;
647 PALETTEENTRY entry[255];
648 } pal;
650 memset( &pal, 0, sizeof(pal) );
652 if (!GetObjectW( hPal, sizeof(pal.hdr.lgpl) + sizeof(pal.entry), &pal.hdr.lgpl ))
653 return 0;
655 for (i = 0; i < pal.hdr.lgpl.palNumEntries; i++)
656 pal.hdr.lgpl.palPalEntry[i].peFlags = 0;
658 pal.hdr.emr.iType = EMR_CREATEPALETTE;
659 pal.hdr.emr.nSize = sizeof(pal.hdr) + pal.hdr.lgpl.palNumEntries * sizeof(PALETTEENTRY);
660 pal.hdr.ihPal = emfdc_add_handle( emf, hPal );
662 if (!emfdc_record( emf, &pal.hdr.emr ))
663 pal.hdr.ihPal = 0;
664 return pal.hdr.ihPal;
667 BOOL EMFDC_SelectPalette( DC_ATTR *dc_attr, HPALETTE palette )
669 struct emf *emf = dc_attr->emf;
670 EMRSELECTPALETTE emr;
671 DWORD index = 0;
673 if (palette == GetStockObject( DEFAULT_PALETTE ))
675 index = DEFAULT_PALETTE | 0x80000000;
677 else if (!(index = emfdc_find_object( emf, palette )))
679 if (!(index = emfdc_create_palette( emf, palette ))) return 0;
680 GDI_hdc_using_object( palette, dc_attr->hdc, emfdc_delete_object );
683 emr.emr.iType = EMR_SELECTPALETTE;
684 emr.emr.nSize = sizeof(emr);
685 emr.ihPal = index;
686 return emfdc_record( emf, &emr.emr );
689 BOOL EMFDC_SelectObject( DC_ATTR *dc_attr, HGDIOBJ obj )
691 switch (gdi_handle_type( obj ))
693 case NTGDI_OBJ_BRUSH:
694 return emfdc_select_brush( dc_attr, obj );
695 case NTGDI_OBJ_FONT:
696 return emfdc_select_font( dc_attr, obj );
697 case NTGDI_OBJ_PEN:
698 case NTGDI_OBJ_EXTPEN:
699 return emfdc_select_pen( dc_attr, obj );
700 default:
701 return TRUE;
705 /* determine if we can use 16-bit points to store all the input points */
706 static BOOL can_use_short_points( const POINT *pts, UINT count )
708 UINT i;
710 for (i = 0; i < count; i++)
711 if (((pts[i].x + 0x8000) & ~0xffff) || ((pts[i].y + 0x8000) & ~0xffff))
712 return FALSE;
713 return TRUE;
716 /* store points in either long or short format; return a pointer to the end of the stored data */
717 static void *store_points( POINTL *dest, const POINT *pts, UINT count, BOOL short_points )
719 if (short_points)
721 UINT i;
722 POINTS *dest_short = (POINTS *)dest;
724 for (i = 0; i < count; i++)
726 dest_short[i].x = pts[i].x;
727 dest_short[i].y = pts[i].y;
729 return dest_short + count;
731 else
733 memcpy( dest, pts, count * sizeof(*dest) );
734 return dest + count;
738 /* compute the bounds of an array of points, optionally including the current position */
739 static void get_points_bounds( RECTL *bounds, const POINT *pts, UINT count, DC_ATTR *dc_attr )
741 UINT i;
743 if (dc_attr)
745 bounds->left = bounds->right = dc_attr->cur_pos.x;
746 bounds->top = bounds->bottom = dc_attr->cur_pos.y;
748 else if (count)
750 bounds->left = bounds->right = pts[0].x;
751 bounds->top = bounds->bottom = pts[0].y;
753 else *bounds = empty_bounds;
755 for (i = 0; i < count; i++)
757 bounds->left = min( bounds->left, pts[i].x );
758 bounds->right = max( bounds->right, pts[i].x );
759 bounds->top = min( bounds->top, pts[i].y );
760 bounds->bottom = max( bounds->bottom, pts[i].y );
764 /* helper for path stroke and fill functions */
765 static BOOL emfdrv_stroke_and_fill_path( struct emf *emf, INT type )
767 EMRSTROKEANDFILLPATH emr;
768 HRGN region;
770 emr.emr.iType = type;
771 emr.emr.nSize = sizeof(emr);
772 emr.rclBounds = empty_bounds;
774 if ((region = NtGdiPathToRegion( emf->dc_attr->hdc )))
776 NtGdiGetRgnBox( region, (RECT *)&emr.rclBounds );
777 DeleteObject( region );
780 if (!emfdc_record( emf, &emr.emr )) return FALSE;
781 if (!region) return FALSE;
782 emfdc_update_bounds( emf, &emr.rclBounds );
783 return TRUE;
786 BOOL EMFDC_MoveTo( DC_ATTR *dc_attr, INT x, INT y )
788 struct emf *emf = dc_attr->emf;
789 EMRMOVETOEX emr;
791 emr.emr.iType = EMR_MOVETOEX;
792 emr.emr.nSize = sizeof(emr);
793 emr.ptl.x = x;
794 emr.ptl.y = y;
795 return emfdc_record( emf, &emr.emr );
798 BOOL EMFDC_LineTo( DC_ATTR *dc_attr, INT x, INT y )
800 EMRLINETO emr;
802 emr.emr.iType = EMR_LINETO;
803 emr.emr.nSize = sizeof(emr);
804 emr.ptl.x = x;
805 emr.ptl.y = y;
806 return emfdc_record( dc_attr->emf, &emr.emr );
809 BOOL EMFDC_ArcChordPie( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom,
810 INT xstart, INT ystart, INT xend, INT yend, DWORD type )
812 struct emf *emf = dc_attr->emf;
813 EMRARC emr;
814 INT temp;
816 if (left == right || top == bottom) return FALSE;
818 if (left > right) { temp = left; left = right; right = temp; }
819 if (top > bottom) { temp = top; top = bottom; bottom = temp; }
821 if (dc_attr->graphics_mode == GM_COMPATIBLE)
823 right--;
824 bottom--;
827 emr.emr.iType = type;
828 emr.emr.nSize = sizeof(emr);
829 emr.rclBox.left = left;
830 emr.rclBox.top = top;
831 emr.rclBox.right = right;
832 emr.rclBox.bottom = bottom;
833 emr.ptlStart.x = xstart;
834 emr.ptlStart.y = ystart;
835 emr.ptlEnd.x = xend;
836 emr.ptlEnd.y = yend;
837 return emfdc_record( emf, &emr.emr );
840 BOOL EMFDC_AngleArc( DC_ATTR *dc_attr, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep )
842 EMRANGLEARC emr;
844 emr.emr.iType = EMR_ANGLEARC;
845 emr.emr.nSize = sizeof( emr );
846 emr.ptlCenter.x = x;
847 emr.ptlCenter.y = y;
848 emr.nRadius = radius;
849 emr.eStartAngle = start;
850 emr.eSweepAngle = sweep;
851 return emfdc_record( dc_attr->emf, &emr.emr );
854 BOOL EMFDC_Ellipse( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom )
856 struct emf *emf = dc_attr->emf;
857 EMRELLIPSE emr;
859 if (left == right || top == bottom) return FALSE;
861 emr.emr.iType = EMR_ELLIPSE;
862 emr.emr.nSize = sizeof(emr);
863 emr.rclBox.left = min( left, right );
864 emr.rclBox.top = min( top, bottom );
865 emr.rclBox.right = max( left, right );
866 emr.rclBox.bottom = max( top, bottom );
867 if (dc_attr->graphics_mode == GM_COMPATIBLE)
869 emr.rclBox.right--;
870 emr.rclBox.bottom--;
872 return emfdc_record( emf, &emr.emr );
875 BOOL EMFDC_Rectangle( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom )
877 struct emf *emf = dc_attr->emf;
878 EMRRECTANGLE emr;
880 if(left == right || top == bottom) return FALSE;
882 emr.emr.iType = EMR_RECTANGLE;
883 emr.emr.nSize = sizeof(emr);
884 emr.rclBox.left = min( left, right );
885 emr.rclBox.top = min( top, bottom );
886 emr.rclBox.right = max( left, right );
887 emr.rclBox.bottom = max( top, bottom );
888 if (dc_attr->graphics_mode == GM_COMPATIBLE)
890 emr.rclBox.right--;
891 emr.rclBox.bottom--;
893 return emfdc_record( emf, &emr.emr );
896 BOOL EMFDC_RoundRect( DC_ATTR *dc_attr, INT left, INT top, INT right,
897 INT bottom, INT ell_width, INT ell_height )
899 struct emf *emf = dc_attr->emf;
900 EMRROUNDRECT emr;
902 if (left == right || top == bottom) return FALSE;
904 emr.emr.iType = EMR_ROUNDRECT;
905 emr.emr.nSize = sizeof(emr);
906 emr.rclBox.left = min( left, right );
907 emr.rclBox.top = min( top, bottom );
908 emr.rclBox.right = max( left, right );
909 emr.rclBox.bottom = max( top, bottom );
910 emr.szlCorner.cx = ell_width;
911 emr.szlCorner.cy = ell_height;
912 if (dc_attr->graphics_mode == GM_COMPATIBLE)
914 emr.rclBox.right--;
915 emr.rclBox.bottom--;
917 return emfdc_record( emf, &emr.emr );
920 BOOL EMFDC_SetPixel( DC_ATTR *dc_attr, INT x, INT y, COLORREF color )
922 EMRSETPIXELV emr;
924 emr.emr.iType = EMR_SETPIXELV;
925 emr.emr.nSize = sizeof(emr);
926 emr.ptlPixel.x = x;
927 emr.ptlPixel.y = y;
928 emr.crColor = color;
929 return emfdc_record( dc_attr->emf, &emr.emr );
932 static BOOL emfdc_polylinegon( DC_ATTR *dc_attr, const POINT *points, INT count, DWORD type )
934 struct emf *emf = dc_attr->emf;
935 EMRPOLYLINE *emr;
936 DWORD size;
937 BOOL ret, use_small_emr = can_use_short_points( points, count );
939 size = use_small_emr ? offsetof( EMRPOLYLINE16, apts[count] ) : offsetof( EMRPOLYLINE, aptl[count] );
941 emr = HeapAlloc( GetProcessHeap(), 0, size );
942 emr->emr.iType = use_small_emr ? type + EMR_POLYLINE16 - EMR_POLYLINE : type;
943 emr->emr.nSize = size;
944 emr->cptl = count;
946 store_points( emr->aptl, points, count, use_small_emr );
948 if (!emf->path)
949 get_points_bounds( &emr->rclBounds, points, count,
950 (type == EMR_POLYBEZIERTO || type == EMR_POLYLINETO) ? dc_attr : 0 );
951 else
952 emr->rclBounds = empty_bounds;
954 ret = emfdc_record( emf, &emr->emr );
955 if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds );
956 HeapFree( GetProcessHeap(), 0, emr );
957 return ret;
960 BOOL EMFDC_Polyline( DC_ATTR *dc_attr, const POINT *points, INT count )
962 return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINE );
965 BOOL EMFDC_PolylineTo( DC_ATTR *dc_attr, const POINT *points, INT count )
967 return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINETO );
970 BOOL EMFDC_Polygon( DC_ATTR *dc_attr, const POINT *pt, INT count )
972 if(count < 2) return FALSE;
973 return emfdc_polylinegon( dc_attr, pt, count, EMR_POLYGON );
976 BOOL EMFDC_PolyBezier( DC_ATTR *dc_attr, const POINT *pts, DWORD count )
978 return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIER );
981 BOOL EMFDC_PolyBezierTo( DC_ATTR *dc_attr, const POINT *pts, DWORD count )
983 return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIERTO );
986 static BOOL emfdc_poly_polylinegon( struct emf *emf, const POINT *pt, const INT *counts,
987 UINT polys, DWORD type)
989 EMRPOLYPOLYLINE *emr;
990 DWORD cptl = 0, poly, size;
991 BOOL ret, use_small_emr, bounds_valid = TRUE;
993 for(poly = 0; poly < polys; poly++) {
994 cptl += counts[poly];
995 if(counts[poly] < 2) bounds_valid = FALSE;
997 if(!cptl) bounds_valid = FALSE;
998 use_small_emr = can_use_short_points( pt, cptl );
1000 size = FIELD_OFFSET(EMRPOLYPOLYLINE, aPolyCounts[polys]);
1001 if(use_small_emr)
1002 size += cptl * sizeof(POINTS);
1003 else
1004 size += cptl * sizeof(POINTL);
1006 emr = HeapAlloc( GetProcessHeap(), 0, size );
1008 emr->emr.iType = type;
1009 if(use_small_emr) emr->emr.iType += EMR_POLYPOLYLINE16 - EMR_POLYPOLYLINE;
1011 emr->emr.nSize = size;
1012 if(bounds_valid && !emf->path)
1013 get_points_bounds( &emr->rclBounds, pt, cptl, 0 );
1014 else
1015 emr->rclBounds = empty_bounds;
1016 emr->nPolys = polys;
1017 emr->cptl = cptl;
1019 if(polys)
1021 memcpy( emr->aPolyCounts, counts, polys * sizeof(DWORD) );
1022 store_points( (POINTL *)(emr->aPolyCounts + polys), pt, cptl, use_small_emr );
1025 ret = emfdc_record( emf, &emr->emr );
1026 if(ret && !bounds_valid)
1028 ret = FALSE;
1029 SetLastError( ERROR_INVALID_PARAMETER );
1031 if(ret && !emf->path)
1032 emfdc_update_bounds( emf, &emr->rclBounds );
1033 HeapFree( GetProcessHeap(), 0, emr );
1034 return ret;
1037 BOOL EMFDC_PolyPolyline( DC_ATTR *dc_attr, const POINT *pt, const DWORD *counts, DWORD polys)
1039 return emfdc_poly_polylinegon( dc_attr->emf, pt, (const INT *)counts, polys, EMR_POLYPOLYLINE );
1042 BOOL EMFDC_PolyPolygon( DC_ATTR *dc_attr, const POINT *pt, const INT *counts, UINT polys )
1044 return emfdc_poly_polylinegon( dc_attr->emf, pt, counts, polys, EMR_POLYPOLYGON );
1047 BOOL EMFDC_PolyDraw( DC_ATTR *dc_attr, const POINT *pts, const BYTE *types, DWORD count )
1049 struct emf *emf = dc_attr->emf;
1050 EMRPOLYDRAW *emr;
1051 BOOL ret;
1052 BYTE *types_dest;
1053 BOOL use_small_emr = can_use_short_points( pts, count );
1054 DWORD size;
1056 size = use_small_emr ? offsetof( EMRPOLYDRAW16, apts[count] )
1057 : offsetof( EMRPOLYDRAW, aptl[count] );
1058 size += (count + 3) & ~3;
1060 if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
1062 emr->emr.iType = use_small_emr ? EMR_POLYDRAW16 : EMR_POLYDRAW;
1063 emr->emr.nSize = size;
1064 emr->cptl = count;
1066 types_dest = store_points( emr->aptl, pts, count, use_small_emr );
1067 memcpy( types_dest, types, count );
1068 if (count & 3) memset( types_dest + count, 0, 4 - (count & 3) );
1070 if (!emf->path)
1071 get_points_bounds( &emr->rclBounds, pts, count, 0 );
1072 else
1073 emr->rclBounds = empty_bounds;
1075 ret = emfdc_record( emf, &emr->emr );
1076 if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds );
1077 HeapFree( GetProcessHeap(), 0, emr );
1078 return ret;
1081 BOOL EMFDC_ExtFloodFill( DC_ATTR *dc_attr, INT x, INT y, COLORREF color, UINT fill_type )
1083 EMREXTFLOODFILL emr;
1085 emr.emr.iType = EMR_EXTFLOODFILL;
1086 emr.emr.nSize = sizeof(emr);
1087 emr.ptlStart.x = x;
1088 emr.ptlStart.y = y;
1089 emr.crColor = color;
1090 emr.iMode = fill_type;
1091 return emfdc_record( dc_attr->emf, &emr.emr );
1094 BOOL EMFDC_FillRgn( DC_ATTR *dc_attr, HRGN hrgn, HBRUSH hbrush )
1096 struct emf *emf = dc_attr->emf;
1097 EMRFILLRGN *emr;
1098 DWORD size, rgnsize, index;
1099 BOOL ret;
1101 if (!(index = emfdc_create_brush( emf, hbrush ))) return FALSE;
1103 rgnsize = NtGdiGetRegionData( hrgn, 0, NULL );
1104 size = rgnsize + offsetof(EMRFILLRGN,RgnData);
1105 emr = HeapAlloc( GetProcessHeap(), 0, size );
1107 NtGdiGetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
1109 emr->emr.iType = EMR_FILLRGN;
1110 emr->emr.nSize = size;
1111 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
1112 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
1113 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
1114 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
1115 emr->cbRgnData = rgnsize;
1116 emr->ihBrush = index;
1118 ret = emfdc_record( emf, &emr->emr );
1119 if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1120 HeapFree( GetProcessHeap(), 0, emr );
1121 return ret;
1124 BOOL EMFDC_FrameRgn( DC_ATTR *dc_attr, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
1126 struct emf *emf = dc_attr->emf;
1127 EMRFRAMERGN *emr;
1128 DWORD size, rgnsize, index;
1129 BOOL ret;
1131 index = emfdc_create_brush( emf, hbrush );
1132 if(!index) return FALSE;
1134 rgnsize = NtGdiGetRegionData( hrgn, 0, NULL );
1135 size = rgnsize + offsetof(EMRFRAMERGN,RgnData);
1136 emr = HeapAlloc( GetProcessHeap(), 0, size );
1138 NtGdiGetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
1140 emr->emr.iType = EMR_FRAMERGN;
1141 emr->emr.nSize = size;
1142 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
1143 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
1144 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
1145 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
1146 emr->cbRgnData = rgnsize;
1147 emr->ihBrush = index;
1148 emr->szlStroke.cx = width;
1149 emr->szlStroke.cy = height;
1151 ret = emfdc_record( emf, &emr->emr );
1152 if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1153 HeapFree( GetProcessHeap(), 0, emr );
1154 return ret;
1157 static BOOL emfdc_paint_invert_region( struct emf *emf, HRGN hrgn, DWORD iType )
1159 EMRINVERTRGN *emr;
1160 DWORD size, rgnsize;
1161 BOOL ret;
1163 rgnsize = NtGdiGetRegionData( hrgn, 0, NULL );
1164 size = rgnsize + offsetof(EMRINVERTRGN,RgnData);
1165 emr = HeapAlloc( GetProcessHeap(), 0, size );
1167 NtGdiGetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
1169 emr->emr.iType = iType;
1170 emr->emr.nSize = size;
1171 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
1172 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
1173 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
1174 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
1175 emr->cbRgnData = rgnsize;
1177 ret = emfdc_record( emf, &emr->emr );
1178 if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1179 HeapFree( GetProcessHeap(), 0, emr );
1180 return ret;
1183 BOOL EMFDC_PaintRgn( DC_ATTR *dc_attr, HRGN hrgn )
1185 return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_PAINTRGN );
1188 BOOL EMFDC_InvertRgn( DC_ATTR *dc_attr, HRGN hrgn )
1190 return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_INVERTRGN );
1193 BOOL EMFDC_ExtTextOut( DC_ATTR *dc_attr, INT x, INT y, UINT flags, const RECT *rect,
1194 const WCHAR *str, UINT count, const INT *dx )
1196 struct emf *emf = dc_attr->emf;
1197 FLOAT ex_scale, ey_scale;
1198 EMREXTTEXTOUTW *emr;
1199 int text_height = 0;
1200 int text_width = 0;
1201 TEXTMETRICW tm;
1202 DWORD size;
1203 BOOL ret;
1205 size = sizeof(*emr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(INT);
1207 TRACE( "%s %s count %d size = %d\n", debugstr_wn(str, count),
1208 wine_dbgstr_rect(rect), count, size );
1209 emr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
1211 if (dc_attr->graphics_mode == GM_COMPATIBLE)
1213 const INT horzSize = GetDeviceCaps( dc_attr->hdc, HORZSIZE );
1214 const INT horzRes = GetDeviceCaps( dc_attr->hdc, HORZRES );
1215 const INT vertSize = GetDeviceCaps( dc_attr->hdc, VERTSIZE );
1216 const INT vertRes = GetDeviceCaps( dc_attr->hdc, VERTRES );
1217 SIZE wndext, vportext;
1219 GetViewportExtEx( dc_attr->hdc, &vportext );
1220 GetWindowExtEx( dc_attr->hdc, &wndext );
1221 ex_scale = 100.0 * ((FLOAT)horzSize / (FLOAT)horzRes) /
1222 ((FLOAT)wndext.cx / (FLOAT)vportext.cx);
1223 ey_scale = 100.0 * ((FLOAT)vertSize / (FLOAT)vertRes) /
1224 ((FLOAT)wndext.cy / (FLOAT)vportext.cy);
1226 else
1228 ex_scale = 0.0;
1229 ey_scale = 0.0;
1232 emr->emr.iType = EMR_EXTTEXTOUTW;
1233 emr->emr.nSize = size;
1234 emr->iGraphicsMode = dc_attr->graphics_mode;
1235 emr->exScale = ex_scale;
1236 emr->eyScale = ey_scale;
1237 emr->emrtext.ptlReference.x = x;
1238 emr->emrtext.ptlReference.y = y;
1239 emr->emrtext.nChars = count;
1240 emr->emrtext.offString = sizeof(*emr);
1241 memcpy( (char*)emr + emr->emrtext.offString, str, count * sizeof(WCHAR) );
1242 emr->emrtext.fOptions = flags;
1243 if (!rect)
1245 emr->emrtext.rcl.left = emr->emrtext.rcl.top = 0;
1246 emr->emrtext.rcl.right = emr->emrtext.rcl.bottom = -1;
1248 else
1250 emr->emrtext.rcl.left = rect->left;
1251 emr->emrtext.rcl.top = rect->top;
1252 emr->emrtext.rcl.right = rect->right;
1253 emr->emrtext.rcl.bottom = rect->bottom;
1256 emr->emrtext.offDx = emr->emrtext.offString + ((count+1) & ~1) * sizeof(WCHAR);
1257 if (dx)
1259 UINT i;
1260 SIZE str_size;
1261 memcpy( (char*)emr + emr->emrtext.offDx, dx, count * sizeof(INT) );
1262 for (i = 0; i < count; i++) text_width += dx[i];
1263 if (GetTextExtentPoint32W( dc_attr->hdc, str, count, &str_size ))
1264 text_height = str_size.cy;
1266 else
1268 UINT i;
1269 INT *emf_dx = (INT *)((char*)emr + emr->emrtext.offDx);
1270 SIZE charSize;
1271 for (i = 0; i < count; i++)
1273 if (GetTextExtentPoint32W( dc_attr->hdc, str + i, 1, &charSize ))
1275 emf_dx[i] = charSize.cx;
1276 text_width += charSize.cx;
1277 text_height = max( text_height, charSize.cy );
1282 if (emf->path)
1284 emr->rclBounds.left = emr->rclBounds.top = 0;
1285 emr->rclBounds.right = emr->rclBounds.bottom = -1;
1286 goto no_bounds;
1289 /* FIXME: handle font escapement */
1290 switch (dc_attr->text_align & (TA_LEFT | TA_RIGHT | TA_CENTER))
1292 case TA_CENTER:
1293 emr->rclBounds.left = x - (text_width / 2) - 1;
1294 emr->rclBounds.right = x + (text_width / 2) + 1;
1295 break;
1297 case TA_RIGHT:
1298 emr->rclBounds.left = x - text_width - 1;
1299 emr->rclBounds.right = x;
1300 break;
1302 default: /* TA_LEFT */
1303 emr->rclBounds.left = x;
1304 emr->rclBounds.right = x + text_width + 1;
1307 switch (dc_attr->text_align & (TA_TOP | TA_BOTTOM | TA_BASELINE))
1309 case TA_BASELINE:
1310 if (!GetTextMetricsW( dc_attr->hdc, &tm )) tm.tmDescent = 0;
1311 /* Play safe here... it's better to have a bounding box */
1312 /* that is too big than too small. */
1313 emr->rclBounds.top = y - text_height - 1;
1314 emr->rclBounds.bottom = y + tm.tmDescent + 1;
1315 break;
1317 case TA_BOTTOM:
1318 emr->rclBounds.top = y - text_height - 1;
1319 emr->rclBounds.bottom = y;
1320 break;
1322 default: /* TA_TOP */
1323 emr->rclBounds.top = y;
1324 emr->rclBounds.bottom = y + text_height + 1;
1326 emfdc_update_bounds( emf, &emr->rclBounds );
1328 no_bounds:
1329 ret = emfdc_record( emf, &emr->emr );
1330 HeapFree( GetProcessHeap(), 0, emr );
1331 return ret;
1334 BOOL EMFDC_GradientFill( DC_ATTR *dc_attr, TRIVERTEX *vert_array, ULONG nvert,
1335 void *grad_array, ULONG ngrad, ULONG mode )
1337 EMRGRADIENTFILL *emr;
1338 ULONG i, pt, size, num_pts = ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2);
1339 const ULONG *pts = (const ULONG *)grad_array;
1340 BOOL ret;
1342 size = FIELD_OFFSET(EMRGRADIENTFILL, Ver[nvert]) + num_pts * sizeof(pts[0]);
1344 emr = HeapAlloc( GetProcessHeap(), 0, size );
1345 if (!emr) return FALSE;
1347 for (i = 0; i < num_pts; i++)
1349 pt = pts[i];
1351 if (i == 0)
1353 emr->rclBounds.left = emr->rclBounds.right = vert_array[pt].x;
1354 emr->rclBounds.top = emr->rclBounds.bottom = vert_array[pt].y;
1356 else
1358 if (vert_array[pt].x < emr->rclBounds.left)
1359 emr->rclBounds.left = vert_array[pt].x;
1360 else if (vert_array[pt].x > emr->rclBounds.right)
1361 emr->rclBounds.right = vert_array[pt].x;
1362 if (vert_array[pt].y < emr->rclBounds.top)
1363 emr->rclBounds.top = vert_array[pt].y;
1364 else if (vert_array[pt].y > emr->rclBounds.bottom)
1365 emr->rclBounds.bottom = vert_array[pt].y;
1368 emr->rclBounds.right--;
1369 emr->rclBounds.bottom--;
1371 emr->emr.iType = EMR_GRADIENTFILL;
1372 emr->emr.nSize = size;
1373 emr->nVer = nvert;
1374 emr->nTri = ngrad;
1375 emr->ulMode = mode;
1376 memcpy( emr->Ver, vert_array, nvert * sizeof(vert_array[0]) );
1377 memcpy( emr->Ver + nvert, pts, num_pts * sizeof(pts[0]) );
1379 emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
1380 ret = emfdc_record( dc_attr->emf, &emr->emr );
1381 HeapFree( GetProcessHeap(), 0, emr );
1382 return ret;
1385 BOOL EMFDC_FillPath( DC_ATTR *dc_attr )
1387 return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_FILLPATH );
1390 BOOL EMFDC_StrokeAndFillPath( DC_ATTR *dc_attr )
1392 return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEANDFILLPATH );
1395 BOOL EMFDC_StrokePath( DC_ATTR *dc_attr )
1397 return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEPATH );
1400 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
1401 static BOOL emfdrv_stretchblt( struct emf *emf, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1402 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
1403 DWORD rop, DWORD type )
1405 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
1406 UINT bmi_size, emr_size, size;
1407 HBITMAP bitmap, blit_bitmap = NULL;
1408 EMRBITBLT *emr = NULL;
1409 BITMAPINFO *bmi;
1410 HDC blit_dc;
1411 BOOL ret = FALSE;
1413 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
1415 blit_dc = hdc_src;
1416 blit_bitmap = bitmap;
1417 if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
1419 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
1420 emr_size = type == EMR_BITBLT ? sizeof(EMRBITBLT) : sizeof(EMRSTRETCHBLT);
1421 size = emr_size + bmi_size + src_info.bmiHeader.biSizeImage;
1423 if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
1425 emr->emr.iType = type;
1426 emr->emr.nSize = size;
1427 emr->rclBounds.left = x_dst;
1428 emr->rclBounds.top = y_dst;
1429 emr->rclBounds.right = x_dst + width_dst - 1;
1430 emr->rclBounds.bottom = y_dst + height_dst - 1;
1431 emr->xDest = x_dst;
1432 emr->yDest = y_dst;
1433 emr->cxDest = width_dst;
1434 emr->cyDest = height_dst;
1435 emr->xSrc = x_src;
1436 emr->ySrc = y_src;
1437 if (type != EMR_BITBLT)
1439 EMRSTRETCHBLT *emr_stretchblt = (EMRSTRETCHBLT *)emr;
1440 emr_stretchblt->cxSrc = width_src;
1441 emr_stretchblt->cySrc = height_src;
1443 emr->dwRop = rop;
1444 NtGdiGetTransform( hdc_src, 0x204, &emr->xformSrc );
1445 emr->crBkColorSrc = GetBkColor( hdc_src );
1446 emr->iUsageSrc = DIB_RGB_COLORS;
1447 emr->offBmiSrc = emr_size;
1448 emr->cbBmiSrc = bmi_size;
1449 emr->offBitsSrc = emr_size + bmi_size;
1450 emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
1452 bmi = (BITMAPINFO *)((BYTE *)emr + emr->offBmiSrc);
1453 bmi->bmiHeader = src_info.bmiHeader;
1454 ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
1455 (BYTE *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
1456 if (ret)
1458 ret = emfdc_record( emf, (EMR *)emr );
1459 if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1462 err:
1463 HeapFree( GetProcessHeap(), 0, emr );
1464 if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
1465 if (blit_dc != hdc_src) DeleteDC( blit_dc );
1466 return ret;
1469 BOOL EMFDC_AlphaBlend( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1470 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
1471 BLENDFUNCTION blend_function )
1473 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst, hdc_src,
1474 x_src, y_src, width_src, height_src, *(DWORD *)&blend_function,
1475 EMR_ALPHABLEND );
1478 BOOL EMFDC_PatBlt( DC_ATTR *dc_attr, INT left, INT top, INT width, INT height, DWORD rop )
1480 struct emf *emf = dc_attr->emf;
1481 EMRBITBLT emr;
1482 BOOL ret;
1484 emr.emr.iType = EMR_BITBLT;
1485 emr.emr.nSize = sizeof(emr);
1486 emr.rclBounds.left = left;
1487 emr.rclBounds.top = top;
1488 emr.rclBounds.right = left + width - 1;
1489 emr.rclBounds.bottom = top + height - 1;
1490 emr.xDest = left;
1491 emr.yDest = top;
1492 emr.cxDest = width;
1493 emr.cyDest = height;
1494 emr.dwRop = rop;
1495 emr.xSrc = 0;
1496 emr.ySrc = 0;
1497 emr.xformSrc.eM11 = 1.0;
1498 emr.xformSrc.eM12 = 0.0;
1499 emr.xformSrc.eM21 = 0.0;
1500 emr.xformSrc.eM22 = 1.0;
1501 emr.xformSrc.eDx = 0.0;
1502 emr.xformSrc.eDy = 0.0;
1503 emr.crBkColorSrc = 0;
1504 emr.iUsageSrc = 0;
1505 emr.offBmiSrc = 0;
1506 emr.cbBmiSrc = 0;
1507 emr.offBitsSrc = 0;
1508 emr.cbBitsSrc = 0;
1510 ret = emfdc_record( emf, &emr.emr );
1511 if (ret) emfdc_update_bounds( emf, &emr.rclBounds );
1512 return ret;
1515 static inline BOOL rop_uses_src( DWORD rop )
1517 return ((rop >> 2) & 0x330000) != (rop & 0x330000);
1520 BOOL EMFDC_BitBlt( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width, INT height,
1521 HDC hdc_src, INT x_src, INT y_src, DWORD rop )
1523 if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width, height, rop );
1524 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width, height,
1525 hdc_src, x_src, y_src, width, height, rop, EMR_BITBLT );
1528 BOOL EMFDC_StretchBlt( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1529 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
1530 DWORD rop )
1532 if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
1533 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
1534 hdc_src, x_src, y_src, width_src,
1535 height_src, rop, EMR_STRETCHBLT );
1538 BOOL EMFDC_TransparentBlt( DC_ATTR *dc_attr, int x_dst, int y_dst, int width_dst, int height_dst,
1539 HDC hdc_src, int x_src, int y_src, int width_src, int height_src,
1540 UINT color )
1542 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
1543 hdc_src, x_src, y_src, width_src,
1544 height_src, color, EMR_TRANSPARENTBLT );
1547 BOOL EMFDC_MaskBlt( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1548 HDC hdc_src, INT x_src, INT y_src, HBITMAP mask,
1549 INT x_mask, INT y_mask, DWORD rop )
1551 unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1552 BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer;
1553 struct emf *emf = dc_attr->emf;
1554 BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }};
1555 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
1556 HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL;
1557 UINT bmi_size, size, mask_info_size = 0;
1558 EMRMASKBLT *emr = NULL;
1559 BITMAPINFO *bmi;
1560 HDC blit_dc, mask_dc = NULL;
1561 BOOL ret = FALSE;
1563 if (!rop_uses_src( rop ))
1564 return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
1566 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
1567 blit_dc = hdc_src;
1568 blit_bitmap = bitmap;
1569 if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
1571 if (mask)
1573 mask_dc = hdc_src;
1574 mask_bitmap = mask;
1575 if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err;
1576 if (mask_info.bmiHeader.biBitCount == 1)
1577 mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */
1579 else mask_info.bmiHeader.biSizeImage = 0;
1581 size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage +
1582 mask_info_size + mask_info.bmiHeader.biSizeImage;
1584 if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
1586 emr->emr.iType = EMR_MASKBLT;
1587 emr->emr.nSize = size;
1588 emr->rclBounds.left = x_dst;
1589 emr->rclBounds.top = y_dst;
1590 emr->rclBounds.right = x_dst + width_dst - 1;
1591 emr->rclBounds.bottom = y_dst + height_dst - 1;
1592 emr->xDest = x_dst;
1593 emr->yDest = y_dst;
1594 emr->cxDest = width_dst;
1595 emr->cyDest = height_dst;
1596 emr->dwRop = rop;
1597 emr->xSrc = x_src;
1598 emr->ySrc = y_src;
1599 NtGdiGetTransform( hdc_src, 0x204, &emr->xformSrc );
1600 emr->crBkColorSrc = GetBkColor( hdc_src );
1601 emr->iUsageSrc = DIB_RGB_COLORS;
1602 emr->offBmiSrc = sizeof(*emr);
1603 emr->cbBmiSrc = bmi_size;
1604 emr->offBitsSrc = emr->offBmiSrc + bmi_size;
1605 emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
1606 emr->xMask = x_mask;
1607 emr->yMask = y_mask;
1608 emr->iUsageMask = DIB_PAL_MONO;
1609 emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0;
1610 emr->cbBmiMask = mask_info_size;
1611 emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask;
1612 emr->cbBitsMask = mask_info.bmiHeader.biSizeImage;
1614 bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc);
1615 bmi->bmiHeader = src_info.bmiHeader;
1616 ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
1617 (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
1618 if (!ret) goto err;
1620 if (mask_info_size)
1622 mask_bits_info->bmiHeader = mask_info.bmiHeader;
1623 ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight,
1624 (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS );
1625 if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size );
1628 if (ret)
1630 ret = emfdc_record( emf, (EMR *)emr );
1631 if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1634 err:
1635 HeapFree( GetProcessHeap(), 0, emr );
1636 if (mask_bitmap != mask) DeleteObject( mask_bitmap );
1637 if (mask_dc != hdc_src) DeleteObject( mask_dc );
1638 if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
1639 if (blit_dc != hdc_src) DeleteDC( blit_dc );
1640 return ret;
1643 BOOL EMFDC_PlgBlt( DC_ATTR *dc_attr, const POINT *points, HDC hdc_src, INT x_src, INT y_src,
1644 INT width, INT height, HBITMAP mask, INT x_mask, INT y_mask )
1646 unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
1647 BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer;
1648 struct emf *emf = dc_attr->emf;
1649 BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }};
1650 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
1651 HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL;
1652 UINT bmi_size, size, mask_info_size = 0;
1653 EMRPLGBLT *emr = NULL;
1654 BITMAPINFO *bmi;
1655 HDC blit_dc, mask_dc = NULL;
1656 int x_min, y_min, x_max, y_max, i;
1657 BOOL ret = FALSE;
1659 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
1661 blit_dc = hdc_src;
1662 blit_bitmap = bitmap;
1663 if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
1665 if (mask)
1667 mask_dc = hdc_src;
1668 mask_bitmap = mask;
1669 if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err;
1670 if (mask_info.bmiHeader.biBitCount == 1)
1671 mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */
1673 else mask_info.bmiHeader.biSizeImage = 0;
1675 size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage +
1676 mask_info_size + mask_info.bmiHeader.biSizeImage;
1678 if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
1680 emr->emr.iType = EMR_PLGBLT;
1681 emr->emr.nSize = size;
1683 /* FIXME: not exactly what native does */
1684 x_min = x_max = points[1].x + points[2].x - points[0].x;
1685 y_min = y_max = points[1].y + points[2].y - points[0].y;
1686 for (i = 0; i < ARRAYSIZE(emr->aptlDest); i++)
1688 x_min = min( x_min, points[i].x );
1689 y_min = min( y_min, points[i].y );
1690 x_max = max( x_max, points[i].x );
1691 y_max = max( y_min, points[i].y );
1693 emr->rclBounds.left = x_min;
1694 emr->rclBounds.top = y_min;
1695 emr->rclBounds.right = x_max;
1696 emr->rclBounds.bottom = y_max;
1697 memcpy( emr->aptlDest, points, sizeof(emr->aptlDest) );
1698 emr->xSrc = x_src;
1699 emr->ySrc = y_src;
1700 emr->cxSrc = width;
1701 emr->cySrc = height;
1702 NtGdiGetTransform( hdc_src, 0x204, &emr->xformSrc );
1703 emr->crBkColorSrc = GetBkColor( hdc_src );
1704 emr->iUsageSrc = DIB_RGB_COLORS;
1705 emr->offBmiSrc = sizeof(*emr);
1706 emr->cbBmiSrc = bmi_size;
1707 emr->offBitsSrc = emr->offBmiSrc + bmi_size;
1708 emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
1709 emr->xMask = x_mask;
1710 emr->yMask = y_mask;
1711 emr->iUsageMask = DIB_PAL_MONO;
1712 emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0;
1713 emr->cbBmiMask = mask_info_size;
1714 emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask;
1715 emr->cbBitsMask = mask_info.bmiHeader.biSizeImage;
1717 bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc);
1718 bmi->bmiHeader = src_info.bmiHeader;
1719 ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
1720 (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
1721 if (!ret) goto err;
1723 if (mask_info_size)
1725 mask_bits_info->bmiHeader = mask_info.bmiHeader;
1726 ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight,
1727 (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS );
1728 if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size );
1731 if (ret)
1733 ret = emfdc_record( emf, (EMR *)emr );
1734 if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1737 err:
1738 HeapFree( GetProcessHeap(), 0, emr );
1739 if (mask_bitmap != mask) DeleteObject( mask_bitmap );
1740 if (mask_dc != hdc_src) DeleteObject( mask_dc );
1741 if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
1742 if (blit_dc != hdc_src) DeleteDC( blit_dc );
1743 return ret;
1746 BOOL EMFDC_StretchDIBits( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1747 INT x_src, INT y_src, INT width_src, INT height_src, const void *bits,
1748 const BITMAPINFO *info, UINT usage, DWORD rop )
1750 EMRSTRETCHDIBITS *emr;
1751 BOOL ret;
1752 UINT bmi_size, img_size, payload_size, emr_size;
1753 BITMAPINFOHEADER bih;
1754 BITMAPINFO *bi;
1756 /* calculate the size of the colour table and the image */
1757 if (!emf_parse_user_bitmapinfo( &bih, &info->bmiHeader, usage, TRUE,
1758 &bmi_size, &img_size )) return 0;
1760 /* check for overflows */
1761 payload_size = bmi_size + img_size;
1762 if (payload_size < bmi_size) return 0;
1764 emr_size = sizeof (EMRSTRETCHDIBITS) + payload_size;
1765 if (emr_size < sizeof (EMRSTRETCHDIBITS)) return 0;
1767 /* allocate record */
1768 if (!(emr = HeapAlloc(GetProcessHeap(), 0, emr_size ))) return 0;
1770 /* write a bitmap info header (with colours) to the record */
1771 bi = (BITMAPINFO *)&emr[1];
1772 bi->bmiHeader = bih;
1773 emf_copy_colours_from_user_bitmapinfo( bi, info, usage );
1775 /* write bitmap bits to the record */
1776 memcpy ( (BYTE *)&emr[1] + bmi_size, bits, img_size );
1778 /* fill in the EMR header at the front of our piece of memory */
1779 emr->emr.iType = EMR_STRETCHDIBITS;
1780 emr->emr.nSize = emr_size;
1782 emr->xDest = x_dst;
1783 emr->yDest = y_dst;
1784 emr->cxDest = width_dst;
1785 emr->cyDest = height_dst;
1786 emr->dwRop = rop;
1787 emr->xSrc = x_src;
1788 emr->ySrc = y_src;
1790 emr->iUsageSrc = usage;
1791 emr->offBmiSrc = sizeof (EMRSTRETCHDIBITS);
1792 emr->cbBmiSrc = bmi_size;
1793 emr->offBitsSrc = emr->offBmiSrc + bmi_size;
1794 emr->cbBitsSrc = img_size;
1796 emr->cxSrc = width_src;
1797 emr->cySrc = height_src;
1799 emr->rclBounds.left = x_dst;
1800 emr->rclBounds.top = y_dst;
1801 emr->rclBounds.right = x_dst + width_dst - 1;
1802 emr->rclBounds.bottom = y_dst + height_dst - 1;
1804 /* save the record we just created */
1805 ret = emfdc_record( dc_attr->emf, &emr->emr );
1806 if (ret) emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
1807 HeapFree( GetProcessHeap(), 0, emr );
1808 return ret;
1811 BOOL EMFDC_SetDIBitsToDevice( DC_ATTR *dc_attr, INT x_dst, INT y_dst, DWORD width, DWORD height,
1812 INT x_src, INT y_src, UINT startscan, UINT lines,
1813 const void *bits, const BITMAPINFO *info, UINT usage )
1815 EMRSETDIBITSTODEVICE *emr;
1816 BOOL ret;
1817 UINT bmi_size, img_size, payload_size, emr_size;
1818 UINT src_height, stride;
1819 BITMAPINFOHEADER bih;
1820 BITMAPINFO *bi;
1822 /* calculate the size of the colour table and the image */
1823 if (!emf_parse_user_bitmapinfo( &bih, &info->bmiHeader, usage, TRUE,
1824 &bmi_size, &img_size )) return 0;
1826 if (bih.biHeight >= 0)
1828 src_height = (UINT)bih.biHeight;
1829 if (src_height > y_src + height) src_height = y_src + height;
1831 if (src_height < startscan) lines = 0;
1832 else if (lines > src_height - startscan) lines = src_height - startscan;
1834 if (!lines) return 0;
1836 if (bih.biCompression == BI_RGB || bih.biCompression == BI_BITFIELDS)
1838 /* truncate image and check for overflows */
1839 stride = get_dib_stride( bih.biWidth, bih.biBitCount );
1840 img_size = lines * stride;
1841 if (img_size / stride != lines) return 0;
1845 /* check for overflows */
1846 payload_size = bmi_size + img_size;
1847 if (payload_size < bmi_size) return 0;
1849 emr_size = sizeof (EMRSETDIBITSTODEVICE) + payload_size;
1850 if (emr_size < sizeof (EMRSETDIBITSTODEVICE)) return 0;
1852 /* allocate record */
1853 if (!(emr = HeapAlloc( GetProcessHeap(), 0, emr_size ))) return FALSE;
1855 /* write a bitmap info header (with colours) to the record */
1856 bi = (BITMAPINFO *)&emr[1];
1857 bi->bmiHeader = bih;
1858 emf_copy_colours_from_user_bitmapinfo( bi, info, usage );
1860 /* write bitmap bits to the record */
1861 memcpy ( (BYTE *)&emr[1] + bmi_size, bits, img_size );
1863 emr->emr.iType = EMR_SETDIBITSTODEVICE;
1864 emr->emr.nSize = emr_size;
1865 emr->rclBounds.left = x_dst;
1866 emr->rclBounds.top = y_dst;
1867 emr->rclBounds.right = x_dst + width - 1;
1868 emr->rclBounds.bottom = y_dst + height - 1;
1869 emr->xDest = x_dst;
1870 emr->yDest = y_dst;
1871 emr->xSrc = x_src;
1872 emr->ySrc = y_src;
1873 emr->cxSrc = width;
1874 emr->cySrc = height;
1875 emr->offBmiSrc = sizeof(EMRSETDIBITSTODEVICE);
1876 emr->cbBmiSrc = bmi_size;
1877 emr->offBitsSrc = sizeof(EMRSETDIBITSTODEVICE) + bmi_size;
1878 emr->cbBitsSrc = img_size;
1879 emr->iUsageSrc = usage;
1880 emr->iStartScan = startscan;
1881 emr->cScans = lines;
1883 if ((ret = emfdc_record( dc_attr->emf, (EMR*)emr )))
1884 emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
1886 HeapFree( GetProcessHeap(), 0, emr );
1887 return ret;
1890 BOOL EMFDC_SetDCBrushColor( DC_ATTR *dc_attr, COLORREF color )
1892 struct emf *emf = dc_attr->emf;
1893 EMRSELECTOBJECT emr;
1894 DWORD index;
1896 if (GetCurrentObject( dc_attr->hdc, OBJ_BRUSH ) != GetStockObject( DC_BRUSH )) return TRUE;
1898 if (emf->dc_brush) DeleteObject( emf->dc_brush );
1899 if (!(emf->dc_brush = CreateSolidBrush( color ))) return FALSE;
1900 if (!(index = emfdc_create_brush( emf, emf->dc_brush ))) return FALSE;
1901 GDI_hdc_using_object( emf->dc_brush, dc_attr->hdc, emfdc_delete_object );
1902 emr.emr.iType = EMR_SELECTOBJECT;
1903 emr.emr.nSize = sizeof(emr);
1904 emr.ihObject = index;
1905 return emfdc_record( emf, &emr.emr );
1908 BOOL EMFDC_SetDCPenColor( DC_ATTR *dc_attr, COLORREF color )
1910 struct emf *emf = dc_attr->emf;
1911 EMRSELECTOBJECT emr;
1912 DWORD index;
1913 LOGPEN logpen = { PS_SOLID, { 0, 0 }, color };
1915 if (GetCurrentObject( dc_attr->hdc, OBJ_PEN ) != GetStockObject( DC_PEN )) return TRUE;
1917 if (emf->dc_pen) DeleteObject( emf->dc_pen );
1918 if (!(emf->dc_pen = CreatePenIndirect( &logpen ))) return FALSE;
1919 if (!(index = emfdc_create_pen( emf, emf->dc_pen ))) return FALSE;
1920 GDI_hdc_using_object( emf->dc_pen, dc_attr->hdc, emfdc_delete_object );
1921 emr.emr.iType = EMR_SELECTOBJECT;
1922 emr.emr.nSize = sizeof(emr);
1923 emr.ihObject = index;
1924 return emfdc_record( emf, &emr.emr );
1927 BOOL EMFDC_SaveDC( DC_ATTR *dc_attr )
1929 EMRSAVEDC emr;
1931 emr.emr.iType = EMR_SAVEDC;
1932 emr.emr.nSize = sizeof(emr);
1933 return emfdc_record( dc_attr->emf, &emr.emr );
1936 BOOL EMFDC_RestoreDC( DC_ATTR *dc_attr, INT level )
1938 EMRRESTOREDC emr;
1940 if (abs(level) > dc_attr->save_level || level == 0) return FALSE;
1942 emr.emr.iType = EMR_RESTOREDC;
1943 emr.emr.nSize = sizeof(emr);
1944 if (level < 0)
1945 emr.iRelative = level;
1946 else
1947 emr.iRelative = level - dc_attr->save_level - 1;
1948 return emfdc_record( dc_attr->emf, &emr.emr );
1951 BOOL EMFDC_SetTextAlign( DC_ATTR *dc_attr, UINT align )
1953 EMRSETTEXTALIGN emr;
1955 emr.emr.iType = EMR_SETTEXTALIGN;
1956 emr.emr.nSize = sizeof(emr);
1957 emr.iMode = align;
1958 return emfdc_record( dc_attr->emf, &emr.emr );
1961 BOOL EMFDC_SetTextJustification( DC_ATTR *dc_attr, INT extra, INT breaks )
1963 EMRSETTEXTJUSTIFICATION emr;
1965 emr.emr.iType = EMR_SETTEXTJUSTIFICATION;
1966 emr.emr.nSize = sizeof(emr);
1967 emr.nBreakExtra = extra;
1968 emr.nBreakCount = breaks;
1969 return emfdc_record( dc_attr->emf, &emr.emr );
1972 BOOL EMFDC_SetBkMode( DC_ATTR *dc_attr, INT mode )
1974 EMRSETBKMODE emr;
1976 emr.emr.iType = EMR_SETBKMODE;
1977 emr.emr.nSize = sizeof(emr);
1978 emr.iMode = mode;
1979 return emfdc_record( dc_attr->emf, &emr.emr );
1982 BOOL EMFDC_SetBkColor( DC_ATTR *dc_attr, COLORREF color )
1984 EMRSETBKCOLOR emr;
1986 emr.emr.iType = EMR_SETBKCOLOR;
1987 emr.emr.nSize = sizeof(emr);
1988 emr.crColor = color;
1989 return emfdc_record( dc_attr->emf, &emr.emr );
1993 BOOL EMFDC_SetTextColor( DC_ATTR *dc_attr, COLORREF color )
1995 EMRSETTEXTCOLOR emr;
1997 emr.emr.iType = EMR_SETTEXTCOLOR;
1998 emr.emr.nSize = sizeof(emr);
1999 emr.crColor = color;
2000 return emfdc_record( dc_attr->emf, &emr.emr );
2003 BOOL EMFDC_SetROP2( DC_ATTR *dc_attr, INT rop )
2005 EMRSETROP2 emr;
2007 emr.emr.iType = EMR_SETROP2;
2008 emr.emr.nSize = sizeof(emr);
2009 emr.iMode = rop;
2010 return emfdc_record( dc_attr->emf, &emr.emr );
2013 BOOL EMFDC_SetPolyFillMode( DC_ATTR *dc_attr, INT mode )
2015 EMRSETPOLYFILLMODE emr;
2017 emr.emr.iType = EMR_SETPOLYFILLMODE;
2018 emr.emr.nSize = sizeof(emr);
2019 emr.iMode = mode;
2020 return emfdc_record( dc_attr->emf, &emr.emr );
2023 BOOL EMFDC_SetStretchBltMode( DC_ATTR *dc_attr, INT mode )
2025 EMRSETSTRETCHBLTMODE emr;
2027 emr.emr.iType = EMR_SETSTRETCHBLTMODE;
2028 emr.emr.nSize = sizeof(emr);
2029 emr.iMode = mode;
2030 return emfdc_record( dc_attr->emf, &emr.emr );
2033 BOOL EMFDC_SetArcDirection( DC_ATTR *dc_attr, INT dir )
2035 EMRSETARCDIRECTION emr;
2037 emr.emr.iType = EMR_SETARCDIRECTION;
2038 emr.emr.nSize = sizeof(emr);
2039 emr.iArcDirection = dir;
2040 return emfdc_record( dc_attr->emf, &emr.emr );
2043 INT EMFDC_ExcludeClipRect( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom )
2045 EMREXCLUDECLIPRECT emr;
2047 emr.emr.iType = EMR_EXCLUDECLIPRECT;
2048 emr.emr.nSize = sizeof(emr);
2049 emr.rclClip.left = left;
2050 emr.rclClip.top = top;
2051 emr.rclClip.right = right;
2052 emr.rclClip.bottom = bottom;
2053 return emfdc_record( dc_attr->emf, &emr.emr );
2056 BOOL EMFDC_IntersectClipRect( DC_ATTR *dc_attr, INT left, INT top, INT right, INT bottom)
2058 EMRINTERSECTCLIPRECT emr;
2060 emr.emr.iType = EMR_INTERSECTCLIPRECT;
2061 emr.emr.nSize = sizeof(emr);
2062 emr.rclClip.left = left;
2063 emr.rclClip.top = top;
2064 emr.rclClip.right = right;
2065 emr.rclClip.bottom = bottom;
2066 return emfdc_record( dc_attr->emf, &emr.emr );
2069 BOOL EMFDC_OffsetClipRgn( DC_ATTR *dc_attr, INT x, INT y )
2071 EMROFFSETCLIPRGN emr;
2073 emr.emr.iType = EMR_OFFSETCLIPRGN;
2074 emr.emr.nSize = sizeof(emr);
2075 emr.ptlOffset.x = x;
2076 emr.ptlOffset.y = y;
2077 return emfdc_record( dc_attr->emf, &emr.emr );
2080 BOOL EMFDC_ExtSelectClipRgn( DC_ATTR *dc_attr, HRGN hrgn, INT mode )
2082 EMREXTSELECTCLIPRGN *emr;
2083 DWORD size, rgnsize;
2084 BOOL ret;
2086 if (!hrgn)
2088 if (mode != RGN_COPY) return ERROR;
2089 rgnsize = 0;
2091 else rgnsize = NtGdiGetRegionData( hrgn, 0, NULL );
2093 size = rgnsize + offsetof(EMREXTSELECTCLIPRGN,RgnData);
2094 emr = HeapAlloc( GetProcessHeap(), 0, size );
2095 if (rgnsize) NtGdiGetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
2097 emr->emr.iType = EMR_EXTSELECTCLIPRGN;
2098 emr->emr.nSize = size;
2099 emr->cbRgnData = rgnsize;
2100 emr->iMode = mode;
2102 ret = emfdc_record( dc_attr->emf, &emr->emr );
2103 HeapFree( GetProcessHeap(), 0, emr );
2104 return ret;
2107 BOOL EMFDC_SetMapMode( DC_ATTR *dc_attr, INT mode )
2109 EMRSETMAPMODE emr;
2111 emr.emr.iType = EMR_SETMAPMODE;
2112 emr.emr.nSize = sizeof(emr);
2113 emr.iMode = mode;
2114 return emfdc_record( dc_attr->emf, &emr.emr );
2117 BOOL EMFDC_SetViewportExtEx( DC_ATTR *dc_attr, INT cx, INT cy )
2119 EMRSETVIEWPORTEXTEX emr;
2121 emr.emr.iType = EMR_SETVIEWPORTEXTEX;
2122 emr.emr.nSize = sizeof(emr);
2123 emr.szlExtent.cx = cx;
2124 emr.szlExtent.cy = cy;
2125 return emfdc_record( dc_attr->emf, &emr.emr );
2128 BOOL EMFDC_SetWindowExtEx( DC_ATTR *dc_attr, INT cx, INT cy )
2130 EMRSETWINDOWEXTEX emr;
2132 emr.emr.iType = EMR_SETWINDOWEXTEX;
2133 emr.emr.nSize = sizeof(emr);
2134 emr.szlExtent.cx = cx;
2135 emr.szlExtent.cy = cy;
2136 return emfdc_record( dc_attr->emf, &emr.emr );
2139 BOOL EMFDC_SetViewportOrgEx( DC_ATTR *dc_attr, INT x, INT y )
2141 EMRSETVIEWPORTORGEX emr;
2143 emr.emr.iType = EMR_SETVIEWPORTORGEX;
2144 emr.emr.nSize = sizeof(emr);
2145 emr.ptlOrigin.x = x;
2146 emr.ptlOrigin.y = y;
2147 return emfdc_record( dc_attr->emf, &emr.emr );
2150 BOOL EMFDC_SetWindowOrgEx( DC_ATTR *dc_attr, INT x, INT y )
2152 EMRSETWINDOWORGEX emr;
2154 emr.emr.iType = EMR_SETWINDOWORGEX;
2155 emr.emr.nSize = sizeof(emr);
2156 emr.ptlOrigin.x = x;
2157 emr.ptlOrigin.y = y;
2158 return emfdc_record( dc_attr->emf, &emr.emr );
2161 BOOL EMFDC_ScaleViewportExtEx( DC_ATTR *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom )
2163 EMRSCALEVIEWPORTEXTEX emr;
2165 emr.emr.iType = EMR_SCALEVIEWPORTEXTEX;
2166 emr.emr.nSize = sizeof(emr);
2167 emr.xNum = x_num;
2168 emr.xDenom = x_denom;
2169 emr.yNum = y_num;
2170 emr.yDenom = y_denom;
2171 return emfdc_record( dc_attr->emf, &emr.emr );
2174 BOOL EMFDC_ScaleWindowExtEx( DC_ATTR *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom )
2176 EMRSCALEWINDOWEXTEX emr;
2178 emr.emr.iType = EMR_SCALEWINDOWEXTEX;
2179 emr.emr.nSize = sizeof(emr);
2180 emr.xNum = x_num;
2181 emr.xDenom = x_denom;
2182 emr.yNum = y_num;
2183 emr.yDenom = y_denom;
2184 return emfdc_record( dc_attr->emf, &emr.emr );
2187 BOOL EMFDC_SetLayout( DC_ATTR *dc_attr, DWORD layout )
2189 EMRSETLAYOUT emr;
2191 emr.emr.iType = EMR_SETLAYOUT;
2192 emr.emr.nSize = sizeof(emr);
2193 emr.iMode = layout;
2194 return emfdc_record( dc_attr->emf, &emr.emr );
2197 BOOL EMFDC_SetWorldTransform( DC_ATTR *dc_attr, const XFORM *xform )
2199 EMRSETWORLDTRANSFORM emr;
2201 emr.emr.iType = EMR_SETWORLDTRANSFORM;
2202 emr.emr.nSize = sizeof(emr);
2203 emr.xform = *xform;
2204 return emfdc_record( dc_attr->emf, &emr.emr );
2207 BOOL EMFDC_ModifyWorldTransform( DC_ATTR *dc_attr, const XFORM *xform, DWORD mode )
2209 EMRMODIFYWORLDTRANSFORM emr;
2211 emr.emr.iType = EMR_MODIFYWORLDTRANSFORM;
2212 emr.emr.nSize = sizeof(emr);
2213 if (mode == MWT_IDENTITY)
2215 emr.xform.eM11 = 1.0f;
2216 emr.xform.eM12 = 0.0f;
2217 emr.xform.eM21 = 0.0f;
2218 emr.xform.eM22 = 1.0f;
2219 emr.xform.eDx = 0.0f;
2220 emr.xform.eDy = 0.0f;
2222 else
2224 emr.xform = *xform;
2226 emr.iMode = mode;
2227 return emfdc_record( dc_attr->emf, &emr.emr );
2230 BOOL EMFDC_SetMapperFlags( DC_ATTR *dc_attr, DWORD flags )
2232 EMRSETMAPPERFLAGS emr;
2234 emr.emr.iType = EMR_SETMAPPERFLAGS;
2235 emr.emr.nSize = sizeof(emr);
2236 emr.dwFlags = flags;
2237 return emfdc_record( dc_attr->emf, &emr.emr );
2240 BOOL EMFDC_AbortPath( DC_ATTR *dc_attr )
2242 struct emf *emf = dc_attr->emf;
2243 EMRABORTPATH emr;
2245 emr.emr.iType = EMR_ABORTPATH;
2246 emr.emr.nSize = sizeof(emr);
2248 emf->path = FALSE;
2249 return emfdc_record( dc_attr->emf, &emr.emr );
2252 BOOL EMFDC_BeginPath( DC_ATTR *dc_attr )
2254 struct emf *emf = dc_attr->emf;
2255 EMRBEGINPATH emr;
2257 emr.emr.iType = EMR_BEGINPATH;
2258 emr.emr.nSize = sizeof(emr);
2259 if (!emfdc_record( emf, &emr.emr )) return FALSE;
2261 emf->path = TRUE;
2262 return TRUE;
2265 BOOL EMFDC_CloseFigure( DC_ATTR *dc_attr )
2267 EMRCLOSEFIGURE emr;
2269 emr.emr.iType = EMR_CLOSEFIGURE;
2270 emr.emr.nSize = sizeof(emr);
2271 return emfdc_record( dc_attr->emf, &emr.emr );
2274 BOOL EMFDC_EndPath( DC_ATTR *dc_attr )
2276 struct emf *emf = dc_attr->emf;
2277 EMRENDPATH emr;
2279 emf->path = FALSE;
2281 emr.emr.iType = EMR_ENDPATH;
2282 emr.emr.nSize = sizeof(emr);
2283 return emfdc_record( emf, &emr.emr );
2286 BOOL EMFDC_FlattenPath( DC_ATTR *dc_attr )
2288 EMRFLATTENPATH emr;
2290 emr.emr.iType = EMR_FLATTENPATH;
2291 emr.emr.nSize = sizeof(emr);
2292 return emfdc_record( dc_attr->emf, &emr.emr );
2295 BOOL EMFDC_SelectClipPath( DC_ATTR *dc_attr, INT mode )
2297 EMRSELECTCLIPPATH emr;
2299 emr.emr.iType = EMR_SELECTCLIPPATH;
2300 emr.emr.nSize = sizeof(emr);
2301 emr.iMode = mode;
2302 return emfdc_record( dc_attr->emf, &emr.emr );
2305 BOOL EMFDC_WidenPath( DC_ATTR *dc_attr )
2307 EMRWIDENPATH emr;
2309 emr.emr.iType = EMR_WIDENPATH;
2310 emr.emr.nSize = sizeof(emr);
2311 return emfdc_record( dc_attr->emf, &emr.emr );
2314 void EMFDC_DeleteDC( DC_ATTR *dc_attr )
2316 struct emf *emf = dc_attr->emf;
2317 UINT index;
2319 HeapFree( GetProcessHeap(), 0, emf->emh );
2320 for (index = 0; index < emf->handles_size; index++)
2321 if (emf->handles[index])
2322 GDI_hdc_not_using_object( emf->handles[index], emf->dc_attr->hdc );
2323 HeapFree( GetProcessHeap(), 0, emf->handles );
2326 /*******************************************************************
2327 * GdiComment (GDI32.@)
2329 BOOL WINAPI GdiComment( HDC hdc, UINT bytes, const BYTE *buffer )
2331 DC_ATTR *dc_attr;
2332 EMRGDICOMMENT *emr;
2333 UINT total, rounded_size;
2334 BOOL ret;
2336 if (!(dc_attr = get_dc_attr( hdc )) || !dc_attr->emf) return FALSE;
2338 rounded_size = (bytes+3) & ~3;
2339 total = offsetof(EMRGDICOMMENT,Data) + rounded_size;
2341 emr = HeapAlloc(GetProcessHeap(), 0, total);
2342 emr->emr.iType = EMR_GDICOMMENT;
2343 emr->emr.nSize = total;
2344 emr->cbData = bytes;
2345 memset(&emr->Data[bytes], 0, rounded_size - bytes);
2346 memcpy(&emr->Data[0], buffer, bytes);
2348 ret = emfdc_record( dc_attr->emf, &emr->emr );
2350 HeapFree(GetProcessHeap(), 0, emr);
2352 return ret;
2355 /**********************************************************************
2356 * CreateEnhMetaFileA (GDI32.@)
2358 HDC WINAPI CreateEnhMetaFileA( HDC hdc, const char *filename, const RECT *rect,
2359 const char *description )
2361 WCHAR *filenameW = NULL;
2362 WCHAR *descriptionW = NULL;
2363 DWORD len1, len2, total;
2364 HDC ret;
2366 if (filename)
2368 total = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
2369 filenameW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) );
2370 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, total );
2373 if(description)
2375 len1 = strlen(description);
2376 len2 = strlen(description + len1 + 1);
2377 total = MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, NULL, 0 );
2378 descriptionW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) );
2379 MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, descriptionW, total );
2382 ret = CreateEnhMetaFileW( hdc, filenameW, rect, descriptionW );
2384 HeapFree( GetProcessHeap(), 0, filenameW );
2385 HeapFree( GetProcessHeap(), 0, descriptionW );
2386 return ret;
2389 /**********************************************************************
2390 * CreateEnhMetaFileW (GDI32.@)
2392 HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect,
2393 const WCHAR *description )
2395 HDC ret;
2396 struct emf *emf;
2397 DC_ATTR *dc_attr;
2398 HANDLE file;
2399 DWORD size = 0, length = 0;
2401 TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect),
2402 debugstr_w(description) );
2404 if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0;
2406 if (!(dc_attr = get_dc_attr( ret )) || !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) )))
2408 DeleteDC( ret );
2409 return 0;
2412 emf->dc_attr = dc_attr;
2413 dc_attr->emf = emf;
2415 if (description) /* App name\0Title\0\0 */
2417 length = lstrlenW( description );
2418 length += lstrlenW( description + length + 1 );
2419 length += 3;
2420 length *= 2;
2422 size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4;
2424 if (!(emf->emh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size)))
2426 DeleteDC( ret );
2427 return 0;
2429 emf->dc_attr = dc_attr;
2431 emf->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2432 HANDLE_LIST_INC * sizeof(emf->handles[0]) );
2433 emf->handles_size = HANDLE_LIST_INC;
2434 emf->cur_handles = 1;
2435 emf->file = 0;
2436 emf->dc_brush = 0;
2437 emf->dc_pen = 0;
2438 emf->path = FALSE;
2440 emf->emh->iType = EMR_HEADER;
2441 emf->emh->nSize = size;
2443 dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0;
2444 dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1;
2446 if (rect)
2448 emf->emh->rclFrame.left = rect->left;
2449 emf->emh->rclFrame.top = rect->top;
2450 emf->emh->rclFrame.right = rect->right;
2451 emf->emh->rclFrame.bottom = rect->bottom;
2453 else
2455 /* Set this to {0,0 - -1,-1} and update it at the end */
2456 emf->emh->rclFrame.left = emf->emh->rclFrame.top = 0;
2457 emf->emh->rclFrame.right = emf->emh->rclFrame.bottom = -1;
2460 emf->emh->dSignature = ENHMETA_SIGNATURE;
2461 emf->emh->nVersion = 0x10000;
2462 emf->emh->nBytes = emf->emh->nSize;
2463 emf->emh->nRecords = 1;
2464 emf->emh->nHandles = 1;
2466 emf->emh->sReserved = 0; /* According to docs, this is reserved and must be 0 */
2467 emf->emh->nDescription = length / 2;
2469 emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0;
2471 emf->emh->nPalEntries = 0; /* I guess this should start at 0 */
2473 /* Size in pixels */
2474 emf->emh->szlDevice.cx = GetDeviceCaps( ret, HORZRES );
2475 emf->emh->szlDevice.cy = GetDeviceCaps( ret, VERTRES );
2477 /* Size in millimeters */
2478 emf->emh->szlMillimeters.cx = GetDeviceCaps( ret, HORZSIZE );
2479 emf->emh->szlMillimeters.cy = GetDeviceCaps( ret, VERTSIZE );
2481 /* Size in micrometers */
2482 emf->emh->szlMicrometers.cx = emf->emh->szlMillimeters.cx * 1000;
2483 emf->emh->szlMicrometers.cy = emf->emh->szlMillimeters.cy * 1000;
2485 memcpy( (char *)emf->emh + sizeof(ENHMETAHEADER), description, length );
2487 if (filename) /* disk based metafile */
2489 if ((file = CreateFileW( filename, GENERIC_WRITE | GENERIC_READ, 0,
2490 NULL, CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE)
2492 DeleteDC( ret );
2493 return 0;
2495 emf->file = file;
2498 TRACE( "returning %p\n", ret );
2499 return ret;
2502 /******************************************************************
2503 * CloseEnhMetaFile (GDI32.@)
2505 HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc )
2507 HENHMETAFILE hmf;
2508 struct emf *emf;
2509 DC_ATTR *dc_attr;
2510 EMREOF emr;
2511 HANDLE mapping = 0;
2513 TRACE("(%p)\n", hdc );
2515 if (!(dc_attr = get_dc_attr( hdc )) || !dc_attr->emf) return 0;
2516 emf = dc_attr->emf;
2518 if (dc_attr->save_level)
2519 RestoreDC( hdc, 1 );
2521 if (emf->dc_brush) DeleteObject( emf->dc_brush );
2522 if (emf->dc_pen) DeleteObject( emf->dc_pen );
2524 emr.emr.iType = EMR_EOF;
2525 emr.emr.nSize = sizeof(emr);
2526 emr.nPalEntries = 0;
2527 emr.offPalEntries = FIELD_OFFSET(EMREOF, nSizeLast);
2528 emr.nSizeLast = emr.emr.nSize;
2529 emfdc_record( emf, &emr.emr );
2531 emf->emh->rclBounds = dc_attr->emf_bounds;
2533 /* Update rclFrame if not initialized in CreateEnhMetaFile */
2534 if (emf->emh->rclFrame.left > emf->emh->rclFrame.right)
2536 emf->emh->rclFrame.left = emf->emh->rclBounds.left *
2537 emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx;
2538 emf->emh->rclFrame.top = emf->emh->rclBounds.top *
2539 emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy;
2540 emf->emh->rclFrame.right = emf->emh->rclBounds.right *
2541 emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx;
2542 emf->emh->rclFrame.bottom = emf->emh->rclBounds.bottom *
2543 emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy;
2546 if (emf->file) /* disk based metafile */
2548 if (!WriteFile( emf->file, emf->emh, emf->emh->nBytes, NULL, NULL ))
2550 CloseHandle( emf->file );
2551 return 0;
2553 HeapFree( GetProcessHeap(), 0, emf->emh );
2554 mapping = CreateFileMappingA( emf->file, NULL, PAGE_READONLY, 0, 0, NULL );
2555 TRACE( "mapping = %p\n", mapping );
2556 emf->emh = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
2557 TRACE( "view = %p\n", emf->emh );
2558 CloseHandle( mapping );
2559 CloseHandle( emf->file );
2562 hmf = EMF_Create_HENHMETAFILE( emf->emh, emf->emh->nBytes, emf->file != 0 );
2563 emf->emh = NULL; /* So it won't be deleted */
2564 DeleteDC( hdc );
2565 return hmf;