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