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