Added/fixed some documentation reported by winapi_check.
[wine] / objects / enhmetafile.c
1 /*
2  * Enhanced metafile functions
3  * Copyright 1998 Douglas Ridgway
4  *           1999 Huw D M Davies 
5  *
6  * 
7  * The enhanced format consists of the following elements: 
8  *
9  *    A header 
10  *    A table of handles to GDI objects 
11  *    An array of metafile records 
12  *    A private palette 
13  *
14  * 
15  *  The standard format consists of a header and an array of metafile records. 
16  *
17  */ 
18
19 #include <string.h>
20 #include <assert.h>
21 #include "winbase.h"
22 #include "wingdi.h"
23 #include "wine/winestring.h"
24 #include "winerror.h"
25 #include "enhmetafile.h"
26 #include "debugtools.h"
27 #include "heap.h"
28 #include "metafile.h"
29
30 DEFAULT_DEBUG_CHANNEL(enhmetafile)
31
32 /* Prototypes */
33 BOOL WINAPI EnumEnhMetaFile( HDC hdc, HENHMETAFILE hmf, ENHMFENUMPROC callback,
34                              LPVOID data, const RECT *rect );
35
36
37 /****************************************************************************
38  *          EMF_Create_HENHMETAFILE
39  */
40 HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, HFILE hFile, HANDLE
41                                      hMapping )
42 {
43     HENHMETAFILE hmf = GDI_AllocObject( sizeof(ENHMETAFILEOBJ),
44                                         ENHMETAFILE_MAGIC );
45     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_HEAP_LOCK( hmf );
46     metaObj->emh = emh;
47     metaObj->hFile = hFile;
48     metaObj->hMapping = hMapping;
49     GDI_HEAP_UNLOCK( hmf );
50     return hmf;
51 }
52
53 /****************************************************************************
54  *          EMF_Delete_HENHMETAFILE
55  */
56 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
57 {
58     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf,
59                                                            ENHMETAFILE_MAGIC );
60     if(!metaObj) return FALSE;
61     if(metaObj->hMapping) {
62         UnmapViewOfFile( metaObj->emh );
63         CloseHandle( metaObj->hMapping );
64         CloseHandle( metaObj->hFile );
65     } else
66         HeapFree( GetProcessHeap(), 0, metaObj->emh );
67     return GDI_FreeObject( hmf );
68 }
69
70 /******************************************************************
71  *         EMF_GetEnhMetaHeader
72  *
73  * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE
74  * Should be followed by call to EMF_ReleaseEnhMetaHeader
75  */
76 static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf )
77 {
78     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf,
79                                                            ENHMETAFILE_MAGIC );
80     TRACE("hmf %04x -> enhmetaObj %p\n", hmf, metaObj);
81     return metaObj ? metaObj->emh : NULL;
82 }
83
84 /******************************************************************
85  *         EMF_ReleaseEnhMetaHeader
86  *
87  * Releases ENHMETAHEADER associated with HENHMETAFILE
88  */
89 static BOOL EMF_ReleaseEnhMetaHeader( HENHMETAFILE hmf )
90 {
91     return GDI_HEAP_UNLOCK( hmf );
92 }
93
94 /*****************************************************************************
95  *         EMF_GetEnhMetaFile
96  *
97  */
98 static HENHMETAFILE EMF_GetEnhMetaFile( HFILE hFile )
99 {
100     ENHMETAHEADER *emh;
101     HANDLE hMapping;
102     
103     hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
104     emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
105
106     if (emh->iType != EMR_HEADER || emh->dSignature != ENHMETA_SIGNATURE) {
107         WARN("Invalid emf header type 0x%08lx sig 0x%08lx.\n",
108              emh->iType, emh->dSignature);
109         UnmapViewOfFile( emh );
110         CloseHandle( hMapping );
111         return 0;
112     }
113     return EMF_Create_HENHMETAFILE( emh, hFile, hMapping );
114 }
115
116
117 /*****************************************************************************
118  *          GetEnhMetaFileA (GDI32.174)
119  *
120  *
121  */
122 HENHMETAFILE WINAPI GetEnhMetaFileA( 
123              LPCSTR lpszMetaFile  /* filename of enhanced metafile */
124     )
125 {
126     HENHMETAFILE hmf;
127     HFILE hFile;
128
129     hFile = CreateFileA(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
130                         OPEN_EXISTING, 0, 0);
131     if (hFile == INVALID_HANDLE_VALUE) {
132         WARN("could not open %s\n", lpszMetaFile);
133         return 0;
134     }
135     hmf = EMF_GetEnhMetaFile( hFile );
136     if(!hmf)
137         CloseHandle( hFile );
138     return hmf;
139 }
140
141 /*****************************************************************************
142  *          GetEnhMetaFileW  (GDI32.180)
143  */
144 HENHMETAFILE WINAPI GetEnhMetaFileW(
145              LPCWSTR lpszMetaFile)  /* filename of enhanced metafile */ 
146 {
147     HENHMETAFILE hmf;
148     HFILE hFile;
149
150     hFile = CreateFileW(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
151                         OPEN_EXISTING, 0, 0);
152     if (hFile == INVALID_HANDLE_VALUE) {
153         WARN("could not open %s\n", debugstr_w(lpszMetaFile));
154         return 0;
155     }
156     hmf = EMF_GetEnhMetaFile( hFile );
157     if(!hmf)
158         CloseHandle( hFile );
159     return hmf;
160 }
161
162 /*****************************************************************************
163  *        GetEnhMetaFileHeader  (GDI32.178)
164  *
165  *  If _buf_ is NULL, returns the size of buffer required.
166  *  Otherwise, copy up to _bufsize_ bytes of enhanced metafile header into 
167  *  _buf.
168  */
169 UINT WINAPI GetEnhMetaFileHeader( 
170        HENHMETAFILE hmf, /* enhanced metafile */
171        UINT bufsize,     /* size of buffer */
172        LPENHMETAHEADER buf /* buffer */ 
173     )
174 {
175     LPENHMETAHEADER emh;
176
177     if (!buf) return sizeof(ENHMETAHEADER);
178     emh = EMF_GetEnhMetaHeader(hmf);
179     if(!emh) return FALSE;
180     memmove(buf, emh, min(sizeof(ENHMETAHEADER), bufsize));
181     EMF_ReleaseEnhMetaHeader(hmf);
182     return min(sizeof(ENHMETAHEADER), bufsize);
183 }
184
185
186 /*****************************************************************************
187  *          GetEnhMetaFileDescriptionA  (GDI32.176)
188  */
189 UINT WINAPI GetEnhMetaFileDescriptionA( 
190        HENHMETAFILE hmf, /* enhanced metafile */
191        UINT size, /* size of buf */ 
192        LPSTR buf /* buffer to receive description */
193     )
194 {
195      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
196      INT first, first_A;
197  
198      if(!emh) return FALSE;
199      if(emh->nDescription == 0 || emh->offDescription == 0) {
200          EMF_ReleaseEnhMetaHeader(hmf);
201         return 0;
202      }
203      if (!buf || !size ) {
204          EMF_ReleaseEnhMetaHeader(hmf);
205         return emh->nDescription;
206      }
207  
208      first = lstrlenW( (WCHAR *) ((char *) emh + emh->offDescription));
209  
210      lstrcpynWtoA(buf, (WCHAR *) ((char *) emh + emh->offDescription), size);
211      first_A = lstrlenA( buf );
212      buf += first_A + 1;
213      lstrcpynWtoA(buf, (WCHAR *) ((char *) emh + emh->offDescription+2*(first+1)),
214                  size - first_A - 1); /* i18n ready */
215      first_A += lstrlenA(buf) + 1;
216  
217      EMF_ReleaseEnhMetaHeader(hmf);
218      return min(size, first_A);
219 }
220
221 /*****************************************************************************
222  *          GetEnhMetaFileDescriptionW  (GDI32.177)
223  *
224  *  Copies the description string of an enhanced metafile into a buffer 
225  *  _buf_.
226  *
227  *  If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
228  *  number of characters copied.
229  */
230 UINT WINAPI GetEnhMetaFileDescriptionW( 
231        HENHMETAFILE hmf, /* enhanced metafile */
232        UINT size, /* size of buf */ 
233        LPWSTR buf /* buffer to receive description */
234     )
235 {
236      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
237
238      if(!emh) return FALSE;
239      if(emh->nDescription == 0 || emh->offDescription == 0) {
240          EMF_ReleaseEnhMetaHeader(hmf);
241         return 0;
242      }
243      if (!buf || !size ) {
244          EMF_ReleaseEnhMetaHeader(hmf);
245         return emh->nDescription;
246      }
247  
248      memmove(buf, (char *) emh + emh->offDescription, 
249             min(size,emh->nDescription));
250      EMF_ReleaseEnhMetaHeader(hmf);
251      return min(size, emh->nDescription);
252 }
253
254 /****************************************************************************
255  *    SetEnhMetaFileBits (GDI32.315)
256  *
257  *  Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
258  */
259 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
260 {
261     ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
262     memmove(emh, buf, bufsize);
263     return EMF_Create_HENHMETAFILE( emh, 0, 0 );
264 }
265
266 INT CALLBACK cbCountSizeOfEnhMetaFile( HDC a, 
267                                        LPHANDLETABLE b,
268                                        LPENHMETARECORD lpEMR, 
269                                        INT c, 
270                                        LPVOID lpData )
271 {
272   LPUINT uSizeOfRecordData = (LPUINT)lpData;
273
274   *uSizeOfRecordData += lpEMR->nSize;
275
276   return TRUE;
277 }
278
279 /*****************************************************************************
280  *  GetEnhMetaFileBits (GDI32.175)
281  *
282  */
283 UINT WINAPI GetEnhMetaFileBits(
284     HENHMETAFILE hmf, 
285     UINT bufsize, 
286     LPBYTE buf  
287
288 {
289   LPENHMETAHEADER lpEnhMetaFile;
290   UINT uEnhMetaFileSize = 0;
291
292   FIXME( "(%04x,%u,%p): untested\n", hmf, bufsize, buf );
293
294   /* Determine the required buffer size */
295   /* Enumerate all records and count their size */ 
296   if( !EnumEnhMetaFile( 0, hmf, cbCountSizeOfEnhMetaFile, &uEnhMetaFileSize, NULL ) )
297   {
298     ERR( "Unable to enumerate enhanced metafile!\n" );
299     return 0;
300   }
301
302   if( buf == NULL )
303   {
304     return uEnhMetaFileSize;
305   }
306
307   /* Copy the lesser of the two byte counts */
308   uEnhMetaFileSize = min( uEnhMetaFileSize, bufsize );
309
310   /* Copy everything */
311   lpEnhMetaFile = EMF_GetEnhMetaHeader( hmf );
312
313   if( lpEnhMetaFile == NULL )
314   {
315     return 0;
316   }
317
318   /* Use memmove just in case they overlap */
319   memmove(buf, lpEnhMetaFile, bufsize);
320
321   EMF_ReleaseEnhMetaHeader( hmf ); 
322
323   return bufsize;
324 }
325
326 /*****************************************************************************
327  *           PlayEnhMetaFileRecord  (GDI32.264)
328  *
329  *  Render a single enhanced metafile record in the device context hdc.
330  *
331  *  RETURNS
332  *    TRUE (non zero) on success, FALSE on error.
333  *  BUGS
334  *    Many unimplemented records.
335  *    No error handling on record play failures (ie checking return codes)
336  */
337 BOOL WINAPI PlayEnhMetaFileRecord( 
338      HDC hdc, /* device context in which to render EMF record */
339      LPHANDLETABLE handletable, /* array of handles to be used in rendering record */
340      const ENHMETARECORD *mr, /* EMF record to render */
341      UINT handles  /* size of handle array */
342      ) 
343 {
344   int type;
345   TRACE(
346         "hdc = %08x, handletable = %p, record = %p, numHandles = %d\n", 
347           hdc, handletable, mr, handles);
348   if (!mr) return FALSE;
349
350   type = mr->iType;
351
352   TRACE(" type=%d\n", type);
353   switch(type) 
354     {
355     case EMR_HEADER:
356       {
357 #if 0
358         ENHMETAHEADER* h = (LPENHMETAHEADER)mr;
359         XFORM dcTransform;
360
361         /* Scale the enhanced metafile according to the reference hdc
362            it was created with */
363         if( h->szlDevice.cx )
364         {
365           dcTransform.eM11 = (FLOAT)( (DOUBLE)GetDeviceCaps( hdc, HORZRES ) /  
366                                       (DOUBLE)h->szlDevice.cx );
367         }
368         else 
369         {
370           ERR( "Invalid szlDevice.cx in header\n" ); 
371           dcTransform.eM11 = (FLOAT)1.0;
372         }
373
374         if( h->szlDevice.cy )
375         { 
376           dcTransform.eM22 = (FLOAT)( (DOUBLE)GetDeviceCaps( hdc, VERTRES ) /
377                                       (DOUBLE)h->szlDevice.cy );
378         }
379         else 
380         {
381           ERR( "Invalid szlDevice.cy in header\n" ); 
382           dcTransform.eM22 = (FLOAT)1.0;
383         }
384
385         dcTransform.eM12 = dcTransform.eM21 = (FLOAT)0;
386         dcTransform.eDx = dcTransform.eDy = (FLOAT)0;
387
388         ModifyWorldTransform( hdc, &dcTransform, MWT_RIGHTMULTIPLY ); 
389 #endif
390         break;
391       }
392     case EMR_EOF:
393       break;
394     case EMR_GDICOMMENT:
395       {
396         PEMRGDICOMMENT lpGdiComment = (PEMRGDICOMMENT)mr;
397         /* In an enhanced metafile, there can be both public and private GDI comments */
398         GdiComment( hdc, lpGdiComment->cbData, lpGdiComment->Data );
399         break;
400       } 
401     case EMR_SETMAPMODE:
402       {
403         DWORD mode = mr->dParm[0];
404         SetMapMode(hdc, mode);
405         break;
406       }
407     case EMR_SETBKMODE:
408       {
409         DWORD mode = mr->dParm[0];
410         SetBkMode(hdc, mode);
411         break;
412       }
413     case EMR_SETBKCOLOR:
414       {
415         DWORD mode = mr->dParm[0];
416         SetBkColor(hdc, mode);
417         break;
418       }
419     case EMR_SETPOLYFILLMODE:
420       {
421         DWORD mode = mr->dParm[0];
422         SetPolyFillMode(hdc, mode);
423         break;
424       }
425     case EMR_SETROP2:
426       {
427         DWORD mode = mr->dParm[0];
428         SetROP2(hdc, mode);
429         break;
430       }
431     case EMR_SETSTRETCHBLTMODE:
432       {
433         DWORD mode = mr->dParm[0];
434         SetStretchBltMode(hdc, mode);
435         break;
436       }
437     case EMR_SETTEXTALIGN:
438       {
439         DWORD align = mr->dParm[0];
440         SetTextAlign(hdc, align);
441         break;
442       }
443     case EMR_SETTEXTCOLOR:
444       {
445         DWORD color = mr->dParm[0];
446         SetTextColor(hdc, color);
447         break;
448       }
449     case EMR_SAVEDC:
450       {
451         SaveDC(hdc);
452         break;
453       }
454     case EMR_RESTOREDC:
455       {
456         RestoreDC(hdc, mr->dParm[0]);
457         break;
458       }
459     case EMR_INTERSECTCLIPRECT:
460       {
461         INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
462               bottom = mr->dParm[3];
463         IntersectClipRect(hdc, left, top, right, bottom);
464         break;
465       }
466     case EMR_SELECTOBJECT:
467       {
468         DWORD obj = mr->dParm[0];
469         SelectObject(hdc, (handletable->objectHandle)[obj]);
470         break;
471       }
472     case EMR_DELETEOBJECT:
473       {
474         DWORD obj = mr->dParm[0];
475         DeleteObject( (handletable->objectHandle)[obj]);
476         (handletable->objectHandle)[obj] = 0;
477         break;
478       }
479     case EMR_SETWINDOWORGEX:
480       {
481         DWORD x = mr->dParm[0], y = mr->dParm[1];
482         SetWindowOrgEx(hdc, x, y, NULL);
483         break;
484       }
485     case EMR_SETWINDOWEXTEX:
486       {
487         DWORD x = mr->dParm[0], y = mr->dParm[1];
488         SetWindowExtEx(hdc, x, y, NULL);
489         break;
490       }
491     case EMR_SETVIEWPORTORGEX:
492       {
493         DWORD x = mr->dParm[0], y = mr->dParm[1];
494         SetViewportOrgEx(hdc, x, y, NULL);
495         break;
496       }
497     case EMR_SETVIEWPORTEXTEX:
498       {
499         DWORD x = mr->dParm[0], y = mr->dParm[1];
500         SetViewportExtEx(hdc, x, y, NULL);
501         break;
502       }
503     case EMR_CREATEPEN:
504       {
505         DWORD obj = mr->dParm[0];
506         (handletable->objectHandle)[obj] = 
507           CreatePenIndirect((LOGPEN *) &(mr->dParm[1]));
508         break;
509       }
510     case EMR_EXTCREATEPEN:
511       {
512         DWORD obj = mr->dParm[0];
513         DWORD style = mr->dParm[1], brush = mr->dParm[2];
514         LOGBRUSH *b = (LOGBRUSH *) &mr->dParm[3];
515         FIXME("Some ExtCreatePen args not handled\n");
516         (handletable->objectHandle)[obj] = 
517           ExtCreatePen(style, brush, b, 0, NULL);
518         break;
519       }
520     case EMR_CREATEBRUSHINDIRECT:
521       {
522         DWORD obj = mr->dParm[0];
523         (handletable->objectHandle)[obj] = 
524           CreateBrushIndirect((LOGBRUSH *) &(mr->dParm[1]));
525         break;
526       }
527     case EMR_EXTCREATEFONTINDIRECTW:
528         {
529         DWORD obj = mr->dParm[0];
530         (handletable->objectHandle)[obj] = 
531           CreateFontIndirectW((LOGFONTW *) &(mr->dParm[1]));
532         break;
533         }
534     case EMR_MOVETOEX:
535       {
536         DWORD x = mr->dParm[0], y = mr->dParm[1];
537         MoveToEx(hdc, x, y, NULL);
538         break;
539       }
540     case EMR_LINETO:
541       {
542         DWORD x = mr->dParm[0], y = mr->dParm[1];
543         LineTo(hdc, x, y);
544         break;
545       }
546     case EMR_RECTANGLE:
547       {
548         INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
549               bottom = mr->dParm[3];
550         Rectangle(hdc, left, top, right, bottom);
551         break;
552       }
553     case EMR_ELLIPSE:
554       {
555         INT left = mr->dParm[0], top = mr->dParm[1], right = mr->dParm[2],
556               bottom = mr->dParm[3];
557         Ellipse(hdc, left, top, right, bottom);
558         break;
559       }
560     case EMR_POLYGON16:
561       {
562         /* 0-3 : a bounding rectangle? */
563         INT count = mr->dParm[4];
564         FIXME("Some Polygon16 args not handled\n");
565         Polygon16(hdc, (POINT16 *)&mr->dParm[5], count);
566         break;
567       }
568     case EMR_POLYLINE16:
569       {
570         /* 0-3 : a bounding rectangle? */
571         INT count = mr->dParm[4];
572         FIXME("Some Polyline16 args not handled\n");
573         Polyline16(hdc, (POINT16 *)&mr->dParm[5], count);
574         break;
575       }
576 #if 0
577     case EMR_POLYPOLYGON16:
578       {
579         PEMRPOLYPOLYGON16 lpPolyPoly16 = (PEMRPOLYPOLYGON16)mr;
580
581         PolyPolygon16( hdc, 
582                        lpPolyPoly16->apts, 
583                        lpPolyPoly16->aPolyCounts,
584                        lpPolyPoly16->nPolys );
585
586         break;
587       }
588 #endif
589     case EMR_STRETCHDIBITS:
590       {
591         LONG xDest = mr->dParm[4];
592         LONG yDest = mr->dParm[5];
593         LONG xSrc = mr->dParm[6];
594         LONG ySrc = mr->dParm[7];
595         LONG cxSrc = mr->dParm[8];
596         LONG cySrc = mr->dParm[9];
597         DWORD offBmiSrc = mr->dParm[10];
598         DWORD offBitsSrc = mr->dParm[12];
599         DWORD iUsageSrc = mr->dParm[14];
600         DWORD dwRop = mr->dParm[15];
601         LONG cxDest = mr->dParm[16];
602         LONG cyDest = mr->dParm[17];
603
604         StretchDIBits(hdc,xDest,yDest,cxDest,cyDest,
605                             xSrc,ySrc,cxSrc,cySrc,
606                             ((char *)mr)+offBitsSrc,
607                             (const BITMAPINFO *)(((char *)mr)+offBmiSrc),
608                             iUsageSrc,dwRop);
609         break;
610       }
611     case EMR_EXTTEXTOUTW:
612       {
613         /* 0-3: ??? */
614         DWORD flags = mr->dParm[4];
615         /* 5, 6: ??? */
616         DWORD x = mr->dParm[7], y = mr->dParm[8];
617         DWORD count = mr->dParm[9];
618         /* 10-16: ??? */
619         LPWSTR str = (LPWSTR)& mr->dParm[17];
620         /* trailing info: dx array? */
621         FIXME("Many ExtTextOut args not handled\n");
622         ExtTextOutW(hdc, x, y, flags, /* lpRect */ NULL, 
623                       str, count, /* lpDx */ NULL); 
624         break;
625       }
626  
627     case EMR_CREATEPALETTE:
628       {
629         PEMRCREATEPALETTE lpCreatePal = (PEMRCREATEPALETTE)mr;
630
631         (handletable->objectHandle)[ lpCreatePal->ihPal ] = 
632                 CreatePalette( &lpCreatePal->lgpl );
633
634         break;
635       }
636
637     case EMR_SELECTPALETTE:
638       {
639         PEMRSELECTPALETTE lpSelectPal = (PEMRSELECTPALETTE)mr;
640
641         /* FIXME: Should this be forcing background mode? */
642         (handletable->objectHandle)[ lpSelectPal->ihPal ] = 
643                 SelectPalette( hdc, lpSelectPal->ihPal, FALSE );
644         break;
645       }
646
647     case EMR_REALIZEPALETTE:
648       {
649         RealizePalette( hdc );
650         break;
651       }
652
653 #if 0
654     case EMR_EXTSELECTCLIPRGN:
655       {
656         PEMREXTSELECTCLIPRGN lpRgn = (PEMREXTSELECTCLIPRGN)mr;
657
658         /* Need to make a region out of the RGNDATA we have */
659         ExtSelectClipRgn( hdc, ..., (INT)(lpRgn->iMode) );
660
661       }
662 #endif
663
664     case EMR_SETMETARGN:
665       {
666         SetMetaRgn( hdc );
667         break;
668       }
669
670     case EMR_SETWORLDTRANSFORM:
671       {
672         PEMRSETWORLDTRANSFORM lpXfrm = (PEMRSETWORLDTRANSFORM)mr;
673
674         SetWorldTransform( hdc, &lpXfrm->xform );
675
676         break;
677       }
678
679     case EMR_POLYBEZIER:
680       {
681         PEMRPOLYBEZIER lpPolyBez = (PEMRPOLYBEZIER)mr; 
682
683         FIXME( "Bounding rectangle ignored for EMR_POLYBEZIER\n" );
684         PolyBezier( hdc, (const LPPOINT)lpPolyBez->aptl, (UINT)lpPolyBez->cptl ); 
685
686         break;
687       }
688
689     case EMR_POLYGON:
690       {
691         PEMRPOLYGON lpPoly = (PEMRPOLYGON)mr;
692      
693         FIXME( "Bounding rectangle ignored for EMR_POLYGON\n" );
694         Polygon( hdc, (const LPPOINT)lpPoly->aptl, (UINT)lpPoly->cptl );
695
696         break;
697       }
698
699     case EMR_POLYLINE:
700       {
701         PEMRPOLYLINE lpPolyLine = (PEMRPOLYLINE)mr;
702  
703         FIXME( "Bounding rectangle ignored for EMR_POLYLINE\n" ); 
704         Polyline( hdc, (const LPPOINT)lpPolyLine->aptl, (UINT)lpPolyLine->cptl );
705
706         break; 
707       }
708
709     case EMR_POLYBEZIERTO:
710       {
711         PEMRPOLYBEZIERTO lpPolyBezierTo = (PEMRPOLYBEZIERTO)mr;
712
713         FIXME( "Bounding rectangle ignored for EMR_POLYBEZIERTO\n" );
714         PolyBezierTo( hdc, (const LPPOINT)lpPolyBezierTo->aptl, (UINT)lpPolyBezierTo->cptl );
715
716         break; 
717       }
718
719     case EMR_POLYLINETO:
720       {
721         PEMRPOLYLINETO lpPolyLineTo = (PEMRPOLYLINETO)mr;
722
723         FIXME( "Bounding rectangle ignored for EMR_POLYLINETO\n" );
724         PolylineTo( hdc, (const LPPOINT)lpPolyLineTo->aptl, (UINT)lpPolyLineTo->cptl );
725
726         break;
727       }
728
729     case EMR_POLYPOLYLINE:
730       {
731         PEMRPOLYPOLYLINE lpPolyPolyLine = (PEMRPOLYPOLYLINE)mr;
732
733         FIXME( "Bounding rectangle ignored for EMR_POLYPOLYLINE\n" );
734         PolyPolyline( hdc, 
735                       (const LPPOINT)lpPolyPolyLine->aptl, 
736                       lpPolyPolyLine->aPolyCounts, 
737                       lpPolyPolyLine->nPolys ); 
738
739         break;
740       }
741
742     case EMR_POLYPOLYGON:
743       {
744         PEMRPOLYPOLYGON lpPolyPolygon = (PEMRPOLYPOLYGON)mr;
745         INT* lpPolyCounts;
746         UINT i;
747
748         /* We get the polygon point counts in a dword struct. Transform
749            this into an INT struct */ 
750         lpPolyCounts = (INT*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
751                                         sizeof(INT)*lpPolyPolygon->cptl ); 
752
753         for( i=0; i<lpPolyPolygon->cptl; i++ )
754         {
755           lpPolyCounts[i] = (INT)lpPolyPolygon->aPolyCounts[i];
756         }
757
758         FIXME( "Bounding rectangle ignored for EMR_POLYPOLYGON\n" );
759         PolyPolygon( hdc, (const LPPOINT)lpPolyPolygon->aptl,
760                      lpPolyCounts, lpPolyPolygon->nPolys );
761
762         HeapFree( GetProcessHeap(), 0, lpPolyCounts ); 
763
764         break;
765       }
766
767     case EMR_SETBRUSHORGEX:
768       {
769         PEMRSETBRUSHORGEX lpSetBrushOrgEx = (PEMRSETBRUSHORGEX)mr;
770
771         SetBrushOrgEx( hdc, 
772                        (INT)lpSetBrushOrgEx->ptlOrigin.x, 
773                        (INT)lpSetBrushOrgEx->ptlOrigin.y, 
774                        NULL );
775
776         break;
777       }
778  
779     case EMR_SETPIXELV:
780       {
781         PEMRSETPIXELV lpSetPixelV = (PEMRSETPIXELV)mr;
782
783         SetPixelV( hdc, 
784                    (INT)lpSetPixelV->ptlPixel.x, 
785                    (INT)lpSetPixelV->ptlPixel.y, 
786                    lpSetPixelV->crColor );
787
788         break;
789       }
790
791     case EMR_SETMAPPERFLAGS:
792       {
793         PEMRSETMAPPERFLAGS lpSetMapperFlags = (PEMRSETMAPPERFLAGS)mr;
794    
795         SetMapperFlags( hdc, lpSetMapperFlags->dwFlags );
796
797         break;
798       }
799
800     case EMR_SETCOLORADJUSTMENT:
801       {
802         PEMRSETCOLORADJUSTMENT lpSetColorAdjust = (PEMRSETCOLORADJUSTMENT)mr; 
803
804         SetColorAdjustment( hdc, &lpSetColorAdjust->ColorAdjustment );
805
806         break;
807       }
808
809     case EMR_OFFSETCLIPRGN:
810       {
811         PEMROFFSETCLIPRGN lpOffsetClipRgn = (PEMROFFSETCLIPRGN)mr;
812
813         OffsetClipRgn( hdc, 
814                        (INT)lpOffsetClipRgn->ptlOffset.x,
815                        (INT)lpOffsetClipRgn->ptlOffset.y );
816
817         break;
818       } 
819
820     case EMR_EXCLUDECLIPRECT:
821       {
822         PEMREXCLUDECLIPRECT lpExcludeClipRect = (PEMREXCLUDECLIPRECT)mr;
823
824         ExcludeClipRect( hdc, 
825                          lpExcludeClipRect->rclClip.left, 
826                          lpExcludeClipRect->rclClip.top, 
827                          lpExcludeClipRect->rclClip.right, 
828                          lpExcludeClipRect->rclClip.bottom  );
829
830          break;
831       }
832
833     case EMR_SCALEVIEWPORTEXTEX:
834       {
835         PEMRSCALEVIEWPORTEXTEX lpScaleViewportExtEx = (PEMRSCALEVIEWPORTEXTEX)mr;
836
837         ScaleViewportExtEx( hdc, 
838                             lpScaleViewportExtEx->xNum,
839                             lpScaleViewportExtEx->xDenom,
840                             lpScaleViewportExtEx->yNum,
841                             lpScaleViewportExtEx->yDenom,
842                             NULL );
843      
844         break;
845       }
846  
847     case EMR_SCALEWINDOWEXTEX:
848       {
849         PEMRSCALEWINDOWEXTEX lpScaleWindowExtEx = (PEMRSCALEWINDOWEXTEX)mr;
850
851         ScaleWindowExtEx( hdc,
852                           lpScaleWindowExtEx->xNum,
853                           lpScaleWindowExtEx->xDenom,
854                           lpScaleWindowExtEx->yNum,
855                           lpScaleWindowExtEx->yDenom, 
856                           NULL );
857
858         break;
859       }
860
861     case EMR_MODIFYWORLDTRANSFORM:
862       {
863         PEMRMODIFYWORLDTRANSFORM lpModifyWorldTrans = (PEMRMODIFYWORLDTRANSFORM)mr;
864
865         ModifyWorldTransform( hdc, &lpModifyWorldTrans->xform, 
866                               lpModifyWorldTrans->iMode );
867
868         break;
869       }
870
871     case EMR_ANGLEARC:
872       {
873         PEMRANGLEARC lpAngleArc = (PEMRANGLEARC)mr; 
874
875         AngleArc( hdc, 
876                  (INT)lpAngleArc->ptlCenter.x, (INT)lpAngleArc->ptlCenter.y,
877                  lpAngleArc->nRadius, lpAngleArc->eStartAngle, 
878                  lpAngleArc->eSweepAngle );
879
880         break;
881       }
882  
883     case EMR_ROUNDRECT: 
884       {
885         PEMRROUNDRECT lpRoundRect = (PEMRROUNDRECT)mr;
886
887         RoundRect( hdc, 
888                    lpRoundRect->rclBox.left,
889                    lpRoundRect->rclBox.top,
890                    lpRoundRect->rclBox.right,
891                    lpRoundRect->rclBox.bottom,
892                    lpRoundRect->szlCorner.cx,
893                    lpRoundRect->szlCorner.cy );
894
895         break; 
896       }
897
898     case EMR_ARC:
899       {
900         PEMRARC lpArc = (PEMRARC)mr;
901
902         Arc( hdc,  
903              (INT)lpArc->rclBox.left,
904              (INT)lpArc->rclBox.top,
905              (INT)lpArc->rclBox.right,
906              (INT)lpArc->rclBox.bottom,
907              (INT)lpArc->ptlStart.x, 
908              (INT)lpArc->ptlStart.y,
909              (INT)lpArc->ptlEnd.x,
910              (INT)lpArc->ptlEnd.y );
911
912         break;  
913       }
914
915     case EMR_CHORD:
916       {
917         PEMRCHORD lpChord = (PEMRCHORD)mr;
918
919         Chord( hdc,
920              (INT)lpChord->rclBox.left,
921              (INT)lpChord->rclBox.top,
922              (INT)lpChord->rclBox.right,
923              (INT)lpChord->rclBox.bottom,
924              (INT)lpChord->ptlStart.x,
925              (INT)lpChord->ptlStart.y,
926              (INT)lpChord->ptlEnd.x,
927              (INT)lpChord->ptlEnd.y );
928
929         break;
930       }
931
932     case EMR_PIE:
933       {
934         PEMRPIE lpPie = (PEMRPIE)mr;
935
936         Pie( hdc,
937              (INT)lpPie->rclBox.left,
938              (INT)lpPie->rclBox.top,
939              (INT)lpPie->rclBox.right,
940              (INT)lpPie->rclBox.bottom,
941              (INT)lpPie->ptlStart.x,
942              (INT)lpPie->ptlStart.y,
943              (INT)lpPie->ptlEnd.x,
944              (INT)lpPie->ptlEnd.y );
945
946        break;
947       }
948
949     case EMR_ARCTO: 
950       {
951         PEMRARC lpArcTo = (PEMRARC)mr;
952
953         ArcTo( hdc,
954                (INT)lpArcTo->rclBox.left,
955                (INT)lpArcTo->rclBox.top,
956                (INT)lpArcTo->rclBox.right,
957                (INT)lpArcTo->rclBox.bottom,
958                (INT)lpArcTo->ptlStart.x,
959                (INT)lpArcTo->ptlStart.y,
960                (INT)lpArcTo->ptlEnd.x,
961                (INT)lpArcTo->ptlEnd.y );
962
963         break;
964       }
965
966     case EMR_EXTFLOODFILL:
967       {
968         PEMREXTFLOODFILL lpExtFloodFill = (PEMREXTFLOODFILL)mr;
969
970         ExtFloodFill( hdc, 
971                       (INT)lpExtFloodFill->ptlStart.x,
972                       (INT)lpExtFloodFill->ptlStart.y,
973                       lpExtFloodFill->crColor,
974                       (UINT)lpExtFloodFill->iMode );
975
976         break;
977       }
978
979     case EMR_POLYDRAW:
980       {
981         PEMRPOLYDRAW lpPolyDraw = (PEMRPOLYDRAW)mr;
982
983         FIXME( "Bounding rectangle ignored for EMR_POLYDRAW\n" );
984         PolyDraw( hdc, 
985                   (const LPPOINT)lpPolyDraw->aptl,
986                   lpPolyDraw->abTypes,
987                   (INT)lpPolyDraw->cptl );
988  
989         break;
990       } 
991
992     case EMR_SETARCDIRECTION:
993       {
994         PEMRSETARCDIRECTION lpSetArcDirection = (PEMRSETARCDIRECTION)mr;
995
996         SetArcDirection( hdc, (INT)lpSetArcDirection->iArcDirection );
997
998         break;
999       }
1000
1001     case EMR_SETMITERLIMIT:
1002       {
1003         PEMRSETMITERLIMIT lpSetMiterLimit = (PEMRSETMITERLIMIT)mr;
1004
1005         SetMiterLimit( hdc, lpSetMiterLimit->eMiterLimit, NULL );
1006
1007         break;
1008       } 
1009
1010     case EMR_BEGINPATH:
1011       {
1012         BeginPath( hdc );
1013         break;
1014       }
1015
1016     case EMR_ENDPATH: 
1017       {
1018         EndPath( hdc );
1019         break;
1020       }
1021
1022     case EMR_CLOSEFIGURE:
1023       {
1024         CloseFigure( hdc );
1025         break;
1026       }
1027
1028     case EMR_FILLPATH:
1029       {
1030         /*PEMRFILLPATH lpFillPath = (PEMRFILLPATH)mr;*/
1031
1032         FIXME( "Bounding rectangle ignored for EMR_FILLPATH\n" );
1033         FillPath( hdc );
1034
1035         break;
1036       }
1037
1038     case EMR_STROKEANDFILLPATH:
1039       {
1040         /*PEMRSTROKEANDFILLPATH lpStrokeAndFillPath = (PEMRSTROKEANDFILLPATH)mr;*/
1041
1042         FIXME( "Bounding rectangle ignored for EMR_STROKEANDFILLPATH\n" );
1043         StrokeAndFillPath( hdc );
1044
1045         break;
1046       }
1047
1048     case EMR_STROKEPATH:
1049       {
1050         /*PEMRSTROKEPATH lpStrokePath = (PEMRSTROKEPATH)mr;*/
1051
1052         FIXME( "Bounding rectangle ignored for EMR_STROKEPATH\n" );  
1053         StrokePath( hdc );
1054
1055         break;
1056       }
1057
1058     case EMR_FLATTENPATH:
1059       {
1060         FlattenPath( hdc ); 
1061         break;
1062       }
1063
1064     case EMR_WIDENPATH:
1065       {
1066         WidenPath( hdc );
1067         break;
1068       }
1069
1070     case EMR_SELECTCLIPPATH:
1071       {
1072         PEMRSELECTCLIPPATH lpSelectClipPath = (PEMRSELECTCLIPPATH)mr;
1073
1074         SelectClipPath( hdc, (INT)lpSelectClipPath->iMode );
1075
1076         break;
1077       }
1078  
1079     case EMR_ABORTPATH:
1080       {
1081         AbortPath( hdc );
1082         break;
1083       }
1084
1085     case EMR_CREATECOLORSPACE:
1086       {
1087         PEMRCREATECOLORSPACE lpCreateColorSpace = (PEMRCREATECOLORSPACE)mr;
1088
1089         (handletable->objectHandle)[lpCreateColorSpace->ihCS] = 
1090            CreateColorSpaceA( &lpCreateColorSpace->lcs ); 
1091
1092         break;
1093       }
1094
1095     case EMR_SETCOLORSPACE:
1096       {
1097         PEMRSETCOLORSPACE lpSetColorSpace = (PEMRSETCOLORSPACE)mr; 
1098
1099         SetColorSpace( hdc, 
1100                        (handletable->objectHandle)[lpSetColorSpace->ihCS] );
1101
1102         break;
1103       }
1104
1105     case EMR_DELETECOLORSPACE:
1106       {
1107         PEMRDELETECOLORSPACE lpDeleteColorSpace = (PEMRDELETECOLORSPACE)mr;
1108
1109         DeleteColorSpace( (handletable->objectHandle)[lpDeleteColorSpace->ihCS] );
1110    
1111         break; 
1112       }
1113
1114     case EMR_SETICMMODE:
1115       {
1116         PERMSETICMMODE lpSetICMMode = (PERMSETICMMODE)mr;
1117
1118         SetICMMode( hdc,
1119                     (INT)lpSetICMMode->iMode );
1120
1121         break;
1122       }
1123
1124     case EMR_PIXELFORMAT: 
1125       {
1126         INT iPixelFormat;
1127         PEMRPIXELFORMAT lpPixelFormat = (PEMRPIXELFORMAT)mr;
1128
1129         iPixelFormat = ChoosePixelFormat( hdc, &lpPixelFormat->pfd );
1130         SetPixelFormat( hdc, iPixelFormat, &lpPixelFormat->pfd ); 
1131          
1132         break;
1133       }
1134
1135     case EMR_SETPALETTEENTRIES:  
1136       {
1137         PEMRSETPALETTEENTRIES lpSetPaletteEntries = (PEMRSETPALETTEENTRIES)mr;
1138
1139         SetPaletteEntries( (handletable->objectHandle)[lpSetPaletteEntries->ihPal],
1140                            (UINT)lpSetPaletteEntries->iStart,
1141                            (UINT)lpSetPaletteEntries->cEntries,
1142                            lpSetPaletteEntries->aPalEntries ); 
1143                            
1144         break;
1145       }
1146
1147     case EMR_RESIZEPALETTE:
1148       {
1149         PEMRRESIZEPALETTE lpResizePalette = (PEMRRESIZEPALETTE)mr;
1150
1151         ResizePalette( (handletable->objectHandle)[lpResizePalette->ihPal],
1152                        (UINT)lpResizePalette->cEntries );
1153
1154         break;
1155       }
1156
1157     case EMR_CREATEDIBPATTERNBRUSHPT:
1158       {
1159         PEMRCREATEDIBPATTERNBRUSHPT lpCreate = (PEMRCREATEDIBPATTERNBRUSHPT)mr;
1160
1161         /* This is a BITMAPINFO struct followed directly by bitmap bits */
1162         LPVOID lpPackedStruct = HeapAlloc( GetProcessHeap(), 
1163                                            0, 
1164                                            lpCreate->cbBmi + lpCreate->cbBits );
1165         /* Now pack this structure */
1166         memcpy( lpPackedStruct, 
1167                 ((BYTE*)lpCreate) + lpCreate->offBmi,
1168                 lpCreate->cbBmi ); 
1169         memcpy( ((BYTE*)lpPackedStruct) + lpCreate->cbBmi,
1170                 ((BYTE*)lpCreate) + lpCreate->offBits,
1171                 lpCreate->cbBits );
1172
1173         (handletable->objectHandle)[lpCreate->ihBrush] = 
1174            CreateDIBPatternBrushPt( lpPackedStruct,
1175                                     (UINT)lpCreate->iUsage ); 
1176
1177         break; 
1178       }
1179
1180     case EMR_BITBLT:
1181     case EMR_STRETCHBLT:
1182     case EMR_MASKBLT:
1183     case EMR_PLGBLT:
1184     case EMR_SETDIBITSTODEVICE:
1185     case EMR_EXTTEXTOUTA:
1186     case EMR_POLYBEZIER16:
1187     case EMR_POLYBEZIERTO16:
1188     case EMR_POLYLINETO16:
1189     case EMR_POLYPOLYLINE16:
1190     case EMR_POLYPOLYGON16:
1191     case EMR_POLYDRAW16:
1192     case EMR_CREATEMONOBRUSH:
1193     case EMR_POLYTEXTOUTA:
1194     case EMR_POLYTEXTOUTW:
1195     case EMR_FILLRGN:
1196     case EMR_FRAMERGN:
1197     case EMR_INVERTRGN:
1198     case EMR_PAINTRGN:
1199     case EMR_GLSRECORD:
1200     case EMR_GLSBOUNDEDRECORD:
1201     default:
1202       /* From docs: If PlayEnhMetaFileRecord doesn't recognize a 
1203                     record then ignore and return TRUE. */
1204       FIXME("type %d is unimplemented\n", type);
1205       break;
1206     }
1207   return TRUE;
1208 }
1209
1210
1211 /*****************************************************************************
1212  *
1213  *        EnumEnhMetaFile  (GDI32.79)
1214  *
1215  *  Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
1216  *  for each
1217  *  record. Returns when either every record has been used or 
1218  *  when _EnhMetaFunc_ returns FALSE.
1219  *
1220  *
1221  * RETURNS
1222  *  TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
1223  *  returns FALSE.
1224  *
1225  * BUGS
1226  *   Ignores rect.
1227  */
1228 BOOL WINAPI EnumEnhMetaFile( 
1229      HDC hdc, /* device context to pass to _EnhMetaFunc_ */
1230      HENHMETAFILE hmf, /* EMF to walk */
1231      ENHMFENUMPROC callback, /* callback function */ 
1232      LPVOID data, /* optional data for callback function */
1233      const RECT *rect  /* bounding rectangle for rendered metafile */
1234     )
1235 {
1236     BOOL ret = TRUE;
1237     LPENHMETARECORD p = (LPENHMETARECORD) EMF_GetEnhMetaHeader(hmf);
1238     INT count;
1239     HANDLETABLE *ht;
1240
1241     if(!p) return FALSE;
1242     count = ((LPENHMETAHEADER) p)->nHandles;
1243     ht = HeapAlloc( GetProcessHeap(), 0, sizeof(HANDLETABLE)*count);
1244     ht->objectHandle[0] = hmf;
1245     while (ret) {
1246         ret = (*callback)(hdc, ht, p, count, data); 
1247         if (p->iType == EMR_EOF) break;
1248         p = (LPENHMETARECORD) ((char *) p + p->nSize);
1249     }
1250     HeapFree( GetProcessHeap(), 0, ht);
1251     EMF_ReleaseEnhMetaHeader(hmf);
1252     return ret;
1253 }
1254
1255
1256 /**************************************************************************
1257  *    PlayEnhMetaFile  (GDI32.263)
1258  *
1259  *    Renders an enhanced metafile into a specified rectangle *lpRect
1260  *    in device context hdc.
1261  *
1262  * BUGS
1263  *    Almost entirely unimplemented
1264  *
1265  */
1266 BOOL WINAPI PlayEnhMetaFile( 
1267        HDC hdc, /* DC to render into */
1268        HENHMETAFILE hmf, /* metafile to render */
1269        const RECT *lpRect  /* rectangle to place metafile inside */
1270       )
1271 {
1272     LPENHMETARECORD p = (LPENHMETARECORD) EMF_GetEnhMetaHeader(hmf);
1273     INT count;
1274     HANDLETABLE *ht;
1275     BOOL ret = FALSE;
1276     INT savedMode = 0;
1277
1278     if(!p) return FALSE;
1279     count = ((LPENHMETAHEADER) p)->nHandles;
1280     ht = HeapAlloc( GetProcessHeap(), 0, sizeof(HANDLETABLE) * count);
1281     if (lpRect) {
1282         LPENHMETAHEADER h = (LPENHMETAHEADER) p;
1283         FLOAT xscale = (h->rclBounds.right - h->rclBounds.left) /
1284           (lpRect->right - lpRect->left);
1285         FLOAT yscale = (h->rclBounds.bottom - h->rclBounds.top) /
1286           (lpRect->bottom - lpRect->top);
1287         XFORM xform;
1288         xform.eM11 = xscale;
1289         xform.eM12 = 0;
1290         xform.eM21 = 0;
1291         xform.eM22 = yscale;
1292         xform.eDx = lpRect->left;
1293         xform.eDy = lpRect->top; 
1294         FIXME("play into rect doesn't work\n");
1295         savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
1296         if (!SetWorldTransform(hdc, &xform)) {
1297             WARN("World transform failed!\n");
1298         }
1299     }
1300
1301     ht->objectHandle[0] = hmf;
1302     while (1) {
1303         PlayEnhMetaFileRecord(hdc, ht, p, count);
1304         if (p->iType == EMR_EOF) break;
1305         p = (LPENHMETARECORD) ((char *) p + p->nSize); /* casted so that arithmetic is in bytes */
1306     }
1307     HeapFree( GetProcessHeap(), 0, ht );
1308     EMF_ReleaseEnhMetaHeader(hmf);
1309     if (savedMode) SetGraphicsMode(hdc, savedMode);
1310     ret = TRUE; /* FIXME: calculate a more accurate return value */
1311     return ret;
1312 }
1313
1314 /*****************************************************************************
1315  *  DeleteEnhMetaFile (GDI32.68)
1316  *
1317  *  Deletes an enhanced metafile and frees the associated storage.
1318  */
1319 BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf)
1320 {
1321     return EMF_Delete_HENHMETAFILE( hmf );
1322 }
1323
1324 /*****************************************************************************
1325  *  CopyEnhMetaFileA (GDI32.21)  Duplicate an enhanced metafile
1326  *
1327  *   
1328  */
1329 HENHMETAFILE WINAPI CopyEnhMetaFileA(
1330     HENHMETAFILE hmfSrc, 
1331     LPCSTR file)
1332 {
1333     ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
1334     HENHMETAFILE hmfDst;
1335
1336     if(!emrSrc) return FALSE;
1337     if (!file) {
1338         emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
1339         memcpy( emrDst, emrSrc, emrSrc->nBytes );
1340         hmfDst = EMF_Create_HENHMETAFILE( emrDst, 0, 0 );
1341     } else {
1342         HFILE hFile;
1343         hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0, NULL,
1344                              CREATE_ALWAYS, 0, -1);
1345         WriteFile( hFile, emrSrc, emrSrc->nBytes, 0, 0);
1346         hmfDst = EMF_GetEnhMetaFile( hFile );
1347     }
1348     EMF_ReleaseEnhMetaHeader( hmfSrc );
1349     return hmfDst;
1350 }
1351
1352
1353 /* Struct to be used to be passed in the LPVOID parameter for cbEnhPaletteCopy */
1354 typedef struct tagEMF_PaletteCopy
1355 {
1356    UINT cEntries;
1357    LPPALETTEENTRY lpPe;
1358 } EMF_PaletteCopy;
1359
1360 /***************************************************************  
1361  * Find the EMR_EOF record and then use it to find the
1362  * palette entries for this enhanced metafile. 
1363  * The lpData is actually a pointer to a EMF_PaletteCopy struct  
1364  * which contains the max number of elements to copy and where
1365  * to copy them to.
1366  *
1367  * NOTE: To be used by GetEnhMetaFilePaletteEntries only!
1368  */
1369 INT CALLBACK cbEnhPaletteCopy( HDC a,
1370                                LPHANDLETABLE b,
1371                                LPENHMETARECORD lpEMR,
1372                                INT c,
1373                                LPVOID lpData )
1374 {
1375  
1376   if ( lpEMR->iType == EMR_EOF )
1377   {
1378     PEMREOF lpEof = (PEMREOF)lpEMR;
1379     EMF_PaletteCopy* info = (EMF_PaletteCopy*)lpData;
1380     DWORD dwNumPalToCopy = min( lpEof->nPalEntries, info->cEntries );
1381
1382     TRACE( "copying 0x%08lx palettes\n", dwNumPalToCopy );
1383
1384     memcpy( (LPVOID)info->lpPe, 
1385             (LPVOID)(((LPSTR)lpEof) + lpEof->offPalEntries), 
1386             sizeof( *(info->lpPe) ) * dwNumPalToCopy );
1387
1388     /* Update the passed data as a return code */
1389     info->lpPe     = NULL; /* Palettes were copied! */
1390     info->cEntries = (UINT)dwNumPalToCopy;  
1391
1392     return FALSE; /* That's all we need */
1393   }
1394   
1395   return TRUE;
1396 }
1397
1398 /*****************************************************************************
1399  *  GetEnhMetaFilePaletteEntries (GDI32.179)  
1400  * 
1401  *  Copy the palette and report size  
1402  * 
1403  *  BUGS: Error codes (SetLastError) are not set on failures
1404  */
1405 UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
1406                                           UINT cEntries,
1407                                           LPPALETTEENTRY lpPe )
1408 {
1409   ENHMETAHEADER* enhHeader = EMF_GetEnhMetaHeader( hEmf );
1410   UINT uReturnValue = GDI_ERROR;
1411   EMF_PaletteCopy infoForCallBack; 
1412
1413   TRACE( "(%04x,%d,%p)\n", hEmf, cEntries, lpPe ); 
1414
1415   /* First check if there are any palettes associated with
1416      this metafile. */
1417   if ( enhHeader->nPalEntries == 0 )
1418   {
1419     /* No palette associated with this enhanced metafile */
1420     uReturnValue = 0;
1421     goto done; 
1422   }
1423
1424   /* Is the user requesting the number of palettes? */
1425   if ( lpPe == NULL )
1426   {
1427      uReturnValue = (UINT)enhHeader->nPalEntries;
1428      goto done;
1429   } 
1430
1431   /* Copy cEntries worth of PALETTEENTRY structs into the buffer */
1432   infoForCallBack.cEntries = cEntries;
1433   infoForCallBack.lpPe     = lpPe; 
1434
1435   if ( !EnumEnhMetaFile( 0, hEmf, cbEnhPaletteCopy, 
1436                          &infoForCallBack, NULL ) )
1437   {
1438      goto done; 
1439   }
1440
1441   /* Verify that the callback executed correctly */
1442   if ( infoForCallBack.lpPe != NULL )
1443   {
1444      /* Callback proc had error! */
1445      ERR( "cbEnhPaletteCopy didn't execute correctly\n" );
1446      goto done;
1447   }
1448
1449   uReturnValue = infoForCallBack.cEntries;
1450
1451 done:
1452   
1453   EMF_ReleaseEnhMetaHeader( hEmf );
1454
1455   return uReturnValue;
1456 }
1457
1458 /******************************************************************
1459  *         SetWinMetaFileBits   (GDI32.343)
1460  *      
1461  *         Translate from old style to new style.
1462  *
1463  * BUGS: - This doesn't take the DC and scaling into account
1464  *       - Most record conversions aren't implemented
1465  *       - Handle slot assignement is primative and most likely doesn't work
1466  */
1467 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
1468                                            CONST BYTE *lpbBuffer,
1469                                            HDC hdcRef,
1470                                            CONST METAFILEPICT *lpmfp
1471                                            ) 
1472 {
1473      HENHMETAFILE    hMf;
1474      LPVOID          lpNewEnhMetaFileBuffer = NULL;
1475      UINT            uNewEnhMetaFileBufferSize = 0;
1476      BOOL            bFoundEOF = FALSE;
1477
1478      FIXME( "(%d,%p,%04x,%p):stub\n", cbBuffer, lpbBuffer, hdcRef, lpmfp );
1479
1480      /* 1. Get the header - skip over this and get straight to the records  */
1481
1482      uNewEnhMetaFileBufferSize = sizeof( ENHMETAHEADER );
1483      lpNewEnhMetaFileBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
1484                                          uNewEnhMetaFileBufferSize );
1485
1486      if( lpNewEnhMetaFileBuffer == NULL )
1487      {
1488        goto error; 
1489      }
1490
1491      /* Fill in the header record */ 
1492      {
1493        LPENHMETAHEADER lpNewEnhMetaFileHeader = (LPENHMETAHEADER)lpNewEnhMetaFileBuffer;
1494
1495        lpNewEnhMetaFileHeader->iType = EMR_HEADER;
1496        lpNewEnhMetaFileHeader->nSize = sizeof( ENHMETAHEADER );
1497
1498        /* FIXME: Not right. Must be able to get this from the DC */
1499        lpNewEnhMetaFileHeader->rclBounds.left   = 0;
1500        lpNewEnhMetaFileHeader->rclBounds.right  = 0;
1501        lpNewEnhMetaFileHeader->rclBounds.top    = 0;
1502        lpNewEnhMetaFileHeader->rclBounds.bottom = 0;
1503
1504        /* FIXME: Not right. Must be able to get this from the DC */
1505        lpNewEnhMetaFileHeader->rclFrame.left   = 0;
1506        lpNewEnhMetaFileHeader->rclFrame.right  = 0;
1507        lpNewEnhMetaFileHeader->rclFrame.top    = 0;
1508        lpNewEnhMetaFileHeader->rclFrame.bottom = 0;
1509
1510        lpNewEnhMetaFileHeader->nHandles = 0; /* No handles yet */
1511
1512        /* FIXME: Add in the rest of the fields to the header */
1513        /* dSignature
1514           nVersion
1515           nRecords
1516           sReserved
1517           nDescription
1518           offDescription
1519           nPalEntries
1520           szlDevice
1521           szlMillimeters
1522           cbPixelFormat
1523           offPixelFormat,
1524           bOpenGL */
1525      } 
1526
1527      (char*)lpbBuffer += ((METAHEADER*)lpbBuffer)->mtHeaderSize * 2; /* Point past the header - FIXME: metafile quirk? */ 
1528
1529      /* 2. Enum over individual records and convert them to the new type of records */
1530      while( !bFoundEOF )
1531      { 
1532
1533         LPMETARECORD lpMetaRecord = (LPMETARECORD)lpbBuffer;
1534
1535 #define EMF_ReAllocAndAdjustPointers( a , b ) \
1536                                         { \
1537                                           LPVOID lpTmp; \
1538                                           lpTmp = HeapReAlloc( GetProcessHeap(), 0, \
1539                                                                lpNewEnhMetaFileBuffer, \
1540                                                                uNewEnhMetaFileBufferSize + (b) ); \
1541                                           if( lpTmp == NULL ) { ERR( "No memory!\n" ); goto error; } \
1542                                           lpNewEnhMetaFileBuffer = lpTmp; \
1543                                           lpRecord = (a)( (char*)lpNewEnhMetaFileBuffer + uNewEnhMetaFileBufferSize ); \
1544                                           uNewEnhMetaFileBufferSize += (b); \
1545                                         }
1546
1547         switch( lpMetaRecord->rdFunction )
1548         {
1549           case META_EOF:  
1550           { 
1551              PEMREOF lpRecord;
1552              size_t uRecord = sizeof(*lpRecord);
1553
1554              EMF_ReAllocAndAdjustPointers(PEMREOF,uRecord);
1555               
1556              /* Fill the new record - FIXME: This is not right */
1557              lpRecord->emr.iType = EMR_EOF; 
1558              lpRecord->emr.nSize = sizeof( *lpRecord );
1559              lpRecord->nPalEntries = 0;     /* FIXME */
1560              lpRecord->offPalEntries = 0;   /* FIXME */ 
1561              lpRecord->nSizeLast = 0;       /* FIXME */
1562
1563              /* No more records after this one */
1564              bFoundEOF = TRUE;
1565
1566              FIXME( "META_EOF conversion not correct\n" );
1567              break;
1568           }
1569
1570           case META_SETMAPMODE:
1571           {  
1572              PEMRSETMAPMODE lpRecord;
1573              size_t uRecord = sizeof(*lpRecord);
1574
1575              EMF_ReAllocAndAdjustPointers(PEMRSETMAPMODE,uRecord);
1576
1577              lpRecord->emr.iType = EMR_SETMAPMODE;
1578              lpRecord->emr.nSize = sizeof( *lpRecord );
1579
1580              lpRecord->iMode = lpMetaRecord->rdParm[0];
1581
1582              break;
1583           }
1584
1585           case META_DELETEOBJECT: /* Select and Delete structures are the same */
1586           case META_SELECTOBJECT: 
1587           {
1588             PEMRDELETEOBJECT lpRecord;
1589             size_t uRecord = sizeof(*lpRecord);
1590
1591             EMF_ReAllocAndAdjustPointers(PEMRDELETEOBJECT,uRecord);
1592
1593             if( lpMetaRecord->rdFunction == META_DELETEOBJECT )
1594             {
1595               lpRecord->emr.iType = EMR_DELETEOBJECT;
1596             }
1597             else
1598             {
1599               lpRecord->emr.iType = EMR_SELECTOBJECT;
1600             }
1601             lpRecord->emr.nSize = sizeof( *lpRecord );
1602
1603             lpRecord->ihObject = lpMetaRecord->rdParm[0]; /* FIXME: Handle */
1604
1605             break;
1606           }
1607
1608           case META_POLYGON: /* This is just plain busted. I don't know what I'm doing */
1609           {
1610              PEMRPOLYGON16 lpRecord; /* FIXME: Should it be a poly or poly16? */  
1611              size_t uRecord = sizeof(*lpRecord);
1612
1613              EMF_ReAllocAndAdjustPointers(PEMRPOLYGON16,uRecord);
1614
1615              /* FIXME: This is mostly all wrong */
1616              lpRecord->emr.iType = EMR_POLYGON16;
1617              lpRecord->emr.nSize = sizeof( *lpRecord );
1618
1619              lpRecord->rclBounds.left   = 0;
1620              lpRecord->rclBounds.right  = 0;
1621              lpRecord->rclBounds.top    = 0;
1622              lpRecord->rclBounds.bottom = 0;
1623
1624              lpRecord->cpts = 0;
1625              lpRecord->apts[0].x = 0;
1626              lpRecord->apts[0].y = 0;
1627
1628              FIXME( "META_POLYGON conversion not correct\n" );
1629
1630              break;
1631           }
1632
1633           case META_SETPOLYFILLMODE:
1634           {
1635              PEMRSETPOLYFILLMODE lpRecord;
1636              size_t uRecord = sizeof(*lpRecord);
1637
1638              EMF_ReAllocAndAdjustPointers(PEMRSETPOLYFILLMODE,uRecord);
1639
1640              lpRecord->emr.iType = EMR_SETPOLYFILLMODE;
1641              lpRecord->emr.nSize = sizeof( *lpRecord );
1642
1643              lpRecord->iMode = lpMetaRecord->rdParm[0];
1644              
1645              break;
1646           }
1647
1648           case META_SETWINDOWORG:
1649           {
1650              PEMRSETWINDOWORGEX lpRecord; /* Seems to be the closest thing */
1651              size_t uRecord = sizeof(*lpRecord);
1652
1653              EMF_ReAllocAndAdjustPointers(PEMRSETWINDOWORGEX,uRecord);
1654
1655              lpRecord->emr.iType = EMR_SETWINDOWORGEX;
1656              lpRecord->emr.nSize = sizeof( *lpRecord );
1657
1658              lpRecord->ptlOrigin.x = lpMetaRecord->rdParm[1];
1659              lpRecord->ptlOrigin.y = lpMetaRecord->rdParm[0];
1660
1661              break;
1662           }
1663
1664           case META_SETWINDOWEXT:  /* Structure is the same for SETWINDOWEXT & SETVIEWPORTEXT */
1665           case META_SETVIEWPORTEXT:
1666           {
1667              PEMRSETWINDOWEXTEX lpRecord;
1668              size_t uRecord = sizeof(*lpRecord);
1669
1670              EMF_ReAllocAndAdjustPointers(PEMRSETWINDOWEXTEX,uRecord);
1671
1672              if ( lpMetaRecord->rdFunction == META_SETWINDOWEXT )
1673              {
1674                lpRecord->emr.iType = EMR_SETWINDOWORGEX;
1675              }
1676              else
1677              {
1678                lpRecord->emr.iType = EMR_SETVIEWPORTEXTEX;
1679              }
1680              lpRecord->emr.nSize = sizeof( *lpRecord );
1681
1682              lpRecord->szlExtent.cx = lpMetaRecord->rdParm[1];
1683              lpRecord->szlExtent.cy = lpMetaRecord->rdParm[0];
1684
1685              break;
1686           }
1687
1688           case META_CREATEBRUSHINDIRECT:
1689           {
1690              PEMRCREATEBRUSHINDIRECT lpRecord;
1691              size_t uRecord = sizeof(*lpRecord);
1692
1693              EMF_ReAllocAndAdjustPointers(PEMRCREATEBRUSHINDIRECT,uRecord);
1694
1695              lpRecord->emr.iType = EMR_CREATEBRUSHINDIRECT;
1696              lpRecord->emr.nSize = sizeof( *lpRecord );
1697
1698              lpRecord->ihBrush    = ((LPENHMETAHEADER)lpNewEnhMetaFileBuffer)->nHandles;
1699              lpRecord->lb.lbStyle = ((LPLOGBRUSH16)lpMetaRecord->rdParm)->lbStyle; 
1700              lpRecord->lb.lbColor = ((LPLOGBRUSH16)lpMetaRecord->rdParm)->lbColor; 
1701              lpRecord->lb.lbHatch = ((LPLOGBRUSH16)lpMetaRecord->rdParm)->lbHatch; 
1702              
1703              ((LPENHMETAHEADER)lpNewEnhMetaFileBuffer)->nHandles += 1; /* New handle */
1704
1705              break;
1706           }
1707
1708
1709           /* These are all unimplemented and as such are intended to fall through to the default case */
1710           case META_SETBKCOLOR:
1711           case META_SETBKMODE:
1712           case META_SETROP2:
1713           case META_SETRELABS:
1714           case META_SETSTRETCHBLTMODE:
1715           case META_SETTEXTCOLOR:
1716           case META_SETVIEWPORTORG:
1717           case META_OFFSETWINDOWORG:
1718           case META_SCALEWINDOWEXT:
1719           case META_OFFSETVIEWPORTORG:
1720           case META_SCALEVIEWPORTEXT:
1721           case META_LINETO:
1722           case META_MOVETO:
1723           case META_EXCLUDECLIPRECT:
1724           case META_INTERSECTCLIPRECT:
1725           case META_ARC:
1726           case META_ELLIPSE:
1727           case META_FLOODFILL:
1728           case META_PIE:
1729           case META_RECTANGLE:
1730           case META_ROUNDRECT:
1731           case META_PATBLT:
1732           case META_SAVEDC:
1733           case META_SETPIXEL:
1734           case META_OFFSETCLIPRGN:
1735           case META_TEXTOUT:
1736           case META_POLYPOLYGON:
1737           case META_POLYLINE:
1738           case META_RESTOREDC:  
1739           case META_CHORD:
1740           case META_CREATEPATTERNBRUSH:
1741           case META_CREATEPENINDIRECT:
1742           case META_CREATEFONTINDIRECT:
1743           case META_CREATEPALETTE:
1744           case META_SETTEXTALIGN:
1745           case META_SELECTPALETTE:
1746           case META_SETMAPPERFLAGS:
1747           case META_REALIZEPALETTE:
1748           case META_ESCAPE:
1749           case META_EXTTEXTOUT:
1750           case META_STRETCHDIB:
1751           case META_DIBSTRETCHBLT:
1752           case META_STRETCHBLT:
1753           case META_BITBLT:
1754           case META_CREATEREGION:
1755           case META_FILLREGION:
1756           case META_FRAMEREGION:
1757           case META_INVERTREGION:
1758           case META_PAINTREGION:
1759           case META_SELECTCLIPREGION:
1760           case META_DIBCREATEPATTERNBRUSH:
1761           case META_DIBBITBLT:
1762           case META_SETTEXTCHAREXTRA:
1763           case META_SETTEXTJUSTIFICATION:
1764           case META_EXTFLOODFILL:
1765           case META_SETDIBTODEV:
1766           case META_DRAWTEXT:
1767           case META_ANIMATEPALETTE:
1768           case META_SETPALENTRIES:
1769           case META_RESIZEPALETTE:
1770           case META_RESETDC:
1771           case META_STARTDOC:
1772           case META_STARTPAGE:
1773           case META_ENDPAGE:
1774           case META_ABORTDOC:
1775           case META_ENDDOC:
1776           case META_CREATEBRUSH:
1777           case META_CREATEBITMAPINDIRECT:
1778           case META_CREATEBITMAP:    
1779           /* Fall through to unimplemented */
1780           default:
1781           {
1782             /* Not implemented yet */
1783             FIXME( "Conversion of record type 0x%x not implemented.\n", lpMetaRecord->rdFunction );
1784             break;
1785           }
1786        }
1787
1788        /* Move to the next record */
1789        (char*)lpbBuffer += ((LPMETARECORD)lpbBuffer)->rdSize * 2; /* FIXME: Seem to be doing this in metafile.c */ 
1790
1791 #undef ReAllocAndAdjustPointers
1792      } 
1793
1794      /* We know the last of the header information now */
1795      ((LPENHMETAHEADER)lpNewEnhMetaFileBuffer)->nBytes = uNewEnhMetaFileBufferSize;
1796
1797      /* Create the enhanced metafile */
1798      hMf = SetEnhMetaFileBits( uNewEnhMetaFileBufferSize, (const BYTE*)lpNewEnhMetaFileBuffer ); 
1799
1800      if( !hMf )
1801        ERR( "Problem creating metafile. Did the conversion fail somewhere?\n" );
1802
1803      return hMf;
1804
1805 error:
1806      /* Free the data associated with our copy since it's been copied */
1807      HeapFree( GetProcessHeap(), 0, lpNewEnhMetaFileBuffer ); 
1808
1809      return 0;  
1810 }
1811
1812
1813