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