Added -dll option for winelib programs. (Note: will not print warnings
[wine] / objects / enhmetafile.c
1 /*
2   Enhanced metafile functions
3   Copyright 1998, Douglas Ridgway
4 */
5
6 #include <string.h>
7 #include <assert.h>
8 #include "winbase.h"
9 #include "wingdi.h"
10 #include "wine/winestring.h"
11 #include "winerror.h"
12 #include "debug.h"
13
14 /*****************************************************************************
15  *          GetEnhMetaFile32A (GDI32.174)
16  *
17  *
18  */
19 HENHMETAFILE WINAPI GetEnhMetaFileA( 
20              LPCSTR lpszMetaFile  /* filename of enhanced metafile */
21     )
22 {
23   HENHMETAFILE hmf = 0;
24   ENHMETAHEADER h;
25   BYTE *p;
26   DWORD read;
27   HFILE hf = CreateFileA(lpszMetaFile, GENERIC_READ, 0, 0, 
28                              OPEN_EXISTING, 0, 0);
29   if (hf == INVALID_HANDLE_VALUE) {
30     FIXME(metafile,"could not open %s\n",lpszMetaFile);
31     return 0;
32   }
33   if (!ReadFile(hf, &h, sizeof(ENHMETAHEADER), &read, NULL)) {
34     FIXME(metafile,"%s can't be read.\n",lpszMetaFile);
35     CloseHandle(hf);
36     return 0;
37   }
38   if (read!=sizeof(ENHMETAHEADER)) {
39     FIXME(metafile,"%s is not long enough.\n",lpszMetaFile);
40     CloseHandle(hf);
41     return 0;
42   }
43   if (h.iType!=1) {
44     FIXME(metafile,"%s has invalid emf header (type 0x%08lx).\n",lpszMetaFile,h.iType);
45     CloseHandle(hf);
46     return 0;
47   }
48   if (memcmp(&(h.dSignature)," EMF",4)) {
49     FIXME(metafile,"%s has invalid EMF header (dSignature 0x%08lx).\n",lpszMetaFile,h.dSignature);
50     CloseHandle(hf);
51     return 0;
52   }
53   SetFilePointer(hf, 0, NULL, FILE_BEGIN); 
54   /*  hmf = CreateFileMapping32A( hf, NULL, NULL, NULL, NULL, "temp"); */
55   hmf = GlobalAlloc(GPTR, h.nBytes);
56   p = GlobalLock(hmf);
57   if (!ReadFile(hf, p, h.nBytes, &read, NULL)) {
58     FIXME(metafile,"%s could not be read.\n",lpszMetaFile);
59     GlobalFree(hmf);
60     CloseHandle(hf);
61     return 0;
62   }
63   if (read!=h.nBytes) {
64     FIXME(metafile,"%s is not long enough (%ld expected, %ld got).\n",lpszMetaFile,h.nBytes,read);
65     GlobalFree(hmf);
66     CloseHandle(hf);
67     return 0;
68   }
69   GlobalUnlock(hmf);
70   return hmf;
71 }
72
73 /*****************************************************************************
74  *          GetEnhMetaFile32W  (GDI32.180)
75  */
76 HENHMETAFILE WINAPI GetEnhMetaFileW(
77              LPCWSTR lpszMetaFile)  /* filename of enhanced metafile */ 
78 {
79   FIXME(metafile, "(%p): stub\n", lpszMetaFile);
80   return 0;
81 }
82
83 /*****************************************************************************
84  *        GetEnhMetaFileHeader  (GDI32.178)
85  *
86  *  If _buf_ is NULL, returns the size of buffer required.
87  *  Otherwise, copy up to _bufsize_ bytes of enhanced metafile header into 
88  *  _buf.
89  */
90 UINT WINAPI GetEnhMetaFileHeader( 
91        HENHMETAFILE hmf, /* enhanced metafile */
92        UINT bufsize,     /* size of buffer */
93        LPENHMETAHEADER buf /* buffer */ 
94     )
95 {
96   LPENHMETAHEADER p = GlobalLock(hmf);
97   if (!buf) return sizeof(ENHMETAHEADER);
98   memmove(buf, p, MIN(sizeof(ENHMETAHEADER), bufsize));
99   GlobalUnlock(hmf);
100   return MIN(sizeof(ENHMETAHEADER), bufsize);
101 }
102
103
104 /*****************************************************************************
105  *          GetEnhMetaFileDescription32A  (GDI32.176)
106  */
107 UINT WINAPI GetEnhMetaFileDescriptionA( 
108        HENHMETAFILE hmf, /* enhanced metafile */
109        UINT size, /* size of buf */ 
110        LPSTR buf /* buffer to receive description */
111     )
112 {
113   LPENHMETAHEADER p = GlobalLock(hmf);
114   INT first  = lstrlenW( (void *)p+p->offDescription);
115
116   if (!buf || !size) return p->nDescription;
117
118   lstrcpynWtoA(buf, (void *)p+p->offDescription, size);
119   buf += first +1;
120   lstrcpynWtoA(buf, (void *)p+p->offDescription+2*(first+1), size-first-1);
121
122   /*  memmove(buf, (void *)p+p->offDescription, MIN(size,p->nDescription)); */
123   GlobalUnlock(hmf);
124   return MIN(size,p->nDescription);
125 }
126
127 /*****************************************************************************
128  *          GetEnhMetaFileDescription32W  (GDI32.177)
129  *
130  *  Copies the description string of an enhanced metafile into a buffer 
131  *  _buf_.
132  *
133  *  If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
134  *  number of characters copied.
135  */
136 UINT WINAPI GetEnhMetaFileDescriptionW( 
137        HENHMETAFILE hmf, /* enhanced metafile */
138        UINT size, /* size of buf */ 
139        LPWSTR buf /* buffer to receive description */
140     )
141 {
142   LPENHMETAHEADER p = GlobalLock(hmf);
143
144   if (!buf || !size) return p->nDescription;
145
146   memmove(buf, (void *)p+p->offDescription, MIN(size,p->nDescription));
147   GlobalUnlock(hmf);
148   return MIN(size,p->nDescription);
149 }
150
151 /****************************************************************************
152  *    SetEnhMetaFileBits (GDI32.315)
153  *
154  *  Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
155  */
156 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
157 {
158   HENHMETAFILE hmf = GlobalAlloc(GPTR, bufsize);
159   LPENHMETAHEADER h = GlobalLock(hmf);
160   memmove(h, buf, bufsize);
161   GlobalUnlock(hmf);
162   return hmf;
163 }
164
165 /*****************************************************************************
166  *  GetEnhMetaFileBits (GDI32.175)
167  *
168  */
169 UINT WINAPI GetEnhMetaFileBits(
170     HENHMETAFILE hmf, 
171     UINT bufsize, 
172     LPBYTE buf  
173 ) {
174   return 0;
175 }
176
177 /*****************************************************************************
178  *           PlayEnhMetaFileRecord  (GDI32.264)
179  *
180  *  Render a single enhanced metafile record in the device context hdc.
181  *
182  *  RETURNS
183  *    TRUE on success, FALSE on error.
184  *  BUGS
185  *    Many unimplemented records.
186  */
187 BOOL WINAPI PlayEnhMetaFileRecord( 
188      HDC hdc, /* device context in which to render EMF record */
189      LPHANDLETABLE handletable, /* array of handles to be used in rendering record */
190      const ENHMETARECORD *mr, /* EMF record to render */
191      UINT handles  /* size of handle array */
192      ) 
193 {
194   int type;
195   TRACE(metafile, 
196         "hdc = %08x, handletable = %p, record = %p, numHandles = %d\n", 
197           hdc, handletable, mr, handles);
198   if (!mr) return FALSE;
199
200   type = mr->iType;
201
202   TRACE(metafile, " type=%d\n", type);
203   switch(type) 
204     {
205     case EMR_HEADER:
206       {
207         /* ENHMETAHEADER *h = (LPENHMETAHEADER) mr; */
208         break;
209       }
210     case EMR_EOF:
211       break;
212     case EMR_GDICOMMENT:
213       /* application defined and processed */
214       break;
215     case EMR_SETMAPMODE:
216       {
217         DWORD mode = mr->dParm[0];
218         SetMapMode(hdc, mode);
219         break;
220       }
221     case EMR_SETBKMODE:
222       {
223         DWORD mode = mr->dParm[0];
224         SetBkMode(hdc, mode);
225         break;
226       }
227     case EMR_SETBKCOLOR:
228       {
229         DWORD mode = mr->dParm[0];
230         SetBkColor(hdc, mode);
231         break;
232       }
233     case EMR_SETPOLYFILLMODE:
234       {
235         DWORD mode = mr->dParm[0];
236         SetPolyFillMode(hdc, mode);
237         break;
238       }
239     case EMR_SETROP2:
240       {
241         DWORD mode = mr->dParm[0];
242         SetROP2(hdc, mode);
243         break;
244       }
245     case EMR_SETSTRETCHBLTMODE:
246       {
247         DWORD mode = mr->dParm[0];
248         SetStretchBltMode(hdc, mode);
249         break;
250       }
251     case EMR_SETTEXTALIGN:
252       {
253         DWORD align = mr->dParm[0];
254         SetTextAlign(hdc, align);
255         break;
256       }
257     case EMR_SETTEXTCOLOR:
258       {
259         DWORD color = mr->dParm[0];
260         SetTextColor(hdc, color);
261         break;
262       }
263     case EMR_SAVEDC:
264       {
265         SaveDC(hdc);
266         break;
267       }
268     case EMR_RESTOREDC:
269       {
270         RestoreDC(hdc, mr->dParm[0]);
271         break;
272       }
273     case EMR_INTERSECTCLIPRECT:
274       {
275         INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
276               bottom = mr->dParm[3];
277         IntersectClipRect(hdc, left, top, right, bottom);
278         break;
279       }
280     case EMR_SELECTOBJECT:
281       {
282         DWORD obj = mr->dParm[0];
283         SelectObject(hdc, (handletable->objectHandle)[obj]);
284         break;
285       }
286     case EMR_DELETEOBJECT:
287       {
288         DWORD obj = mr->dParm[0];
289         DeleteObject( (handletable->objectHandle)[obj]);
290         (handletable->objectHandle)[obj] = 0;
291         break;
292       }
293     case EMR_SETWINDOWORGEX:
294       {
295         DWORD x = mr->dParm[0], y = mr->dParm[1];
296         SetWindowOrgEx(hdc, x, y, NULL);
297         break;
298       }
299     case EMR_SETWINDOWEXTEX:
300       {
301         DWORD x = mr->dParm[0], y = mr->dParm[1];
302         SetWindowExtEx(hdc, x, y, NULL);
303         break;
304       }
305     case EMR_SETVIEWPORTORGEX:
306       {
307         DWORD x = mr->dParm[0], y = mr->dParm[1];
308         SetViewportOrgEx(hdc, x, y, NULL);
309         break;
310       }
311     case EMR_SETVIEWPORTEXTEX:
312       {
313         DWORD x = mr->dParm[0], y = mr->dParm[1];
314         SetViewportExtEx(hdc, x, y, NULL);
315         break;
316       }
317     case EMR_CREATEPEN:
318       {
319         DWORD obj = mr->dParm[0];
320         (handletable->objectHandle)[obj] = 
321           CreatePenIndirect((LOGPEN *) &(mr->dParm[1]));
322         break;
323       }
324     case EMR_EXTCREATEPEN:
325       {
326         DWORD obj = mr->dParm[0];
327         DWORD style = mr->dParm[1], brush = mr->dParm[2];
328         LOGBRUSH *b = (LOGBRUSH *) &mr->dParm[3];
329         FIXME(metafile, "Some ExtCreatePen args not handled\n");
330         (handletable->objectHandle)[obj] = 
331           ExtCreatePen(style, brush, b, 0, NULL);
332         break;
333       }
334     case EMR_CREATEBRUSHINDIRECT:
335       {
336         DWORD obj = mr->dParm[0];
337         (handletable->objectHandle)[obj] = 
338           CreateBrushIndirect((LOGBRUSH *) &(mr->dParm[1]));
339         break;
340       }
341     case EMR_EXTCREATEFONTINDIRECTW:
342         {
343         DWORD obj = mr->dParm[0];
344         (handletable->objectHandle)[obj] = 
345           CreateFontIndirectW((LOGFONTW *) &(mr->dParm[1]));
346         break;
347         }
348     case EMR_MOVETOEX:
349       {
350         DWORD x = mr->dParm[0], y = mr->dParm[1];
351         MoveToEx(hdc, x, y, NULL);
352         break;
353       }
354     case EMR_LINETO:
355       {
356         DWORD x = mr->dParm[0], y = mr->dParm[1];
357         LineTo(hdc, x, y);
358         break;
359       }
360     case EMR_RECTANGLE:
361       {
362         INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
363               bottom = mr->dParm[3];
364         Rectangle(hdc, left, top, right, bottom);
365         break;
366       }
367     case EMR_ELLIPSE:
368       {
369         INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
370               bottom = mr->dParm[3];
371         Ellipse(hdc, left, top, right, bottom);
372         break;
373       }
374     case EMR_POLYGON16:
375       {
376         /* 0-3 : a bounding rectangle? */
377         INT count = mr->dParm[4];
378         FIXME(metafile, "Some Polygon16 args not handled\n");
379         Polygon16(hdc, (POINT16 *)&mr->dParm[5], count);
380         break;
381       }
382     case EMR_POLYLINE16:
383       {
384         /* 0-3 : a bounding rectangle? */
385         INT count = mr->dParm[4];
386         FIXME(metafile, "Some Polyline16 args not handled\n");
387         Polyline16(hdc, (POINT16 *)&mr->dParm[5], count);
388         break;
389       }
390
391 #if 0
392     case EMR_POLYPOLYGON16:
393       {
394         INT polygons = mr->dParm[z];
395         LPPOINT16 pts = (LPPOINT16) &mr->dParm[x];
396         LPINT16 counts = (LPINT16) &mr->dParm[y];
397         PolyPolygon16(hdc, pts, counts, polygons);
398         break;
399       }
400 #endif
401     case EMR_STRETCHDIBITS:
402       {
403         LONG xDest = mr->dParm[4];
404         LONG yDest = mr->dParm[5];
405         LONG xSrc = mr->dParm[6];
406         LONG ySrc = mr->dParm[7];
407         LONG cxSrc = mr->dParm[8];
408         LONG cySrc = mr->dParm[9];
409         DWORD offBmiSrc = mr->dParm[10];
410         DWORD offBitsSrc = mr->dParm[12];
411         DWORD iUsageSrc = mr->dParm[14];
412         DWORD dwRop = mr->dParm[15];
413         LONG cxDest = mr->dParm[16];
414         LONG cyDest = mr->dParm[17];
415
416         StretchDIBits(hdc,xDest,yDest,cxDest,cyDest,
417                             xSrc,ySrc,cxSrc,cySrc,
418                             ((char *)mr)+offBitsSrc,
419                             (const BITMAPINFO *)(((char *)mr)+offBmiSrc),
420                             iUsageSrc,dwRop);
421         break;
422     }
423     case EMR_EXTTEXTOUTW:
424       {
425         /* 0-3: ??? */
426         DWORD flags = mr->dParm[4];
427         /* 5, 6: ??? */
428         DWORD x = mr->dParm[7], y = mr->dParm[8];
429         DWORD count = mr->dParm[9];
430         /* 10-16: ??? */
431         LPWSTR str = (LPWSTR)& mr->dParm[17];
432         /* trailing info: dx array? */
433         FIXME(metafile, "Many ExtTextOut args not handled\n");
434         ExtTextOutW(hdc, x, y, flags, /* lpRect */ NULL, 
435                       str, count, /* lpDx */ NULL); 
436         break;
437       }
438
439     default:
440       FIXME(metafile, "type %d is unimplemented\n", type);
441       /*  SetLastError(E_NOTIMPL); */
442       break;
443     }
444   return TRUE;
445 }
446
447
448 /*****************************************************************************
449  *
450  *        EnumEnhMetaFile32  (GDI32.79)
451  *
452  *  Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
453  *  for each
454  *  record. Returns when either every record has been used or 
455  *  when _EnhMetaFunc_ returns FALSE.
456  *
457  *
458  * RETURNS
459  *  TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
460  *  returns FALSE.
461  *
462  * BUGS
463  *   Ignores rect.
464  */
465 BOOL WINAPI EnumEnhMetaFile( 
466      HDC hdc, /* device context to pass to _EnhMetaFunc_ */
467      HENHMETAFILE hmf, /* EMF to walk */
468      ENHMFENUMPROC callback, /* callback function */ 
469      LPVOID data, /* optional data for callback function */
470      const RECT *rect  /* bounding rectangle for rendered metafile */
471     )
472 {
473   BOOL ret = TRUE;
474   LPENHMETARECORD p = GlobalLock(hmf);
475   INT count = ((LPENHMETAHEADER) p)->nHandles;
476   HANDLETABLE *ht = (HANDLETABLE *)GlobalAlloc(GPTR, sizeof(HANDLETABLE)*count);
477   ht->objectHandle[0] = hmf;
478   while (ret) {
479     ret = (*callback)(hdc, ht, p, count, data); 
480     if (p->iType == EMR_EOF) break;
481     p = (void *) p + p->nSize;
482   }
483   GlobalFree((HGLOBAL)ht);
484   GlobalUnlock(hmf);
485   return ret;
486 }
487
488
489 /**************************************************************************
490  *    PlayEnhMetaFile  (GDI32.263)
491  *
492  *    Renders an enhanced metafile into a specified rectangle *lpRect
493  *    in device context hdc.
494  *
495  * BUGS
496  *    Almost entirely unimplemented
497  *
498  */
499 BOOL WINAPI PlayEnhMetaFile( 
500        HDC hdc, /* DC to render into */
501        HENHMETAFILE hmf, /* metafile to render */
502        const RECT *lpRect  /* rectangle to place metafile inside */
503       )
504 {
505   LPENHMETARECORD p = GlobalLock(hmf);
506   INT count = ((LPENHMETAHEADER) p)->nHandles;
507   HANDLETABLE *ht = (HANDLETABLE *)GlobalAlloc(GPTR, 
508                                     sizeof(HANDLETABLE)*count);
509   BOOL ret = FALSE;
510   INT savedMode = 0;
511   if (lpRect) {
512     LPENHMETAHEADER h = (LPENHMETAHEADER) p;
513     FLOAT xscale = (h->rclBounds.right-h->rclBounds.left)/(lpRect->right-lpRect->left);
514     FLOAT yscale = (h->rclBounds.bottom-h->rclBounds.top)/(lpRect->bottom-lpRect->top);
515     XFORM xform = {xscale, 0, 0, yscale, 0, 0};
516         xform.eDx = lpRect->left;
517           xform.eDy = lpRect->top; 
518     FIXME(metafile, "play into rect doesn't work\n");
519     savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
520     if (!SetWorldTransform(hdc, &xform)) {
521       WARN(metafile, "World transform failed!\n");
522     }
523   }
524
525   ht->objectHandle[0] = hmf;
526   while (1) {
527     PlayEnhMetaFileRecord(hdc, ht, p, count);
528     if (p->iType == EMR_EOF) break;
529     p = (void *) p + p->nSize; /* casted so that arithmetic is in bytes */
530   }
531   GlobalUnlock(hmf);
532   if (savedMode) SetGraphicsMode(hdc, savedMode);
533   ret = TRUE; /* FIXME: calculate a more accurate return value */
534   return ret;
535 }
536
537 /*****************************************************************************
538  *  DeleteEnhMetaFile (GDI32.68)
539  *
540  *  Deletes an enhanced metafile and frees the associated storage.
541  */
542 BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf) {
543   return !GlobalFree(hmf);
544 }
545
546 /*****************************************************************************
547  *  CopyEnhMetaFileA (GDI32.21)  Duplicate an enhanced metafile
548  *
549  *   
550  */
551 HENHMETAFILE WINAPI CopyEnhMetaFileA(
552     HENHMETAFILE hmf, 
553     LPCSTR file)
554 {
555   if (!file) {
556     LPENHMETAHEADER h = GlobalLock(hmf);
557     HENHMETAFILE hmf2 = GlobalAlloc(GPTR, h->nBytes);
558     LPENHMETAHEADER h2 = GlobalLock(hmf2);
559     if (!h2) return 0;
560     memmove(h2, h, h->nBytes);
561     GlobalUnlock(hmf2);
562     GlobalUnlock(hmf);
563     return hmf2;
564   } else {
565     FIXME(metafile, "write to file not implemented\n");
566     return 0;
567   }
568 }
569
570 /*****************************************************************************
571  *  GetEnhMetaFilePaletteEntries (GDI32.179)  
572  * 
573  *  Copy the palette and report size  
574  */
575
576 UINT WINAPI GetEnhMetaFilePaletteEntries(HENHMETAFILE hemf,
577                                              UINT cEntries,
578                                              LPPALETTEENTRY lppe)
579 {
580   LPENHMETAHEADER h = GlobalLock(hemf);
581
582   if ( h == NULL ){
583     GlobalUnlock(hemf);
584     return(0);
585   } else {
586     if ((lppe)&&(cEntries>0)){
587       FIXME(metafile,"Stub\n");
588       GlobalUnlock(hemf);
589       return(GDI_ERROR);
590     } else{
591       GlobalUnlock(hemf);
592       return(0);
593     }
594   }
595 }
596
597
598
599 /******************************************************************
600  *         SetWinMetaFileBits   (GDI32.343)
601  *      
602  *         Translate from old style to new style.
603  */
604
605 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
606                                            CONST BYTE *lpbBuffer,
607                                            HDC hdcRef,
608                                            CONST METAFILEPICT *lpmfp
609                                            ) 
610 {
611    FIXME(metafile,"Stub\n");
612    return 0;
613
614 }
615
616
617
618