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
26 #include "gdi_private.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile
);
38 UINT handles_size
, cur_handles
;
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
)
54 TRACE( "record %d, size %d\n", emr
->iType
, emr
->nSize
);
56 assert( !(emr
->nSize
& 3) );
58 emf
->emh
->nBytes
+= emr
->nSize
;
61 size
= HeapSize( GetProcessHeap(), 0, emf
->emh
);
62 len
= emf
->emh
->nBytes
;
65 size
+= (size
/ 2) + emr
->nSize
;
66 emh
= HeapReAlloc( GetProcessHeap(), 0, emf
->emh
, size
);
67 if (!emh
) return FALSE
;
70 memcpy( (char *)emf
->emh
+ emf
->emh
->nBytes
- emr
->nSize
, emr
, emr
->nSize
);
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 */
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
)
117 if (!(info_size
= GetObjectW( *bitmap
, sizeof(dib
), &dib
))) return 0;
119 if (info_size
== sizeof(dib
))
122 blit_bitmap
= *bitmap
;
126 unsigned char dib_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
127 BITMAPINFO
*dib_info
= (BITMAPINFO
*)dib_info_buffer
;
128 BITMAP bmp
= dib
.dsBm
;
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
)
148 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xf800;
149 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x07e0;
150 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x001f;
153 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xff0000;
154 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x00ff00;
155 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x0000ff;
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
))
164 if (!(blit_dc
= NtGdiCreateCompatibleDC( *hdc
))) return FALSE
;
165 if (!(blit_bitmap
= CreateDIBSection( blit_dc
, dib_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0 )))
167 if (!SelectObject( blit_dc
, blit_bitmap
)) goto err
;
168 if (!BitBlt( blit_dc
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, *hdc
, 0, 0, SRCCOPY
))
171 if (!GetDIBits( blit_dc
, blit_bitmap
, 0, INT_MAX
, NULL
, info
, DIB_RGB_COLORS
))
174 bpp
= info
->bmiHeader
.biBitCount
;
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
);
183 if (blit_dc
&& blit_dc
!= *hdc
) DeleteDC( blit_dc
);
184 if (blit_bitmap
&& blit_bitmap
!= *bitmap
) DeleteObject( blit_bitmap
);
188 static UINT
emfdc_add_handle( struct emf
*emf
, HGDIOBJ obj
)
192 for (index
= 0; index
< emf
->handles_size
; index
++)
193 if (emf
->handles
[index
] == 0) break;
195 if (index
== emf
->handles_size
)
197 emf
->handles_size
+= HANDLE_LIST_INC
;
198 emf
->handles
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
200 emf
->handles_size
* sizeof(emf
->handles
[0]) );
202 emf
->handles
[index
] = obj
;
205 if (emf
->cur_handles
> emf
->emh
->nHandles
)
206 emf
->emh
->nHandles
++;
208 return index
+ 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
211 static UINT
emfdc_find_object( struct emf
*emf
, HGDIOBJ obj
)
215 for (index
= 0; index
< emf
->handles_size
; index
++)
216 if (emf
->handles
[index
] == obj
) return index
+ 1;
221 static void emfdc_delete_object( HDC hdc
, HGDIOBJ obj
)
223 DC_ATTR
*dc_attr
= get_dc_attr( hdc
);
224 struct emf
*emf
= dc_attr
->emf
;
228 if(!(index
= emfdc_find_object( emf
, obj
))) return;
230 emr
.emr
.iType
= EMR_DELETEOBJECT
;
231 emr
.emr
.nSize
= sizeof(emr
);
232 emr
.ihObject
= index
;
234 emfdc_record( emf
, &emr
.emr
);
236 emf
->handles
[index
- 1] = 0;
240 static DWORD
emfdc_create_brush( struct emf
*emf
, HBRUSH brush
)
245 if (!GetObjectA( brush
, sizeof(logbrush
), &logbrush
)) return 0;
247 switch (logbrush
.lbStyle
) {
252 EMRCREATEBRUSHINDIRECT emr
;
253 emr
.emr
.iType
= EMR_CREATEBRUSHINDIRECT
;
254 emr
.emr
.nSize
= sizeof(emr
);
255 emr
.ihBrush
= index
= emfdc_add_handle( emf
, brush
);
256 emr
.lb
.lbStyle
= logbrush
.lbStyle
;
257 emr
.lb
.lbColor
= logbrush
.lbColor
;
258 emr
.lb
.lbHatch
= logbrush
.lbHatch
;
260 if(!emfdc_record( emf
, &emr
.emr
))
267 EMRCREATEDIBPATTERNBRUSHPT
*emr
;
268 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
269 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
273 if (!__wine_get_brush_bitmap_info( brush
, info
, NULL
, &usage
)) break;
274 info_size
= get_dib_info_size( info
, usage
);
276 emr
= HeapAlloc( GetProcessHeap(), 0,
277 sizeof(EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
) +
278 info_size
+info
->bmiHeader
.biSizeImage
);
281 /* FIXME: There is an extra DWORD written by native before the BMI.
282 * Not sure what it's meant to contain.
284 emr
->offBmi
= sizeof( EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
);
285 *(DWORD
*)(emr
+ 1) = 0x20000000;
287 if (logbrush
.lbStyle
== BS_PATTERN
&& info
->bmiHeader
.biBitCount
== 1)
289 /* Presumably to reduce the size of the written EMF, MS supports an
290 * undocumented iUsage value of 2, indicating a mono bitmap without the
291 * 8 byte 2 entry black/white palette. Stupidly, they could have saved
292 * over 20 bytes more by also ignoring the BITMAPINFO fields that are
293 * irrelevant/constant for monochrome bitmaps.
294 * FIXME: It may be that the DIB functions themselves accept this value.
296 emr
->emr
.iType
= EMR_CREATEMONOBRUSH
;
297 usage
= DIB_PAL_MONO
;
298 emr
->cbBmi
= sizeof( BITMAPINFOHEADER
);
302 emr
->emr
.iType
= EMR_CREATEDIBPATTERNBRUSHPT
;
303 emr
->cbBmi
= info_size
;
305 emr
->ihBrush
= index
= emfdc_add_handle( emf
, brush
);
307 emr
->offBits
= emr
->offBmi
+ emr
->cbBmi
;
308 emr
->cbBits
= info
->bmiHeader
.biSizeImage
;
309 emr
->emr
.nSize
= emr
->offBits
+ emr
->cbBits
;
311 if (info
->bmiHeader
.biClrUsed
== 1 << info
->bmiHeader
.biBitCount
)
312 info
->bmiHeader
.biClrUsed
= 0;
313 memcpy( (BYTE
*)emr
+ emr
->offBmi
, info
, emr
->cbBmi
);
314 __wine_get_brush_bitmap_info( brush
, NULL
, (char *)emr
+ emr
->offBits
, NULL
);
316 if (!emfdc_record( emf
, &emr
->emr
)) index
= 0;
317 HeapFree( GetProcessHeap(), 0, emr
);
322 FIXME("Unknown style %x\n", logbrush
.lbStyle
);
329 static BOOL
emfdc_select_brush( DC_ATTR
*dc_attr
, HBRUSH brush
)
331 struct emf
*emf
= dc_attr
->emf
;
336 /* If the object is a stock brush object, do not need to create it.
337 * See definitions in wingdi.h for range of stock brushes.
338 * We do however have to handle setting the higher order bit to
339 * designate that this is a stock object.
341 for (i
= WHITE_BRUSH
; i
<= DC_BRUSH
; i
++)
343 if (brush
== GetStockObject(i
))
345 index
= i
| 0x80000000;
350 if (!index
&& !(index
= emfdc_find_object( emf
, brush
)))
352 if (!(index
= emfdc_create_brush( emf
, brush
))) return 0;
353 GDI_hdc_using_object( brush
, dc_attr
->hdc
, emfdc_delete_object
);
356 emr
.emr
.iType
= EMR_SELECTOBJECT
;
357 emr
.emr
.nSize
= sizeof(emr
);
358 emr
.ihObject
= index
;
359 return emfdc_record( emf
, &emr
.emr
);
362 static BOOL
emfdc_create_font( struct emf
*emf
, HFONT font
)
365 EMREXTCREATEFONTINDIRECTW emr
;
368 if (!GetObjectW( font
, sizeof(emr
.elfw
.elfLogFont
), &emr
.elfw
.elfLogFont
)) return FALSE
;
370 emr
.emr
.iType
= EMR_EXTCREATEFONTINDIRECTW
;
371 emr
.emr
.nSize
= (sizeof(emr
) + 3) / 4 * 4;
372 emr
.ihFont
= index
= emfdc_add_handle( emf
, font
);
373 emr
.elfw
.elfFullName
[0] = '\0';
374 emr
.elfw
.elfStyle
[0] = '\0';
375 emr
.elfw
.elfVersion
= 0;
376 emr
.elfw
.elfStyleSize
= 0;
377 emr
.elfw
.elfMatch
= 0;
378 emr
.elfw
.elfReserved
= 0;
379 for (i
= 0; i
< ELF_VENDOR_SIZE
; i
++)
380 emr
.elfw
.elfVendorId
[i
] = 0;
381 emr
.elfw
.elfCulture
= PAN_CULTURE_LATIN
;
382 emr
.elfw
.elfPanose
.bFamilyType
= PAN_NO_FIT
;
383 emr
.elfw
.elfPanose
.bSerifStyle
= PAN_NO_FIT
;
384 emr
.elfw
.elfPanose
.bWeight
= PAN_NO_FIT
;
385 emr
.elfw
.elfPanose
.bProportion
= PAN_NO_FIT
;
386 emr
.elfw
.elfPanose
.bContrast
= PAN_NO_FIT
;
387 emr
.elfw
.elfPanose
.bStrokeVariation
= PAN_NO_FIT
;
388 emr
.elfw
.elfPanose
.bArmStyle
= PAN_NO_FIT
;
389 emr
.elfw
.elfPanose
.bLetterform
= PAN_NO_FIT
;
390 emr
.elfw
.elfPanose
.bMidline
= PAN_NO_FIT
;
391 emr
.elfw
.elfPanose
.bXHeight
= PAN_NO_FIT
;
393 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
396 static BOOL
emfdc_select_font( DC_ATTR
*dc_attr
, HFONT font
)
398 struct emf
*emf
= dc_attr
->emf
;
403 /* If the object is a stock font object, do not need to create it.
404 * See definitions in wingdi.h for range of stock fonts.
405 * We do however have to handle setting the higher order bit to
406 * designate that this is a stock object.
409 for (i
= OEM_FIXED_FONT
; i
<= DEFAULT_GUI_FONT
; i
++)
411 if (i
!= DEFAULT_PALETTE
&& font
== GetStockObject(i
))
413 index
= i
| 0x80000000;
418 if (!(index
= emfdc_find_object( emf
, font
)))
420 if (!(index
= emfdc_create_font( emf
, font
))) return FALSE
;
421 GDI_hdc_using_object( font
, dc_attr
->hdc
, emfdc_delete_object
);
425 emr
.emr
.iType
= EMR_SELECTOBJECT
;
426 emr
.emr
.nSize
= sizeof(emr
);
427 emr
.ihObject
= index
;
428 return emfdc_record( emf
, &emr
.emr
);
431 static DWORD
emfdc_create_pen( struct emf
*emf
, HPEN hPen
)
436 if (!GetObjectW( hPen
, sizeof(emr
.lopn
), &emr
.lopn
))
438 /* must be an extended pen */
440 INT size
= GetObjectW( hPen
, 0, NULL
);
444 elp
= HeapAlloc( GetProcessHeap(), 0, size
);
446 GetObjectW( hPen
, size
, elp
);
447 /* FIXME: add support for user style pens */
448 emr
.lopn
.lopnStyle
= elp
->elpPenStyle
;
449 emr
.lopn
.lopnWidth
.x
= elp
->elpWidth
;
450 emr
.lopn
.lopnWidth
.y
= 0;
451 emr
.lopn
.lopnColor
= elp
->elpColor
;
453 HeapFree( GetProcessHeap(), 0, elp
);
456 emr
.emr
.iType
= EMR_CREATEPEN
;
457 emr
.emr
.nSize
= sizeof(emr
);
458 emr
.ihPen
= index
= emfdc_add_handle( emf
, hPen
);
459 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
462 static BOOL
emfdc_select_pen( DC_ATTR
*dc_attr
, HPEN pen
)
464 struct emf
*emf
= dc_attr
->emf
;
469 /* If the object is a stock pen object, do not need to create it.
470 * See definitions in wingdi.h for range of stock pens.
471 * We do however have to handle setting the higher order bit to
472 * designate that this is a stock object.
475 for (i
= WHITE_PEN
; i
<= DC_PEN
; i
++)
477 if (pen
== GetStockObject(i
))
479 index
= i
| 0x80000000;
483 if (!index
&& !(index
= emfdc_find_object( emf
, pen
)))
485 if (!(index
= emfdc_create_pen( emf
, pen
))) return FALSE
;
486 GDI_hdc_using_object( pen
, dc_attr
->hdc
, emfdc_delete_object
);
489 emr
.emr
.iType
= EMR_SELECTOBJECT
;
490 emr
.emr
.nSize
= sizeof(emr
);
491 emr
.ihObject
= index
;
492 return emfdc_record( emf
, &emr
.emr
);
495 static DWORD
emfdc_create_palette( struct emf
*emf
, HPALETTE hPal
)
499 EMRCREATEPALETTE hdr
;
500 PALETTEENTRY entry
[255];
503 memset( &pal
, 0, sizeof(pal
) );
505 if (!GetObjectW( hPal
, sizeof(pal
.hdr
.lgpl
) + sizeof(pal
.entry
), &pal
.hdr
.lgpl
))
508 for (i
= 0; i
< pal
.hdr
.lgpl
.palNumEntries
; i
++)
509 pal
.hdr
.lgpl
.palPalEntry
[i
].peFlags
= 0;
511 pal
.hdr
.emr
.iType
= EMR_CREATEPALETTE
;
512 pal
.hdr
.emr
.nSize
= sizeof(pal
.hdr
) + pal
.hdr
.lgpl
.palNumEntries
* sizeof(PALETTEENTRY
);
513 pal
.hdr
.ihPal
= emfdc_add_handle( emf
, hPal
);
515 if (!emfdc_record( emf
, &pal
.hdr
.emr
))
517 return pal
.hdr
.ihPal
;
520 BOOL
EMFDC_SelectPalette( DC_ATTR
*dc_attr
, HPALETTE palette
)
522 struct emf
*emf
= dc_attr
->emf
;
523 EMRSELECTPALETTE emr
;
526 if (palette
== GetStockObject( DEFAULT_PALETTE
))
528 index
= DEFAULT_PALETTE
| 0x80000000;
530 else if (!(index
= emfdc_find_object( emf
, palette
)))
532 if (!(index
= emfdc_create_palette( emf
, palette
))) return 0;
533 GDI_hdc_using_object( palette
, dc_attr
->hdc
, emfdc_delete_object
);
536 emr
.emr
.iType
= EMR_SELECTPALETTE
;
537 emr
.emr
.nSize
= sizeof(emr
);
539 return emfdc_record( emf
, &emr
.emr
);
542 BOOL
EMFDC_SelectObject( DC_ATTR
*dc_attr
, HGDIOBJ obj
)
544 switch (gdi_handle_type( obj
))
546 case NTGDI_OBJ_BRUSH
:
547 return emfdc_select_brush( dc_attr
, obj
);
549 return emfdc_select_font( dc_attr
, obj
);
551 case NTGDI_OBJ_EXTPEN
:
552 return emfdc_select_pen( dc_attr
, obj
);
558 /* determine if we can use 16-bit points to store all the input points */
559 static BOOL
can_use_short_points( const POINT
*pts
, UINT count
)
563 for (i
= 0; i
< count
; i
++)
564 if (((pts
[i
].x
+ 0x8000) & ~0xffff) || ((pts
[i
].y
+ 0x8000) & ~0xffff))
569 /* store points in either long or short format; return a pointer to the end of the stored data */
570 static void *store_points( POINTL
*dest
, const POINT
*pts
, UINT count
, BOOL short_points
)
575 POINTS
*dest_short
= (POINTS
*)dest
;
577 for (i
= 0; i
< count
; i
++)
579 dest_short
[i
].x
= pts
[i
].x
;
580 dest_short
[i
].y
= pts
[i
].y
;
582 return dest_short
+ count
;
586 memcpy( dest
, pts
, count
* sizeof(*dest
) );
591 /* compute the bounds of an array of points, optionally including the current position */
592 static void get_points_bounds( RECTL
*bounds
, const POINT
*pts
, UINT count
, DC_ATTR
*dc_attr
)
598 bounds
->left
= bounds
->right
= dc_attr
->cur_pos
.x
;
599 bounds
->top
= bounds
->bottom
= dc_attr
->cur_pos
.y
;
603 bounds
->left
= bounds
->right
= pts
[0].x
;
604 bounds
->top
= bounds
->bottom
= pts
[0].y
;
606 else *bounds
= empty_bounds
;
608 for (i
= 0; i
< count
; i
++)
610 bounds
->left
= min( bounds
->left
, pts
[i
].x
);
611 bounds
->right
= max( bounds
->right
, pts
[i
].x
);
612 bounds
->top
= min( bounds
->top
, pts
[i
].y
);
613 bounds
->bottom
= max( bounds
->bottom
, pts
[i
].y
);
617 /* helper for path stroke and fill functions */
618 static BOOL
emfdrv_stroke_and_fill_path( struct emf
*emf
, INT type
)
620 EMRSTROKEANDFILLPATH emr
;
623 emr
.emr
.iType
= type
;
624 emr
.emr
.nSize
= sizeof(emr
);
625 emr
.rclBounds
= empty_bounds
;
627 if ((region
= NtGdiPathToRegion( emf
->dc_attr
->hdc
)))
629 NtGdiGetRgnBox( region
, (RECT
*)&emr
.rclBounds
);
630 DeleteObject( region
);
633 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
634 if (!region
) return FALSE
;
635 emfdc_update_bounds( emf
, &emr
.rclBounds
);
639 BOOL
EMFDC_MoveTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
641 struct emf
*emf
= dc_attr
->emf
;
644 emr
.emr
.iType
= EMR_MOVETOEX
;
645 emr
.emr
.nSize
= sizeof(emr
);
648 return emfdc_record( emf
, &emr
.emr
);
651 BOOL
EMFDC_LineTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
655 emr
.emr
.iType
= EMR_LINETO
;
656 emr
.emr
.nSize
= sizeof(emr
);
659 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
662 BOOL
EMFDC_ArcChordPie( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
,
663 INT xstart
, INT ystart
, INT xend
, INT yend
, DWORD type
)
665 struct emf
*emf
= dc_attr
->emf
;
669 if (left
== right
|| top
== bottom
) return FALSE
;
671 if (left
> right
) { temp
= left
; left
= right
; right
= temp
; }
672 if (top
> bottom
) { temp
= top
; top
= bottom
; bottom
= temp
; }
674 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
680 emr
.emr
.iType
= type
;
681 emr
.emr
.nSize
= sizeof(emr
);
682 emr
.rclBox
.left
= left
;
683 emr
.rclBox
.top
= top
;
684 emr
.rclBox
.right
= right
;
685 emr
.rclBox
.bottom
= bottom
;
686 emr
.ptlStart
.x
= xstart
;
687 emr
.ptlStart
.y
= ystart
;
690 return emfdc_record( emf
, &emr
.emr
);
693 BOOL
EMFDC_AngleArc( DC_ATTR
*dc_attr
, INT x
, INT y
, DWORD radius
, FLOAT start
, FLOAT sweep
)
697 emr
.emr
.iType
= EMR_ANGLEARC
;
698 emr
.emr
.nSize
= sizeof( emr
);
701 emr
.nRadius
= radius
;
702 emr
.eStartAngle
= start
;
703 emr
.eSweepAngle
= sweep
;
704 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
707 BOOL
EMFDC_Ellipse( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
709 struct emf
*emf
= dc_attr
->emf
;
712 if (left
== right
|| top
== bottom
) return FALSE
;
714 emr
.emr
.iType
= EMR_ELLIPSE
;
715 emr
.emr
.nSize
= sizeof(emr
);
716 emr
.rclBox
.left
= min( left
, right
);
717 emr
.rclBox
.top
= min( top
, bottom
);
718 emr
.rclBox
.right
= max( left
, right
);
719 emr
.rclBox
.bottom
= max( top
, bottom
);
720 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
725 return emfdc_record( emf
, &emr
.emr
);
728 BOOL
EMFDC_Rectangle( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
730 struct emf
*emf
= dc_attr
->emf
;
733 if(left
== right
|| top
== bottom
) return FALSE
;
735 emr
.emr
.iType
= EMR_RECTANGLE
;
736 emr
.emr
.nSize
= sizeof(emr
);
737 emr
.rclBox
.left
= min( left
, right
);
738 emr
.rclBox
.top
= min( top
, bottom
);
739 emr
.rclBox
.right
= max( left
, right
);
740 emr
.rclBox
.bottom
= max( top
, bottom
);
741 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
746 return emfdc_record( emf
, &emr
.emr
);
749 BOOL
EMFDC_RoundRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
,
750 INT bottom
, INT ell_width
, INT ell_height
)
752 struct emf
*emf
= dc_attr
->emf
;
755 if (left
== right
|| top
== bottom
) return FALSE
;
757 emr
.emr
.iType
= EMR_ROUNDRECT
;
758 emr
.emr
.nSize
= sizeof(emr
);
759 emr
.rclBox
.left
= min( left
, right
);
760 emr
.rclBox
.top
= min( top
, bottom
);
761 emr
.rclBox
.right
= max( left
, right
);
762 emr
.rclBox
.bottom
= max( top
, bottom
);
763 emr
.szlCorner
.cx
= ell_width
;
764 emr
.szlCorner
.cy
= ell_height
;
765 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
770 return emfdc_record( emf
, &emr
.emr
);
773 BOOL
EMFDC_SetPixel( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
)
777 emr
.emr
.iType
= EMR_SETPIXELV
;
778 emr
.emr
.nSize
= sizeof(emr
);
782 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
785 static BOOL
emfdc_polylinegon( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
, DWORD type
)
787 struct emf
*emf
= dc_attr
->emf
;
790 BOOL ret
, use_small_emr
= can_use_short_points( points
, count
);
792 size
= use_small_emr
? offsetof( EMRPOLYLINE16
, apts
[count
] ) : offsetof( EMRPOLYLINE
, aptl
[count
] );
794 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
795 emr
->emr
.iType
= use_small_emr
? type
+ EMR_POLYLINE16
- EMR_POLYLINE
: type
;
796 emr
->emr
.nSize
= size
;
799 store_points( emr
->aptl
, points
, count
, use_small_emr
);
802 get_points_bounds( &emr
->rclBounds
, points
, count
,
803 (type
== EMR_POLYBEZIERTO
|| type
== EMR_POLYLINETO
) ? dc_attr
: 0 );
805 emr
->rclBounds
= empty_bounds
;
807 ret
= emfdc_record( emf
, &emr
->emr
);
808 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
809 HeapFree( GetProcessHeap(), 0, emr
);
813 BOOL
EMFDC_Polyline( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
815 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINE
);
818 BOOL
EMFDC_PolylineTo( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
820 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINETO
);
823 BOOL
EMFDC_Polygon( DC_ATTR
*dc_attr
, const POINT
*pt
, INT count
)
825 if(count
< 2) return FALSE
;
826 return emfdc_polylinegon( dc_attr
, pt
, count
, EMR_POLYGON
);
829 BOOL
EMFDC_PolyBezier( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
831 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIER
);
834 BOOL
EMFDC_PolyBezierTo( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
836 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIERTO
);
839 static BOOL
emfdc_poly_polylinegon( struct emf
*emf
, const POINT
*pt
, const INT
*counts
,
840 UINT polys
, DWORD type
)
842 EMRPOLYPOLYLINE
*emr
;
843 DWORD cptl
= 0, poly
, size
;
844 BOOL ret
, use_small_emr
, bounds_valid
= TRUE
;
846 for(poly
= 0; poly
< polys
; poly
++) {
847 cptl
+= counts
[poly
];
848 if(counts
[poly
] < 2) bounds_valid
= FALSE
;
850 if(!cptl
) bounds_valid
= FALSE
;
851 use_small_emr
= can_use_short_points( pt
, cptl
);
853 size
= FIELD_OFFSET(EMRPOLYPOLYLINE
, aPolyCounts
[polys
]);
855 size
+= cptl
* sizeof(POINTS
);
857 size
+= cptl
* sizeof(POINTL
);
859 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
861 emr
->emr
.iType
= type
;
862 if(use_small_emr
) emr
->emr
.iType
+= EMR_POLYPOLYLINE16
- EMR_POLYPOLYLINE
;
864 emr
->emr
.nSize
= size
;
865 if(bounds_valid
&& !emf
->path
)
866 get_points_bounds( &emr
->rclBounds
, pt
, cptl
, 0 );
868 emr
->rclBounds
= empty_bounds
;
874 memcpy( emr
->aPolyCounts
, counts
, polys
* sizeof(DWORD
) );
875 store_points( (POINTL
*)(emr
->aPolyCounts
+ polys
), pt
, cptl
, use_small_emr
);
878 ret
= emfdc_record( emf
, &emr
->emr
);
879 if(ret
&& !bounds_valid
)
882 SetLastError( ERROR_INVALID_PARAMETER
);
884 if(ret
&& !emf
->path
)
885 emfdc_update_bounds( emf
, &emr
->rclBounds
);
886 HeapFree( GetProcessHeap(), 0, emr
);
890 BOOL
EMFDC_PolyPolyline( DC_ATTR
*dc_attr
, const POINT
*pt
, const DWORD
*counts
, DWORD polys
)
892 return emfdc_poly_polylinegon( dc_attr
->emf
, pt
, (const INT
*)counts
, polys
, EMR_POLYPOLYLINE
);
895 BOOL
EMFDC_PolyPolygon( DC_ATTR
*dc_attr
, const POINT
*pt
, const INT
*counts
, UINT polys
)
897 return emfdc_poly_polylinegon( dc_attr
->emf
, pt
, counts
, polys
, EMR_POLYPOLYGON
);
900 BOOL
EMFDC_PolyDraw( DC_ATTR
*dc_attr
, const POINT
*pts
, const BYTE
*types
, DWORD count
)
902 struct emf
*emf
= dc_attr
->emf
;
906 BOOL use_small_emr
= can_use_short_points( pts
, count
);
909 size
= use_small_emr
? offsetof( EMRPOLYDRAW16
, apts
[count
] )
910 : offsetof( EMRPOLYDRAW
, aptl
[count
] );
911 size
+= (count
+ 3) & ~3;
913 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
915 emr
->emr
.iType
= use_small_emr
? EMR_POLYDRAW16
: EMR_POLYDRAW
;
916 emr
->emr
.nSize
= size
;
919 types_dest
= store_points( emr
->aptl
, pts
, count
, use_small_emr
);
920 memcpy( types_dest
, types
, count
);
921 if (count
& 3) memset( types_dest
+ count
, 0, 4 - (count
& 3) );
924 get_points_bounds( &emr
->rclBounds
, pts
, count
, 0 );
926 emr
->rclBounds
= empty_bounds
;
928 ret
= emfdc_record( emf
, &emr
->emr
);
929 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
930 HeapFree( GetProcessHeap(), 0, emr
);
934 BOOL
EMFDC_ExtFloodFill( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
, UINT fill_type
)
938 emr
.emr
.iType
= EMR_EXTFLOODFILL
;
939 emr
.emr
.nSize
= sizeof(emr
);
943 emr
.iMode
= fill_type
;
944 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
947 BOOL
EMFDC_FillRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
)
949 struct emf
*emf
= dc_attr
->emf
;
951 DWORD size
, rgnsize
, index
;
954 if (!(index
= emfdc_create_brush( emf
, hbrush
))) return FALSE
;
956 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
957 size
= rgnsize
+ offsetof(EMRFILLRGN
,RgnData
);
958 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
960 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
962 emr
->emr
.iType
= EMR_FILLRGN
;
963 emr
->emr
.nSize
= size
;
964 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
965 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
966 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
967 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
968 emr
->cbRgnData
= rgnsize
;
969 emr
->ihBrush
= index
;
971 ret
= emfdc_record( emf
, &emr
->emr
);
972 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
973 HeapFree( GetProcessHeap(), 0, emr
);
977 BOOL
EMFDC_FrameRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
, INT width
, INT height
)
979 struct emf
*emf
= dc_attr
->emf
;
981 DWORD size
, rgnsize
, index
;
984 index
= emfdc_create_brush( emf
, hbrush
);
985 if(!index
) return FALSE
;
987 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
988 size
= rgnsize
+ offsetof(EMRFRAMERGN
,RgnData
);
989 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
991 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
993 emr
->emr
.iType
= EMR_FRAMERGN
;
994 emr
->emr
.nSize
= size
;
995 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
996 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
997 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
998 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
999 emr
->cbRgnData
= rgnsize
;
1000 emr
->ihBrush
= index
;
1001 emr
->szlStroke
.cx
= width
;
1002 emr
->szlStroke
.cy
= height
;
1004 ret
= emfdc_record( emf
, &emr
->emr
);
1005 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1006 HeapFree( GetProcessHeap(), 0, emr
);
1010 static BOOL
emfdc_paint_invert_region( struct emf
*emf
, HRGN hrgn
, DWORD iType
)
1013 DWORD size
, rgnsize
;
1016 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1017 size
= rgnsize
+ offsetof(EMRINVERTRGN
,RgnData
);
1018 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1020 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1022 emr
->emr
.iType
= iType
;
1023 emr
->emr
.nSize
= size
;
1024 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1025 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1026 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1027 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1028 emr
->cbRgnData
= rgnsize
;
1030 ret
= emfdc_record( emf
, &emr
->emr
);
1031 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1032 HeapFree( GetProcessHeap(), 0, emr
);
1036 BOOL
EMFDC_PaintRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1038 return emfdc_paint_invert_region( dc_attr
->emf
, hrgn
, EMR_PAINTRGN
);
1041 BOOL
EMFDC_InvertRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1043 return emfdc_paint_invert_region( dc_attr
->emf
, hrgn
, EMR_INVERTRGN
);
1046 BOOL
EMFDC_ExtTextOut( DC_ATTR
*dc_attr
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
1047 const WCHAR
*str
, UINT count
, const INT
*dx
)
1049 struct emf
*emf
= dc_attr
->emf
;
1050 FLOAT ex_scale
, ey_scale
;
1051 EMREXTTEXTOUTW
*emr
;
1052 int text_height
= 0;
1058 size
= sizeof(*emr
) + ((count
+1) & ~1) * sizeof(WCHAR
) + count
* sizeof(INT
);
1060 TRACE( "%s %s count %d size = %d\n", debugstr_wn(str
, count
),
1061 wine_dbgstr_rect(rect
), count
, size
);
1062 emr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1064 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1066 const INT horzSize
= GetDeviceCaps( dc_attr
->hdc
, HORZSIZE
);
1067 const INT horzRes
= GetDeviceCaps( dc_attr
->hdc
, HORZRES
);
1068 const INT vertSize
= GetDeviceCaps( dc_attr
->hdc
, VERTSIZE
);
1069 const INT vertRes
= GetDeviceCaps( dc_attr
->hdc
, VERTRES
);
1070 SIZE wndext
, vportext
;
1072 GetViewportExtEx( dc_attr
->hdc
, &vportext
);
1073 GetWindowExtEx( dc_attr
->hdc
, &wndext
);
1074 ex_scale
= 100.0 * ((FLOAT
)horzSize
/ (FLOAT
)horzRes
) /
1075 ((FLOAT
)wndext
.cx
/ (FLOAT
)vportext
.cx
);
1076 ey_scale
= 100.0 * ((FLOAT
)vertSize
/ (FLOAT
)vertRes
) /
1077 ((FLOAT
)wndext
.cy
/ (FLOAT
)vportext
.cy
);
1085 emr
->emr
.iType
= EMR_EXTTEXTOUTW
;
1086 emr
->emr
.nSize
= size
;
1087 emr
->iGraphicsMode
= dc_attr
->graphics_mode
;
1088 emr
->exScale
= ex_scale
;
1089 emr
->eyScale
= ey_scale
;
1090 emr
->emrtext
.ptlReference
.x
= x
;
1091 emr
->emrtext
.ptlReference
.y
= y
;
1092 emr
->emrtext
.nChars
= count
;
1093 emr
->emrtext
.offString
= sizeof(*emr
);
1094 memcpy( (char*)emr
+ emr
->emrtext
.offString
, str
, count
* sizeof(WCHAR
) );
1095 emr
->emrtext
.fOptions
= flags
;
1098 emr
->emrtext
.rcl
.left
= emr
->emrtext
.rcl
.top
= 0;
1099 emr
->emrtext
.rcl
.right
= emr
->emrtext
.rcl
.bottom
= -1;
1103 emr
->emrtext
.rcl
.left
= rect
->left
;
1104 emr
->emrtext
.rcl
.top
= rect
->top
;
1105 emr
->emrtext
.rcl
.right
= rect
->right
;
1106 emr
->emrtext
.rcl
.bottom
= rect
->bottom
;
1109 emr
->emrtext
.offDx
= emr
->emrtext
.offString
+ ((count
+1) & ~1) * sizeof(WCHAR
);
1114 memcpy( (char*)emr
+ emr
->emrtext
.offDx
, dx
, count
* sizeof(INT
) );
1115 for (i
= 0; i
< count
; i
++) text_width
+= dx
[i
];
1116 if (GetTextExtentPoint32W( dc_attr
->hdc
, str
, count
, &str_size
))
1117 text_height
= str_size
.cy
;
1122 INT
*emf_dx
= (INT
*)((char*)emr
+ emr
->emrtext
.offDx
);
1124 for (i
= 0; i
< count
; i
++)
1126 if (GetTextExtentPoint32W( dc_attr
->hdc
, str
+ i
, 1, &charSize
))
1128 emf_dx
[i
] = charSize
.cx
;
1129 text_width
+= charSize
.cx
;
1130 text_height
= max( text_height
, charSize
.cy
);
1137 emr
->rclBounds
.left
= emr
->rclBounds
.top
= 0;
1138 emr
->rclBounds
.right
= emr
->rclBounds
.bottom
= -1;
1142 /* FIXME: handle font escapement */
1143 switch (dc_attr
->text_align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
))
1146 emr
->rclBounds
.left
= x
- (text_width
/ 2) - 1;
1147 emr
->rclBounds
.right
= x
+ (text_width
/ 2) + 1;
1151 emr
->rclBounds
.left
= x
- text_width
- 1;
1152 emr
->rclBounds
.right
= x
;
1155 default: /* TA_LEFT */
1156 emr
->rclBounds
.left
= x
;
1157 emr
->rclBounds
.right
= x
+ text_width
+ 1;
1160 switch (dc_attr
->text_align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
))
1163 if (!GetTextMetricsW( dc_attr
->hdc
, &tm
)) tm
.tmDescent
= 0;
1164 /* Play safe here... it's better to have a bounding box */
1165 /* that is too big than too small. */
1166 emr
->rclBounds
.top
= y
- text_height
- 1;
1167 emr
->rclBounds
.bottom
= y
+ tm
.tmDescent
+ 1;
1171 emr
->rclBounds
.top
= y
- text_height
- 1;
1172 emr
->rclBounds
.bottom
= y
;
1175 default: /* TA_TOP */
1176 emr
->rclBounds
.top
= y
;
1177 emr
->rclBounds
.bottom
= y
+ text_height
+ 1;
1179 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1182 ret
= emfdc_record( emf
, &emr
->emr
);
1183 HeapFree( GetProcessHeap(), 0, emr
);
1187 BOOL
EMFDC_GradientFill( DC_ATTR
*dc_attr
, TRIVERTEX
*vert_array
, ULONG nvert
,
1188 void *grad_array
, ULONG ngrad
, ULONG mode
)
1190 EMRGRADIENTFILL
*emr
;
1191 ULONG i
, pt
, size
, num_pts
= ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2);
1192 const ULONG
*pts
= (const ULONG
*)grad_array
;
1195 size
= FIELD_OFFSET(EMRGRADIENTFILL
, Ver
[nvert
]) + num_pts
* sizeof(pts
[0]);
1197 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1198 if (!emr
) return FALSE
;
1200 for (i
= 0; i
< num_pts
; i
++)
1206 emr
->rclBounds
.left
= emr
->rclBounds
.right
= vert_array
[pt
].x
;
1207 emr
->rclBounds
.top
= emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1211 if (vert_array
[pt
].x
< emr
->rclBounds
.left
)
1212 emr
->rclBounds
.left
= vert_array
[pt
].x
;
1213 else if (vert_array
[pt
].x
> emr
->rclBounds
.right
)
1214 emr
->rclBounds
.right
= vert_array
[pt
].x
;
1215 if (vert_array
[pt
].y
< emr
->rclBounds
.top
)
1216 emr
->rclBounds
.top
= vert_array
[pt
].y
;
1217 else if (vert_array
[pt
].y
> emr
->rclBounds
.bottom
)
1218 emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1221 emr
->rclBounds
.right
--;
1222 emr
->rclBounds
.bottom
--;
1224 emr
->emr
.iType
= EMR_GRADIENTFILL
;
1225 emr
->emr
.nSize
= size
;
1229 memcpy( emr
->Ver
, vert_array
, nvert
* sizeof(vert_array
[0]) );
1230 memcpy( emr
->Ver
+ nvert
, pts
, num_pts
* sizeof(pts
[0]) );
1232 emfdc_update_bounds( dc_attr
->emf
, &emr
->rclBounds
);
1233 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
1234 HeapFree( GetProcessHeap(), 0, emr
);
1238 BOOL
EMFDC_FillPath( DC_ATTR
*dc_attr
)
1240 return emfdrv_stroke_and_fill_path( dc_attr
->emf
, EMR_FILLPATH
);
1243 BOOL
EMFDC_StrokeAndFillPath( DC_ATTR
*dc_attr
)
1245 return emfdrv_stroke_and_fill_path( dc_attr
->emf
, EMR_STROKEANDFILLPATH
);
1248 BOOL
EMFDC_StrokePath( DC_ATTR
*dc_attr
)
1250 return emfdrv_stroke_and_fill_path( dc_attr
->emf
, EMR_STROKEPATH
);
1253 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
1254 static BOOL
emfdrv_stretchblt( struct emf
*emf
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1255 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1256 DWORD rop
, DWORD type
)
1258 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1259 UINT bmi_size
, emr_size
, size
;
1260 HBITMAP bitmap
, blit_bitmap
= NULL
;
1261 EMRBITBLT
*emr
= NULL
;
1266 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1269 blit_bitmap
= bitmap
;
1270 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1272 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
1273 emr_size
= type
== EMR_BITBLT
? sizeof(EMRBITBLT
) : sizeof(EMRSTRETCHBLT
);
1274 size
= emr_size
+ bmi_size
+ src_info
.bmiHeader
.biSizeImage
;
1276 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1278 emr
->emr
.iType
= type
;
1279 emr
->emr
.nSize
= size
;
1280 emr
->rclBounds
.left
= x_dst
;
1281 emr
->rclBounds
.top
= y_dst
;
1282 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1283 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1286 emr
->cxDest
= width_dst
;
1287 emr
->cyDest
= height_dst
;
1290 if (type
!= EMR_BITBLT
)
1292 EMRSTRETCHBLT
*emr_stretchblt
= (EMRSTRETCHBLT
*)emr
;
1293 emr_stretchblt
->cxSrc
= width_src
;
1294 emr_stretchblt
->cySrc
= height_src
;
1297 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1298 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1299 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1300 emr
->offBmiSrc
= emr_size
;
1301 emr
->cbBmiSrc
= bmi_size
;
1302 emr
->offBitsSrc
= emr_size
+ bmi_size
;
1303 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1305 bmi
= (BITMAPINFO
*)((BYTE
*)emr
+ emr
->offBmiSrc
);
1306 bmi
->bmiHeader
= src_info
.bmiHeader
;
1307 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1308 (BYTE
*)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1311 ret
= emfdc_record( emf
, (EMR
*)emr
);
1312 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1316 HeapFree( GetProcessHeap(), 0, emr
);
1317 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1318 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1322 BOOL
EMFDC_AlphaBlend( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1323 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1324 BLENDFUNCTION blend_function
)
1326 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
, hdc_src
,
1327 x_src
, y_src
, width_src
, height_src
, *(DWORD
*)&blend_function
,
1331 BOOL
EMFDC_PatBlt( DC_ATTR
*dc_attr
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
1333 struct emf
*emf
= dc_attr
->emf
;
1337 emr
.emr
.iType
= EMR_BITBLT
;
1338 emr
.emr
.nSize
= sizeof(emr
);
1339 emr
.rclBounds
.left
= left
;
1340 emr
.rclBounds
.top
= top
;
1341 emr
.rclBounds
.right
= left
+ width
- 1;
1342 emr
.rclBounds
.bottom
= top
+ height
- 1;
1346 emr
.cyDest
= height
;
1350 emr
.xformSrc
.eM11
= 1.0;
1351 emr
.xformSrc
.eM12
= 0.0;
1352 emr
.xformSrc
.eM21
= 0.0;
1353 emr
.xformSrc
.eM22
= 1.0;
1354 emr
.xformSrc
.eDx
= 0.0;
1355 emr
.xformSrc
.eDy
= 0.0;
1356 emr
.crBkColorSrc
= 0;
1363 ret
= emfdc_record( emf
, &emr
.emr
);
1364 if (ret
) emfdc_update_bounds( emf
, &emr
.rclBounds
);
1368 static inline BOOL
rop_uses_src( DWORD rop
)
1370 return ((rop
>> 2) & 0x330000) != (rop
& 0x330000);
1373 BOOL
EMFDC_BitBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width
, INT height
,
1374 HDC hdc_src
, INT x_src
, INT y_src
, DWORD rop
)
1376 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width
, height
, rop
);
1377 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width
, height
,
1378 hdc_src
, x_src
, y_src
, width
, height
, rop
, EMR_BITBLT
);
1381 BOOL
EMFDC_StretchBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1382 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1385 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1386 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
,
1387 hdc_src
, x_src
, y_src
, width_src
,
1388 height_src
, rop
, EMR_STRETCHBLT
);
1391 BOOL
EMFDC_TransparentBlt( DC_ATTR
*dc_attr
, int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1392 HDC hdc_src
, int x_src
, int y_src
, int width_src
, int height_src
,
1395 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
,
1396 hdc_src
, x_src
, y_src
, width_src
,
1397 height_src
, color
, EMR_TRANSPARENTBLT
);
1400 BOOL
EMFDC_MaskBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1401 HDC hdc_src
, INT x_src
, INT y_src
, HBITMAP mask
,
1402 INT x_mask
, INT y_mask
, DWORD rop
)
1404 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1405 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1406 struct emf
*emf
= dc_attr
->emf
;
1407 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1408 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1409 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1410 UINT bmi_size
, size
, mask_info_size
= 0;
1411 EMRMASKBLT
*emr
= NULL
;
1413 HDC blit_dc
, mask_dc
= NULL
;
1416 if (!rop_uses_src( rop
))
1417 return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1419 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1421 blit_bitmap
= bitmap
;
1422 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1428 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1429 if (mask_info
.bmiHeader
.biBitCount
== 1)
1430 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1432 else mask_info
.bmiHeader
.biSizeImage
= 0;
1434 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1435 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1437 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1439 emr
->emr
.iType
= EMR_MASKBLT
;
1440 emr
->emr
.nSize
= size
;
1441 emr
->rclBounds
.left
= x_dst
;
1442 emr
->rclBounds
.top
= y_dst
;
1443 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1444 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1447 emr
->cxDest
= width_dst
;
1448 emr
->cyDest
= height_dst
;
1452 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1453 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1454 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1455 emr
->offBmiSrc
= sizeof(*emr
);
1456 emr
->cbBmiSrc
= bmi_size
;
1457 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1458 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1459 emr
->xMask
= x_mask
;
1460 emr
->yMask
= y_mask
;
1461 emr
->iUsageMask
= DIB_PAL_MONO
;
1462 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1463 emr
->cbBmiMask
= mask_info_size
;
1464 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1465 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1467 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1468 bmi
->bmiHeader
= src_info
.bmiHeader
;
1469 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1470 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1475 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1476 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1477 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1478 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1483 ret
= emfdc_record( emf
, (EMR
*)emr
);
1484 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1488 HeapFree( GetProcessHeap(), 0, emr
);
1489 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1490 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1491 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1492 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1496 BOOL
EMFDC_PlgBlt( DC_ATTR
*dc_attr
, const POINT
*points
, HDC hdc_src
, INT x_src
, INT y_src
,
1497 INT width
, INT height
, HBITMAP mask
, INT x_mask
, INT y_mask
)
1499 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1500 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1501 struct emf
*emf
= dc_attr
->emf
;
1502 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1503 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1504 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1505 UINT bmi_size
, size
, mask_info_size
= 0;
1506 EMRPLGBLT
*emr
= NULL
;
1508 HDC blit_dc
, mask_dc
= NULL
;
1509 int x_min
, y_min
, x_max
, y_max
, i
;
1512 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1515 blit_bitmap
= bitmap
;
1516 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1522 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1523 if (mask_info
.bmiHeader
.biBitCount
== 1)
1524 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1526 else mask_info
.bmiHeader
.biSizeImage
= 0;
1528 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1529 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1531 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1533 emr
->emr
.iType
= EMR_PLGBLT
;
1534 emr
->emr
.nSize
= size
;
1536 /* FIXME: not exactly what native does */
1537 x_min
= x_max
= points
[1].x
+ points
[2].x
- points
[0].x
;
1538 y_min
= y_max
= points
[1].y
+ points
[2].y
- points
[0].y
;
1539 for (i
= 0; i
< ARRAYSIZE(emr
->aptlDest
); i
++)
1541 x_min
= min( x_min
, points
[i
].x
);
1542 y_min
= min( y_min
, points
[i
].y
);
1543 x_max
= max( x_max
, points
[i
].x
);
1544 y_max
= max( y_min
, points
[i
].y
);
1546 emr
->rclBounds
.left
= x_min
;
1547 emr
->rclBounds
.top
= y_min
;
1548 emr
->rclBounds
.right
= x_max
;
1549 emr
->rclBounds
.bottom
= y_max
;
1550 memcpy( emr
->aptlDest
, points
, sizeof(emr
->aptlDest
) );
1554 emr
->cySrc
= height
;
1555 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1556 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1557 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1558 emr
->offBmiSrc
= sizeof(*emr
);
1559 emr
->cbBmiSrc
= bmi_size
;
1560 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1561 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1562 emr
->xMask
= x_mask
;
1563 emr
->yMask
= y_mask
;
1564 emr
->iUsageMask
= DIB_PAL_MONO
;
1565 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1566 emr
->cbBmiMask
= mask_info_size
;
1567 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1568 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1570 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1571 bmi
->bmiHeader
= src_info
.bmiHeader
;
1572 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1573 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1578 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1579 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1580 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1581 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1586 ret
= emfdc_record( emf
, (EMR
*)emr
);
1587 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1591 HeapFree( GetProcessHeap(), 0, emr
);
1592 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1593 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1594 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1595 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1599 BOOL
EMFDC_StretchDIBits( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1600 INT x_src
, INT y_src
, INT width_src
, INT height_src
, const void *bits
,
1601 const BITMAPINFO
*info
, UINT usage
, DWORD rop
)
1603 EMRSTRETCHDIBITS
*emr
;
1605 UINT bmi_size
, emr_size
;
1607 /* calculate the size of the colour table */
1608 bmi_size
= get_dib_info_size( info
, usage
);
1610 emr_size
= sizeof (EMRSTRETCHDIBITS
) + bmi_size
+ info
->bmiHeader
.biSizeImage
;
1611 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, emr_size
))) return 0;
1613 /* write a bitmap info header (with colours) to the record */
1614 memcpy( &emr
[1], info
, bmi_size
);
1616 /* write bitmap bits to the record */
1617 memcpy ( (BYTE
*)&emr
[1] + bmi_size
, bits
, info
->bmiHeader
.biSizeImage
);
1619 /* fill in the EMR header at the front of our piece of memory */
1620 emr
->emr
.iType
= EMR_STRETCHDIBITS
;
1621 emr
->emr
.nSize
= emr_size
;
1625 emr
->cxDest
= width_dst
;
1626 emr
->cyDest
= height_dst
;
1631 emr
->iUsageSrc
= usage
;
1632 emr
->offBmiSrc
= sizeof (EMRSTRETCHDIBITS
);
1633 emr
->cbBmiSrc
= bmi_size
;
1634 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1635 emr
->cbBitsSrc
= info
->bmiHeader
.biSizeImage
;
1637 emr
->cxSrc
= width_src
;
1638 emr
->cySrc
= height_src
;
1640 emr
->rclBounds
.left
= x_dst
;
1641 emr
->rclBounds
.top
= y_dst
;
1642 emr
->rclBounds
.right
= x_dst
+ width_dst
;
1643 emr
->rclBounds
.bottom
= y_dst
+ height_dst
;
1645 /* save the record we just created */
1646 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
1647 if (ret
) emfdc_update_bounds( dc_attr
->emf
, &emr
->rclBounds
);
1648 HeapFree( GetProcessHeap(), 0, emr
);
1652 BOOL
EMFDC_SetDIBitsToDevice( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, DWORD width
, DWORD height
,
1653 INT x_src
, INT y_src
, UINT startscan
, UINT lines
,
1654 const void *bits
, const BITMAPINFO
*info
, UINT usage
)
1656 EMRSETDIBITSTODEVICE
*emr
;
1657 DWORD bmiSize
= get_dib_info_size( info
, usage
);
1658 DWORD size
= sizeof(EMRSETDIBITSTODEVICE
) + bmiSize
+ info
->bmiHeader
.biSizeImage
;
1661 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
1663 emr
->emr
.iType
= EMR_SETDIBITSTODEVICE
;
1664 emr
->emr
.nSize
= size
;
1665 emr
->rclBounds
.left
= x_dst
;
1666 emr
->rclBounds
.top
= y_dst
;
1667 emr
->rclBounds
.right
= x_dst
+ width
- 1;
1668 emr
->rclBounds
.bottom
= y_dst
+ height
- 1;
1674 emr
->cySrc
= height
;
1675 emr
->offBmiSrc
= sizeof(EMRSETDIBITSTODEVICE
);
1676 emr
->cbBmiSrc
= bmiSize
;
1677 emr
->offBitsSrc
= sizeof(EMRSETDIBITSTODEVICE
) + bmiSize
;
1678 emr
->cbBitsSrc
= info
->bmiHeader
.biSizeImage
;
1679 emr
->iUsageSrc
= usage
;
1680 emr
->iStartScan
= startscan
;
1681 emr
->cScans
= lines
;
1682 memcpy( (BYTE
*)emr
+ emr
->offBmiSrc
, info
, bmiSize
);
1683 memcpy( (BYTE
*)emr
+ emr
->offBitsSrc
, bits
, info
->bmiHeader
.biSizeImage
);
1685 if ((ret
= emfdc_record( dc_attr
->emf
, (EMR
*)emr
)))
1686 emfdc_update_bounds( dc_attr
->emf
, &emr
->rclBounds
);
1688 HeapFree( GetProcessHeap(), 0, emr
);
1692 BOOL
EMFDC_SetDCBrushColor( DC_ATTR
*dc_attr
, COLORREF color
)
1694 struct emf
*emf
= dc_attr
->emf
;
1695 EMRSELECTOBJECT emr
;
1698 if (GetCurrentObject( dc_attr
->hdc
, OBJ_BRUSH
) != GetStockObject( DC_BRUSH
)) return TRUE
;
1700 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
1701 if (!(emf
->dc_brush
= CreateSolidBrush( color
))) return FALSE
;
1702 if (!(index
= emfdc_create_brush( emf
, emf
->dc_brush
))) return FALSE
;
1703 GDI_hdc_using_object( emf
->dc_brush
, dc_attr
->hdc
, emfdc_delete_object
);
1704 emr
.emr
.iType
= EMR_SELECTOBJECT
;
1705 emr
.emr
.nSize
= sizeof(emr
);
1706 emr
.ihObject
= index
;
1707 return emfdc_record( emf
, &emr
.emr
);
1710 BOOL
EMFDC_SetDCPenColor( DC_ATTR
*dc_attr
, COLORREF color
)
1712 struct emf
*emf
= dc_attr
->emf
;
1713 EMRSELECTOBJECT emr
;
1715 LOGPEN logpen
= { PS_SOLID
, { 0, 0 }, color
};
1717 if (GetCurrentObject( dc_attr
->hdc
, OBJ_PEN
) != GetStockObject( DC_PEN
)) return TRUE
;
1719 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
1720 if (!(emf
->dc_pen
= CreatePenIndirect( &logpen
))) return FALSE
;
1721 if (!(index
= emfdc_create_pen( emf
, emf
->dc_pen
))) return FALSE
;
1722 GDI_hdc_using_object( emf
->dc_pen
, dc_attr
->hdc
, emfdc_delete_object
);
1723 emr
.emr
.iType
= EMR_SELECTOBJECT
;
1724 emr
.emr
.nSize
= sizeof(emr
);
1725 emr
.ihObject
= index
;
1726 return emfdc_record( emf
, &emr
.emr
);
1729 BOOL
EMFDC_SaveDC( DC_ATTR
*dc_attr
)
1733 emr
.emr
.iType
= EMR_SAVEDC
;
1734 emr
.emr
.nSize
= sizeof(emr
);
1735 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1738 BOOL
EMFDC_RestoreDC( DC_ATTR
*dc_attr
, INT level
)
1742 if (abs(level
) > dc_attr
->save_level
|| level
== 0) return FALSE
;
1744 emr
.emr
.iType
= EMR_RESTOREDC
;
1745 emr
.emr
.nSize
= sizeof(emr
);
1747 emr
.iRelative
= level
;
1749 emr
.iRelative
= level
- dc_attr
->save_level
- 1;
1750 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1753 BOOL
EMFDC_SetTextAlign( DC_ATTR
*dc_attr
, UINT align
)
1755 EMRSETTEXTALIGN emr
;
1757 emr
.emr
.iType
= EMR_SETTEXTALIGN
;
1758 emr
.emr
.nSize
= sizeof(emr
);
1760 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1763 BOOL
EMFDC_SetTextJustification( DC_ATTR
*dc_attr
, INT extra
, INT breaks
)
1765 EMRSETTEXTJUSTIFICATION emr
;
1767 emr
.emr
.iType
= EMR_SETTEXTJUSTIFICATION
;
1768 emr
.emr
.nSize
= sizeof(emr
);
1769 emr
.nBreakExtra
= extra
;
1770 emr
.nBreakCount
= breaks
;
1771 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1774 BOOL
EMFDC_SetBkMode( DC_ATTR
*dc_attr
, INT mode
)
1778 emr
.emr
.iType
= EMR_SETBKMODE
;
1779 emr
.emr
.nSize
= sizeof(emr
);
1781 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1784 BOOL
EMFDC_SetBkColor( DC_ATTR
*dc_attr
, COLORREF color
)
1788 emr
.emr
.iType
= EMR_SETBKCOLOR
;
1789 emr
.emr
.nSize
= sizeof(emr
);
1790 emr
.crColor
= color
;
1791 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1795 BOOL
EMFDC_SetTextColor( DC_ATTR
*dc_attr
, COLORREF color
)
1797 EMRSETTEXTCOLOR emr
;
1799 emr
.emr
.iType
= EMR_SETTEXTCOLOR
;
1800 emr
.emr
.nSize
= sizeof(emr
);
1801 emr
.crColor
= color
;
1802 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1805 BOOL
EMFDC_SetROP2( DC_ATTR
*dc_attr
, INT rop
)
1809 emr
.emr
.iType
= EMR_SETROP2
;
1810 emr
.emr
.nSize
= sizeof(emr
);
1812 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1815 BOOL
EMFDC_SetPolyFillMode( DC_ATTR
*dc_attr
, INT mode
)
1817 EMRSETPOLYFILLMODE emr
;
1819 emr
.emr
.iType
= EMR_SETPOLYFILLMODE
;
1820 emr
.emr
.nSize
= sizeof(emr
);
1822 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1825 BOOL
EMFDC_SetStretchBltMode( DC_ATTR
*dc_attr
, INT mode
)
1827 EMRSETSTRETCHBLTMODE emr
;
1829 emr
.emr
.iType
= EMR_SETSTRETCHBLTMODE
;
1830 emr
.emr
.nSize
= sizeof(emr
);
1832 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1835 BOOL
EMFDC_SetArcDirection( DC_ATTR
*dc_attr
, INT dir
)
1837 EMRSETARCDIRECTION emr
;
1839 emr
.emr
.iType
= EMR_SETARCDIRECTION
;
1840 emr
.emr
.nSize
= sizeof(emr
);
1841 emr
.iArcDirection
= dir
;
1842 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1845 INT
EMFDC_ExcludeClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
1847 EMREXCLUDECLIPRECT emr
;
1849 emr
.emr
.iType
= EMR_EXCLUDECLIPRECT
;
1850 emr
.emr
.nSize
= sizeof(emr
);
1851 emr
.rclClip
.left
= left
;
1852 emr
.rclClip
.top
= top
;
1853 emr
.rclClip
.right
= right
;
1854 emr
.rclClip
.bottom
= bottom
;
1855 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1858 BOOL
EMFDC_IntersectClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
1860 EMRINTERSECTCLIPRECT emr
;
1862 emr
.emr
.iType
= EMR_INTERSECTCLIPRECT
;
1863 emr
.emr
.nSize
= sizeof(emr
);
1864 emr
.rclClip
.left
= left
;
1865 emr
.rclClip
.top
= top
;
1866 emr
.rclClip
.right
= right
;
1867 emr
.rclClip
.bottom
= bottom
;
1868 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1871 BOOL
EMFDC_OffsetClipRgn( DC_ATTR
*dc_attr
, INT x
, INT y
)
1873 EMROFFSETCLIPRGN emr
;
1875 emr
.emr
.iType
= EMR_OFFSETCLIPRGN
;
1876 emr
.emr
.nSize
= sizeof(emr
);
1877 emr
.ptlOffset
.x
= x
;
1878 emr
.ptlOffset
.y
= y
;
1879 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1882 BOOL
EMFDC_ExtSelectClipRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, INT mode
)
1884 EMREXTSELECTCLIPRGN
*emr
;
1885 DWORD size
, rgnsize
;
1890 if (mode
!= RGN_COPY
) return ERROR
;
1893 else rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1895 size
= rgnsize
+ offsetof(EMREXTSELECTCLIPRGN
,RgnData
);
1896 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1897 if (rgnsize
) NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1899 emr
->emr
.iType
= EMR_EXTSELECTCLIPRGN
;
1900 emr
->emr
.nSize
= size
;
1901 emr
->cbRgnData
= rgnsize
;
1904 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
1905 HeapFree( GetProcessHeap(), 0, emr
);
1909 BOOL
EMFDC_SetMapMode( DC_ATTR
*dc_attr
, INT mode
)
1913 emr
.emr
.iType
= EMR_SETMAPMODE
;
1914 emr
.emr
.nSize
= sizeof(emr
);
1916 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1919 BOOL
EMFDC_SetViewportExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
1921 EMRSETVIEWPORTEXTEX emr
;
1923 emr
.emr
.iType
= EMR_SETVIEWPORTEXTEX
;
1924 emr
.emr
.nSize
= sizeof(emr
);
1925 emr
.szlExtent
.cx
= cx
;
1926 emr
.szlExtent
.cy
= cy
;
1927 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1930 BOOL
EMFDC_SetWindowExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
1932 EMRSETWINDOWEXTEX emr
;
1934 emr
.emr
.iType
= EMR_SETWINDOWEXTEX
;
1935 emr
.emr
.nSize
= sizeof(emr
);
1936 emr
.szlExtent
.cx
= cx
;
1937 emr
.szlExtent
.cy
= cy
;
1938 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1941 BOOL
EMFDC_SetViewportOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
1943 EMRSETVIEWPORTORGEX emr
;
1945 emr
.emr
.iType
= EMR_SETVIEWPORTORGEX
;
1946 emr
.emr
.nSize
= sizeof(emr
);
1947 emr
.ptlOrigin
.x
= x
;
1948 emr
.ptlOrigin
.y
= y
;
1949 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1952 BOOL
EMFDC_SetWindowOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
1954 EMRSETWINDOWORGEX emr
;
1956 emr
.emr
.iType
= EMR_SETWINDOWORGEX
;
1957 emr
.emr
.nSize
= sizeof(emr
);
1958 emr
.ptlOrigin
.x
= x
;
1959 emr
.ptlOrigin
.y
= y
;
1960 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1963 BOOL
EMFDC_ScaleViewportExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
1965 EMRSCALEVIEWPORTEXTEX emr
;
1967 emr
.emr
.iType
= EMR_SCALEVIEWPORTEXTEX
;
1968 emr
.emr
.nSize
= sizeof(emr
);
1970 emr
.xDenom
= x_denom
;
1972 emr
.yDenom
= y_denom
;
1973 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1976 BOOL
EMFDC_ScaleWindowExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
1978 EMRSCALEWINDOWEXTEX emr
;
1980 emr
.emr
.iType
= EMR_SCALEWINDOWEXTEX
;
1981 emr
.emr
.nSize
= sizeof(emr
);
1983 emr
.xDenom
= x_denom
;
1985 emr
.yDenom
= y_denom
;
1986 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1989 BOOL
EMFDC_SetLayout( DC_ATTR
*dc_attr
, DWORD layout
)
1993 emr
.emr
.iType
= EMR_SETLAYOUT
;
1994 emr
.emr
.nSize
= sizeof(emr
);
1996 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1999 BOOL
EMFDC_SetWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
)
2001 EMRSETWORLDTRANSFORM emr
;
2003 emr
.emr
.iType
= EMR_SETWORLDTRANSFORM
;
2004 emr
.emr
.nSize
= sizeof(emr
);
2006 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2009 BOOL
EMFDC_ModifyWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
, DWORD mode
)
2011 EMRMODIFYWORLDTRANSFORM emr
;
2013 emr
.emr
.iType
= EMR_MODIFYWORLDTRANSFORM
;
2014 emr
.emr
.nSize
= sizeof(emr
);
2015 if (mode
== MWT_IDENTITY
)
2017 emr
.xform
.eM11
= 1.0f
;
2018 emr
.xform
.eM12
= 0.0f
;
2019 emr
.xform
.eM21
= 0.0f
;
2020 emr
.xform
.eM22
= 1.0f
;
2021 emr
.xform
.eDx
= 0.0f
;
2022 emr
.xform
.eDy
= 0.0f
;
2029 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2032 BOOL
EMFDC_SetMapperFlags( DC_ATTR
*dc_attr
, DWORD flags
)
2034 EMRSETMAPPERFLAGS emr
;
2036 emr
.emr
.iType
= EMR_SETMAPPERFLAGS
;
2037 emr
.emr
.nSize
= sizeof(emr
);
2038 emr
.dwFlags
= flags
;
2039 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2042 BOOL
EMFDC_AbortPath( DC_ATTR
*dc_attr
)
2044 struct emf
*emf
= dc_attr
->emf
;
2047 emr
.emr
.iType
= EMR_ABORTPATH
;
2048 emr
.emr
.nSize
= sizeof(emr
);
2051 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2054 BOOL
EMFDC_BeginPath( DC_ATTR
*dc_attr
)
2056 struct emf
*emf
= dc_attr
->emf
;
2059 emr
.emr
.iType
= EMR_BEGINPATH
;
2060 emr
.emr
.nSize
= sizeof(emr
);
2061 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
2067 BOOL
EMFDC_CloseFigure( DC_ATTR
*dc_attr
)
2071 emr
.emr
.iType
= EMR_CLOSEFIGURE
;
2072 emr
.emr
.nSize
= sizeof(emr
);
2073 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2076 BOOL
EMFDC_EndPath( DC_ATTR
*dc_attr
)
2078 struct emf
*emf
= dc_attr
->emf
;
2083 emr
.emr
.iType
= EMR_ENDPATH
;
2084 emr
.emr
.nSize
= sizeof(emr
);
2085 return emfdc_record( emf
, &emr
.emr
);
2088 BOOL
EMFDC_FlattenPath( DC_ATTR
*dc_attr
)
2092 emr
.emr
.iType
= EMR_FLATTENPATH
;
2093 emr
.emr
.nSize
= sizeof(emr
);
2094 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2097 BOOL
EMFDC_SelectClipPath( DC_ATTR
*dc_attr
, INT mode
)
2099 EMRSELECTCLIPPATH emr
;
2101 emr
.emr
.iType
= EMR_SELECTCLIPPATH
;
2102 emr
.emr
.nSize
= sizeof(emr
);
2104 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2107 BOOL
EMFDC_WidenPath( DC_ATTR
*dc_attr
)
2111 emr
.emr
.iType
= EMR_WIDENPATH
;
2112 emr
.emr
.nSize
= sizeof(emr
);
2113 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2116 void EMFDC_DeleteDC( DC_ATTR
*dc_attr
)
2118 struct emf
*emf
= dc_attr
->emf
;
2121 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2122 for (index
= 0; index
< emf
->handles_size
; index
++)
2123 if (emf
->handles
[index
])
2124 GDI_hdc_not_using_object( emf
->handles
[index
], emf
->dc_attr
->hdc
);
2125 HeapFree( GetProcessHeap(), 0, emf
->handles
);
2128 /*******************************************************************
2129 * GdiComment (GDI32.@)
2131 BOOL WINAPI
GdiComment( HDC hdc
, UINT bytes
, const BYTE
*buffer
)
2135 UINT total
, rounded_size
;
2138 if (!(dc_attr
= get_dc_attr( hdc
)) || !dc_attr
->emf
) return FALSE
;
2140 rounded_size
= (bytes
+3) & ~3;
2141 total
= offsetof(EMRGDICOMMENT
,Data
) + rounded_size
;
2143 emr
= HeapAlloc(GetProcessHeap(), 0, total
);
2144 emr
->emr
.iType
= EMR_GDICOMMENT
;
2145 emr
->emr
.nSize
= total
;
2146 emr
->cbData
= bytes
;
2147 memset(&emr
->Data
[bytes
], 0, rounded_size
- bytes
);
2148 memcpy(&emr
->Data
[0], buffer
, bytes
);
2150 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
2152 HeapFree(GetProcessHeap(), 0, emr
);
2157 /**********************************************************************
2158 * CreateEnhMetaFileA (GDI32.@)
2160 HDC WINAPI
CreateEnhMetaFileA( HDC hdc
, const char *filename
, const RECT
*rect
,
2161 const char *description
)
2163 WCHAR
*filenameW
= NULL
;
2164 WCHAR
*descriptionW
= NULL
;
2165 DWORD len1
, len2
, total
;
2170 total
= MultiByteToWideChar( CP_ACP
, 0, filename
, -1, NULL
, 0 );
2171 filenameW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2172 MultiByteToWideChar( CP_ACP
, 0, filename
, -1, filenameW
, total
);
2177 len1
= strlen(description
);
2178 len2
= strlen(description
+ len1
+ 1);
2179 total
= MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, NULL
, 0 );
2180 descriptionW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2181 MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, descriptionW
, total
);
2184 ret
= CreateEnhMetaFileW( hdc
, filenameW
, rect
, descriptionW
);
2186 HeapFree( GetProcessHeap(), 0, filenameW
);
2187 HeapFree( GetProcessHeap(), 0, descriptionW
);
2191 /**********************************************************************
2192 * CreateEnhMetaFileW (GDI32.@)
2194 HDC WINAPI
CreateEnhMetaFileW( HDC hdc
, const WCHAR
*filename
, const RECT
*rect
,
2195 const WCHAR
*description
)
2201 DWORD size
= 0, length
= 0;
2203 TRACE( "(%p %s %s %s)\n", hdc
, debugstr_w(filename
), wine_dbgstr_rect(rect
),
2204 debugstr_w(description
) );
2206 if (!(ret
= NtGdiCreateMetafileDC( hdc
))) return 0;
2208 if (!(dc_attr
= get_dc_attr( ret
)) || !(emf
= HeapAlloc( GetProcessHeap(), 0, sizeof(*emf
) )))
2214 emf
->dc_attr
= dc_attr
;
2217 if (description
) /* App name\0Title\0\0 */
2219 length
= lstrlenW( description
);
2220 length
+= lstrlenW( description
+ length
+ 1 );
2224 size
= sizeof(ENHMETAHEADER
) + (length
+ 3) / 4 * 4;
2226 if (!(emf
->emh
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
)))
2231 emf
->dc_attr
= dc_attr
;
2233 emf
->handles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
2234 HANDLE_LIST_INC
* sizeof(emf
->handles
[0]) );
2235 emf
->handles_size
= HANDLE_LIST_INC
;
2236 emf
->cur_handles
= 1;
2242 emf
->emh
->iType
= EMR_HEADER
;
2243 emf
->emh
->nSize
= size
;
2245 dc_attr
->emf_bounds
.left
= dc_attr
->emf_bounds
.top
= 0;
2246 dc_attr
->emf_bounds
.right
= dc_attr
->emf_bounds
.bottom
= -1;
2250 emf
->emh
->rclFrame
.left
= rect
->left
;
2251 emf
->emh
->rclFrame
.top
= rect
->top
;
2252 emf
->emh
->rclFrame
.right
= rect
->right
;
2253 emf
->emh
->rclFrame
.bottom
= rect
->bottom
;
2257 /* Set this to {0,0 - -1,-1} and update it at the end */
2258 emf
->emh
->rclFrame
.left
= emf
->emh
->rclFrame
.top
= 0;
2259 emf
->emh
->rclFrame
.right
= emf
->emh
->rclFrame
.bottom
= -1;
2262 emf
->emh
->dSignature
= ENHMETA_SIGNATURE
;
2263 emf
->emh
->nVersion
= 0x10000;
2264 emf
->emh
->nBytes
= emf
->emh
->nSize
;
2265 emf
->emh
->nRecords
= 1;
2266 emf
->emh
->nHandles
= 1;
2268 emf
->emh
->sReserved
= 0; /* According to docs, this is reserved and must be 0 */
2269 emf
->emh
->nDescription
= length
/ 2;
2271 emf
->emh
->offDescription
= length
? sizeof(ENHMETAHEADER
) : 0;
2273 emf
->emh
->nPalEntries
= 0; /* I guess this should start at 0 */
2275 /* Size in pixels */
2276 emf
->emh
->szlDevice
.cx
= GetDeviceCaps( ret
, HORZRES
);
2277 emf
->emh
->szlDevice
.cy
= GetDeviceCaps( ret
, VERTRES
);
2279 /* Size in millimeters */
2280 emf
->emh
->szlMillimeters
.cx
= GetDeviceCaps( ret
, HORZSIZE
);
2281 emf
->emh
->szlMillimeters
.cy
= GetDeviceCaps( ret
, VERTSIZE
);
2283 /* Size in micrometers */
2284 emf
->emh
->szlMicrometers
.cx
= emf
->emh
->szlMillimeters
.cx
* 1000;
2285 emf
->emh
->szlMicrometers
.cy
= emf
->emh
->szlMillimeters
.cy
* 1000;
2287 memcpy( (char *)emf
->emh
+ sizeof(ENHMETAHEADER
), description
, length
);
2289 if (filename
) /* disk based metafile */
2291 if ((file
= CreateFileW( filename
, GENERIC_WRITE
| GENERIC_READ
, 0,
2292 NULL
, CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
)
2300 TRACE( "returning %p\n", ret
);
2304 /******************************************************************
2305 * CloseEnhMetaFile (GDI32.@)
2307 HENHMETAFILE WINAPI
CloseEnhMetaFile( HDC hdc
)
2315 TRACE("(%p)\n", hdc
);
2317 if (!(dc_attr
= get_dc_attr( hdc
)) || !dc_attr
->emf
) return 0;
2320 if (dc_attr
->save_level
)
2321 RestoreDC( hdc
, 1 );
2323 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2324 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2326 emr
.emr
.iType
= EMR_EOF
;
2327 emr
.emr
.nSize
= sizeof(emr
);
2328 emr
.nPalEntries
= 0;
2329 emr
.offPalEntries
= FIELD_OFFSET(EMREOF
, nSizeLast
);
2330 emr
.nSizeLast
= emr
.emr
.nSize
;
2331 emfdc_record( emf
, &emr
.emr
);
2333 emf
->emh
->rclBounds
= dc_attr
->emf_bounds
;
2335 /* Update rclFrame if not initialized in CreateEnhMetaFile */
2336 if (emf
->emh
->rclFrame
.left
> emf
->emh
->rclFrame
.right
)
2338 emf
->emh
->rclFrame
.left
= emf
->emh
->rclBounds
.left
*
2339 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2340 emf
->emh
->rclFrame
.top
= emf
->emh
->rclBounds
.top
*
2341 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2342 emf
->emh
->rclFrame
.right
= emf
->emh
->rclBounds
.right
*
2343 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2344 emf
->emh
->rclFrame
.bottom
= emf
->emh
->rclBounds
.bottom
*
2345 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2348 if (emf
->file
) /* disk based metafile */
2350 if (!WriteFile( emf
->file
, emf
->emh
, emf
->emh
->nBytes
, NULL
, NULL
))
2352 CloseHandle( emf
->file
);
2355 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2356 mapping
= CreateFileMappingA( emf
->file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
2357 TRACE( "mapping = %p\n", mapping
);
2358 emf
->emh
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
2359 TRACE( "view = %p\n", emf
->emh
);
2360 CloseHandle( mapping
);
2361 CloseHandle( emf
->file
);
2364 hmf
= EMF_Create_HENHMETAFILE( emf
->emh
, emf
->emh
->nBytes
, emf
->file
!= 0 );
2365 emf
->emh
= NULL
; /* So it won't be deleted */