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