Winspool DocumentProperties and DeviceCapabilities should now work on
[wine.git] / objects / enhmetafile.c
blob4ea7bcd46d9620f296987f6fc82a7a6262953f5e
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 ? 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 /*****************************************************************************
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, FILE_SHARE_READ, 0,
112 OPEN_EXISTING, 0, 0);
113 if (hFile == INVALID_HANDLE_VALUE) {
114 WARN("could not open %s\n", lpszMetaFile);
115 return 0;
117 hmf = EMF_GetEnhMetaFile( hFile );
118 if(!hmf)
119 CloseHandle( hFile );
120 return hmf;
123 /*****************************************************************************
124 * GetEnhMetaFile32W (GDI32.180)
126 HENHMETAFILE WINAPI GetEnhMetaFileW(
127 LPCWSTR lpszMetaFile) /* filename of enhanced metafile */
129 HENHMETAFILE hmf;
130 HFILE hFile;
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));
136 return 0;
138 hmf = EMF_GetEnhMetaFile( hFile );
139 if(!hmf)
140 CloseHandle( hFile );
141 return hmf;
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
149 * _buf.
151 UINT WINAPI GetEnhMetaFileHeader(
152 HENHMETAFILE hmf, /* enhanced metafile */
153 UINT bufsize, /* size of buffer */
154 LPENHMETAHEADER buf /* buffer */
157 LPENHMETAHEADER emh;
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);
178 INT first;
180 if(!emh) return FALSE;
181 if(emh->nDescription == 0 || emh->offDescription == 0) {
182 EMF_ReleaseEnhMetaHeader(hmf);
183 return 0;
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);
193 buf += first + 1;
194 lstrcpynWtoA(buf, (WCHAR *) ((char *) emh + emh->offDescription+2*(first+1)),
195 size - 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
205 * _buf_.
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);
221 return 0;
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(
251 HENHMETAFILE hmf,
252 UINT bufsize,
253 LPBYTE buf
255 return 0;
258 /*****************************************************************************
259 * PlayEnhMetaFileRecord (GDI32.264)
261 * Render a single enhanced metafile record in the device context hdc.
263 * RETURNS
264 * TRUE on success, FALSE on error.
265 * BUGS
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 */
275 int type;
276 TRACE(
277 "hdc = %08x, handletable = %p, record = %p, numHandles = %d\n",
278 hdc, handletable, mr, handles);
279 if (!mr) return FALSE;
281 type = mr->iType;
283 TRACE(" type=%d\n", type);
284 switch(type)
286 case EMR_HEADER:
288 /* ENHMETAHEADER *h = (LPENHMETAHEADER) mr; */
289 break;
291 case EMR_EOF:
292 break;
293 case EMR_GDICOMMENT:
294 /* application defined and processed */
295 break;
296 case EMR_SETMAPMODE:
298 DWORD mode = mr->dParm[0];
299 SetMapMode(hdc, mode);
300 break;
302 case EMR_SETBKMODE:
304 DWORD mode = mr->dParm[0];
305 SetBkMode(hdc, mode);
306 break;
308 case EMR_SETBKCOLOR:
310 DWORD mode = mr->dParm[0];
311 SetBkColor(hdc, mode);
312 break;
314 case EMR_SETPOLYFILLMODE:
316 DWORD mode = mr->dParm[0];
317 SetPolyFillMode(hdc, mode);
318 break;
320 case EMR_SETROP2:
322 DWORD mode = mr->dParm[0];
323 SetROP2(hdc, mode);
324 break;
326 case EMR_SETSTRETCHBLTMODE:
328 DWORD mode = mr->dParm[0];
329 SetStretchBltMode(hdc, mode);
330 break;
332 case EMR_SETTEXTALIGN:
334 DWORD align = mr->dParm[0];
335 SetTextAlign(hdc, align);
336 break;
338 case EMR_SETTEXTCOLOR:
340 DWORD color = mr->dParm[0];
341 SetTextColor(hdc, color);
342 break;
344 case EMR_SAVEDC:
346 SaveDC(hdc);
347 break;
349 case EMR_RESTOREDC:
351 RestoreDC(hdc, mr->dParm[0]);
352 break;
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);
359 break;
361 case EMR_SELECTOBJECT:
363 DWORD obj = mr->dParm[0];
364 SelectObject(hdc, (handletable->objectHandle)[obj]);
365 break;
367 case EMR_DELETEOBJECT:
369 DWORD obj = mr->dParm[0];
370 DeleteObject( (handletable->objectHandle)[obj]);
371 (handletable->objectHandle)[obj] = 0;
372 break;
374 case EMR_SETWINDOWORGEX:
376 DWORD x = mr->dParm[0], y = mr->dParm[1];
377 SetWindowOrgEx(hdc, x, y, NULL);
378 break;
380 case EMR_SETWINDOWEXTEX:
382 DWORD x = mr->dParm[0], y = mr->dParm[1];
383 SetWindowExtEx(hdc, x, y, NULL);
384 break;
386 case EMR_SETVIEWPORTORGEX:
388 DWORD x = mr->dParm[0], y = mr->dParm[1];
389 SetViewportOrgEx(hdc, x, y, NULL);
390 break;
392 case EMR_SETVIEWPORTEXTEX:
394 DWORD x = mr->dParm[0], y = mr->dParm[1];
395 SetViewportExtEx(hdc, x, y, NULL);
396 break;
398 case EMR_CREATEPEN:
400 DWORD obj = mr->dParm[0];
401 (handletable->objectHandle)[obj] =
402 CreatePenIndirect((LOGPEN *) &(mr->dParm[1]));
403 break;
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);
413 break;
415 case EMR_CREATEBRUSHINDIRECT:
417 DWORD obj = mr->dParm[0];
418 (handletable->objectHandle)[obj] =
419 CreateBrushIndirect((LOGBRUSH *) &(mr->dParm[1]));
420 break;
422 case EMR_EXTCREATEFONTINDIRECTW:
424 DWORD obj = mr->dParm[0];
425 (handletable->objectHandle)[obj] =
426 CreateFontIndirectW((LOGFONTW *) &(mr->dParm[1]));
427 break;
429 case EMR_MOVETOEX:
431 DWORD x = mr->dParm[0], y = mr->dParm[1];
432 MoveToEx(hdc, x, y, NULL);
433 break;
435 case EMR_LINETO:
437 DWORD x = mr->dParm[0], y = mr->dParm[1];
438 LineTo(hdc, x, y);
439 break;
441 case EMR_RECTANGLE:
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);
446 break;
448 case EMR_ELLIPSE:
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);
453 break;
455 case EMR_POLYGON16:
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);
461 break;
463 case EMR_POLYLINE16:
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);
469 break;
472 #if 0
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);
479 break;
481 #endif
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),
501 iUsageSrc,dwRop);
502 break;
504 case EMR_EXTTEXTOUTW:
506 /* 0-3: ??? */
507 DWORD flags = mr->dParm[4];
508 /* 5, 6: ??? */
509 DWORD x = mr->dParm[7], y = mr->dParm[8];
510 DWORD count = mr->dParm[9];
511 /* 10-16: ??? */
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);
517 break;
520 default:
521 FIXME("type %d is unimplemented\n", type);
522 /* SetLastError(E_NOTIMPL); */
523 break;
525 return TRUE;
529 /*****************************************************************************
531 * EnumEnhMetaFile32 (GDI32.79)
533 * Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
534 * for each
535 * record. Returns when either every record has been used or
536 * when _EnhMetaFunc_ returns FALSE.
539 * RETURNS
540 * TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
541 * returns FALSE.
543 * BUGS
544 * Ignores rect.
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 */
554 BOOL ret = TRUE;
555 LPENHMETARECORD p = (LPENHMETARECORD) EMF_GetEnhMetaHeader(hmf);
556 INT count;
557 HANDLETABLE *ht;
559 if(!p) return FALSE;
560 count = ((LPENHMETAHEADER) p)->nHandles;
561 ht = HeapAlloc( GetProcessHeap(), 0, sizeof(HANDLETABLE)*count);
562 ht->objectHandle[0] = hmf;
563 while (ret) {
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);
570 return ret;
574 /**************************************************************************
575 * PlayEnhMetaFile (GDI32.263)
577 * Renders an enhanced metafile into a specified rectangle *lpRect
578 * in device context hdc.
580 * BUGS
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);
591 INT count;
592 HANDLETABLE *ht;
593 BOOL ret = FALSE;
594 INT savedMode = 0;
596 if(!p) return FALSE;
597 count = ((LPENHMETAHEADER) p)->nHandles;
598 ht = HeapAlloc( GetProcessHeap(), 0, sizeof(HANDLETABLE) * count);
599 if (lpRect) {
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);
605 XFORM xform;
606 xform.eM11 = xscale;
607 xform.eM12 = 0;
608 xform.eM21 = 0;
609 xform.eM22 = yscale;
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;
620 while (1) {
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 */
629 return ret;
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(
648 HENHMETAFILE hmfSrc,
649 LPCSTR file)
651 ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
652 HENHMETAFILE hmfDst;
654 if(!emrSrc) return FALSE;
655 if (!file) {
656 emrDst = HeapAlloc( SystemHeap, 0, emrSrc->nBytes );
657 memcpy( emrDst, emrSrc, emrSrc->nBytes );
658 hmfDst = EMF_Create_HENHMETAFILE( emrDst, 0, 0 );
659 } else {
660 HFILE hFile;
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 );
667 return hmfDst;
671 /*****************************************************************************
672 * GetEnhMetaFilePaletteEntries (GDI32.179)
674 * Copy the palette and report size
677 UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,
678 UINT cEntries,
679 LPPALETTEENTRY lppe)
681 return 0;
685 /******************************************************************
686 * SetWinMetaFileBits (GDI32.343)
688 * Translate from old style to new style.
691 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
692 CONST BYTE *lpbBuffer,
693 HDC hdcRef,
694 CONST METAFILEPICT *lpmfp
697 FIXME("Stub\n");
698 return 0;