2 * Enhanced metafile functions
3 * Copyright 1998 Douglas Ridgway
11 #include "wine/winestring.h"
13 #include "enhmetafile.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(enhmetafile, "hmf %04x -> enhmetaObj %p\n", hmf, metaObj);
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(enhmetafile, "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, 0, 0, OPEN_EXISTING, 0, 0);
112 if (hFile == INVALID_HANDLE_VALUE) {
113 WARN(enhmetafile,"could not open %s\n", lpszMetaFile);
116 hmf = EMF_GetEnhMetaFile( hFile );
118 CloseHandle( hFile );
122 /*****************************************************************************
123 * GetEnhMetaFile32W (GDI32.180)
125 HENHMETAFILE WINAPI GetEnhMetaFileW(
126 LPCWSTR lpszMetaFile) /* filename of enhanced metafile */
131 hFile = CreateFileW(lpszMetaFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
132 if (hFile == INVALID_HANDLE_VALUE) {
133 WARN(enhmetafile,"could not open %s\n", debugstr_w(lpszMetaFile));
136 hmf = EMF_GetEnhMetaFile( hFile );
138 CloseHandle( hFile );
142 /*****************************************************************************
143 * GetEnhMetaFileHeader (GDI32.178)
145 * If _buf_ is NULL, returns the size of buffer required.
146 * Otherwise, copy up to _bufsize_ bytes of enhanced metafile header into
149 UINT WINAPI GetEnhMetaFileHeader(
150 HENHMETAFILE hmf, /* enhanced metafile */
151 UINT bufsize, /* size of buffer */
152 LPENHMETAHEADER buf /* buffer */
157 if (!buf) return sizeof(ENHMETAHEADER);
158 emh = EMF_GetEnhMetaHeader(hmf);
159 memmove(buf, emh, MIN(sizeof(ENHMETAHEADER), bufsize));
160 EMF_ReleaseEnhMetaHeader(hmf);
161 return MIN(sizeof(ENHMETAHEADER), bufsize);
165 /*****************************************************************************
166 * GetEnhMetaFileDescription32A (GDI32.176)
168 UINT WINAPI GetEnhMetaFileDescriptionA(
169 HENHMETAFILE hmf, /* enhanced metafile */
170 UINT size, /* size of buf */
171 LPSTR buf /* buffer to receive description */
174 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
177 if(emh->nDescription == 0 || emh->offDescription == 0) {
178 EMF_ReleaseEnhMetaHeader(hmf);
181 if (!buf || !size ) {
182 EMF_ReleaseEnhMetaHeader(hmf);
183 return emh->nDescription;
186 first = lstrlenW( (WCHAR *) ((char *) emh + emh->offDescription));
188 lstrcpynWtoA(buf, (WCHAR *) ((char *) emh + emh->offDescription), size);
190 lstrcpynWtoA(buf, (WCHAR *) ((char *) emh + emh->offDescription+2*(first+1)),
193 EMF_ReleaseEnhMetaHeader(hmf);
194 return MIN(size, emh->nDescription);
197 /*****************************************************************************
198 * GetEnhMetaFileDescription32W (GDI32.177)
200 * Copies the description string of an enhanced metafile into a buffer
203 * If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
204 * number of characters copied.
206 UINT WINAPI GetEnhMetaFileDescriptionW(
207 HENHMETAFILE hmf, /* enhanced metafile */
208 UINT size, /* size of buf */
209 LPWSTR buf /* buffer to receive description */
212 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
214 if(emh->nDescription == 0 || emh->offDescription == 0) {
215 EMF_ReleaseEnhMetaHeader(hmf);
218 if (!buf || !size ) {
219 EMF_ReleaseEnhMetaHeader(hmf);
220 return emh->nDescription;
223 memmove(buf, (char *) emh + emh->offDescription,
224 MIN(size,emh->nDescription));
225 EMF_ReleaseEnhMetaHeader(hmf);
226 return MIN(size, emh->nDescription);
229 /****************************************************************************
230 * SetEnhMetaFileBits (GDI32.315)
232 * Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
234 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
236 ENHMETAHEADER *emh = HeapAlloc( SystemHeap, 0, bufsize );
237 memmove(emh, buf, bufsize);
238 return EMF_Create_HENHMETAFILE( emh, 0, 0 );
241 /*****************************************************************************
242 * GetEnhMetaFileBits (GDI32.175)
245 UINT WINAPI GetEnhMetaFileBits(
253 /*****************************************************************************
254 * PlayEnhMetaFileRecord (GDI32.264)
256 * Render a single enhanced metafile record in the device context hdc.
259 * TRUE on success, FALSE on error.
261 * Many unimplemented records.
263 BOOL WINAPI PlayEnhMetaFileRecord(
264 HDC hdc, /* device context in which to render EMF record */
265 LPHANDLETABLE handletable, /* array of handles to be used in rendering record */
266 const ENHMETARECORD *mr, /* EMF record to render */
267 UINT handles /* size of handle array */
272 "hdc = %08x, handletable = %p, record = %p, numHandles = %d\n",
273 hdc, handletable, mr, handles);
274 if (!mr) return FALSE;
278 TRACE(enhmetafile, " type=%d\n", type);
283 /* ENHMETAHEADER *h = (LPENHMETAHEADER) mr; */
289 /* application defined and processed */
293 DWORD mode = mr->dParm[0];
294 SetMapMode(hdc, mode);
299 DWORD mode = mr->dParm[0];
300 SetBkMode(hdc, mode);
305 DWORD mode = mr->dParm[0];
306 SetBkColor(hdc, mode);
309 case EMR_SETPOLYFILLMODE:
311 DWORD mode = mr->dParm[0];
312 SetPolyFillMode(hdc, mode);
317 DWORD mode = mr->dParm[0];
321 case EMR_SETSTRETCHBLTMODE:
323 DWORD mode = mr->dParm[0];
324 SetStretchBltMode(hdc, mode);
327 case EMR_SETTEXTALIGN:
329 DWORD align = mr->dParm[0];
330 SetTextAlign(hdc, align);
333 case EMR_SETTEXTCOLOR:
335 DWORD color = mr->dParm[0];
336 SetTextColor(hdc, color);
346 RestoreDC(hdc, mr->dParm[0]);
349 case EMR_INTERSECTCLIPRECT:
351 INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
352 bottom = mr->dParm[3];
353 IntersectClipRect(hdc, left, top, right, bottom);
356 case EMR_SELECTOBJECT:
358 DWORD obj = mr->dParm[0];
359 SelectObject(hdc, (handletable->objectHandle)[obj]);
362 case EMR_DELETEOBJECT:
364 DWORD obj = mr->dParm[0];
365 DeleteObject( (handletable->objectHandle)[obj]);
366 (handletable->objectHandle)[obj] = 0;
369 case EMR_SETWINDOWORGEX:
371 DWORD x = mr->dParm[0], y = mr->dParm[1];
372 SetWindowOrgEx(hdc, x, y, NULL);
375 case EMR_SETWINDOWEXTEX:
377 DWORD x = mr->dParm[0], y = mr->dParm[1];
378 SetWindowExtEx(hdc, x, y, NULL);
381 case EMR_SETVIEWPORTORGEX:
383 DWORD x = mr->dParm[0], y = mr->dParm[1];
384 SetViewportOrgEx(hdc, x, y, NULL);
387 case EMR_SETVIEWPORTEXTEX:
389 DWORD x = mr->dParm[0], y = mr->dParm[1];
390 SetViewportExtEx(hdc, x, y, NULL);
395 DWORD obj = mr->dParm[0];
396 (handletable->objectHandle)[obj] =
397 CreatePenIndirect((LOGPEN *) &(mr->dParm[1]));
400 case EMR_EXTCREATEPEN:
402 DWORD obj = mr->dParm[0];
403 DWORD style = mr->dParm[1], brush = mr->dParm[2];
404 LOGBRUSH *b = (LOGBRUSH *) &mr->dParm[3];
405 FIXME(enhmetafile, "Some ExtCreatePen args not handled\n");
406 (handletable->objectHandle)[obj] =
407 ExtCreatePen(style, brush, b, 0, NULL);
410 case EMR_CREATEBRUSHINDIRECT:
412 DWORD obj = mr->dParm[0];
413 (handletable->objectHandle)[obj] =
414 CreateBrushIndirect((LOGBRUSH *) &(mr->dParm[1]));
417 case EMR_EXTCREATEFONTINDIRECTW:
419 DWORD obj = mr->dParm[0];
420 (handletable->objectHandle)[obj] =
421 CreateFontIndirectW((LOGFONTW *) &(mr->dParm[1]));
426 DWORD x = mr->dParm[0], y = mr->dParm[1];
427 MoveToEx(hdc, x, y, NULL);
432 DWORD x = mr->dParm[0], y = mr->dParm[1];
438 INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
439 bottom = mr->dParm[3];
440 Rectangle(hdc, left, top, right, bottom);
445 INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
446 bottom = mr->dParm[3];
447 Ellipse(hdc, left, top, right, bottom);
452 /* 0-3 : a bounding rectangle? */
453 INT count = mr->dParm[4];
454 FIXME(enhmetafile, "Some Polygon16 args not handled\n");
455 Polygon16(hdc, (POINT16 *)&mr->dParm[5], count);
460 /* 0-3 : a bounding rectangle? */
461 INT count = mr->dParm[4];
462 FIXME(enhmetafile, "Some Polyline16 args not handled\n");
463 Polyline16(hdc, (POINT16 *)&mr->dParm[5], count);
468 case EMR_POLYPOLYGON16:
470 INT polygons = mr->dParm[z];
471 LPPOINT16 pts = (LPPOINT16) &mr->dParm[x];
472 LPINT16 counts = (LPINT16) &mr->dParm[y];
473 PolyPolygon16(hdc, pts, counts, polygons);
477 case EMR_STRETCHDIBITS:
479 LONG xDest = mr->dParm[4];
480 LONG yDest = mr->dParm[5];
481 LONG xSrc = mr->dParm[6];
482 LONG ySrc = mr->dParm[7];
483 LONG cxSrc = mr->dParm[8];
484 LONG cySrc = mr->dParm[9];
485 DWORD offBmiSrc = mr->dParm[10];
486 DWORD offBitsSrc = mr->dParm[12];
487 DWORD iUsageSrc = mr->dParm[14];
488 DWORD dwRop = mr->dParm[15];
489 LONG cxDest = mr->dParm[16];
490 LONG cyDest = mr->dParm[17];
492 StretchDIBits(hdc,xDest,yDest,cxDest,cyDest,
493 xSrc,ySrc,cxSrc,cySrc,
494 ((char *)mr)+offBitsSrc,
495 (const BITMAPINFO *)(((char *)mr)+offBmiSrc),
499 case EMR_EXTTEXTOUTW:
502 DWORD flags = mr->dParm[4];
504 DWORD x = mr->dParm[7], y = mr->dParm[8];
505 DWORD count = mr->dParm[9];
507 LPWSTR str = (LPWSTR)& mr->dParm[17];
508 /* trailing info: dx array? */
509 FIXME(enhmetafile, "Many ExtTextOut args not handled\n");
510 ExtTextOutW(hdc, x, y, flags, /* lpRect */ NULL,
511 str, count, /* lpDx */ NULL);
516 FIXME(enhmetafile, "type %d is unimplemented\n", type);
517 /* SetLastError(E_NOTIMPL); */
524 /*****************************************************************************
526 * EnumEnhMetaFile32 (GDI32.79)
528 * Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
530 * record. Returns when either every record has been used or
531 * when _EnhMetaFunc_ returns FALSE.
535 * TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
541 BOOL WINAPI EnumEnhMetaFile(
542 HDC hdc, /* device context to pass to _EnhMetaFunc_ */
543 HENHMETAFILE hmf, /* EMF to walk */
544 ENHMFENUMPROC callback, /* callback function */
545 LPVOID data, /* optional data for callback function */
546 const RECT *rect /* bounding rectangle for rendered metafile */
550 LPENHMETARECORD p = (LPENHMETARECORD) EMF_GetEnhMetaHeader(hmf);
551 INT count = ((LPENHMETAHEADER) p)->nHandles;
552 HANDLETABLE *ht = HeapAlloc( GetProcessHeap(), 0,
553 sizeof(HANDLETABLE)*count);
554 ht->objectHandle[0] = hmf;
556 ret = (*callback)(hdc, ht, p, count, data);
557 if (p->iType == EMR_EOF) break;
558 p = (LPENHMETARECORD) ((char *) p + p->nSize);
560 HeapFree( GetProcessHeap(), 0, ht);
561 EMF_ReleaseEnhMetaHeader(hmf);
566 /**************************************************************************
567 * PlayEnhMetaFile (GDI32.263)
569 * Renders an enhanced metafile into a specified rectangle *lpRect
570 * in device context hdc.
573 * Almost entirely unimplemented
576 BOOL WINAPI PlayEnhMetaFile(
577 HDC hdc, /* DC to render into */
578 HENHMETAFILE hmf, /* metafile to render */
579 const RECT *lpRect /* rectangle to place metafile inside */
582 LPENHMETARECORD p = (LPENHMETARECORD) EMF_GetEnhMetaHeader(hmf);
583 INT count = ((LPENHMETAHEADER) p)->nHandles;
584 HANDLETABLE *ht = HeapAlloc( GetProcessHeap(), 0,
585 sizeof(HANDLETABLE) * count);
589 LPENHMETAHEADER h = (LPENHMETAHEADER) p;
590 FLOAT xscale = (h->rclBounds.right - h->rclBounds.left) /
591 (lpRect->right - lpRect->left);
592 FLOAT yscale = (h->rclBounds.bottom - h->rclBounds.top) /
593 (lpRect->bottom - lpRect->top);
599 xform.eDx = lpRect->left;
600 xform.eDy = lpRect->top;
601 FIXME(enhmetafile, "play into rect doesn't work\n");
602 savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
603 if (!SetWorldTransform(hdc, &xform)) {
604 WARN(enhmetafile, "World transform failed!\n");
608 ht->objectHandle[0] = hmf;
610 PlayEnhMetaFileRecord(hdc, ht, p, count);
611 if (p->iType == EMR_EOF) break;
612 p = (LPENHMETARECORD) ((char *) p + p->nSize); /* casted so that arithmetic is in bytes */
614 HeapFree( GetProcessHeap(), 0, ht );
615 EMF_ReleaseEnhMetaHeader(hmf);
616 if (savedMode) SetGraphicsMode(hdc, savedMode);
617 ret = TRUE; /* FIXME: calculate a more accurate return value */
621 /*****************************************************************************
622 * DeleteEnhMetaFile (GDI32.68)
624 * Deletes an enhanced metafile and frees the associated storage.
626 BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf)
628 return EMF_Delete_HENHMETAFILE( hmf );
631 /*****************************************************************************
632 * CopyEnhMetaFileA (GDI32.21) Duplicate an enhanced metafile
636 HENHMETAFILE WINAPI CopyEnhMetaFileA(
640 ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
644 emrDst = HeapAlloc( SystemHeap, 0, emrSrc->nBytes );
645 memcpy( emrDst, emrSrc, emrSrc->nBytes );
646 hmfDst = EMF_Create_HENHMETAFILE( emrDst, 0, 0 );
649 hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0, NULL,
650 CREATE_ALWAYS, 0, -1);
651 WriteFile( hFile, emrSrc, emrSrc->nBytes, 0, 0);
652 hmfDst = EMF_GetEnhMetaFile( hFile );
654 EMF_ReleaseEnhMetaHeader( hmfSrc );
659 /*****************************************************************************
660 * GetEnhMetaFilePaletteEntries (GDI32.179)
662 * Copy the palette and report size
665 UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,
673 /******************************************************************
674 * SetWinMetaFileBits (GDI32.343)
676 * Translate from old style to new style.
679 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
680 CONST BYTE *lpbBuffer,
682 CONST METAFILEPICT *lpmfp
685 FIXME(enhmetafile,"Stub\n");