Fixed header dependencies to be fully compatible with the Windows
[wine] / objects / enhmetafile.c
1 /*
2  * Enhanced metafile functions
3  * Copyright 1998 Douglas Ridgway
4  *           1999 Huw D M Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * NOTES:
21  *
22  * The enhanced format consists of the following elements:
23  *
24  *    A header
25  *    A table of handles to GDI objects
26  *    An array of metafile records
27  *    A private palette
28  *
29  *
30  *  The standard format consists of a header and an array of metafile records.
31  *
32  */
33
34 #include "config.h"
35 #include "wine/port.h"
36
37 #include <stdarg.h>
38 #include <string.h>
39 #include <assert.h>
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wingdi.h"
43 #include "winnls.h"
44 #include "winerror.h"
45 #include "gdi.h"
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
49
50 typedef struct
51 {
52     GDIOBJHDR      header;
53     ENHMETAHEADER  *emh;
54     BOOL           on_disk;   /* true if metafile is on disk */
55 } ENHMETAFILEOBJ;
56
57
58 /****************************************************************************
59  *          EMF_Create_HENHMETAFILE
60  */
61 HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk )
62 {
63     HENHMETAFILE hmf = 0;
64     ENHMETAFILEOBJ *metaObj = GDI_AllocObject( sizeof(ENHMETAFILEOBJ),
65                                                ENHMETAFILE_MAGIC,
66                                                (HGDIOBJ *)&hmf, NULL );
67     if (metaObj)
68     {
69         metaObj->emh = emh;
70         metaObj->on_disk = on_disk;
71         GDI_ReleaseObj( hmf );
72     }
73     return hmf;
74 }
75
76 /****************************************************************************
77  *          EMF_Delete_HENHMETAFILE
78  */
79 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
80 {
81     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf,
82                                                            ENHMETAFILE_MAGIC );
83     if(!metaObj) return FALSE;
84
85     if(metaObj->on_disk)
86         UnmapViewOfFile( metaObj->emh );
87     else
88         HeapFree( GetProcessHeap(), 0, metaObj->emh );
89     return GDI_FreeObject( hmf, metaObj );
90 }
91
92 /******************************************************************
93  *         EMF_GetEnhMetaHeader
94  *
95  * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE
96  */
97 static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf )
98 {
99     ENHMETAHEADER *ret = NULL;
100     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf, ENHMETAFILE_MAGIC );
101     TRACE("hmf %p -> enhmetaObj %p\n", hmf, metaObj);
102     if (metaObj)
103     {
104         ret = metaObj->emh;
105         GDI_ReleaseObj( hmf );
106     }
107     return ret;
108 }
109
110 /*****************************************************************************
111  *         EMF_GetEnhMetaFile
112  *
113  */
114 static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
115 {
116     ENHMETAHEADER *emh;
117     HANDLE hMapping;
118
119     hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
120     emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
121     CloseHandle( hMapping );
122
123     if (!emh) return 0;
124
125     if (emh->iType != EMR_HEADER || emh->dSignature != ENHMETA_SIGNATURE) {
126         WARN("Invalid emf header type 0x%08lx sig 0x%08lx.\n",
127              emh->iType, emh->dSignature);
128         goto err;
129     }
130
131     /* refuse to load unaligned EMF as Windows does */
132     if (emh->nBytes & 3)
133     {
134         WARN("Refusing to load unaligned EMF\n");
135         goto err;
136     }
137
138     return EMF_Create_HENHMETAFILE( emh, TRUE );
139
140 err:
141     UnmapViewOfFile( emh );
142     return 0;
143 }
144
145
146 /*****************************************************************************
147  *          GetEnhMetaFileA (GDI32.@)
148  *
149  *
150  */
151 HENHMETAFILE WINAPI GetEnhMetaFileA(
152              LPCSTR lpszMetaFile  /* [in] filename of enhanced metafile */
153     )
154 {
155     HENHMETAFILE hmf;
156     HANDLE hFile;
157
158     hFile = CreateFileA(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
159                         OPEN_EXISTING, 0, 0);
160     if (hFile == INVALID_HANDLE_VALUE) {
161         WARN("could not open %s\n", lpszMetaFile);
162         return 0;
163     }
164     hmf = EMF_GetEnhMetaFile( hFile );
165     CloseHandle( hFile );
166     return hmf;
167 }
168
169 /*****************************************************************************
170  *          GetEnhMetaFileW  (GDI32.@)
171  */
172 HENHMETAFILE WINAPI GetEnhMetaFileW(
173              LPCWSTR lpszMetaFile)  /* [in] filename of enhanced metafile */
174 {
175     HENHMETAFILE hmf;
176     HANDLE hFile;
177
178     hFile = CreateFileW(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
179                         OPEN_EXISTING, 0, 0);
180     if (hFile == INVALID_HANDLE_VALUE) {
181         WARN("could not open %s\n", debugstr_w(lpszMetaFile));
182         return 0;
183     }
184     hmf = EMF_GetEnhMetaFile( hFile );
185     CloseHandle( hFile );
186     return hmf;
187 }
188
189 /*****************************************************************************
190  *        GetEnhMetaFileHeader  (GDI32.@)
191  *
192  *  If buf is NULL, returns the size of buffer required.
193  *  Otherwise, copy up to bufsize bytes of enhanced metafile header into
194  *  buf.
195  */
196 UINT WINAPI GetEnhMetaFileHeader(
197        HENHMETAFILE hmf,   /* [in] enhanced metafile */
198        UINT bufsize,       /* [in] size of buffer */
199        LPENHMETAHEADER buf /* [out] buffer */
200     )
201 {
202     LPENHMETAHEADER emh;
203     UINT size;
204
205     emh = EMF_GetEnhMetaHeader(hmf);
206     if(!emh) return FALSE;
207     size = emh->nSize;
208     if (!buf) return size;
209     size = min(size, bufsize);
210     memmove(buf, emh, size);
211     return size;
212 }
213
214
215 /*****************************************************************************
216  *          GetEnhMetaFileDescriptionA  (GDI32.@)
217  */
218 UINT WINAPI GetEnhMetaFileDescriptionA(
219        HENHMETAFILE hmf, /* [in] enhanced metafile */
220        UINT size,        /* [in] size of buf */
221        LPSTR buf         /* [out] buffer to receive description */
222     )
223 {
224      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
225      DWORD len;
226      WCHAR *descrW;
227
228      if(!emh) return FALSE;
229      if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
230      descrW = (WCHAR *) ((char *) emh + emh->offDescription);
231      len = WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, NULL, 0, NULL, NULL );
232
233      if (!buf || !size ) return len;
234
235      len = min( size, len );
236      WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, buf, len, NULL, NULL );
237      return len;
238 }
239
240 /*****************************************************************************
241  *          GetEnhMetaFileDescriptionW  (GDI32.@)
242  *
243  *  Copies the description string of an enhanced metafile into a buffer
244  *  _buf_.
245  *
246  *  If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
247  *  number of characters copied.
248  */
249 UINT WINAPI GetEnhMetaFileDescriptionW(
250        HENHMETAFILE hmf, /* [in] enhanced metafile */
251        UINT size,        /* [in] size of buf */
252        LPWSTR buf        /* [out] buffer to receive description */
253     )
254 {
255      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
256
257      if(!emh) return FALSE;
258      if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
259      if (!buf || !size ) return emh->nDescription;
260
261      memmove(buf, (char *) emh + emh->offDescription, min(size,emh->nDescription)*sizeof(WCHAR));
262      return min(size, emh->nDescription);
263 }
264
265 /****************************************************************************
266  *    SetEnhMetaFileBits (GDI32.@)
267  *
268  *  Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
269  */
270 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
271 {
272     ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
273     memmove(emh, buf, bufsize);
274     return EMF_Create_HENHMETAFILE( emh, FALSE );
275 }
276
277 /*****************************************************************************
278  *  GetEnhMetaFileBits (GDI32.@)
279  *
280  */
281 UINT WINAPI GetEnhMetaFileBits(
282     HENHMETAFILE hmf,
283     UINT bufsize,
284     LPBYTE buf
285 )
286 {
287     LPENHMETAHEADER emh = EMF_GetEnhMetaHeader( hmf );
288     UINT size;
289
290     if(!emh) return 0;
291
292     size = emh->nBytes;
293     if( buf == NULL ) return size;
294
295     size = min( size, bufsize );
296     memmove(buf, emh, size);
297     return size;
298 }
299
300 typedef struct enum_emh_data
301 {
302     INT   mode;
303     XFORM init_transform;
304     XFORM world_transform;
305     INT   wndOrgX;
306     INT   wndOrgY;
307     INT   wndExtX;
308     INT   wndExtY;
309     INT   vportOrgX;
310     INT   vportOrgY;
311     INT   vportExtX;
312     INT   vportExtY;
313 } enum_emh_data;
314
315 #define ENUM_GET_PRIVATE_DATA(ht) \
316     ((enum_emh_data*)(((unsigned char*)(ht))-sizeof (enum_emh_data)))
317
318 #define WIDTH(rect) ( (rect).right - (rect).left )
319 #define HEIGHT(rect) ( (rect).bottom - (rect).top )
320
321 #define IS_WIN9X() (GetVersion()&0x80000000)
322
323 void EMF_Update_MF_Xform(HDC hdc, enum_emh_data *info)
324 {
325     XFORM mapping_mode_trans, final_trans;
326     FLOAT scaleX, scaleY;
327
328     scaleX = (FLOAT)info->vportExtX / (FLOAT)info->wndExtX;
329     scaleY = (FLOAT)info->vportExtY / (FLOAT)info->wndExtY;
330     mapping_mode_trans.eM11 = scaleX;
331     mapping_mode_trans.eM12 = 0.0;
332     mapping_mode_trans.eM21 = 0.0;
333     mapping_mode_trans.eM22 = scaleY;
334     mapping_mode_trans.eDx  = (FLOAT)info->vportOrgX - scaleX * (FLOAT)info->wndOrgX;
335     mapping_mode_trans.eDy  = (FLOAT)info->vportOrgY - scaleY * (FLOAT)info->wndOrgY;
336
337     CombineTransform(&final_trans, &info->world_transform, &mapping_mode_trans);
338     CombineTransform(&final_trans, &final_trans, &info->init_transform);
339  
340     if (!SetWorldTransform(hdc, &final_trans))
341     {
342         ERR("World transform failed!\n");
343     }
344 }
345
346 void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
347 {
348     INT horzSize = GetDeviceCaps( hdc, HORZSIZE );
349     INT vertSize = GetDeviceCaps( hdc, VERTSIZE );
350     INT horzRes  = GetDeviceCaps( hdc, HORZRES );
351     INT vertRes  = GetDeviceCaps( hdc, VERTRES );
352
353     TRACE("%d\n",info->mode);
354
355     switch(info->mode)
356     {
357     case MM_TEXT:
358         info->wndExtX   = 1;
359         info->wndExtY   = 1;
360         info->vportExtX = 1;
361         info->vportExtY = 1;
362         break;
363     case MM_LOMETRIC:
364     case MM_ISOTROPIC:
365         info->wndExtX   = horzSize * 10;
366         info->wndExtY   = vertSize * 10;
367         info->vportExtX = horzRes;
368         info->vportExtY = -vertRes;
369         break;
370     case MM_HIMETRIC:
371         info->wndExtX   = horzSize * 100;
372         info->wndExtY   = vertSize * 100;
373         info->vportExtX = horzRes;
374         info->vportExtY = -vertRes;
375         break;
376     case MM_LOENGLISH:
377         info->wndExtX   = MulDiv(1000, horzSize, 254);
378         info->wndExtY   = MulDiv(1000, vertSize, 254);
379         info->vportExtX = horzRes;
380         info->vportExtY = -vertRes;
381         break;
382     case MM_HIENGLISH:
383         info->wndExtX   = MulDiv(10000, horzSize, 254);
384         info->wndExtY   = MulDiv(10000, vertSize, 254);
385         info->vportExtX = horzRes;
386         info->vportExtY = -vertRes;
387         break;
388     case MM_TWIPS:
389         info->wndExtX   = MulDiv(14400, horzSize, 254);
390         info->wndExtY   = MulDiv(14400, vertSize, 254);
391         info->vportExtX = horzRes;
392         info->vportExtY = -vertRes;
393         break;
394     case MM_ANISOTROPIC:
395         break;
396     default:
397         return;
398     }
399 }
400
401 /*****************************************************************************
402  *       emr_produces_output
403  *
404  * Returns TRUE if the record type writes something to the dc.  Used by
405  * PlayEnhMetaFileRecord to determine whether it needs to update the
406  * dc's xform when in win9x mode.
407  *
408  * FIXME: need to test which records should be here.
409  */
410 static BOOL emr_produces_output(int type)
411 {
412     switch(type) {
413     case EMR_POLYBEZIER:
414     case EMR_POLYGON:
415     case EMR_POLYLINE:
416     case EMR_POLYBEZIERTO:
417     case EMR_POLYLINETO:
418     case EMR_POLYPOLYLINE:
419     case EMR_POLYPOLYGON:
420     case EMR_SETPIXELV:
421     case EMR_MOVETOEX:
422     case EMR_EXCLUDECLIPRECT:
423     case EMR_INTERSECTCLIPRECT:
424     case EMR_SELECTOBJECT:
425     case EMR_ANGLEARC:
426     case EMR_ELLIPSE:
427     case EMR_RECTANGLE:
428     case EMR_ROUNDRECT:
429     case EMR_ARC:
430     case EMR_CHORD:
431     case EMR_PIE:
432     case EMR_EXTFLOODFILL:
433     case EMR_LINETO:
434     case EMR_ARCTO:
435     case EMR_POLYDRAW:
436     case EMR_FILLRGN:
437     case EMR_FRAMERGN:
438     case EMR_INVERTRGN:
439     case EMR_PAINTRGN:
440     case EMR_BITBLT:
441     case EMR_STRETCHBLT:
442     case EMR_MASKBLT:
443     case EMR_PLGBLT:
444     case EMR_SETDIBITSTODEVICE:
445     case EMR_STRETCHDIBITS:
446     case EMR_EXTTEXTOUTA:
447     case EMR_EXTTEXTOUTW:
448     case EMR_POLYBEZIER16:
449     case EMR_POLYGON16:
450     case EMR_POLYLINE16:
451     case EMR_POLYBEZIERTO16:
452     case EMR_POLYLINETO16:
453     case EMR_POLYPOLYLINE16:
454     case EMR_POLYPOLYGON16:
455     case EMR_POLYDRAW16:
456     case EMR_POLYTEXTOUTA:
457     case EMR_POLYTEXTOUTW:
458     case EMR_SMALLTEXTOUT:
459     case EMR_TRANSPARENTBLT:
460         return TRUE;
461     default:
462         return FALSE;
463     }
464 }
465
466
467 /*****************************************************************************
468  *           PlayEnhMetaFileRecord  (GDI32.@)
469  *
470  *  Render a single enhanced metafile record in the device context hdc.
471  *
472  *  RETURNS
473  *    TRUE (non zero) on success, FALSE on error.
474  *  BUGS
475  *    Many unimplemented records.
476  *    No error handling on record play failures (ie checking return codes)
477  *
478  * NOTES
479  *    WinNT actually updates the current world transform in this function
480  *     whereas Win9x does not.
481  */
482 BOOL WINAPI PlayEnhMetaFileRecord(
483      HDC hdc,                   /* [in] device context in which to render EMF record */
484      LPHANDLETABLE handletable, /* [in] array of handles to be used in rendering record */
485      const ENHMETARECORD *mr,   /* [in] EMF record to render */
486      UINT handles               /* [in] size of handle array */
487      )
488 {
489   int type;
490   RECT tmprc;
491   enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
492
493   TRACE("hdc = %p, handletable = %p, record = %p, numHandles = %d\n",
494         hdc, handletable, mr, handles);
495   if (!mr) return FALSE;
496
497   type = mr->iType;
498
499   /* In Win9x mode we update the xform if the record will produce output */
500   if ( IS_WIN9X() && emr_produces_output(type) )
501      EMF_Update_MF_Xform(hdc, info);
502
503   TRACE(" type=%d\n", type);
504   switch(type)
505     {
506     case EMR_HEADER:
507       break;
508     case EMR_EOF:
509       break;
510     case EMR_GDICOMMENT:
511       {
512         PEMRGDICOMMENT lpGdiComment = (PEMRGDICOMMENT)mr;
513         /* In an enhanced metafile, there can be both public and private GDI comments */
514         GdiComment( hdc, lpGdiComment->cbData, lpGdiComment->Data );
515         break;
516       }
517     case EMR_SETMAPMODE:
518       {
519         PEMRSETMAPMODE pSetMapMode = (PEMRSETMAPMODE) mr;
520
521         if(info->mode == pSetMapMode->iMode && (info->mode == MM_ISOTROPIC || info->mode == MM_ANISOTROPIC))
522             break;
523         info->mode = pSetMapMode->iMode;
524         EMF_SetMapMode(hdc, info);
525         break;
526       }
527     case EMR_SETBKMODE:
528       {
529         PEMRSETBKMODE pSetBkMode = (PEMRSETBKMODE) mr;
530         SetBkMode(hdc, pSetBkMode->iMode);
531         break;
532       }
533     case EMR_SETBKCOLOR:
534       {
535         PEMRSETBKCOLOR pSetBkColor = (PEMRSETBKCOLOR) mr;
536         SetBkColor(hdc, pSetBkColor->crColor);
537         break;
538       }
539     case EMR_SETPOLYFILLMODE:
540       {
541         PEMRSETPOLYFILLMODE pSetPolyFillMode = (PEMRSETPOLYFILLMODE) mr;
542         SetPolyFillMode(hdc, pSetPolyFillMode->iMode);
543         break;
544       }
545     case EMR_SETROP2:
546       {
547         PEMRSETROP2 pSetROP2 = (PEMRSETROP2) mr;
548         SetROP2(hdc, pSetROP2->iMode);
549         break;
550       }
551     case EMR_SETSTRETCHBLTMODE:
552       {
553         PEMRSETSTRETCHBLTMODE pSetStretchBltMode = (PEMRSETSTRETCHBLTMODE) mr;
554         SetStretchBltMode(hdc, pSetStretchBltMode->iMode);
555         break;
556       }
557     case EMR_SETTEXTALIGN:
558       {
559         PEMRSETTEXTALIGN pSetTextAlign = (PEMRSETTEXTALIGN) mr;
560         SetTextAlign(hdc, pSetTextAlign->iMode);
561         break;
562       }
563     case EMR_SETTEXTCOLOR:
564       {
565         PEMRSETTEXTCOLOR pSetTextColor = (PEMRSETTEXTCOLOR) mr;
566         SetTextColor(hdc, pSetTextColor->crColor);
567         break;
568       }
569     case EMR_SAVEDC:
570       {
571         SaveDC(hdc);
572         break;
573       }
574     case EMR_RESTOREDC:
575       {
576         PEMRRESTOREDC pRestoreDC = (PEMRRESTOREDC) mr;
577         RestoreDC(hdc, pRestoreDC->iRelative);
578         break;
579       }
580     case EMR_INTERSECTCLIPRECT:
581       {
582         PEMRINTERSECTCLIPRECT pClipRect = (PEMRINTERSECTCLIPRECT) mr;
583         IntersectClipRect(hdc, pClipRect->rclClip.left, pClipRect->rclClip.top,
584                           pClipRect->rclClip.right, pClipRect->rclClip.bottom);
585         break;
586       }
587     case EMR_SELECTOBJECT:
588       {
589         PEMRSELECTOBJECT pSelectObject = (PEMRSELECTOBJECT) mr;
590         if( pSelectObject->ihObject & 0x80000000 ) {
591           /* High order bit is set - it's a stock object
592            * Strip the high bit to get the index.
593            * See MSDN article Q142319
594            */
595           SelectObject( hdc, GetStockObject( pSelectObject->ihObject &
596                                              0x7fffffff ) );
597         } else {
598           /* High order bit wasn't set - not a stock object
599            */
600               SelectObject( hdc,
601                         (handletable->objectHandle)[pSelectObject->ihObject] );
602         }
603         break;
604       }
605     case EMR_DELETEOBJECT:
606       {
607         PEMRDELETEOBJECT pDeleteObject = (PEMRDELETEOBJECT) mr;
608         DeleteObject( (handletable->objectHandle)[pDeleteObject->ihObject]);
609         (handletable->objectHandle)[pDeleteObject->ihObject] = 0;
610         break;
611       }
612     case EMR_SETWINDOWORGEX:
613       {
614         PEMRSETWINDOWORGEX pSetWindowOrgEx = (PEMRSETWINDOWORGEX) mr;
615
616         info->wndOrgX = pSetWindowOrgEx->ptlOrigin.x;
617         info->wndOrgY = pSetWindowOrgEx->ptlOrigin.y;
618
619         TRACE("SetWindowOrgEx: %d,%d\n",info->wndOrgX,info->wndOrgY);
620         break;
621       }
622     case EMR_SETWINDOWEXTEX:
623       {
624         PEMRSETWINDOWEXTEX pSetWindowExtEx = (PEMRSETWINDOWEXTEX) mr;
625         
626         if(info->mode != MM_ISOTROPIC && info->mode != MM_ANISOTROPIC)
627             break;
628         info->wndExtX = pSetWindowExtEx->szlExtent.cx;
629         info->wndExtY = pSetWindowExtEx->szlExtent.cy;
630
631         TRACE("SetWindowExtEx: %d,%d\n",info->wndExtX,info->wndExtY);
632         break;
633       }
634     case EMR_SETVIEWPORTORGEX:
635       {
636         PEMRSETVIEWPORTORGEX pSetViewportOrgEx = (PEMRSETVIEWPORTORGEX) mr;
637         enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
638
639         info->vportOrgX = pSetViewportOrgEx->ptlOrigin.x;
640         info->vportOrgY = pSetViewportOrgEx->ptlOrigin.y;
641         TRACE("SetViewportOrgEx: %d,%d\n",info->vportOrgX,info->vportOrgY);
642         break;
643       }
644     case EMR_SETVIEWPORTEXTEX:
645       {
646         PEMRSETVIEWPORTEXTEX pSetViewportExtEx = (PEMRSETVIEWPORTEXTEX) mr;
647         enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
648
649         if(info->mode != MM_ISOTROPIC && info->mode != MM_ANISOTROPIC)
650             break;
651         info->vportExtX = pSetViewportExtEx->szlExtent.cx;
652         info->vportExtY = pSetViewportExtEx->szlExtent.cy;
653         TRACE("SetViewportExtEx: %d,%d\n",info->vportExtX,info->vportExtY);
654         break;
655       }
656     case EMR_CREATEPEN:
657       {
658         PEMRCREATEPEN pCreatePen = (PEMRCREATEPEN) mr;
659         (handletable->objectHandle)[pCreatePen->ihPen] =
660           CreatePenIndirect(&pCreatePen->lopn);
661         break;
662       }
663     case EMR_EXTCREATEPEN:
664       {
665         PEMREXTCREATEPEN pPen = (PEMREXTCREATEPEN) mr;
666         LOGBRUSH lb;
667         lb.lbStyle = pPen->elp.elpBrushStyle;
668         lb.lbColor = pPen->elp.elpColor;
669         lb.lbHatch = pPen->elp.elpHatch;
670
671         if(pPen->offBmi || pPen->offBits)
672           FIXME("EMR_EXTCREATEPEN: Need to copy brush bitmap\n");
673
674         (handletable->objectHandle)[pPen->ihPen] =
675           ExtCreatePen(pPen->elp.elpPenStyle, pPen->elp.elpWidth, &lb,
676                        pPen->elp.elpNumEntries, pPen->elp.elpStyleEntry);
677         break;
678       }
679     case EMR_CREATEBRUSHINDIRECT:
680       {
681         PEMRCREATEBRUSHINDIRECT pBrush = (PEMRCREATEBRUSHINDIRECT) mr;
682         (handletable->objectHandle)[pBrush->ihBrush] =
683           CreateBrushIndirect(&pBrush->lb);
684         break;
685       }
686     case EMR_EXTCREATEFONTINDIRECTW:
687       {
688         PEMREXTCREATEFONTINDIRECTW pFont = (PEMREXTCREATEFONTINDIRECTW) mr;
689         (handletable->objectHandle)[pFont->ihFont] =
690           CreateFontIndirectW(&pFont->elfw.elfLogFont);
691         break;
692       }
693     case EMR_MOVETOEX:
694       {
695         PEMRMOVETOEX pMoveToEx = (PEMRMOVETOEX) mr;
696         MoveToEx(hdc, pMoveToEx->ptl.x, pMoveToEx->ptl.y, NULL);
697         break;
698       }
699     case EMR_LINETO:
700       {
701         PEMRLINETO pLineTo = (PEMRLINETO) mr;
702         LineTo(hdc, pLineTo->ptl.x, pLineTo->ptl.y);
703         break;
704       }
705     case EMR_RECTANGLE:
706       {
707         PEMRRECTANGLE pRect = (PEMRRECTANGLE) mr;
708         Rectangle(hdc, pRect->rclBox.left, pRect->rclBox.top,
709                   pRect->rclBox.right, pRect->rclBox.bottom);
710         break;
711       }
712     case EMR_ELLIPSE:
713       {
714         PEMRELLIPSE pEllipse = (PEMRELLIPSE) mr;
715         Ellipse(hdc, pEllipse->rclBox.left, pEllipse->rclBox.top,
716                 pEllipse->rclBox.right, pEllipse->rclBox.bottom);
717         break;
718       }
719     case EMR_POLYGON16:
720       {
721         PEMRPOLYGON16 pPoly = (PEMRPOLYGON16) mr;
722         /* Shouldn't use Polygon16 since pPoly->cpts is DWORD */
723         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
724                                 pPoly->cpts * sizeof(POINT) );
725         DWORD i;
726         for(i = 0; i < pPoly->cpts; i++)
727           CONV_POINT16TO32(pPoly->apts + i, pts + i);
728         Polygon(hdc, pts, pPoly->cpts);
729         HeapFree( GetProcessHeap(), 0, pts );
730         break;
731       }
732     case EMR_POLYLINE16:
733       {
734         PEMRPOLYLINE16 pPoly = (PEMRPOLYLINE16) mr;
735         /* Shouldn't use Polyline16 since pPoly->cpts is DWORD */
736         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
737                                 pPoly->cpts * sizeof(POINT) );
738         DWORD i;
739         for(i = 0; i < pPoly->cpts; i++)
740           CONV_POINT16TO32(pPoly->apts + i, pts + i);
741         Polyline(hdc, pts, pPoly->cpts);
742         HeapFree( GetProcessHeap(), 0, pts );
743         break;
744       }
745     case EMR_POLYLINETO16:
746       {
747         PEMRPOLYLINETO16 pPoly = (PEMRPOLYLINETO16) mr;
748         /* Shouldn't use PolylineTo16 since pPoly->cpts is DWORD */
749         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
750                                 pPoly->cpts * sizeof(POINT) );
751         DWORD i;
752         for(i = 0; i < pPoly->cpts; i++)
753           CONV_POINT16TO32(pPoly->apts + i, pts + i);
754         PolylineTo(hdc, pts, pPoly->cpts);
755         HeapFree( GetProcessHeap(), 0, pts );
756         break;
757       }
758     case EMR_POLYBEZIER16:
759       {
760         PEMRPOLYBEZIER16 pPoly = (PEMRPOLYBEZIER16) mr;
761         /* Shouldn't use PolyBezier16 since pPoly->cpts is DWORD */
762         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
763                                 pPoly->cpts * sizeof(POINT) );
764         DWORD i;
765         for(i = 0; i < pPoly->cpts; i++)
766           CONV_POINT16TO32(pPoly->apts + i, pts + i);
767         PolyBezier(hdc, pts, pPoly->cpts);
768         HeapFree( GetProcessHeap(), 0, pts );
769         break;
770       }
771     case EMR_POLYBEZIERTO16:
772       {
773         PEMRPOLYBEZIERTO16 pPoly = (PEMRPOLYBEZIERTO16) mr;
774         /* Shouldn't use PolyBezierTo16 since pPoly->cpts is DWORD */
775         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
776                                 pPoly->cpts * sizeof(POINT) );
777         DWORD i;
778         for(i = 0; i < pPoly->cpts; i++)
779           CONV_POINT16TO32(pPoly->apts + i, pts + i);
780         PolyBezierTo(hdc, pts, pPoly->cpts);
781         HeapFree( GetProcessHeap(), 0, pts );
782         break;
783       }
784     case EMR_POLYPOLYGON16:
785       {
786         PEMRPOLYPOLYGON16 pPolyPoly = (PEMRPOLYPOLYGON16) mr;
787         /* NB POINTS array doesn't start at pPolyPoly->apts it's actually
788            pPolyPoly->aPolyCounts + pPolyPoly->nPolys */
789
790         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
791                                 pPolyPoly->cpts * sizeof(POINT) );
792         DWORD i;
793         for(i = 0; i < pPolyPoly->cpts; i++)
794           CONV_POINT16TO32((POINT16*) (pPolyPoly->aPolyCounts +
795                                       pPolyPoly->nPolys) + i, pts + i);
796
797         PolyPolygon(hdc, pts, (INT*)pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
798         HeapFree( GetProcessHeap(), 0, pts );
799         break;
800       }
801     case EMR_POLYPOLYLINE16:
802       {
803         PEMRPOLYPOLYLINE16 pPolyPoly = (PEMRPOLYPOLYLINE16) mr;
804         /* NB POINTS array doesn't start at pPolyPoly->apts it's actually
805            pPolyPoly->aPolyCounts + pPolyPoly->nPolys */
806
807         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
808                                 pPolyPoly->cpts * sizeof(POINT) );
809         DWORD i;
810         for(i = 0; i < pPolyPoly->cpts; i++)
811           CONV_POINT16TO32((POINT16*) (pPolyPoly->aPolyCounts +
812                                       pPolyPoly->nPolys) + i, pts + i);
813
814         PolyPolyline(hdc, pts, pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
815         HeapFree( GetProcessHeap(), 0, pts );
816         break;
817       }
818
819     case EMR_STRETCHDIBITS:
820       {
821         EMRSTRETCHDIBITS *pStretchDIBits = (EMRSTRETCHDIBITS *)mr;
822
823         StretchDIBits(hdc,
824                       pStretchDIBits->xDest,
825                       pStretchDIBits->yDest,
826                       pStretchDIBits->cxDest,
827                       pStretchDIBits->cyDest,
828                       pStretchDIBits->xSrc,
829                       pStretchDIBits->ySrc,
830                       pStretchDIBits->cxSrc,
831                       pStretchDIBits->cySrc,
832                       (BYTE *)mr + pStretchDIBits->offBitsSrc,
833                       (const BITMAPINFO *)((BYTE *)mr + pStretchDIBits->offBmiSrc),
834                       pStretchDIBits->iUsageSrc,
835                       pStretchDIBits->dwRop);
836         break;
837       }
838
839     case EMR_EXTTEXTOUTA:
840     {
841         PEMREXTTEXTOUTA pExtTextOutA = (PEMREXTTEXTOUTA)mr;
842         RECT rc;
843
844         rc.left = pExtTextOutA->emrtext.rcl.left;
845         rc.top = pExtTextOutA->emrtext.rcl.top;
846         rc.right = pExtTextOutA->emrtext.rcl.right;
847         rc.bottom = pExtTextOutA->emrtext.rcl.bottom;
848         ExtTextOutA(hdc, pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y,
849             pExtTextOutA->emrtext.fOptions, &rc,
850             (LPSTR)((BYTE *)mr + pExtTextOutA->emrtext.offString), pExtTextOutA->emrtext.nChars,
851             (INT *)((BYTE *)mr + pExtTextOutA->emrtext.offDx));
852         break;
853     }
854
855     case EMR_EXTTEXTOUTW:
856     {
857         PEMREXTTEXTOUTW pExtTextOutW = (PEMREXTTEXTOUTW)mr;
858         RECT rc;
859
860         rc.left = pExtTextOutW->emrtext.rcl.left;
861         rc.top = pExtTextOutW->emrtext.rcl.top;
862         rc.right = pExtTextOutW->emrtext.rcl.right;
863         rc.bottom = pExtTextOutW->emrtext.rcl.bottom;
864         ExtTextOutW(hdc, pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y,
865             pExtTextOutW->emrtext.fOptions, &rc,
866             (LPWSTR)((BYTE *)mr + pExtTextOutW->emrtext.offString), pExtTextOutW->emrtext.nChars,
867             (INT *)((BYTE *)mr + pExtTextOutW->emrtext.offDx));
868         break;
869     }
870
871     case EMR_CREATEPALETTE:
872       {
873         PEMRCREATEPALETTE lpCreatePal = (PEMRCREATEPALETTE)mr;
874
875         (handletable->objectHandle)[ lpCreatePal->ihPal ] =
876                 CreatePalette( &lpCreatePal->lgpl );
877
878         break;
879       }
880
881     case EMR_SELECTPALETTE:
882       {
883         PEMRSELECTPALETTE lpSelectPal = (PEMRSELECTPALETTE)mr;
884
885         if( lpSelectPal->ihPal & 0x80000000 ) {
886                 SelectPalette( hdc, GetStockObject(lpSelectPal->ihPal & 0x7fffffff), TRUE);
887         } else {
888         (handletable->objectHandle)[ lpSelectPal->ihPal ] =
889                 SelectPalette( hdc, (handletable->objectHandle)[lpSelectPal->ihPal], TRUE);
890         }
891         break;
892       }
893
894     case EMR_REALIZEPALETTE:
895       {
896         RealizePalette( hdc );
897         break;
898       }
899
900     case EMR_EXTSELECTCLIPRGN:
901       {
902 #if 0
903         PEMREXTSELECTCLIPRGN lpRgn = (PEMREXTSELECTCLIPRGN)mr;
904         HRGN hRgn = ExtCreateRegion(NULL, lpRgn->cbRgnData, (RGNDATA *)lpRgn->RgnData);
905         ExtSelectClipRgn(hdc, hRgn, (INT)(lpRgn->iMode));
906         /* ExtSelectClipRgn created a copy of the region */
907         DeleteObject(hRgn);
908 #endif
909         FIXME("ExtSelectClipRgn\n");
910         break;
911       }
912
913     case EMR_SETMETARGN:
914       {
915         SetMetaRgn( hdc );
916         break;
917       }
918
919     case EMR_SETWORLDTRANSFORM:
920       {
921         PEMRSETWORLDTRANSFORM lpXfrm = (PEMRSETWORLDTRANSFORM)mr;
922         info->world_transform = lpXfrm->xform;
923         break;
924       }
925
926     case EMR_POLYBEZIER:
927       {
928         PEMRPOLYBEZIER lpPolyBez = (PEMRPOLYBEZIER)mr;
929         PolyBezier(hdc, (const LPPOINT)lpPolyBez->aptl, (UINT)lpPolyBez->cptl);
930         break;
931       }
932
933     case EMR_POLYGON:
934       {
935         PEMRPOLYGON lpPoly = (PEMRPOLYGON)mr;
936         Polygon( hdc, (const LPPOINT)lpPoly->aptl, (UINT)lpPoly->cptl );
937         break;
938       }
939
940     case EMR_POLYLINE:
941       {
942         PEMRPOLYLINE lpPolyLine = (PEMRPOLYLINE)mr;
943         Polyline(hdc, (const LPPOINT)lpPolyLine->aptl, (UINT)lpPolyLine->cptl);
944         break;
945       }
946
947     case EMR_POLYBEZIERTO:
948       {
949         PEMRPOLYBEZIERTO lpPolyBezierTo = (PEMRPOLYBEZIERTO)mr;
950         PolyBezierTo( hdc, (const LPPOINT)lpPolyBezierTo->aptl,
951                       (UINT)lpPolyBezierTo->cptl );
952         break;
953       }
954
955     case EMR_POLYLINETO:
956       {
957         PEMRPOLYLINETO lpPolyLineTo = (PEMRPOLYLINETO)mr;
958         PolylineTo( hdc, (const LPPOINT)lpPolyLineTo->aptl,
959                     (UINT)lpPolyLineTo->cptl );
960         break;
961       }
962
963     case EMR_POLYPOLYLINE:
964       {
965         PEMRPOLYPOLYLINE pPolyPolyline = (PEMRPOLYPOLYLINE) mr;
966         /* NB Points at pPolyPolyline->aPolyCounts + pPolyPolyline->nPolys */
967
968         PolyPolyline(hdc, (LPPOINT)(pPolyPolyline->aPolyCounts +
969                                     pPolyPolyline->nPolys),
970                      pPolyPolyline->aPolyCounts,
971                      pPolyPolyline->nPolys );
972
973         break;
974       }
975
976     case EMR_POLYPOLYGON:
977       {
978         PEMRPOLYPOLYGON pPolyPolygon = (PEMRPOLYPOLYGON) mr;
979
980         /* NB Points at pPolyPolygon->aPolyCounts + pPolyPolygon->nPolys */
981
982         PolyPolygon(hdc, (LPPOINT)(pPolyPolygon->aPolyCounts +
983                                    pPolyPolygon->nPolys),
984                     (INT*)pPolyPolygon->aPolyCounts, pPolyPolygon->nPolys );
985         break;
986       }
987
988     case EMR_SETBRUSHORGEX:
989       {
990         PEMRSETBRUSHORGEX lpSetBrushOrgEx = (PEMRSETBRUSHORGEX)mr;
991
992         SetBrushOrgEx( hdc,
993                        (INT)lpSetBrushOrgEx->ptlOrigin.x,
994                        (INT)lpSetBrushOrgEx->ptlOrigin.y,
995                        NULL );
996
997         break;
998       }
999
1000     case EMR_SETPIXELV:
1001       {
1002         PEMRSETPIXELV lpSetPixelV = (PEMRSETPIXELV)mr;
1003
1004         SetPixelV( hdc,
1005                    (INT)lpSetPixelV->ptlPixel.x,
1006                    (INT)lpSetPixelV->ptlPixel.y,
1007                    lpSetPixelV->crColor );
1008
1009         break;
1010       }
1011
1012     case EMR_SETMAPPERFLAGS:
1013       {
1014         PEMRSETMAPPERFLAGS lpSetMapperFlags = (PEMRSETMAPPERFLAGS)mr;
1015
1016         SetMapperFlags( hdc, lpSetMapperFlags->dwFlags );
1017
1018         break;
1019       }
1020
1021     case EMR_SETCOLORADJUSTMENT:
1022       {
1023         PEMRSETCOLORADJUSTMENT lpSetColorAdjust = (PEMRSETCOLORADJUSTMENT)mr;
1024
1025         SetColorAdjustment( hdc, &lpSetColorAdjust->ColorAdjustment );
1026
1027         break;
1028       }
1029
1030     case EMR_OFFSETCLIPRGN:
1031       {
1032         PEMROFFSETCLIPRGN lpOffsetClipRgn = (PEMROFFSETCLIPRGN)mr;
1033
1034         OffsetClipRgn( hdc,
1035                        (INT)lpOffsetClipRgn->ptlOffset.x,
1036                        (INT)lpOffsetClipRgn->ptlOffset.y );
1037         FIXME("OffsetClipRgn\n");
1038
1039         break;
1040       }
1041
1042     case EMR_EXCLUDECLIPRECT:
1043       {
1044         PEMREXCLUDECLIPRECT lpExcludeClipRect = (PEMREXCLUDECLIPRECT)mr;
1045
1046         ExcludeClipRect( hdc,
1047                          lpExcludeClipRect->rclClip.left,
1048                          lpExcludeClipRect->rclClip.top,
1049                          lpExcludeClipRect->rclClip.right,
1050                          lpExcludeClipRect->rclClip.bottom  );
1051         FIXME("ExcludeClipRect\n");
1052
1053          break;
1054       }
1055
1056     case EMR_SCALEVIEWPORTEXTEX:
1057       {
1058         PEMRSCALEVIEWPORTEXTEX lpScaleViewportExtEx = (PEMRSCALEVIEWPORTEXTEX)mr;
1059
1060         if ((info->mode != MM_ISOTROPIC) && (info->mode != MM_ANISOTROPIC))
1061             break;
1062         if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom || 
1063             !lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->yDenom)
1064             break;
1065         info->vportExtX = (info->vportExtX * lpScaleViewportExtEx->xNum) / 
1066                                   lpScaleViewportExtEx->xDenom;
1067         info->vportExtY = (info->vportExtY * lpScaleViewportExtEx->yNum) / 
1068                                   lpScaleViewportExtEx->yDenom;
1069         if (info->vportExtX == 0) info->vportExtX = 1;
1070         if (info->vportExtY == 0) info->vportExtY = 1;
1071         if (info->mode == MM_ISOTROPIC)
1072             FIXME("EMRSCALEVIEWPORTEXTEX MM_ISOTROPIC mapping\n");
1073             /* MAPPING_FixIsotropic( dc ); */
1074
1075         TRACE("EMRSCALEVIEWPORTEXTEX %ld/%ld %ld/%ld\n",
1076              lpScaleViewportExtEx->xNum,lpScaleViewportExtEx->xDenom,
1077              lpScaleViewportExtEx->yNum,lpScaleViewportExtEx->yDenom);
1078
1079         break;
1080       }
1081
1082     case EMR_SCALEWINDOWEXTEX:
1083       {
1084         PEMRSCALEWINDOWEXTEX lpScaleWindowExtEx = (PEMRSCALEWINDOWEXTEX)mr;
1085
1086         if ((info->mode != MM_ISOTROPIC) && (info->mode != MM_ANISOTROPIC))
1087             break;
1088         if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom || 
1089             !lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->yDenom)
1090             break;
1091         info->wndExtX = (info->wndExtX * lpScaleWindowExtEx->xNum) / 
1092                                   lpScaleWindowExtEx->xDenom;
1093         info->wndExtY = (info->wndExtY * lpScaleWindowExtEx->yNum) / 
1094                                   lpScaleWindowExtEx->yDenom;
1095         if (info->wndExtX == 0) info->wndExtX = 1;
1096         if (info->wndExtY == 0) info->wndExtY = 1;
1097         if (info->mode == MM_ISOTROPIC)
1098             FIXME("EMRSCALEWINDOWEXTEX MM_ISOTROPIC mapping\n");
1099             /* MAPPING_FixIsotropic( dc ); */
1100
1101         TRACE("EMRSCALEWINDOWEXTEX %ld/%ld %ld/%ld\n",
1102              lpScaleWindowExtEx->xNum,lpScaleWindowExtEx->xDenom,
1103              lpScaleWindowExtEx->yNum,lpScaleWindowExtEx->yDenom);
1104
1105         break;
1106       }
1107
1108     case EMR_MODIFYWORLDTRANSFORM:
1109       {
1110         PEMRMODIFYWORLDTRANSFORM lpModifyWorldTrans = (PEMRMODIFYWORLDTRANSFORM)mr;
1111
1112         switch(lpModifyWorldTrans->iMode) {
1113         case MWT_IDENTITY:
1114             info->world_transform.eM11 = info->world_transform.eM22 = 1;
1115             info->world_transform.eM12 = info->world_transform.eM21 = 0;
1116             info->world_transform.eDx  = info->world_transform.eDy  = 0;
1117             break;
1118         case MWT_LEFTMULTIPLY:
1119             CombineTransform(&info->world_transform, &lpModifyWorldTrans->xform,
1120                              &info->world_transform);
1121             break;
1122         case MWT_RIGHTMULTIPLY:
1123             CombineTransform(&info->world_transform, &info->world_transform,
1124                              &lpModifyWorldTrans->xform);
1125             break;
1126         default:
1127             FIXME("Unknown imode %ld\n", lpModifyWorldTrans->iMode);
1128             break;
1129         }
1130         break;
1131       }
1132
1133     case EMR_ANGLEARC:
1134       {
1135         PEMRANGLEARC lpAngleArc = (PEMRANGLEARC)mr;
1136
1137         AngleArc( hdc,
1138                  (INT)lpAngleArc->ptlCenter.x, (INT)lpAngleArc->ptlCenter.y,
1139                  lpAngleArc->nRadius, lpAngleArc->eStartAngle,
1140                  lpAngleArc->eSweepAngle );
1141
1142         break;
1143       }
1144
1145     case EMR_ROUNDRECT:
1146       {
1147         PEMRROUNDRECT lpRoundRect = (PEMRROUNDRECT)mr;
1148
1149         RoundRect( hdc,
1150                    lpRoundRect->rclBox.left,
1151                    lpRoundRect->rclBox.top,
1152                    lpRoundRect->rclBox.right,
1153                    lpRoundRect->rclBox.bottom,
1154                    lpRoundRect->szlCorner.cx,
1155                    lpRoundRect->szlCorner.cy );
1156
1157         break;
1158       }
1159
1160     case EMR_ARC:
1161       {
1162         PEMRARC lpArc = (PEMRARC)mr;
1163
1164         Arc( hdc,
1165              (INT)lpArc->rclBox.left,
1166              (INT)lpArc->rclBox.top,
1167              (INT)lpArc->rclBox.right,
1168              (INT)lpArc->rclBox.bottom,
1169              (INT)lpArc->ptlStart.x,
1170              (INT)lpArc->ptlStart.y,
1171              (INT)lpArc->ptlEnd.x,
1172              (INT)lpArc->ptlEnd.y );
1173
1174         break;
1175       }
1176
1177     case EMR_CHORD:
1178       {
1179         PEMRCHORD lpChord = (PEMRCHORD)mr;
1180
1181         Chord( hdc,
1182              (INT)lpChord->rclBox.left,
1183              (INT)lpChord->rclBox.top,
1184              (INT)lpChord->rclBox.right,
1185              (INT)lpChord->rclBox.bottom,
1186              (INT)lpChord->ptlStart.x,
1187              (INT)lpChord->ptlStart.y,
1188              (INT)lpChord->ptlEnd.x,
1189              (INT)lpChord->ptlEnd.y );
1190
1191         break;
1192       }
1193
1194     case EMR_PIE:
1195       {
1196         PEMRPIE lpPie = (PEMRPIE)mr;
1197
1198         Pie( hdc,
1199              (INT)lpPie->rclBox.left,
1200              (INT)lpPie->rclBox.top,
1201              (INT)lpPie->rclBox.right,
1202              (INT)lpPie->rclBox.bottom,
1203              (INT)lpPie->ptlStart.x,
1204              (INT)lpPie->ptlStart.y,
1205              (INT)lpPie->ptlEnd.x,
1206              (INT)lpPie->ptlEnd.y );
1207
1208        break;
1209       }
1210
1211     case EMR_ARCTO:
1212       {
1213         PEMRARC lpArcTo = (PEMRARC)mr;
1214
1215         ArcTo( hdc,
1216                (INT)lpArcTo->rclBox.left,
1217                (INT)lpArcTo->rclBox.top,
1218                (INT)lpArcTo->rclBox.right,
1219                (INT)lpArcTo->rclBox.bottom,
1220                (INT)lpArcTo->ptlStart.x,
1221                (INT)lpArcTo->ptlStart.y,
1222                (INT)lpArcTo->ptlEnd.x,
1223                (INT)lpArcTo->ptlEnd.y );
1224
1225         break;
1226       }
1227
1228     case EMR_EXTFLOODFILL:
1229       {
1230         PEMREXTFLOODFILL lpExtFloodFill = (PEMREXTFLOODFILL)mr;
1231
1232         ExtFloodFill( hdc,
1233                       (INT)lpExtFloodFill->ptlStart.x,
1234                       (INT)lpExtFloodFill->ptlStart.y,
1235                       lpExtFloodFill->crColor,
1236                       (UINT)lpExtFloodFill->iMode );
1237
1238         break;
1239       }
1240
1241     case EMR_POLYDRAW:
1242       {
1243         PEMRPOLYDRAW lpPolyDraw = (PEMRPOLYDRAW)mr;
1244         PolyDraw( hdc,
1245                   (const LPPOINT)lpPolyDraw->aptl,
1246                   lpPolyDraw->abTypes,
1247                   (INT)lpPolyDraw->cptl );
1248
1249         break;
1250       }
1251
1252     case EMR_SETARCDIRECTION:
1253       {
1254         PEMRSETARCDIRECTION lpSetArcDirection = (PEMRSETARCDIRECTION)mr;
1255         SetArcDirection( hdc, (INT)lpSetArcDirection->iArcDirection );
1256         break;
1257       }
1258
1259     case EMR_SETMITERLIMIT:
1260       {
1261         PEMRSETMITERLIMIT lpSetMiterLimit = (PEMRSETMITERLIMIT)mr;
1262         SetMiterLimit( hdc, lpSetMiterLimit->eMiterLimit, NULL );
1263         break;
1264       }
1265
1266     case EMR_BEGINPATH:
1267       {
1268         BeginPath( hdc );
1269         break;
1270       }
1271
1272     case EMR_ENDPATH:
1273       {
1274         EndPath( hdc );
1275         break;
1276       }
1277
1278     case EMR_CLOSEFIGURE:
1279       {
1280         CloseFigure( hdc );
1281         break;
1282       }
1283
1284     case EMR_FILLPATH:
1285       {
1286         /*PEMRFILLPATH lpFillPath = (PEMRFILLPATH)mr;*/
1287         FillPath( hdc );
1288         break;
1289       }
1290
1291     case EMR_STROKEANDFILLPATH:
1292       {
1293         /*PEMRSTROKEANDFILLPATH lpStrokeAndFillPath = (PEMRSTROKEANDFILLPATH)mr;*/
1294         StrokeAndFillPath( hdc );
1295         break;
1296       }
1297
1298     case EMR_STROKEPATH:
1299       {
1300         /*PEMRSTROKEPATH lpStrokePath = (PEMRSTROKEPATH)mr;*/
1301         StrokePath( hdc );
1302         break;
1303       }
1304
1305     case EMR_FLATTENPATH:
1306       {
1307         FlattenPath( hdc );
1308         break;
1309       }
1310
1311     case EMR_WIDENPATH:
1312       {
1313         WidenPath( hdc );
1314         break;
1315       }
1316
1317     case EMR_SELECTCLIPPATH:
1318       {
1319         PEMRSELECTCLIPPATH lpSelectClipPath = (PEMRSELECTCLIPPATH)mr;
1320         SelectClipPath( hdc, (INT)lpSelectClipPath->iMode );
1321         break;
1322       }
1323
1324     case EMR_ABORTPATH:
1325       {
1326         AbortPath( hdc );
1327         break;
1328       }
1329
1330     case EMR_CREATECOLORSPACE:
1331       {
1332         PEMRCREATECOLORSPACE lpCreateColorSpace = (PEMRCREATECOLORSPACE)mr;
1333         (handletable->objectHandle)[lpCreateColorSpace->ihCS] =
1334            CreateColorSpaceA( &lpCreateColorSpace->lcs );
1335         break;
1336       }
1337
1338     case EMR_SETCOLORSPACE:
1339       {
1340         PEMRSETCOLORSPACE lpSetColorSpace = (PEMRSETCOLORSPACE)mr;
1341         SetColorSpace( hdc,
1342                        (handletable->objectHandle)[lpSetColorSpace->ihCS] );
1343         break;
1344       }
1345
1346     case EMR_DELETECOLORSPACE:
1347       {
1348         PEMRDELETECOLORSPACE lpDeleteColorSpace = (PEMRDELETECOLORSPACE)mr;
1349         DeleteColorSpace( (handletable->objectHandle)[lpDeleteColorSpace->ihCS] );
1350         break;
1351       }
1352
1353     case EMR_SETICMMODE:
1354       {
1355         PEMRSETICMMODE lpSetICMMode = (PEMRSETICMMODE)mr;
1356         SetICMMode( hdc, (INT)lpSetICMMode->iMode );
1357         break;
1358       }
1359
1360     case EMR_PIXELFORMAT:
1361       {
1362         INT iPixelFormat;
1363         PEMRPIXELFORMAT lpPixelFormat = (PEMRPIXELFORMAT)mr;
1364
1365         iPixelFormat = ChoosePixelFormat( hdc, &lpPixelFormat->pfd );
1366         SetPixelFormat( hdc, iPixelFormat, &lpPixelFormat->pfd );
1367
1368         break;
1369       }
1370
1371     case EMR_SETPALETTEENTRIES:
1372       {
1373         PEMRSETPALETTEENTRIES lpSetPaletteEntries = (PEMRSETPALETTEENTRIES)mr;
1374
1375         SetPaletteEntries( (handletable->objectHandle)[lpSetPaletteEntries->ihPal],
1376                            (UINT)lpSetPaletteEntries->iStart,
1377                            (UINT)lpSetPaletteEntries->cEntries,
1378                            lpSetPaletteEntries->aPalEntries );
1379
1380         break;
1381       }
1382
1383     case EMR_RESIZEPALETTE:
1384       {
1385         PEMRRESIZEPALETTE lpResizePalette = (PEMRRESIZEPALETTE)mr;
1386
1387         ResizePalette( (handletable->objectHandle)[lpResizePalette->ihPal],
1388                        (UINT)lpResizePalette->cEntries );
1389
1390         break;
1391       }
1392
1393     case EMR_CREATEDIBPATTERNBRUSHPT:
1394       {
1395         PEMRCREATEDIBPATTERNBRUSHPT lpCreate = (PEMRCREATEDIBPATTERNBRUSHPT)mr;
1396         LPVOID lpPackedStruct;
1397
1398         /* check that offsets and data are contained within the record */
1399         if ( !( (lpCreate->cbBmi>=0) && (lpCreate->cbBits>=0) &&
1400                 (lpCreate->offBmi>=0) && (lpCreate->offBits>=0) &&
1401                 ((lpCreate->offBmi +lpCreate->cbBmi ) <= mr->nSize) &&
1402                 ((lpCreate->offBits+lpCreate->cbBits) <= mr->nSize) ) )
1403         {
1404             ERR("Invalid EMR_CREATEDIBPATTERNBRUSHPT record\n");
1405             break;
1406         }
1407
1408         /* This is a BITMAPINFO struct followed directly by bitmap bits */
1409         lpPackedStruct = HeapAlloc( GetProcessHeap(), 0,
1410                                     lpCreate->cbBmi + lpCreate->cbBits );
1411         if(!lpPackedStruct)
1412         {
1413             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1414             break;
1415         }
1416
1417         /* Now pack this structure */
1418         memcpy( lpPackedStruct,
1419                 ((BYTE*)lpCreate) + lpCreate->offBmi,
1420                 lpCreate->cbBmi );
1421         memcpy( ((BYTE*)lpPackedStruct) + lpCreate->cbBmi,
1422                 ((BYTE*)lpCreate) + lpCreate->offBits,
1423                 lpCreate->cbBits );
1424
1425         (handletable->objectHandle)[lpCreate->ihBrush] =
1426            CreateDIBPatternBrushPt( lpPackedStruct,
1427                                     (UINT)lpCreate->iUsage );
1428
1429         HeapFree(GetProcessHeap(), 0, lpPackedStruct);
1430
1431         break;
1432       }
1433
1434     case EMR_CREATEMONOBRUSH:
1435     {
1436         PEMRCREATEMONOBRUSH pCreateMonoBrush = (PEMRCREATEMONOBRUSH)mr;
1437         BITMAPINFO *pbi = (BITMAPINFO *)((BYTE *)mr + pCreateMonoBrush->offBmi);
1438         HBITMAP hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1439                 (BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage);
1440         (handletable->objectHandle)[pCreateMonoBrush->ihBrush] = CreatePatternBrush(hBmp);
1441         /* CreatePatternBrush created a copy of the bitmap */
1442         DeleteObject(hBmp);
1443         break;
1444     }
1445
1446     case EMR_BITBLT:
1447     {
1448         PEMRBITBLT pBitBlt = (PEMRBITBLT)mr;
1449         HDC hdcSrc = CreateCompatibleDC(hdc);
1450         HBRUSH hBrush, hBrushOld;
1451         HBITMAP hBmp = 0, hBmpOld = 0;
1452         BITMAPINFO *pbi = (BITMAPINFO *)((BYTE *)mr + pBitBlt->offBmiSrc);
1453
1454         SetWorldTransform(hdcSrc, &pBitBlt->xformSrc);
1455
1456         hBrush = CreateSolidBrush(pBitBlt->crBkColorSrc);
1457         hBrushOld = SelectObject(hdcSrc, hBrush);
1458         PatBlt(hdcSrc, pBitBlt->rclBounds.left, pBitBlt->rclBounds.top,
1459                pBitBlt->rclBounds.right - pBitBlt->rclBounds.left,
1460                pBitBlt->rclBounds.bottom - pBitBlt->rclBounds.top, PATCOPY);
1461         SelectObject(hdcSrc, hBrushOld);
1462         DeleteObject(hBrush);
1463
1464         if (pBitBlt->offBmiSrc > 0)
1465         {
1466                 hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1467                                           (BYTE *)mr + pBitBlt->offBitsSrc, pbi, pBitBlt->iUsageSrc);
1468                 hBmpOld = SelectObject(hdcSrc, hBmp);
1469         }
1470
1471         BitBlt(hdc,
1472                pBitBlt->xDest,
1473                pBitBlt->yDest,
1474                pBitBlt->cxDest,
1475                pBitBlt->cyDest,
1476                hdcSrc,
1477                pBitBlt->xSrc,
1478                pBitBlt->ySrc,
1479                pBitBlt->dwRop);
1480
1481         if (pBitBlt->offBmiSrc > 0)
1482         {
1483                 SelectObject(hdcSrc, hBmpOld);
1484                 DeleteObject(hBmp);
1485         }
1486         DeleteDC(hdcSrc);
1487         break;
1488     }
1489
1490     case EMR_STRETCHBLT:
1491     {
1492         PEMRSTRETCHBLT pStretchBlt= (PEMRSTRETCHBLT)mr;
1493         HDC hdcSrc = CreateCompatibleDC(hdc);
1494         HBRUSH hBrush, hBrushOld;
1495         HBITMAP hBmp = 0, hBmpOld = 0;
1496         BITMAPINFO *pbi = (BITMAPINFO *)((BYTE *)mr + pStretchBlt->offBmiSrc);
1497
1498         SetWorldTransform(hdcSrc, &pStretchBlt->xformSrc);
1499
1500         hBrush = CreateSolidBrush(pStretchBlt->crBkColorSrc);
1501         hBrushOld = SelectObject(hdcSrc, hBrush);
1502         PatBlt(hdcSrc, pStretchBlt->rclBounds.left, pStretchBlt->rclBounds.top,
1503                pStretchBlt->rclBounds.right - pStretchBlt->rclBounds.left,
1504                pStretchBlt->rclBounds.bottom - pStretchBlt->rclBounds.top, PATCOPY);
1505         SelectObject(hdcSrc, hBrushOld);
1506         DeleteObject(hBrush);
1507
1508         if (pStretchBlt->offBmiSrc)
1509         {
1510                 hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1511                                           (BYTE *)mr + pStretchBlt->offBitsSrc, pbi, pStretchBlt->iUsageSrc);
1512                 hBmpOld = SelectObject(hdcSrc, hBmp);
1513         }
1514
1515         StretchBlt(hdc,
1516                pStretchBlt->xDest,
1517                pStretchBlt->yDest,
1518                pStretchBlt->cxDest,
1519                pStretchBlt->cyDest,
1520                hdcSrc,
1521                pStretchBlt->xSrc,
1522                pStretchBlt->ySrc,
1523                pStretchBlt->cxSrc,
1524                pStretchBlt->cySrc,
1525                pStretchBlt->dwRop);
1526
1527
1528         if (pStretchBlt->offBmiSrc)
1529         {
1530                 SelectObject(hdcSrc, hBmpOld);
1531                 DeleteObject(hBmp);
1532         }
1533
1534         DeleteDC(hdcSrc);
1535         break;
1536     }
1537
1538     case EMR_MASKBLT:
1539     {
1540         PEMRMASKBLT pMaskBlt= (PEMRMASKBLT)mr;
1541         HDC hdcSrc = CreateCompatibleDC(hdc);
1542         HBRUSH hBrush, hBrushOld;
1543         HBITMAP hBmp, hBmpOld, hBmpMask;
1544         BITMAPINFO *pbi;
1545
1546         SetWorldTransform(hdcSrc, &pMaskBlt->xformSrc);
1547
1548         hBrush = CreateSolidBrush(pMaskBlt->crBkColorSrc);
1549         hBrushOld = SelectObject(hdcSrc, hBrush);
1550         PatBlt(hdcSrc, pMaskBlt->rclBounds.left, pMaskBlt->rclBounds.top,
1551                pMaskBlt->rclBounds.right - pMaskBlt->rclBounds.left,
1552                pMaskBlt->rclBounds.bottom - pMaskBlt->rclBounds.top, PATCOPY);
1553         SelectObject(hdcSrc, hBrushOld);
1554         DeleteObject(hBrush);
1555
1556         pbi = (BITMAPINFO *)((BYTE *)mr + pMaskBlt->offBmiMask);
1557         hBmpMask = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1558                               (BYTE *)mr + pMaskBlt->offBitsMask, pbi, pMaskBlt->iUsageMask);
1559
1560         pbi = (BITMAPINFO *)((BYTE *)mr + pMaskBlt->offBmiSrc);
1561         hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1562                               (BYTE *)mr + pMaskBlt->offBitsSrc, pbi, pMaskBlt->iUsageSrc);
1563         hBmpOld = SelectObject(hdcSrc, hBmp);
1564         MaskBlt(hdc,
1565                 pMaskBlt->xDest,
1566                 pMaskBlt->yDest,
1567                 pMaskBlt->cxDest,
1568                 pMaskBlt->cyDest,
1569                 hdcSrc,
1570                 pMaskBlt->xSrc,
1571                 pMaskBlt->ySrc,
1572                 hBmpMask,
1573                 pMaskBlt->xMask,
1574                 pMaskBlt->yMask,
1575                 pMaskBlt->dwRop);
1576         SelectObject(hdcSrc, hBmpOld);
1577         DeleteObject(hBmp);
1578         DeleteObject(hBmpMask);
1579         DeleteDC(hdcSrc);
1580         break;
1581     }
1582
1583     case EMR_PLGBLT:
1584     {
1585         PEMRPLGBLT pPlgBlt= (PEMRPLGBLT)mr;
1586         HDC hdcSrc = CreateCompatibleDC(hdc);
1587         HBRUSH hBrush, hBrushOld;
1588         HBITMAP hBmp, hBmpOld, hBmpMask;
1589         BITMAPINFO *pbi;
1590         POINT pts[3];
1591
1592         SetWorldTransform(hdcSrc, &pPlgBlt->xformSrc);
1593
1594         pts[0].x = pPlgBlt->aptlDest[0].x; pts[0].y = pPlgBlt->aptlDest[0].y;
1595         pts[1].x = pPlgBlt->aptlDest[1].x; pts[1].y = pPlgBlt->aptlDest[1].y;
1596         pts[2].x = pPlgBlt->aptlDest[2].x; pts[2].y = pPlgBlt->aptlDest[2].y;
1597
1598         hBrush = CreateSolidBrush(pPlgBlt->crBkColorSrc);
1599         hBrushOld = SelectObject(hdcSrc, hBrush);
1600         PatBlt(hdcSrc, pPlgBlt->rclBounds.left, pPlgBlt->rclBounds.top,
1601                pPlgBlt->rclBounds.right - pPlgBlt->rclBounds.left,
1602                pPlgBlt->rclBounds.bottom - pPlgBlt->rclBounds.top, PATCOPY);
1603         SelectObject(hdcSrc, hBrushOld);
1604         DeleteObject(hBrush);
1605
1606         pbi = (BITMAPINFO *)((BYTE *)mr + pPlgBlt->offBmiMask);
1607         hBmpMask = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1608                               (BYTE *)mr + pPlgBlt->offBitsMask, pbi, pPlgBlt->iUsageMask);
1609
1610         pbi = (BITMAPINFO *)((BYTE *)mr + pPlgBlt->offBmiSrc);
1611         hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1612                               (BYTE *)mr + pPlgBlt->offBitsSrc, pbi, pPlgBlt->iUsageSrc);
1613         hBmpOld = SelectObject(hdcSrc, hBmp);
1614         PlgBlt(hdc,
1615                pts,
1616                hdcSrc,
1617                pPlgBlt->xSrc,
1618                pPlgBlt->ySrc,
1619                pPlgBlt->cxSrc,
1620                pPlgBlt->cySrc,
1621                hBmpMask,
1622                pPlgBlt->xMask,
1623                pPlgBlt->yMask);
1624         SelectObject(hdcSrc, hBmpOld);
1625         DeleteObject(hBmp);
1626         DeleteObject(hBmpMask);
1627         DeleteDC(hdcSrc);
1628         break;
1629     }
1630
1631     case EMR_SETDIBITSTODEVICE:
1632     {
1633         PEMRSETDIBITSTODEVICE pSetDIBitsToDevice = (PEMRSETDIBITSTODEVICE)mr;
1634
1635         SetDIBitsToDevice(hdc,
1636                           pSetDIBitsToDevice->xDest,
1637                           pSetDIBitsToDevice->yDest,
1638                           pSetDIBitsToDevice->cxSrc,
1639                           pSetDIBitsToDevice->cySrc,
1640                           pSetDIBitsToDevice->xSrc,
1641                           pSetDIBitsToDevice->ySrc,
1642                           pSetDIBitsToDevice->iStartScan,
1643                           pSetDIBitsToDevice->cScans,
1644                           (BYTE *)mr + pSetDIBitsToDevice->offBitsSrc,
1645                           (BITMAPINFO *)((BYTE *)mr + pSetDIBitsToDevice->offBmiSrc),
1646                           pSetDIBitsToDevice->iUsageSrc);
1647         break;
1648     }
1649
1650     case EMR_POLYTEXTOUTA:
1651     {
1652         PEMRPOLYTEXTOUTA pPolyTextOutA = (PEMRPOLYTEXTOUTA)mr;
1653         POLYTEXTA *polytextA = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutA->cStrings * sizeof(POLYTEXTA));
1654         LONG i;
1655         XFORM xform, xformOld;
1656         int gModeOld;
1657
1658         gModeOld = SetGraphicsMode(hdc, pPolyTextOutA->iGraphicsMode);
1659         GetWorldTransform(hdc, &xformOld);
1660
1661         xform.eM11 = pPolyTextOutA->exScale;
1662         xform.eM12 = 0.0;
1663         xform.eM21 = 0.0;
1664         xform.eM22 = pPolyTextOutA->eyScale;
1665         xform.eDx = 0.0;
1666         xform.eDy = 0.0;
1667         SetWorldTransform(hdc, &xform);
1668
1669         /* Set up POLYTEXTA structures */
1670         for(i = 0; i < pPolyTextOutA->cStrings; i++)
1671         {
1672             polytextA[i].x = pPolyTextOutA->aemrtext[i].ptlReference.x;
1673             polytextA[i].y = pPolyTextOutA->aemrtext[i].ptlReference.y;
1674             polytextA[i].n = pPolyTextOutA->aemrtext[i].nChars;
1675             polytextA[i].lpstr = (LPSTR)((BYTE *)mr + pPolyTextOutA->aemrtext[i].offString);
1676             polytextA[i].uiFlags = pPolyTextOutA->aemrtext[i].fOptions;
1677             polytextA[i].rcl.left = pPolyTextOutA->aemrtext[i].rcl.left;
1678             polytextA[i].rcl.right = pPolyTextOutA->aemrtext[i].rcl.right;
1679             polytextA[i].rcl.top = pPolyTextOutA->aemrtext[i].rcl.top;
1680             polytextA[i].rcl.bottom = pPolyTextOutA->aemrtext[i].rcl.bottom;
1681             polytextA[i].pdx = (int *)((BYTE *)mr + pPolyTextOutA->aemrtext[i].offDx);
1682         }
1683         PolyTextOutA(hdc, polytextA, pPolyTextOutA->cStrings);
1684         HeapFree(GetProcessHeap(), 0, polytextA);
1685
1686         SetWorldTransform(hdc, &xformOld);
1687         SetGraphicsMode(hdc, gModeOld);
1688         break;
1689     }
1690
1691     case EMR_POLYTEXTOUTW:
1692     {
1693         PEMRPOLYTEXTOUTW pPolyTextOutW = (PEMRPOLYTEXTOUTW)mr;
1694         POLYTEXTW *polytextW = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutW->cStrings * sizeof(POLYTEXTW));
1695         LONG i;
1696         XFORM xform, xformOld;
1697         int gModeOld;
1698
1699         gModeOld = SetGraphicsMode(hdc, pPolyTextOutW->iGraphicsMode);
1700         GetWorldTransform(hdc, &xformOld);
1701
1702         xform.eM11 = pPolyTextOutW->exScale;
1703         xform.eM12 = 0.0;
1704         xform.eM21 = 0.0;
1705         xform.eM22 = pPolyTextOutW->eyScale;
1706         xform.eDx = 0.0;
1707         xform.eDy = 0.0;
1708         SetWorldTransform(hdc, &xform);
1709
1710         /* Set up POLYTEXTW structures */
1711         for(i = 0; i < pPolyTextOutW->cStrings; i++)
1712         {
1713             polytextW[i].x = pPolyTextOutW->aemrtext[i].ptlReference.x;
1714             polytextW[i].y = pPolyTextOutW->aemrtext[i].ptlReference.y;
1715             polytextW[i].n = pPolyTextOutW->aemrtext[i].nChars;
1716             polytextW[i].lpstr = (LPWSTR)((BYTE *)mr + pPolyTextOutW->aemrtext[i].offString);
1717             polytextW[i].uiFlags = pPolyTextOutW->aemrtext[i].fOptions;
1718             polytextW[i].rcl.left = pPolyTextOutW->aemrtext[i].rcl.left;
1719             polytextW[i].rcl.right = pPolyTextOutW->aemrtext[i].rcl.right;
1720             polytextW[i].rcl.top = pPolyTextOutW->aemrtext[i].rcl.top;
1721             polytextW[i].rcl.bottom = pPolyTextOutW->aemrtext[i].rcl.bottom;
1722             polytextW[i].pdx = (int *)((BYTE *)mr + pPolyTextOutW->aemrtext[i].offDx);
1723         }
1724         PolyTextOutW(hdc, polytextW, pPolyTextOutW->cStrings);
1725         HeapFree(GetProcessHeap(), 0, polytextW);
1726
1727         SetWorldTransform(hdc, &xformOld);
1728         SetGraphicsMode(hdc, gModeOld);
1729         break;
1730     }
1731
1732     case EMR_FILLRGN:
1733     {
1734         PEMRFILLRGN pFillRgn = (PEMRFILLRGN)mr;
1735         HRGN hRgn = ExtCreateRegion(NULL, pFillRgn->cbRgnData, (RGNDATA *)pFillRgn->RgnData);
1736         FillRgn(hdc,
1737                 hRgn,
1738                 (handletable->objectHandle)[pFillRgn->ihBrush]);
1739         DeleteObject(hRgn);
1740         break;
1741     }
1742
1743     case EMR_FRAMERGN:
1744     {
1745         PEMRFRAMERGN pFrameRgn = (PEMRFRAMERGN)mr;
1746         HRGN hRgn = ExtCreateRegion(NULL, pFrameRgn->cbRgnData, (RGNDATA *)pFrameRgn->RgnData);
1747         FrameRgn(hdc,
1748                  hRgn,
1749                  (handletable->objectHandle)[pFrameRgn->ihBrush],
1750                  pFrameRgn->szlStroke.cx,
1751                  pFrameRgn->szlStroke.cy);
1752         DeleteObject(hRgn);
1753         break;
1754     }
1755
1756     case EMR_INVERTRGN:
1757     {
1758         PEMRINVERTRGN pInvertRgn = (PEMRINVERTRGN)mr;
1759         HRGN hRgn = ExtCreateRegion(NULL, pInvertRgn->cbRgnData, (RGNDATA *)pInvertRgn->RgnData);
1760         InvertRgn(hdc, hRgn);
1761         DeleteObject(hRgn);
1762         break;
1763     }
1764
1765     case EMR_PAINTRGN:
1766     {
1767         PEMRPAINTRGN pPaintRgn = (PEMRPAINTRGN)mr;
1768         HRGN hRgn = ExtCreateRegion(NULL, pPaintRgn->cbRgnData, (RGNDATA *)pPaintRgn->RgnData);
1769         PaintRgn(hdc, hRgn);
1770         DeleteObject(hRgn);
1771         break;
1772     }
1773
1774     case EMR_SETTEXTJUSTIFICATION:
1775     {
1776         PEMRSETTEXTJUSTIFICATION pSetTextJust = (PEMRSETTEXTJUSTIFICATION)mr;
1777         SetTextJustification(hdc, pSetTextJust->nBreakExtra, pSetTextJust->nBreakCount);
1778         break;
1779     }
1780
1781     case EMR_SETLAYOUT:
1782     {
1783         PEMRSETLAYOUT pSetLayout = (PEMRSETLAYOUT)mr;
1784         SetLayout(hdc, pSetLayout->iMode);
1785         break;
1786     }
1787
1788     case EMR_POLYDRAW16:
1789     case EMR_GLSRECORD:
1790     case EMR_GLSBOUNDEDRECORD:
1791         case EMR_DRAWESCAPE :
1792         case EMR_EXTESCAPE:
1793         case EMR_STARTDOC:
1794         case EMR_SMALLTEXTOUT:
1795         case EMR_FORCEUFIMAPPING:
1796         case EMR_NAMEDESCAPE:
1797         case EMR_COLORCORRECTPALETTE:
1798         case EMR_SETICMPROFILEA:
1799         case EMR_SETICMPROFILEW:
1800         case EMR_ALPHABLEND:
1801         case EMR_TRANSPARENTBLT:
1802         case EMR_GRADIENTFILL:
1803         case EMR_SETLINKEDUFI:
1804         case EMR_COLORMATCHTOTARGETW:
1805         case EMR_CREATECOLORSPACEW:
1806
1807     default:
1808       /* From docs: If PlayEnhMetaFileRecord doesn't recognize a
1809                     record then ignore and return TRUE. */
1810       FIXME("type %d is unimplemented\n", type);
1811       break;
1812     }
1813   tmprc.left = tmprc.top = 0;
1814   tmprc.right = tmprc.bottom = 1000;
1815   LPtoDP(hdc, (POINT*)&tmprc, 2);
1816   TRACE("L:0,0 - 1000,1000 -> D:%ld,%ld - %ld,%ld\n", tmprc.left,
1817         tmprc.top, tmprc.right, tmprc.bottom);
1818
1819   if ( !IS_WIN9X() )
1820   {
1821     /* WinNT - update the transform (win9x updates when the next graphics output
1822        record is played). */
1823     EMF_Update_MF_Xform(hdc, info);
1824   }
1825
1826   return TRUE;
1827 }
1828
1829
1830 /*****************************************************************************
1831  *
1832  *        EnumEnhMetaFile  (GDI32.@)
1833  *
1834  *  Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
1835  *  for each
1836  *  record. Returns when either every record has been used or
1837  *  when _EnhMetaFunc_ returns FALSE.
1838  *
1839  *
1840  * RETURNS
1841  *  TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
1842  *  returns FALSE.
1843  *
1844  * BUGS
1845  *   Ignores rect.
1846  *
1847  * NOTES
1848  *   This function behaves differently in Win9x and WinNT.
1849  *
1850  *   In WinNT, the DC's world transform is updated as the EMF changes
1851  *    the Window/Viewport Extent and Origin or it's world transform.
1852  *    The actual Window/Viewport Extent and Origin are left untouched.
1853  *
1854  *   In Win9x, the DC is left untouched, and PlayEnhMetaFileRecord
1855  *    updates the scaling itself but only just before a record that
1856  *    writes anything to the DC.
1857  *
1858  *   I'm not sure where the data (enum_emh_data) is stored in either
1859  *    version. For this implementation, it is stored before the handle
1860  *    table, but it could be stored in the DC, in the EMF handle or in
1861  *    TLS.
1862  *             MJM  5 Oct 2002
1863  */
1864 BOOL WINAPI EnumEnhMetaFile(
1865      HDC hdc,                /* [in] device context to pass to _EnhMetaFunc_ */
1866      HENHMETAFILE hmf,       /* [in] EMF to walk */
1867      ENHMFENUMPROC callback, /* [in] callback function */
1868      LPVOID data,            /* [in] optional data for callback function */
1869      const RECT *lpRect      /* [in] bounding rectangle for rendered metafile */
1870     )
1871 {
1872     BOOL ret;
1873     ENHMETAHEADER *emh;
1874     ENHMETARECORD *emr;
1875     DWORD offset;
1876     UINT i;
1877     HANDLETABLE *ht;
1878     INT savedMode = 0;
1879     XFORM savedXform;
1880     HPEN hPen = NULL;
1881     HBRUSH hBrush = NULL;
1882     HFONT hFont = NULL;
1883     enum_emh_data *info;
1884     SIZE vp_size, win_size;
1885     POINT vp_org, win_org;
1886     INT mapMode = MM_TEXT;
1887
1888     if(!lpRect)
1889     {
1890         SetLastError(ERROR_INVALID_PARAMETER);
1891         return FALSE;
1892     }
1893
1894     emh = EMF_GetEnhMetaHeader(hmf);
1895     if(!emh) {
1896         SetLastError(ERROR_INVALID_HANDLE);
1897         return FALSE;
1898     }
1899
1900     info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1901                     sizeof (enum_emh_data) + sizeof(HANDLETABLE) * emh->nHandles );
1902     if(!info)
1903     {
1904         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1905         return FALSE;
1906     }
1907     info->wndOrgX = 0;
1908     info->wndOrgY = 0;
1909     info->wndExtX = 1;
1910     info->wndExtY = 1;
1911     info->vportOrgX = 0;
1912     info->vportOrgY = 0;
1913     info->vportExtX = 1;
1914     info->vportExtY = 1;
1915     info->world_transform.eM11 = info->world_transform.eM22 = 1;
1916     info->world_transform.eM12 = info->world_transform.eM21 = 0;
1917     info->world_transform.eDx  = info->world_transform.eDy =  0;
1918
1919     ht = (HANDLETABLE*) &info[1];
1920     ht->objectHandle[0] = hmf;
1921
1922     if(hdc)
1923     {
1924         savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
1925         GetWorldTransform(hdc, &savedXform);
1926         GetViewportExtEx(hdc, &vp_size);
1927         GetWindowExtEx(hdc, &win_size);
1928         GetViewportOrgEx(hdc, &vp_org);
1929         GetWindowOrgEx(hdc, &win_org);
1930         mapMode = GetMapMode(hdc);
1931
1932         /* save the current pen, brush and font */
1933         hPen = GetCurrentObject(hdc, OBJ_PEN);
1934         hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
1935         hFont = GetCurrentObject(hdc, OBJ_FONT);
1936     }
1937
1938     info->mode = MM_TEXT;
1939
1940     if ( IS_WIN9X() )
1941     {
1942         /* Win95 leaves the vp/win ext/org info alone */
1943         info->init_transform.eM11 = 1.0;
1944         info->init_transform.eM12 = 0.0;
1945         info->init_transform.eM21 = 0.0;
1946         info->init_transform.eM22 = 1.0;
1947         info->init_transform.eDx  = 0.0;
1948         info->init_transform.eDy  = 0.0;
1949     }
1950     else
1951     {
1952         /* WinNT combines the vp/win ext/org info into a transform */
1953         FLOAT xscale, yscale;
1954         xscale = (FLOAT)vp_size.cx / (FLOAT)win_size.cx;
1955         yscale = (FLOAT)vp_size.cy / (FLOAT)win_size.cy;
1956         info->init_transform.eM11 = xscale;
1957         info->init_transform.eM12 = 0.0;
1958         info->init_transform.eM21 = 0.0;
1959         info->init_transform.eM22 = yscale;
1960         info->init_transform.eDx  = (FLOAT)vp_org.x - xscale * (FLOAT)win_org.x;
1961         info->init_transform.eDy  = (FLOAT)vp_org.y - yscale * (FLOAT)win_org.y; 
1962
1963         CombineTransform(&info->init_transform, &savedXform, &info->init_transform);
1964     }
1965
1966     if ( WIDTH(emh->rclFrame) && HEIGHT(emh->rclFrame) )
1967     {
1968         FLOAT xSrcPixSize, ySrcPixSize, xscale, yscale;
1969         XFORM xform;
1970
1971         TRACE("rect: %ld,%ld - %ld,%ld. rclFrame: %ld,%ld - %ld,%ld\n",
1972            lpRect->left, lpRect->top, lpRect->right, lpRect->bottom,
1973            emh->rclFrame.left, emh->rclFrame.top, emh->rclFrame.right,
1974            emh->rclFrame.bottom);
1975
1976         xSrcPixSize = (FLOAT) emh->szlMillimeters.cx / emh->szlDevice.cx;
1977         ySrcPixSize = (FLOAT) emh->szlMillimeters.cy / emh->szlDevice.cy;
1978         xscale = (FLOAT) WIDTH(*lpRect) * 100.0 /
1979                  WIDTH(emh->rclFrame) * xSrcPixSize;
1980         yscale = (FLOAT) HEIGHT(*lpRect) * 100.0 /
1981                  HEIGHT(emh->rclFrame) * ySrcPixSize;
1982
1983         xform.eM11 = xscale;
1984         xform.eM12 = 0;
1985         xform.eM21 = 0;
1986         xform.eM22 = yscale;
1987         xform.eDx = (FLOAT) lpRect->left - (FLOAT) WIDTH(*lpRect) / WIDTH(emh->rclFrame) * emh->rclFrame.left;
1988         xform.eDy = (FLOAT) lpRect->top - (FLOAT) HEIGHT(*lpRect) / HEIGHT(emh->rclFrame) * emh->rclFrame.top;
1989
1990         CombineTransform(&info->init_transform, &xform, &info->init_transform);
1991     }
1992
1993     /* WinNT resets the current vp/win org/ext */
1994     if ( !IS_WIN9X() )
1995     {
1996         SetMapMode(hdc, MM_TEXT);
1997         SetWindowOrgEx(hdc, 0, 0, NULL);
1998         SetViewportOrgEx(hdc, 0, 0, NULL);
1999         EMF_Update_MF_Xform(hdc, info);
2000     }
2001
2002     ret = TRUE;
2003     offset = 0;
2004     while(ret && offset < emh->nBytes)
2005     {
2006         emr = (ENHMETARECORD *)((char *)emh + offset);
2007         TRACE("Calling EnumFunc with record type %ld, size %ld\n", emr->iType, emr->nSize);
2008         ret = (*callback)(hdc, ht, emr, emh->nHandles, (LPARAM)data);
2009         offset += emr->nSize;
2010     }
2011
2012     if (hdc)
2013     {
2014         /* restore pen, brush and font */
2015         SelectObject(hdc, hBrush);
2016         SelectObject(hdc, hPen);
2017         SelectObject(hdc, hFont);
2018
2019         SetWorldTransform(hdc, &savedXform);
2020         if (savedMode)
2021             SetGraphicsMode(hdc, savedMode);
2022         SetMapMode(hdc, mapMode);
2023         SetWindowOrgEx(hdc, win_org.x, win_org.y, NULL);
2024         SetWindowExtEx(hdc, win_size.cx, win_size.cy, NULL);
2025         SetViewportOrgEx(hdc, vp_org.x, vp_org.y, NULL);
2026         SetViewportExtEx(hdc, vp_size.cx, vp_size.cy, NULL);
2027     }
2028
2029     for(i = 1; i < emh->nHandles; i++) /* Don't delete element 0 (hmf) */
2030         if( (ht->objectHandle)[i] )
2031             DeleteObject( (ht->objectHandle)[i] );
2032
2033     HeapFree( GetProcessHeap(), 0, info );
2034     return ret;
2035 }
2036
2037 static INT CALLBACK EMF_PlayEnhMetaFileCallback(HDC hdc, HANDLETABLE *ht,
2038                                                 const ENHMETARECORD *emr,
2039                                                 INT handles, LPARAM data)
2040 {
2041     return PlayEnhMetaFileRecord(hdc, ht, emr, handles);
2042 }
2043
2044 /**************************************************************************
2045  *    PlayEnhMetaFile  (GDI32.@)
2046  *
2047  *    Renders an enhanced metafile into a specified rectangle *lpRect
2048  *    in device context hdc.
2049  *
2050  */
2051 BOOL WINAPI PlayEnhMetaFile(
2052        HDC hdc,           /* [in] DC to render into */
2053        HENHMETAFILE hmf,  /* [in] metafile to render */
2054        const RECT *lpRect /* [in] rectangle to place metafile inside */
2055       )
2056 {
2057     return EnumEnhMetaFile(hdc, hmf, EMF_PlayEnhMetaFileCallback, NULL,
2058                            lpRect);
2059 }
2060
2061 /*****************************************************************************
2062  *  DeleteEnhMetaFile (GDI32.@)
2063  *
2064  *  Deletes an enhanced metafile and frees the associated storage.
2065  */
2066 BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf)
2067 {
2068     return EMF_Delete_HENHMETAFILE( hmf );
2069 }
2070
2071 /*****************************************************************************
2072  *  CopyEnhMetaFileA (GDI32.@)  Duplicate an enhanced metafile
2073  *
2074  *
2075  */
2076 HENHMETAFILE WINAPI CopyEnhMetaFileA(
2077     HENHMETAFILE hmfSrc,
2078     LPCSTR file)
2079 {
2080     ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
2081     HENHMETAFILE hmfDst;
2082
2083     if(!emrSrc) return FALSE;
2084     if (!file) {
2085         emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
2086         memcpy( emrDst, emrSrc, emrSrc->nBytes );
2087         hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
2088     } else {
2089         HANDLE hFile;
2090         hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0,
2091                              NULL, CREATE_ALWAYS, 0, 0);
2092         WriteFile( hFile, emrSrc, emrSrc->nBytes, 0, 0);
2093         CloseHandle( hFile );
2094         /* Reopen file for reading only, so that apps can share
2095            read access to the file while hmf is still valid */
2096         hFile = CreateFileA( file, GENERIC_READ, FILE_SHARE_READ,
2097                              NULL, OPEN_EXISTING, 0, 0);
2098         if(hFile == INVALID_HANDLE_VALUE) {
2099             ERR("Can't reopen emf for reading\n");
2100             return 0;
2101         }
2102         hmfDst = EMF_GetEnhMetaFile( hFile );
2103         CloseHandle( hFile );
2104     }
2105     return hmfDst;
2106 }
2107
2108
2109 /* Struct to be used to be passed in the LPVOID parameter for cbEnhPaletteCopy */
2110 typedef struct tagEMF_PaletteCopy
2111 {
2112    UINT cEntries;
2113    LPPALETTEENTRY lpPe;
2114 } EMF_PaletteCopy;
2115
2116 /***************************************************************
2117  * Find the EMR_EOF record and then use it to find the
2118  * palette entries for this enhanced metafile.
2119  * The lpData is actually a pointer to a EMF_PaletteCopy struct
2120  * which contains the max number of elements to copy and where
2121  * to copy them to.
2122  *
2123  * NOTE: To be used by GetEnhMetaFilePaletteEntries only!
2124  */
2125 INT CALLBACK cbEnhPaletteCopy( HDC a,
2126                                HANDLETABLE *b,
2127                                const ENHMETARECORD *lpEMR,
2128                                INT c,
2129                                LPARAM lpData )
2130 {
2131
2132   if ( lpEMR->iType == EMR_EOF )
2133   {
2134     PEMREOF lpEof = (PEMREOF)lpEMR;
2135     EMF_PaletteCopy* info = (EMF_PaletteCopy*)lpData;
2136     DWORD dwNumPalToCopy = min( lpEof->nPalEntries, info->cEntries );
2137
2138     TRACE( "copying 0x%08lx palettes\n", dwNumPalToCopy );
2139
2140     memcpy( (LPVOID)info->lpPe,
2141             (LPVOID)(((LPSTR)lpEof) + lpEof->offPalEntries),
2142             sizeof( *(info->lpPe) ) * dwNumPalToCopy );
2143
2144     /* Update the passed data as a return code */
2145     info->lpPe     = NULL; /* Palettes were copied! */
2146     info->cEntries = (UINT)dwNumPalToCopy;
2147
2148     return FALSE; /* That's all we need */
2149   }
2150
2151   return TRUE;
2152 }
2153
2154 /*****************************************************************************
2155  *  GetEnhMetaFilePaletteEntries (GDI32.@)
2156  *
2157  *  Copy the palette and report size
2158  *
2159  *  BUGS: Error codes (SetLastError) are not set on failures
2160  */
2161 UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
2162                                           UINT cEntries,
2163                                           LPPALETTEENTRY lpPe )
2164 {
2165   ENHMETAHEADER* enhHeader = EMF_GetEnhMetaHeader( hEmf );
2166   EMF_PaletteCopy infoForCallBack;
2167
2168   TRACE( "(%p,%d,%p)\n", hEmf, cEntries, lpPe );
2169
2170   /* First check if there are any palettes associated with
2171      this metafile. */
2172   if ( enhHeader->nPalEntries == 0 ) return 0;
2173
2174   /* Is the user requesting the number of palettes? */
2175   if ( lpPe == NULL ) return (UINT)enhHeader->nPalEntries;
2176
2177   /* Copy cEntries worth of PALETTEENTRY structs into the buffer */
2178   infoForCallBack.cEntries = cEntries;
2179   infoForCallBack.lpPe     = lpPe;
2180
2181   if ( !EnumEnhMetaFile( 0, hEmf, cbEnhPaletteCopy,
2182                          &infoForCallBack, 0 ) )
2183       return GDI_ERROR;
2184
2185   /* Verify that the callback executed correctly */
2186   if ( infoForCallBack.lpPe != NULL )
2187   {
2188      /* Callback proc had error! */
2189      ERR( "cbEnhPaletteCopy didn't execute correctly\n" );
2190      return GDI_ERROR;
2191   }
2192
2193   return infoForCallBack.cEntries;
2194 }
2195
2196 typedef struct gdi_mf_comment
2197 {
2198     DWORD ident;
2199     DWORD iComment;
2200     DWORD nVersion;
2201     DWORD nChecksum;
2202     DWORD fFlags;
2203     DWORD cbWinMetaFile;
2204 } gdi_mf_comment;
2205
2206 /******************************************************************
2207  *         SetWinMetaFileBits   (GDI32.@)
2208  *
2209  *         Translate from old style to new style.
2210  *
2211  */
2212 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
2213                                            CONST BYTE *lpbBuffer,
2214                                            HDC hdcRef,
2215                                            CONST METAFILEPICT *lpmfp
2216                                            )
2217 {
2218     HMETAFILE hmf = 0;
2219     HENHMETAFILE ret = 0;
2220     HDC hdc = 0, hdcdisp = 0;
2221     METAFILEPICT mfp;
2222     RECT rc, *prcFrame = NULL;
2223     gdi_mf_comment *mfcomment;
2224     UINT mfcomment_size;
2225     INT horzres, vertres, horzsize, vertsize, xext, yext;
2226
2227     TRACE("(%d, %p, %p, %p)\n", cbBuffer, lpbBuffer, hdcRef, lpmfp);
2228
2229     hmf = SetMetaFileBitsEx(cbBuffer, lpbBuffer);
2230     if(!hmf)
2231     {
2232         WARN("SetMetaFileBitsEx failed\n");
2233         return 0;
2234     }
2235
2236     if(!hdcRef)
2237         hdcRef = hdcdisp = CreateDCA("DISPLAY", NULL, NULL, NULL);
2238
2239     if(!lpmfp) {
2240         lpmfp = &mfp;
2241         mfp.mm = MM_ANISOTROPIC;
2242         mfp.xExt = 100;
2243         mfp.yExt = 100;
2244         FIXME("Correct Exts from dc\n");
2245     }
2246     else
2247     {
2248         TRACE("mm = %ld %ldx%ld\n", lpmfp->mm, lpmfp->xExt, lpmfp->yExt);
2249         if ( ( mfp.xExt < 0 ) || ( mfp.yExt < 0) )
2250             FIXME("Negative coordinates!\n");
2251     }
2252
2253     if(lpmfp->mm == MM_ISOTROPIC || lpmfp->mm == MM_ANISOTROPIC) {
2254         rc.left = rc.top = 0;
2255         rc.right = lpmfp->xExt;
2256         rc.bottom = lpmfp->yExt;
2257         prcFrame = &rc;
2258     }
2259
2260     if(!(hdc = CreateEnhMetaFileW(hdcRef, NULL, prcFrame, NULL))) {
2261         ERR("CreateEnhMetaFile fails?\n");
2262         goto end;
2263     }
2264
2265     horzres = GetDeviceCaps(hdcRef, HORZRES);
2266     vertres = GetDeviceCaps(hdcRef, VERTRES);
2267     horzsize = GetDeviceCaps(hdcRef, HORZSIZE);
2268     vertsize = GetDeviceCaps(hdcRef, VERTSIZE);
2269
2270     if(hdcdisp) {
2271         DeleteDC(hdcdisp);
2272         hdcRef = 0;
2273     }
2274
2275     /*
2276      * Write the original METAFILE into the enhanced metafile.
2277      * It is encapsulated in a GDICOMMENT_WINDOWS_METAFILE record.
2278      */
2279     mfcomment_size = sizeof (gdi_mf_comment) + cbBuffer;
2280     mfcomment = HeapAlloc(GetProcessHeap(), 0, mfcomment_size);
2281     if(mfcomment)
2282     {
2283         mfcomment->ident = GDICOMMENT_IDENTIFIER;
2284         mfcomment->iComment = GDICOMMENT_WINDOWS_METAFILE;
2285         mfcomment->nVersion = 0x00000300;
2286         mfcomment->nChecksum = 0; /* FIXME */
2287         mfcomment->fFlags = 0;
2288         mfcomment->cbWinMetaFile = cbBuffer;
2289         memcpy(&mfcomment[1], lpbBuffer, cbBuffer);
2290         GdiComment(hdc, mfcomment_size, (BYTE*) mfcomment);
2291         HeapFree(GetProcessHeap(), 0, mfcomment);
2292     }
2293
2294     if(lpmfp->mm != MM_TEXT)
2295         SetMapMode(hdc, lpmfp->mm);
2296
2297     /* set the initial viewport:window ratio as 1:1 */
2298     xext = lpmfp->xExt*horzres/(100*horzsize);
2299     yext = lpmfp->yExt*vertres/(100*vertsize);
2300     SetViewportExtEx(hdc, xext, yext, NULL);
2301     SetWindowExtEx(hdc,   xext, yext, NULL);
2302
2303     PlayMetaFile(hdc, hmf);
2304
2305     ret = CloseEnhMetaFile(hdc);
2306 end:
2307     DeleteMetaFile(hmf);
2308     return ret;
2309 }