Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine.git] / objects / enhmetafile.c
blobb275c08a678ec5de9a7ee8bef8becb276a50ca86
1 /*
2 * Enhanced metafile functions
3 * Copyright 1998 Douglas Ridgway
4 * 1999 Huw D M Davies
5 */
7 #include <string.h>
8 #include <assert.h>
9 #include "winbase.h"
10 #include "wingdi.h"
11 #include "wine/winestring.h"
12 #include "winerror.h"
13 #include "enhmetafile.h"
14 #include "debugtools.h"
15 #include "heap.h"
17 DEFAULT_DEBUG_CHANNEL(enhmetafile)
19 /****************************************************************************
20 * EMF_Create_HENHMETAFILE
22 HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, HFILE hFile, HANDLE
23 hMapping )
25 HENHMETAFILE hmf = GDI_AllocObject( sizeof(ENHMETAFILEOBJ),
26 ENHMETAFILE_MAGIC );
27 ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_HEAP_LOCK( hmf );
28 metaObj->emh = emh;
29 metaObj->hFile = hFile;
30 metaObj->hMapping = hMapping;
31 GDI_HEAP_UNLOCK( hmf );
32 return hmf;
35 /****************************************************************************
36 * EMF_Delete_HENHMETAFILE
38 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
40 ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf,
41 ENHMETAFILE_MAGIC );
42 if(!metaObj) return FALSE;
43 if(metaObj->hMapping) {
44 UnmapViewOfFile( metaObj->emh );
45 CloseHandle( metaObj->hMapping );
46 CloseHandle( metaObj->hFile );
47 } else
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,
61 ENHMETAFILE_MAGIC );
62 TRACE("hmf %04x -> enhmetaObj %p\n", hmf, metaObj);
63 return metaObj->emh;
66 /******************************************************************
67 * EMF_ReleaseEnhMetaHeader
69 * Releases ENHMETAHEADER associated with HENHMETAFILE
71 static BOOL EMF_ReleaseEnhMetaHeader( HENHMETAFILE hmf )
73 return GDI_HEAP_UNLOCK( hmf );
76 /*****************************************************************************
77 * EMF_GetEnhMetaFile
80 static HENHMETAFILE EMF_GetEnhMetaFile( HFILE hFile )
82 ENHMETAHEADER *emh;
83 HANDLE hMapping;
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 );
93 return 0;
95 return EMF_Create_HENHMETAFILE( emh, hFile, hMapping );
99 /*****************************************************************************
100 * GetEnhMetaFileA (GDI32.174)
104 HENHMETAFILE WINAPI GetEnhMetaFileA(
105 LPCSTR lpszMetaFile /* filename of enhanced metafile */
108 HENHMETAFILE hmf;
109 HFILE hFile;
111 hFile = CreateFileA(lpszMetaFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
112 if (hFile == INVALID_HANDLE_VALUE) {
113 WARN("could not open %s\n", lpszMetaFile);
114 return 0;
116 hmf = EMF_GetEnhMetaFile( hFile );
117 if(!hmf)
118 CloseHandle( hFile );
119 return hmf;
122 /*****************************************************************************
123 * GetEnhMetaFile32W (GDI32.180)
125 HENHMETAFILE WINAPI GetEnhMetaFileW(
126 LPCWSTR lpszMetaFile) /* filename of enhanced metafile */
128 HENHMETAFILE hmf;
129 HFILE hFile;
131 hFile = CreateFileW(lpszMetaFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
132 if (hFile == INVALID_HANDLE_VALUE) {
133 WARN("could not open %s\n", debugstr_w(lpszMetaFile));
134 return 0;
136 hmf = EMF_GetEnhMetaFile( hFile );
137 if(!hmf)
138 CloseHandle( hFile );
139 return hmf;
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
147 * _buf.
149 UINT WINAPI GetEnhMetaFileHeader(
150 HENHMETAFILE hmf, /* enhanced metafile */
151 UINT bufsize, /* size of buffer */
152 LPENHMETAHEADER buf /* buffer */
155 LPENHMETAHEADER emh;
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);
175 INT first;
177 if(emh->nDescription == 0 || emh->offDescription == 0) {
178 EMF_ReleaseEnhMetaHeader(hmf);
179 return 0;
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);
189 buf += first + 1;
190 lstrcpynWtoA(buf, (WCHAR *) ((char *) emh + emh->offDescription+2*(first+1)),
191 size - 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
201 * _buf_.
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);
216 return 0;
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(
246 HENHMETAFILE hmf,
247 UINT bufsize,
248 LPBYTE buf
250 return 0;
253 /*****************************************************************************
254 * PlayEnhMetaFileRecord (GDI32.264)
256 * Render a single enhanced metafile record in the device context hdc.
258 * RETURNS
259 * TRUE on success, FALSE on error.
260 * BUGS
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 */
270 int type;
271 TRACE(
272 "hdc = %08x, handletable = %p, record = %p, numHandles = %d\n",
273 hdc, handletable, mr, handles);
274 if (!mr) return FALSE;
276 type = mr->iType;
278 TRACE(" type=%d\n", type);
279 switch(type)
281 case EMR_HEADER:
283 /* ENHMETAHEADER *h = (LPENHMETAHEADER) mr; */
284 break;
286 case EMR_EOF:
287 break;
288 case EMR_GDICOMMENT:
289 /* application defined and processed */
290 break;
291 case EMR_SETMAPMODE:
293 DWORD mode = mr->dParm[0];
294 SetMapMode(hdc, mode);
295 break;
297 case EMR_SETBKMODE:
299 DWORD mode = mr->dParm[0];
300 SetBkMode(hdc, mode);
301 break;
303 case EMR_SETBKCOLOR:
305 DWORD mode = mr->dParm[0];
306 SetBkColor(hdc, mode);
307 break;
309 case EMR_SETPOLYFILLMODE:
311 DWORD mode = mr->dParm[0];
312 SetPolyFillMode(hdc, mode);
313 break;
315 case EMR_SETROP2:
317 DWORD mode = mr->dParm[0];
318 SetROP2(hdc, mode);
319 break;
321 case EMR_SETSTRETCHBLTMODE:
323 DWORD mode = mr->dParm[0];
324 SetStretchBltMode(hdc, mode);
325 break;
327 case EMR_SETTEXTALIGN:
329 DWORD align = mr->dParm[0];
330 SetTextAlign(hdc, align);
331 break;
333 case EMR_SETTEXTCOLOR:
335 DWORD color = mr->dParm[0];
336 SetTextColor(hdc, color);
337 break;
339 case EMR_SAVEDC:
341 SaveDC(hdc);
342 break;
344 case EMR_RESTOREDC:
346 RestoreDC(hdc, mr->dParm[0]);
347 break;
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);
354 break;
356 case EMR_SELECTOBJECT:
358 DWORD obj = mr->dParm[0];
359 SelectObject(hdc, (handletable->objectHandle)[obj]);
360 break;
362 case EMR_DELETEOBJECT:
364 DWORD obj = mr->dParm[0];
365 DeleteObject( (handletable->objectHandle)[obj]);
366 (handletable->objectHandle)[obj] = 0;
367 break;
369 case EMR_SETWINDOWORGEX:
371 DWORD x = mr->dParm[0], y = mr->dParm[1];
372 SetWindowOrgEx(hdc, x, y, NULL);
373 break;
375 case EMR_SETWINDOWEXTEX:
377 DWORD x = mr->dParm[0], y = mr->dParm[1];
378 SetWindowExtEx(hdc, x, y, NULL);
379 break;
381 case EMR_SETVIEWPORTORGEX:
383 DWORD x = mr->dParm[0], y = mr->dParm[1];
384 SetViewportOrgEx(hdc, x, y, NULL);
385 break;
387 case EMR_SETVIEWPORTEXTEX:
389 DWORD x = mr->dParm[0], y = mr->dParm[1];
390 SetViewportExtEx(hdc, x, y, NULL);
391 break;
393 case EMR_CREATEPEN:
395 DWORD obj = mr->dParm[0];
396 (handletable->objectHandle)[obj] =
397 CreatePenIndirect((LOGPEN *) &(mr->dParm[1]));
398 break;
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("Some ExtCreatePen args not handled\n");
406 (handletable->objectHandle)[obj] =
407 ExtCreatePen(style, brush, b, 0, NULL);
408 break;
410 case EMR_CREATEBRUSHINDIRECT:
412 DWORD obj = mr->dParm[0];
413 (handletable->objectHandle)[obj] =
414 CreateBrushIndirect((LOGBRUSH *) &(mr->dParm[1]));
415 break;
417 case EMR_EXTCREATEFONTINDIRECTW:
419 DWORD obj = mr->dParm[0];
420 (handletable->objectHandle)[obj] =
421 CreateFontIndirectW((LOGFONTW *) &(mr->dParm[1]));
422 break;
424 case EMR_MOVETOEX:
426 DWORD x = mr->dParm[0], y = mr->dParm[1];
427 MoveToEx(hdc, x, y, NULL);
428 break;
430 case EMR_LINETO:
432 DWORD x = mr->dParm[0], y = mr->dParm[1];
433 LineTo(hdc, x, y);
434 break;
436 case EMR_RECTANGLE:
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);
441 break;
443 case EMR_ELLIPSE:
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);
448 break;
450 case EMR_POLYGON16:
452 /* 0-3 : a bounding rectangle? */
453 INT count = mr->dParm[4];
454 FIXME("Some Polygon16 args not handled\n");
455 Polygon16(hdc, (POINT16 *)&mr->dParm[5], count);
456 break;
458 case EMR_POLYLINE16:
460 /* 0-3 : a bounding rectangle? */
461 INT count = mr->dParm[4];
462 FIXME("Some Polyline16 args not handled\n");
463 Polyline16(hdc, (POINT16 *)&mr->dParm[5], count);
464 break;
467 #if 0
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);
474 break;
476 #endif
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),
496 iUsageSrc,dwRop);
497 break;
499 case EMR_EXTTEXTOUTW:
501 /* 0-3: ??? */
502 DWORD flags = mr->dParm[4];
503 /* 5, 6: ??? */
504 DWORD x = mr->dParm[7], y = mr->dParm[8];
505 DWORD count = mr->dParm[9];
506 /* 10-16: ??? */
507 LPWSTR str = (LPWSTR)& mr->dParm[17];
508 /* trailing info: dx array? */
509 FIXME("Many ExtTextOut args not handled\n");
510 ExtTextOutW(hdc, x, y, flags, /* lpRect */ NULL,
511 str, count, /* lpDx */ NULL);
512 break;
515 default:
516 FIXME("type %d is unimplemented\n", type);
517 /* SetLastError(E_NOTIMPL); */
518 break;
520 return TRUE;
524 /*****************************************************************************
526 * EnumEnhMetaFile32 (GDI32.79)
528 * Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
529 * for each
530 * record. Returns when either every record has been used or
531 * when _EnhMetaFunc_ returns FALSE.
534 * RETURNS
535 * TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
536 * returns FALSE.
538 * BUGS
539 * Ignores rect.
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 */
549 BOOL ret = TRUE;
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;
555 while (ret) {
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);
562 return ret;
566 /**************************************************************************
567 * PlayEnhMetaFile (GDI32.263)
569 * Renders an enhanced metafile into a specified rectangle *lpRect
570 * in device context hdc.
572 * BUGS
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);
586 BOOL ret = FALSE;
587 INT savedMode = 0;
588 if (lpRect) {
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);
594 XFORM xform;
595 xform.eM11 = xscale;
596 xform.eM12 = 0;
597 xform.eM21 = 0;
598 xform.eM22 = yscale;
599 xform.eDx = lpRect->left;
600 xform.eDy = lpRect->top;
601 FIXME("play into rect doesn't work\n");
602 savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
603 if (!SetWorldTransform(hdc, &xform)) {
604 WARN("World transform failed!\n");
608 ht->objectHandle[0] = hmf;
609 while (1) {
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 */
618 return ret;
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(
637 HENHMETAFILE hmfSrc,
638 LPCSTR file)
640 ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
641 HENHMETAFILE hmfDst;
643 if (!file) {
644 emrDst = HeapAlloc( SystemHeap, 0, emrSrc->nBytes );
645 memcpy( emrDst, emrSrc, emrSrc->nBytes );
646 hmfDst = EMF_Create_HENHMETAFILE( emrDst, 0, 0 );
647 } else {
648 HFILE hFile;
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 );
655 return hmfDst;
659 /*****************************************************************************
660 * GetEnhMetaFilePaletteEntries (GDI32.179)
662 * Copy the palette and report size
665 UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,
666 UINT cEntries,
667 LPPALETTEENTRY lppe)
669 return 0;
673 /******************************************************************
674 * SetWinMetaFileBits (GDI32.343)
676 * Translate from old style to new style.
679 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
680 CONST BYTE *lpbBuffer,
681 HDC hdcRef,
682 CONST METAFILEPICT *lpmfp
685 FIXME("Stub\n");
686 return 0;