~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/gdi32/enhmetafile.c

Version: ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <stdlib.h>
 39 #include <string.h>
 40 #include <assert.h>
 41 #include "windef.h"
 42 #include "winbase.h"
 43 #include "wingdi.h"
 44 #include "winnls.h"
 45 #include "winerror.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     unsigned 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 %d\n", type);
196    return NULL;
197 }
198 
199 /***********************************************************************
200  *          is_dib_monochrome
201  *
202  * Returns whether a DIB can be converted to a monochrome DDB.
203  *
204  * A DIB can be converted if its color table contains only black and
205  * white. Black must be the first color in the color table.
206  *
207  * Note : If the first color in the color table is white followed by
208  *        black, we can't convert it to a monochrome DDB with
209  *        SetDIBits, because black and white would be inverted.
210  */
211 static inline BOOL is_dib_monochrome( const BITMAPINFO* info )
212 {
213     if (info->bmiHeader.biBitCount != 1) return FALSE;
214 
215     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
216     {
217         const RGBTRIPLE *rgb = ((const BITMAPCOREINFO *) info)->bmciColors;
218 
219         /* Check if the first color is black */
220         if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
221         {
222             rgb++;
223             /* Check if the second color is white */
224             return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
225                  && (rgb->rgbtBlue == 0xff));
226         }
227         else return FALSE;
228     }
229     else  /* assume BITMAPINFOHEADER */
230     {
231         const RGBQUAD *rgb = info->bmiColors;
232 
233         /* Check if the first color is black */
234         if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
235             (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
236         {
237             rgb++;
238 
239             /* Check if the second color is white */
240             return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
241                  && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
242         }
243         else return FALSE;
244     }
245 }
246 
247 /****************************************************************************
248  *          EMF_Create_HENHMETAFILE
249  */
250 HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk )
251 {
252     HENHMETAFILE hmf = 0;
253     ENHMETAFILEOBJ *metaObj;
254 
255     if (emh->iType != EMR_HEADER || emh->dSignature != ENHMETA_SIGNATURE ||
256         (emh->nBytes & 3)) /* refuse to load unaligned EMF as Windows does */
257     {
258         WARN("Invalid emf header type 0x%08x sig 0x%08x.\n",
259              emh->iType, emh->dSignature);
260         SetLastError(ERROR_INVALID_DATA);
261         return 0;
262     }
263 
264     metaObj = GDI_AllocObject( sizeof(ENHMETAFILEOBJ),
265                                ENHMETAFILE_MAGIC,
266                                (HGDIOBJ *)&hmf, NULL );
267     if (metaObj)
268     {
269         metaObj->emh = emh;
270         metaObj->on_disk = on_disk;
271         GDI_ReleaseObj( hmf );
272     }
273     return hmf;
274 }
275 
276 /****************************************************************************
277  *          EMF_Delete_HENHMETAFILE
278  */
279 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
280 {
281     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf,
282                                                            ENHMETAFILE_MAGIC );
283     if(!metaObj) return FALSE;
284 
285     if(metaObj->on_disk)
286         UnmapViewOfFile( metaObj->emh );
287     else
288         HeapFree( GetProcessHeap(), 0, metaObj->emh );
289     return GDI_FreeObject( hmf, metaObj );
290 }
291 
292 /******************************************************************
293  *         EMF_GetEnhMetaHeader
294  *
295  * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE
296  */
297 static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf )
298 {
299     ENHMETAHEADER *ret = NULL;
300     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf, ENHMETAFILE_MAGIC );
301     TRACE("hmf %p -> enhmetaObj %p\n", hmf, metaObj);
302     if (metaObj)
303     {
304         ret = metaObj->emh;
305         GDI_ReleaseObj( hmf );
306     }
307     return ret;
308 }
309 
310 /*****************************************************************************
311  *         EMF_GetEnhMetaFile
312  *
313  */
314 static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
315 {
316     ENHMETAHEADER *emh;
317     HANDLE hMapping;
318     HENHMETAFILE hemf;
319 
320     hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
321     emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
322     CloseHandle( hMapping );
323 
324     if (!emh) return 0;
325 
326     hemf = EMF_Create_HENHMETAFILE( emh, TRUE );
327     if (!hemf)
328         UnmapViewOfFile( emh );
329     return hemf;
330 }
331 
332 
333 /*****************************************************************************
334  *          GetEnhMetaFileA (GDI32.@)
335  *
336  *
337  */
338 HENHMETAFILE WINAPI GetEnhMetaFileA(
339              LPCSTR lpszMetaFile  /* [in] filename of enhanced metafile */
340     )
341 {
342     HENHMETAFILE hmf;
343     HANDLE hFile;
344 
345     hFile = CreateFileA(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
346                         OPEN_EXISTING, 0, 0);
347     if (hFile == INVALID_HANDLE_VALUE) {
348         WARN("could not open %s\n", lpszMetaFile);
349         return 0;
350     }
351     hmf = EMF_GetEnhMetaFile( hFile );
352     CloseHandle( hFile );
353     return hmf;
354 }
355 
356 /*****************************************************************************
357  *          GetEnhMetaFileW  (GDI32.@)
358  */
359 HENHMETAFILE WINAPI GetEnhMetaFileW(
360              LPCWSTR lpszMetaFile)  /* [in] filename of enhanced metafile */
361 {
362     HENHMETAFILE hmf;
363     HANDLE hFile;
364 
365     hFile = CreateFileW(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
366                         OPEN_EXISTING, 0, 0);
367     if (hFile == INVALID_HANDLE_VALUE) {
368         WARN("could not open %s\n", debugstr_w(lpszMetaFile));
369         return 0;
370     }
371     hmf = EMF_GetEnhMetaFile( hFile );
372     CloseHandle( hFile );
373     return hmf;
374 }
375 
376 /*****************************************************************************
377  *        GetEnhMetaFileHeader  (GDI32.@)
378  *
379  * Retrieves the record containing the header for the specified
380  * enhanced-format metafile.
381  *
382  * RETURNS
383  *  If buf is NULL, returns the size of buffer required.
384  *  Otherwise, copy up to bufsize bytes of enhanced metafile header into
385  *  buf.
386  */
387 UINT WINAPI GetEnhMetaFileHeader(
388        HENHMETAFILE hmf,   /* [in] enhanced metafile */
389        UINT bufsize,       /* [in] size of buffer */
390        LPENHMETAHEADER buf /* [out] buffer */
391     )
392 {
393     LPENHMETAHEADER emh;
394     UINT size;
395 
396     emh = EMF_GetEnhMetaHeader(hmf);
397     if(!emh) return FALSE;
398     size = emh->nSize;
399     if (!buf) return size;
400     size = min(size, bufsize);
401     memmove(buf, emh, size);
402     return size;
403 }
404 
405 
406 /*****************************************************************************
407  *          GetEnhMetaFileDescriptionA  (GDI32.@)
408  *
409  * See GetEnhMetaFileDescriptionW.
410  */
411 UINT WINAPI GetEnhMetaFileDescriptionA(
412        HENHMETAFILE hmf, /* [in] enhanced metafile */
413        UINT size,        /* [in] size of buf */
414        LPSTR buf         /* [out] buffer to receive description */
415     )
416 {
417      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
418      DWORD len;
419      WCHAR *descrW;
420 
421      if(!emh) return FALSE;
422      if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
423      descrW = (WCHAR *) ((char *) emh + emh->offDescription);
424      len = WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, NULL, 0, NULL, NULL );
425 
426      if (!buf || !size ) return len;
427 
428      len = min( size, len );
429      WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, buf, len, NULL, NULL );
430      return len;
431 }
432 
433 /*****************************************************************************
434  *          GetEnhMetaFileDescriptionW  (GDI32.@)
435  *
436  *  Copies the description string of an enhanced metafile into a buffer
437  *  _buf_.
438  *
439  * RETURNS
440  *  If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
441  *  number of characters copied.
442  */
443 UINT WINAPI GetEnhMetaFileDescriptionW(
444        HENHMETAFILE hmf, /* [in] enhanced metafile */
445        UINT size,        /* [in] size of buf */
446        LPWSTR buf        /* [out] buffer to receive description */
447     )
448 {
449      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
450 
451      if(!emh) return FALSE;
452      if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
453      if (!buf || !size ) return emh->nDescription;
454 
455      memmove(buf, (char *) emh + emh->offDescription, min(size,emh->nDescription)*sizeof(WCHAR));
456      return min(size, emh->nDescription);
457 }
458 
459 /****************************************************************************
460  *    SetEnhMetaFileBits (GDI32.@)
461  *
462  *  Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
463  */
464 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
465 {
466     ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
467     memmove(emh, buf, bufsize);
468     return EMF_Create_HENHMETAFILE( emh, FALSE );
469 }
470 
471 /*****************************************************************************
472  *  GetEnhMetaFileBits (GDI32.@)
473  *
474  */
475 UINT WINAPI GetEnhMetaFileBits(
476     HENHMETAFILE hmf,
477     UINT bufsize,
478     LPBYTE buf
479 )
480 {
481     LPENHMETAHEADER emh = EMF_GetEnhMetaHeader( hmf );
482     UINT size;
483 
484     if(!emh) return 0;
485 
486     size = emh->nBytes;
487     if( buf == NULL ) return size;
488 
489     size = min( size, bufsize );
490     memmove(buf, emh, size);
491     return size;
492 }
493 
494 typedef struct EMF_dc_state
495 {
496     INT   mode;
497     XFORM world_transform;
498     INT   wndOrgX;
499     INT   wndOrgY;
500     INT   wndExtX;
501     INT   wndExtY;
502     INT   vportOrgX;
503     INT   vportOrgY;
504     INT   vportExtX;
505     INT   vportExtY;
506     struct EMF_dc_state *next;
507 } EMF_dc_state;
508 
509 typedef struct enum_emh_data
510 {
511     XFORM init_transform;
512     EMF_dc_state state;
513     INT save_level;
514     EMF_dc_state *saved_state;
515 } enum_emh_data;
516 
517 #define ENUM_GET_PRIVATE_DATA(ht) \
518     ((enum_emh_data*)(((unsigned char*)(ht))-sizeof (enum_emh_data)))
519 
520 #define WIDTH(rect) ( (rect).right - (rect).left )
521 #define HEIGHT(rect) ( (rect).bottom - (rect).top )
522 
523 #define IS_WIN9X() (GetVersion()&0x80000000)
524 
525 static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info)
526 {
527     XFORM mapping_mode_trans, final_trans;
528     double scaleX, scaleY;
529 
530     scaleX = (double)info->state.vportExtX / (double)info->state.wndExtX;
531     scaleY = (double)info->state.vportExtY / (double)info->state.wndExtY;
532     mapping_mode_trans.eM11 = scaleX;
533     mapping_mode_trans.eM12 = 0.0;
534     mapping_mode_trans.eM21 = 0.0;
535     mapping_mode_trans.eM22 = scaleY;
536     mapping_mode_trans.eDx  = (double)info->state.vportOrgX - scaleX * (double)info->state.wndOrgX;
537     mapping_mode_trans.eDy  = (double)info->state.vportOrgY - scaleY * (double)info->state.wndOrgY;
538 
539     CombineTransform(&final_trans, &info->state.world_transform, &mapping_mode_trans);
540     CombineTransform(&final_trans, &final_trans, &info->init_transform);
541  
542     if (!SetWorldTransform(hdc, &final_trans))
543     {
544         ERR("World transform failed!\n");
545     }
546 }
547 
548 static void EMF_RestoreDC( enum_emh_data *info, INT level )
549 {
550     if (abs(level) > info->save_level || level == 0) return;
551 
552     if (level < 0) level = info->save_level + level + 1;
553 
554     while (info->save_level >= level)
555     {
556         EMF_dc_state *state = info->saved_state;
557         info->saved_state = state->next;
558         state->next = NULL;
559         if (--info->save_level < level)
560             info->state = *state;
561         HeapFree( GetProcessHeap(), 0, state );
562     }
563 }
564 
565 static void EMF_SaveDC( enum_emh_data *info )
566 {
567     EMF_dc_state *state = HeapAlloc( GetProcessHeap(), 0, sizeof(*state));
568     if (state)
569     {
570         *state = info->state;
571         state->next = info->saved_state;
572         info->saved_state = state;
573         info->save_level++;
574         TRACE("save_level %d\n", info->save_level);
575     }
576 }
577 
578 static void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
579 {
580     INT horzSize = GetDeviceCaps( hdc, HORZSIZE );
581     INT vertSize = GetDeviceCaps( hdc, VERTSIZE );
582     INT horzRes  = GetDeviceCaps( hdc, HORZRES );
583     INT vertRes  = GetDeviceCaps( hdc, VERTRES );
584 
585     TRACE("%d\n", info->state.mode);
586 
587     switch(info->state.mode)
588     {
589     case MM_TEXT:
590         info->state.wndExtX   = 1;
591         info->state.wndExtY   = 1;
592         info->state.vportExtX = 1;
593         info->state.vportExtY = 1;
594         break;
595     case MM_LOMETRIC:
596     case MM_ISOTROPIC:
597         info->state.wndExtX   = horzSize * 10;
598         info->state.wndExtY   = vertSize * 10;
599         info->state.vportExtX = horzRes;
600         info->state.vportExtY = -vertRes;
601         break;
602     case MM_HIMETRIC:
603         info->state.wndExtX   = horzSize * 100;
604         info->state.wndExtY   = vertSize * 100;
605         info->state.vportExtX = horzRes;
606         info->state.vportExtY = -vertRes;
607         break;
608     case MM_LOENGLISH:
609         info->state.wndExtX   = MulDiv(1000, horzSize, 254);
610         info->state.wndExtY   = MulDiv(1000, vertSize, 254);
611         info->state.vportExtX = horzRes;
612         info->state.vportExtY = -vertRes;
613         break;
614     case MM_HIENGLISH:
615         info->state.wndExtX   = MulDiv(10000, horzSize, 254);
616         info->state.wndExtY   = MulDiv(10000, vertSize, 254);
617         info->state.vportExtX = horzRes;
618         info->state.vportExtY = -vertRes;
619         break;
620     case MM_TWIPS:
621         info->state.wndExtX   = MulDiv(14400, horzSize, 254);
622         info->state.wndExtY   = MulDiv(14400, vertSize, 254);
623         info->state.vportExtX = horzRes;
624         info->state.vportExtY = -vertRes;
625         break;
626     case MM_ANISOTROPIC:
627         break;
628     default:
629         return;
630     }
631 }
632 
633 /***********************************************************************
634  *           EMF_FixIsotropic
635  *
636  * Fix viewport extensions for isotropic mode.
637  */
638 
639 static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info)
640 {
641     double xdim = fabs((double)info->state.vportExtX * GetDeviceCaps( hdc, HORZSIZE ) /
642                   (GetDeviceCaps( hdc, HORZRES ) * info->state.wndExtX));
643     double ydim = fabs((double)info->state.vportExtY * GetDeviceCaps( hdc, VERTSIZE ) /
644                   (GetDeviceCaps( hdc, VERTRES ) * info->state.wndExtY));
645 
646     if (xdim > ydim)
647     {
648         INT mincx = (info->state.vportExtX >= 0) ? 1 : -1;
649         info->state.vportExtX = floor(info->state.vportExtX * ydim / xdim + 0.5);
650         if (!info->state.vportExtX) info->state.vportExtX = mincx;
651     }
652     else
653     {
654         INT mincy = (info->state.vportExtY >= 0) ? 1 : -1;
655         info->state.vportExtY = floor(info->state.vportExtY * xdim / ydim + 0.5);
656         if (!info->state.vportExtY) info->state.vportExtY = mincy;
657     }
658 }
659 
660 /*****************************************************************************
661  *       emr_produces_output
662  *
663  * Returns TRUE if the record type writes something to the dc.  Used by
664  * PlayEnhMetaFileRecord to determine whether it needs to update the
665  * dc's xform when in win9x mode.
666  *
667  * FIXME: need to test which records should be here.
668  */
669 static BOOL emr_produces_output(int type)
670 {
671     switch(type) {
672     case EMR_POLYBEZIER:
673     case EMR_POLYGON:
674     case EMR_POLYLINE:
675     case EMR_POLYBEZIERTO:
676     case EMR_POLYLINETO:
677     case EMR_POLYPOLYLINE:
678     case EMR_POLYPOLYGON:
679     case EMR_SETPIXELV:
680     case EMR_MOVETOEX:
681     case EMR_EXCLUDECLIPRECT:
682     case EMR_INTERSECTCLIPRECT:
683     case EMR_SELECTOBJECT:
684     case EMR_ANGLEARC:
685     case EMR_ELLIPSE:
686     case EMR_RECTANGLE:
687     case EMR_ROUNDRECT:
688     case EMR_ARC:
689     case EMR_CHORD:
690     case EMR_PIE:
691     case EMR_EXTFLOODFILL:
692     case EMR_LINETO:
693     case EMR_ARCTO:
694     case EMR_POLYDRAW:
695     case EMR_FILLRGN:
696     case EMR_FRAMERGN:
697     case EMR_INVERTRGN:
698     case EMR_PAINTRGN:
699     case EMR_BITBLT:
700     case EMR_STRETCHBLT:
701     case EMR_MASKBLT:
702     case EMR_PLGBLT:
703     case EMR_SETDIBITSTODEVICE:
704     case EMR_STRETCHDIBITS:
705     case EMR_EXTTEXTOUTA:
706     case EMR_EXTTEXTOUTW:
707     case EMR_POLYBEZIER16:
708     case EMR_POLYGON16:
709     case EMR_POLYLINE16:
710     case EMR_POLYBEZIERTO16:
711     case EMR_POLYLINETO16:
712     case EMR_POLYPOLYLINE16:
713     case EMR_POLYPOLYGON16:
714     case EMR_POLYDRAW16:
715     case EMR_POLYTEXTOUTA:
716     case EMR_POLYTEXTOUTW:
717     case EMR_SMALLTEXTOUT:
718     case EMR_ALPHABLEND:
719     case EMR_TRANSPARENTBLT:
720         return TRUE;
721     default:
722         return FALSE;
723     }
724 }
725 
726 
727 /*****************************************************************************
728  *           PlayEnhMetaFileRecord  (GDI32.@)
729  *
730  *  Render a single enhanced metafile record in the device context hdc.
731  *
732  *  RETURNS
733  *    TRUE (non zero) on success, FALSE on error.
734  *  BUGS
735  *    Many unimplemented records.
736  *    No error handling on record play failures (ie checking return codes)
737  *
738  * NOTES
739  *    WinNT actually updates the current world transform in this function
740  *     whereas Win9x does not.
741  */
742 BOOL WINAPI PlayEnhMetaFileRecord(
743      HDC hdc,                   /* [in] device context in which to render EMF record */
744      LPHANDLETABLE handletable, /* [in] array of handles to be used in rendering record */
745      const ENHMETARECORD *mr,   /* [in] EMF record to render */
746      UINT handles               /* [in] size of handle array */
747      )
748 {
749   int type;
750   RECT tmprc;
751   enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
752 
753   TRACE("hdc = %p, handletable = %p, record = %p, numHandles = %d\n",
754         hdc, handletable, mr, handles);
755   if (!mr) return FALSE;
756 
757   type = mr->iType;
758 
759   /* In Win9x mode we update the xform if the record will produce output */
760   if ( IS_WIN9X() && emr_produces_output(type) )
761      EMF_Update_MF_Xform(hdc, info);
762 
763   TRACE("record %s\n", get_emr_name(type));
764   switch(type)
765     {
766     case EMR_HEADER:
767       break;
768     case EMR_EOF:
769       break;
770     case EMR_GDICOMMENT:
771       {
772         const EMRGDICOMMENT *lpGdiComment = (const EMRGDICOMMENT *)mr;
773         /* In an enhanced metafile, there can be both public and private GDI comments */
774         GdiComment( hdc, lpGdiComment->cbData, lpGdiComment->Data );
775         break;
776       }
777     case EMR_SETMAPMODE:
778       {
779         const EMRSETMAPMODE *pSetMapMode = (const EMRSETMAPMODE *)mr;
780 
781         if (info->state.mode == pSetMapMode->iMode &&
782             (info->state.mode == MM_ISOTROPIC || info->state.mode == MM_ANISOTROPIC))
783             break;
784         info->state.mode = pSetMapMode->iMode;
785         EMF_SetMapMode(hdc, info);
786         break;
787       }
788     case EMR_SETBKMODE:
789       {
790         const EMRSETBKMODE *pSetBkMode = (const EMRSETBKMODE *)mr;
791         SetBkMode(hdc, pSetBkMode->iMode);
792         break;
793       }
794     case EMR_SETBKCOLOR:
795       {
796         const EMRSETBKCOLOR *pSetBkColor = (const EMRSETBKCOLOR *)mr;
797         SetBkColor(hdc, pSetBkColor->crColor);
798         break;
799       }
800     case EMR_SETPOLYFILLMODE:
801       {
802         const EMRSETPOLYFILLMODE *pSetPolyFillMode = (const EMRSETPOLYFILLMODE *)mr;
803         SetPolyFillMode(hdc, pSetPolyFillMode->iMode);
804         break;
805       }
806     case EMR_SETROP2:
807       {
808         const EMRSETROP2 *pSetROP2 = (const EMRSETROP2 *)mr;
809         SetROP2(hdc, pSetROP2->iMode);
810         break;
811       }
812     case EMR_SETSTRETCHBLTMODE:
813       {
814         const EMRSETSTRETCHBLTMODE *pSetStretchBltMode = (const EMRSETSTRETCHBLTMODE *)mr;
815         SetStretchBltMode(hdc, pSetStretchBltMode->iMode);
816         break;
817       }
818     case EMR_SETTEXTALIGN:
819       {
820         const EMRSETTEXTALIGN *pSetTextAlign = (const EMRSETTEXTALIGN *)mr;
821         SetTextAlign(hdc, pSetTextAlign->iMode);
822         break;
823       }
824     case EMR_SETTEXTCOLOR:
825       {
826         const EMRSETTEXTCOLOR *pSetTextColor = (const EMRSETTEXTCOLOR *)mr;
827         SetTextColor(hdc, pSetTextColor->crColor);
828         break;
829       }
830     case EMR_SAVEDC:
831       {
832         if (SaveDC( hdc ))
833             EMF_SaveDC( info );
834         break;
835       }
836     case EMR_RESTOREDC:
837       {
838         const EMRRESTOREDC *pRestoreDC = (const EMRRESTOREDC *)mr;
839         TRACE("EMR_RESTORE: %d\n", pRestoreDC->iRelative);
840         if (RestoreDC( hdc, pRestoreDC->iRelative ))
841             EMF_RestoreDC( info, pRestoreDC->iRelative );
842         break;
843       }
844     case EMR_INTERSECTCLIPRECT:
845       {
846         const EMRINTERSECTCLIPRECT *pClipRect = (const EMRINTERSECTCLIPRECT *)mr;
847         TRACE("EMR_INTERSECTCLIPRECT: rect %d,%d - %d, %d\n",
848               pClipRect->rclClip.left, pClipRect->rclClip.top,
849               pClipRect->rclClip.right, pClipRect->rclClip.bottom);
850         IntersectClipRect(hdc, pClipRect->rclClip.left, pClipRect->rclClip.top,
851                           pClipRect->rclClip.right, pClipRect->rclClip.bottom);
852         break;
853       }
854     case EMR_SELECTOBJECT:
855       {
856         const EMRSELECTOBJECT *pSelectObject = (const EMRSELECTOBJECT *)mr;
857         if( pSelectObject->ihObject & 0x80000000 ) {
858           /* High order bit is set - it's a stock object
859            * Strip the high bit to get the index.
860            * See MSDN article Q142319
861            */
862           SelectObject( hdc, GetStockObject( pSelectObject->ihObject &
863                                              0x7fffffff ) );
864         } else {
865           /* High order bit wasn't set - not a stock object
866            */
867               SelectObject( hdc,
868                         (handletable->objectHandle)[pSelectObject->ihObject] );
869         }
870         break;
871       }
872     case EMR_DELETEOBJECT:
873       {
874         const EMRDELETEOBJECT *pDeleteObject = (const EMRDELETEOBJECT *)mr;
875         DeleteObject( (handletable->objectHandle)[pDeleteObject->ihObject]);
876         (handletable->objectHandle)[pDeleteObject->ihObject] = 0;
877         break;
878       }
879     case EMR_SETWINDOWORGEX:
880       {
881         const EMRSETWINDOWORGEX *pSetWindowOrgEx = (const EMRSETWINDOWORGEX *)mr;
882 
883         info->state.wndOrgX = pSetWindowOrgEx->ptlOrigin.x;
884         info->state.wndOrgY = pSetWindowOrgEx->ptlOrigin.y;
885 
886         TRACE("SetWindowOrgEx: %d,%d\n", info->state.wndOrgX, info->state.wndOrgY);
887         break;
888       }
889     case EMR_SETWINDOWEXTEX:
890       {
891         const EMRSETWINDOWEXTEX *pSetWindowExtEx = (const EMRSETWINDOWEXTEX *)mr;
892         
893         if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC)
894             break;
895         info->state.wndExtX = pSetWindowExtEx->szlExtent.cx;
896         info->state.wndExtY = pSetWindowExtEx->szlExtent.cy;
897         if (info->state.mode == MM_ISOTROPIC)
898             EMF_FixIsotropic(hdc, info);
899 
900         TRACE("SetWindowExtEx: %d,%d\n",info->state.wndExtX, info->state.wndExtY);
901         break;
902       }
903     case EMR_SETVIEWPORTORGEX:
904       {
905         const EMRSETVIEWPORTORGEX *pSetViewportOrgEx = (const EMRSETVIEWPORTORGEX *)mr;
906 
907         info->state.vportOrgX = pSetViewportOrgEx->ptlOrigin.