2 * Enhanced metafile functions
3 * Copyright 1998 Douglas Ridgway
11 #include "wine/winestring.h"
13 #include "enhmetafile.h"
14 #include "debugtools.h"
17 DEFAULT_DEBUG_CHANNEL(enhmetafile
)
19 /****************************************************************************
20 * EMF_Create_HENHMETAFILE
22 HENHMETAFILE
EMF_Create_HENHMETAFILE(ENHMETAHEADER
*emh
, HFILE hFile
, HANDLE
25 HENHMETAFILE hmf
= GDI_AllocObject( sizeof(ENHMETAFILEOBJ
),
27 ENHMETAFILEOBJ
*metaObj
= (ENHMETAFILEOBJ
*)GDI_HEAP_LOCK( hmf
);
29 metaObj
->hFile
= hFile
;
30 metaObj
->hMapping
= hMapping
;
31 GDI_HEAP_UNLOCK( hmf
);
35 /****************************************************************************
36 * EMF_Delete_HENHMETAFILE
38 static BOOL
EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf
)
40 ENHMETAFILEOBJ
*metaObj
= (ENHMETAFILEOBJ
*)GDI_GetObjPtr( hmf
,
42 if(!metaObj
) return FALSE
;
43 if(metaObj
->hMapping
) {
44 UnmapViewOfFile( metaObj
->emh
);
45 CloseHandle( metaObj
->hMapping
);
46 CloseHandle( metaObj
->hFile
);
48 HeapFree( SystemHeap
, 0, metaObj
->emh
);
49 return GDI_FreeObject( hmf
);
52 /******************************************************************
53 * EMF_GetEnhMetaHeader
55 * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE
56 * Should be followed by call to EMF_ReleaseEnhMetaHeader
58 static ENHMETAHEADER
*EMF_GetEnhMetaHeader( HENHMETAFILE hmf
)
60 ENHMETAFILEOBJ
*metaObj
= (ENHMETAFILEOBJ
*)GDI_GetObjPtr( hmf
,
62 TRACE("hmf %04x -> enhmetaObj %p\n", hmf
, metaObj
);
63 return metaObj
? metaObj
->emh
: NULL
;
66 /******************************************************************
67 * EMF_ReleaseEnhMetaHeader
69 * Releases ENHMETAHEADER associated with HENHMETAFILE
71 static BOOL
EMF_ReleaseEnhMetaHeader( HENHMETAFILE hmf
)
73 return GDI_HEAP_UNLOCK( hmf
);
76 /*****************************************************************************
80 static HENHMETAFILE
EMF_GetEnhMetaFile( HFILE hFile
)
85 hMapping
= CreateFileMappingA( hFile
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
86 emh
= MapViewOfFile( hMapping
, FILE_MAP_READ
, 0, 0, 0 );
88 if (emh
->iType
!= EMR_HEADER
|| emh
->dSignature
!= ENHMETA_SIGNATURE
) {
89 WARN("Invalid emf header type 0x%08lx sig 0x%08lx.\n",
90 emh
->iType
, emh
->dSignature
);
91 UnmapViewOfFile( emh
);
92 CloseHandle( hMapping
);
95 return EMF_Create_HENHMETAFILE( emh
, hFile
, hMapping
);
99 /*****************************************************************************
100 * GetEnhMetaFileA (GDI32.174)
104 HENHMETAFILE WINAPI
GetEnhMetaFileA(
105 LPCSTR lpszMetaFile
/* filename of enhanced metafile */
111 hFile
= CreateFileA(lpszMetaFile
, GENERIC_READ
, FILE_SHARE_READ
, 0,
112 OPEN_EXISTING
, 0, 0);
113 if (hFile
== INVALID_HANDLE_VALUE
) {
114 WARN("could not open %s\n", lpszMetaFile
);
117 hmf
= EMF_GetEnhMetaFile( hFile
);
119 CloseHandle( hFile
);
123 /*****************************************************************************
124 * GetEnhMetaFile32W (GDI32.180)
126 HENHMETAFILE WINAPI
GetEnhMetaFileW(
127 LPCWSTR lpszMetaFile
) /* filename of enhanced metafile */
132 hFile
= CreateFileW(lpszMetaFile
, GENERIC_READ
, FILE_SHARE_READ
, 0,
133 OPEN_EXISTING
, 0, 0);
134 if (hFile
== INVALID_HANDLE_VALUE
) {
135 WARN("could not open %s\n", debugstr_w(lpszMetaFile
));
138 hmf
= EMF_GetEnhMetaFile( hFile
);
140 CloseHandle( hFile
);
144 /*****************************************************************************
145 * GetEnhMetaFileHeader (GDI32.178)
147 * If _buf_ is NULL, returns the size of buffer required.
148 * Otherwise, copy up to _bufsize_ bytes of enhanced metafile header into
151 UINT WINAPI
GetEnhMetaFileHeader(
152 HENHMETAFILE hmf
, /* enhanced metafile */
153 UINT bufsize
, /* size of buffer */
154 LPENHMETAHEADER buf
/* buffer */
159 if (!buf
) return sizeof(ENHMETAHEADER
);
160 emh
= EMF_GetEnhMetaHeader(hmf
);
161 if(!emh
) return FALSE
;
162 memmove(buf
, emh
, MIN(sizeof(ENHMETAHEADER
), bufsize
));
163 EMF_ReleaseEnhMetaHeader(hmf
);
164 return MIN(sizeof(ENHMETAHEADER
), bufsize
);
168 /*****************************************************************************
169 * GetEnhMetaFileDescription32A (GDI32.176)
171 UINT WINAPI
GetEnhMetaFileDescriptionA(
172 HENHMETAFILE hmf
, /* enhanced metafile */
173 UINT size
, /* size of buf */
174 LPSTR buf
/* buffer to receive description */
177 LPENHMETAHEADER emh
= EMF_GetEnhMetaHeader(hmf
);
180 if(!emh
) return FALSE
;
181 if(emh
->nDescription
== 0 || emh
->offDescription
== 0) {
182 EMF_ReleaseEnhMetaHeader(hmf
);
185 if (!buf
|| !size
) {
186 EMF_ReleaseEnhMetaHeader(hmf
);
187 return emh
->nDescription
;
190 first
= lstrlenW( (WCHAR
*) ((char *) emh
+ emh
->offDescription
));
192 lstrcpynWtoA(buf
, (WCHAR
*) ((char *) emh
+ emh
->offDescription
), size
);
194 lstrcpynWtoA(buf
, (WCHAR
*) ((char *) emh
+ emh
->offDescription
+2*(first
+1)),
197 EMF_ReleaseEnhMetaHeader(hmf
);
198 return MIN(size
, emh
->nDescription
);
201 /*****************************************************************************
202 * GetEnhMetaFileDescription32W (GDI32.177)
204 * Copies the description string of an enhanced metafile into a buffer
207 * If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
208 * number of characters copied.
210 UINT WINAPI
GetEnhMetaFileDescriptionW(
211 HENHMETAFILE hmf
, /* enhanced metafile */
212 UINT size
, /* size of buf */
213 LPWSTR buf
/* buffer to receive description */
216 LPENHMETAHEADER emh
= EMF_GetEnhMetaHeader(hmf
);
218 if(!emh
) return FALSE
;
219 if(emh
->nDescription
== 0 || emh
->offDescription
== 0) {
220 EMF_ReleaseEnhMetaHeader(hmf
);
223 if (!buf
|| !size
) {
224 EMF_ReleaseEnhMetaHeader(hmf
);
225 return emh
->nDescription
;
228 memmove(buf
, (char *) emh
+ emh
->offDescription
,
229 MIN(size
,emh
->nDescription
));
230 EMF_ReleaseEnhMetaHeader(hmf
);
231 return MIN(size
, emh
->nDescription
);
234 /****************************************************************************
235 * SetEnhMetaFileBits (GDI32.315)
237 * Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
239 HENHMETAFILE WINAPI
SetEnhMetaFileBits(UINT bufsize
, const BYTE
*buf
)
241 ENHMETAHEADER
*emh
= HeapAlloc( SystemHeap
, 0, bufsize
);
242 memmove(emh
, buf
, bufsize
);
243 return EMF_Create_HENHMETAFILE( emh
, 0, 0 );
246 /*****************************************************************************
247 * GetEnhMetaFileBits (GDI32.175)
250 UINT WINAPI
GetEnhMetaFileBits(
258 /*****************************************************************************
259 * PlayEnhMetaFileRecord (GDI32.264)
261 * Render a single enhanced metafile record in the device context hdc.
264 * TRUE on success, FALSE on error.
266 * Many unimplemented records.
268 BOOL WINAPI
PlayEnhMetaFileRecord(
269 HDC hdc
, /* device context in which to render EMF record */
270 LPHANDLETABLE handletable
, /* array of handles to be used in rendering record */
271 const ENHMETARECORD
*mr
, /* EMF record to render */
272 UINT handles
/* size of handle array */
277 "hdc = %08x, handletable = %p, record = %p, numHandles = %d\n",
278 hdc
, handletable
, mr
, handles
);
279 if (!mr
) return FALSE
;
283 TRACE(" type=%d\n", type
);
288 /* ENHMETAHEADER *h = (LPENHMETAHEADER) mr; */
294 /* application defined and processed */
298 DWORD mode
= mr
->dParm
[0];
299 SetMapMode(hdc
, mode
);
304 DWORD mode
= mr
->dParm
[0];
305 SetBkMode(hdc
, mode
);
310 DWORD mode
= mr
->dParm
[0];
311 SetBkColor(hdc
, mode
);
314 case EMR_SETPOLYFILLMODE
:
316 DWORD mode
= mr
->dParm
[0];
317 SetPolyFillMode(hdc
, mode
);
322 DWORD mode
= mr
->dParm
[0];
326 case EMR_SETSTRETCHBLTMODE
:
328 DWORD mode
= mr
->dParm
[0];
329 SetStretchBltMode(hdc
, mode
);
332 case EMR_SETTEXTALIGN
:
334 DWORD align
= mr
->dParm
[0];
335 SetTextAlign(hdc
, align
);
338 case EMR_SETTEXTCOLOR
:
340 DWORD color
= mr
->dParm
[0];
341 SetTextColor(hdc
, color
);
351 RestoreDC(hdc
, mr
->dParm
[0]);
354 case EMR_INTERSECTCLIPRECT
:
356 INT left
= mr
->dParm
[0], top
= mr
->dParm
[1], right
= mr
->dParm
[2],
357 bottom
= mr
->dParm
[3];
358 IntersectClipRect(hdc
, left
, top
, right
, bottom
);
361 case EMR_SELECTOBJECT
:
363 DWORD obj
= mr
->dParm
[0];
364 SelectObject(hdc
, (handletable
->objectHandle
)[obj
]);
367 case EMR_DELETEOBJECT
:
369 DWORD obj
= mr
->dParm
[0];
370 DeleteObject( (handletable
->objectHandle
)[obj
]);
371 (handletable
->objectHandle
)[obj
] = 0;
374 case EMR_SETWINDOWORGEX
:
376 DWORD x
= mr
->dParm
[0], y
= mr
->dParm
[1];
377 SetWindowOrgEx(hdc
, x
, y
, NULL
);
380 case EMR_SETWINDOWEXTEX
:
382 DWORD x
= mr
->dParm
[0], y
= mr
->dParm
[1];
383 SetWindowExtEx(hdc
, x
, y
, NULL
);
386 case EMR_SETVIEWPORTORGEX
:
388 DWORD x
= mr
->dParm
[0], y
= mr
->dParm
[1];
389 SetViewportOrgEx(hdc
, x
, y
, NULL
);
392 case EMR_SETVIEWPORTEXTEX
:
394 DWORD x
= mr
->dParm
[0], y
= mr
->dParm
[1];
395 SetViewportExtEx(hdc
, x
, y
, NULL
);
400 DWORD obj
= mr
->dParm
[0];
401 (handletable
->objectHandle
)[obj
] =
402 CreatePenIndirect((LOGPEN
*) &(mr
->dParm
[1]));
405 case EMR_EXTCREATEPEN
:
407 DWORD obj
= mr
->dParm
[0];
408 DWORD style
= mr
->dParm
[1], brush
= mr
->dParm
[2];
409 LOGBRUSH
*b
= (LOGBRUSH
*) &mr
->dParm
[3];
410 FIXME("Some ExtCreatePen args not handled\n");
411 (handletable
->objectHandle
)[obj
] =
412 ExtCreatePen(style
, brush
, b
, 0, NULL
);
415 case EMR_CREATEBRUSHINDIRECT
:
417 DWORD obj
= mr
->dParm
[0];
418 (handletable
->objectHandle
)[obj
] =
419 CreateBrushIndirect((LOGBRUSH
*) &(mr
->dParm
[1]));
422 case EMR_EXTCREATEFONTINDIRECTW
:
424 DWORD obj
= mr
->dParm
[0];
425 (handletable
->objectHandle
)[obj
] =
426 CreateFontIndirectW((LOGFONTW
*) &(mr
->dParm
[1]));
431 DWORD x
= mr
->dParm
[0], y
= mr
->dParm
[1];
432 MoveToEx(hdc
, x
, y
, NULL
);
437 DWORD x
= mr
->dParm
[0], y
= mr
->dParm
[1];
443 INT left
= mr
->dParm
[0], top
= mr
->dParm
[1], right
= mr
->dParm
[2],
444 bottom
= mr
->dParm
[3];
445 Rectangle(hdc
, left
, top
, right
, bottom
);
450 INT left
= mr
->dParm
[0], top
= mr
->dParm
[1], right
= mr
->dParm
[2],
451 bottom
= mr
->dParm
[3];
452 Ellipse(hdc
, left
, top
, right
, bottom
);
457 /* 0-3 : a bounding rectangle? */
458 INT count
= mr
->dParm
[4];
459 FIXME("Some Polygon16 args not handled\n");
460 Polygon16(hdc
, (POINT16
*)&mr
->dParm
[5], count
);
465 /* 0-3 : a bounding rectangle? */
466 INT count
= mr
->dParm
[4];
467 FIXME("Some Polyline16 args not handled\n");
468 Polyline16(hdc
, (POINT16
*)&mr
->dParm
[5], count
);
473 case EMR_POLYPOLYGON16
:
475 INT polygons
= mr
->dParm
[z
];
476 LPPOINT16 pts
= (LPPOINT16
) &mr
->dParm
[x
];
477 LPINT16 counts
= (LPINT16
) &mr
->dParm
[y
];
478 PolyPolygon16(hdc
, pts
, counts
, polygons
);
482 case EMR_STRETCHDIBITS
:
484 LONG xDest
= mr
->dParm
[4];
485 LONG yDest
= mr
->dParm
[5];
486 LONG xSrc
= mr
->dParm
[6];
487 LONG ySrc
= mr
->dParm
[7];
488 LONG cxSrc
= mr
->dParm
[8];
489 LONG cySrc
= mr
->dParm
[9];
490 DWORD offBmiSrc
= mr
->dParm
[10];
491 DWORD offBitsSrc
= mr
->dParm
[12];
492 DWORD iUsageSrc
= mr
->dParm
[14];
493 DWORD dwRop
= mr
->dParm
[15];
494 LONG cxDest
= mr
->dParm
[16];
495 LONG cyDest
= mr
->dParm
[17];
497 StretchDIBits(hdc
,xDest
,yDest
,cxDest
,cyDest
,
498 xSrc
,ySrc
,cxSrc
,cySrc
,
499 ((char *)mr
)+offBitsSrc
,
500 (const BITMAPINFO
*)(((char *)mr
)+offBmiSrc
),
504 case EMR_EXTTEXTOUTW
:
507 DWORD flags
= mr
->dParm
[4];
509 DWORD x
= mr
->dParm
[7], y
= mr
->dParm
[8];
510 DWORD count
= mr
->dParm
[9];
512 LPWSTR str
= (LPWSTR
)& mr
->dParm
[17];
513 /* trailing info: dx array? */
514 FIXME("Many ExtTextOut args not handled\n");
515 ExtTextOutW(hdc
, x
, y
, flags
, /* lpRect */ NULL
,
516 str
, count
, /* lpDx */ NULL
);
521 FIXME("type %d is unimplemented\n", type
);
522 /* SetLastError(E_NOTIMPL); */
529 /*****************************************************************************
531 * EnumEnhMetaFile32 (GDI32.79)
533 * Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
535 * record. Returns when either every record has been used or
536 * when _EnhMetaFunc_ returns FALSE.
540 * TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
546 BOOL WINAPI
EnumEnhMetaFile(
547 HDC hdc
, /* device context to pass to _EnhMetaFunc_ */
548 HENHMETAFILE hmf
, /* EMF to walk */
549 ENHMFENUMPROC callback
, /* callback function */
550 LPVOID data
, /* optional data for callback function */
551 const RECT
*rect
/* bounding rectangle for rendered metafile */
555 LPENHMETARECORD p
= (LPENHMETARECORD
) EMF_GetEnhMetaHeader(hmf
);
560 count
= ((LPENHMETAHEADER
) p
)->nHandles
;
561 ht
= HeapAlloc( GetProcessHeap(), 0, sizeof(HANDLETABLE
)*count
);
562 ht
->objectHandle
[0] = hmf
;
564 ret
= (*callback
)(hdc
, ht
, p
, count
, data
);
565 if (p
->iType
== EMR_EOF
) break;
566 p
= (LPENHMETARECORD
) ((char *) p
+ p
->nSize
);
568 HeapFree( GetProcessHeap(), 0, ht
);
569 EMF_ReleaseEnhMetaHeader(hmf
);
574 /**************************************************************************
575 * PlayEnhMetaFile (GDI32.263)
577 * Renders an enhanced metafile into a specified rectangle *lpRect
578 * in device context hdc.
581 * Almost entirely unimplemented
584 BOOL WINAPI
PlayEnhMetaFile(
585 HDC hdc
, /* DC to render into */
586 HENHMETAFILE hmf
, /* metafile to render */
587 const RECT
*lpRect
/* rectangle to place metafile inside */
590 LPENHMETARECORD p
= (LPENHMETARECORD
) EMF_GetEnhMetaHeader(hmf
);
597 count
= ((LPENHMETAHEADER
) p
)->nHandles
;
598 ht
= HeapAlloc( GetProcessHeap(), 0, sizeof(HANDLETABLE
) * count
);
600 LPENHMETAHEADER h
= (LPENHMETAHEADER
) p
;
601 FLOAT xscale
= (h
->rclBounds
.right
- h
->rclBounds
.left
) /
602 (lpRect
->right
- lpRect
->left
);
603 FLOAT yscale
= (h
->rclBounds
.bottom
- h
->rclBounds
.top
) /
604 (lpRect
->bottom
- lpRect
->top
);
610 xform
.eDx
= lpRect
->left
;
611 xform
.eDy
= lpRect
->top
;
612 FIXME("play into rect doesn't work\n");
613 savedMode
= SetGraphicsMode(hdc
, GM_ADVANCED
);
614 if (!SetWorldTransform(hdc
, &xform
)) {
615 WARN("World transform failed!\n");
619 ht
->objectHandle
[0] = hmf
;
621 PlayEnhMetaFileRecord(hdc
, ht
, p
, count
);
622 if (p
->iType
== EMR_EOF
) break;
623 p
= (LPENHMETARECORD
) ((char *) p
+ p
->nSize
); /* casted so that arithmetic is in bytes */
625 HeapFree( GetProcessHeap(), 0, ht
);
626 EMF_ReleaseEnhMetaHeader(hmf
);
627 if (savedMode
) SetGraphicsMode(hdc
, savedMode
);
628 ret
= TRUE
; /* FIXME: calculate a more accurate return value */
632 /*****************************************************************************
633 * DeleteEnhMetaFile (GDI32.68)
635 * Deletes an enhanced metafile and frees the associated storage.
637 BOOL WINAPI
DeleteEnhMetaFile(HENHMETAFILE hmf
)
639 return EMF_Delete_HENHMETAFILE( hmf
);
642 /*****************************************************************************
643 * CopyEnhMetaFileA (GDI32.21) Duplicate an enhanced metafile
647 HENHMETAFILE WINAPI
CopyEnhMetaFileA(
651 ENHMETAHEADER
*emrSrc
= EMF_GetEnhMetaHeader( hmfSrc
), *emrDst
;
654 if(!emrSrc
) return FALSE
;
656 emrDst
= HeapAlloc( SystemHeap
, 0, emrSrc
->nBytes
);
657 memcpy( emrDst
, emrSrc
, emrSrc
->nBytes
);
658 hmfDst
= EMF_Create_HENHMETAFILE( emrDst
, 0, 0 );
661 hFile
= CreateFileA( file
, GENERIC_WRITE
| GENERIC_READ
, 0, NULL
,
662 CREATE_ALWAYS
, 0, -1);
663 WriteFile( hFile
, emrSrc
, emrSrc
->nBytes
, 0, 0);
664 hmfDst
= EMF_GetEnhMetaFile( hFile
);
666 EMF_ReleaseEnhMetaHeader( hmfSrc
);
671 /*****************************************************************************
672 * GetEnhMetaFilePaletteEntries (GDI32.179)
674 * Copy the palette and report size
677 UINT WINAPI
GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf
,
685 /******************************************************************
686 * SetWinMetaFileBits (GDI32.343)
688 * Translate from old style to new style.
691 HENHMETAFILE WINAPI
SetWinMetaFileBits(UINT cbBuffer
,
692 CONST BYTE
*lpbBuffer
,
694 CONST METAFILEPICT
*lpmfp