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