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