Implemented EnumThemes.
[wine] / objects / metafile.c
1 /*
2  * Metafile functions
3  *
4  * Copyright  David W. Metcalfe, 1994
5  *            Niels de Carpentier, Albrecht Kleine, Huw Davies 1996
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /*
23  * These functions are primarily involved with metafile playback or anything
24  * that touches a HMETAFILE.
25  * For recording of metafiles look in graphics/metafiledrv/
26  *
27  * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
28  * global memory handles so these cannot be interchanged.
29  *
30  * Memory-based metafiles are just stored as a continuous block of memory with
31  * a METAHEADER at the head with METARECORDs appended to it.  mtType is
32  * METAFILE_MEMORY (1).  Note this is indentical to the disk image of a
33  * disk-based metafile - even mtType is METAFILE_MEMORY.
34  * 16bit HMETAFILE16s are global handles to this block
35  * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
36  * the memory.
37  * Disk-based metafiles are rather different. HMETAFILE16s point to a
38  * METAHEADER which has mtType equal to METAFILE_DISK (2).  Following the 9
39  * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
40  * more 0, then 2 which may be a time stamp of the file and then the path of
41  * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
42  *
43  * HDMD - 14/4/1999
44  */
45
46 #include "config.h"
47
48 #include <string.h>
49 #include <fcntl.h>
50
51 #include "wine/winbase16.h"
52 #include "wine/wingdi16.h"
53 #include "gdi.h"
54 #include "wownt32.h"
55 #include "winreg.h"
56 #include "winternl.h"
57 #include "gdi_private.h"
58 #include "wine/debug.h"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
61
62 #include "pshpack1.h"
63 typedef struct
64 {
65     DWORD dw1, dw2, dw3;
66     WORD w4;
67     CHAR filename[0x100];
68 } METAHEADERDISK;
69 #include "poppack.h"
70
71 typedef struct
72 {
73     GDIOBJHDR   header;
74     METAHEADER  *mh;
75 } METAFILEOBJ;
76
77 #define MFHEADERSIZE (sizeof(METAHEADER))
78 #define MFVERSION 0x300
79
80
81 /******************************************************************
82  *         MF_AddHandle
83  *
84  *    Add a handle to an external handle table and return the index
85  */
86 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
87 {
88     int i;
89
90     for (i = 0; i < htlen; i++)
91     {
92         if (*(ht->objectHandle + i) == 0)
93         {
94             *(ht->objectHandle + i) = hobj;
95             return i;
96         }
97     }
98     return -1;
99 }
100
101
102 /******************************************************************
103  *         MF_Create_HMETATFILE
104  *
105  * Creates a (32 bit) HMETAFILE object from a METAHEADER
106  *
107  * HMETAFILEs are GDI objects.
108  */
109 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
110 {
111     HMETAFILE hmf = 0;
112     METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
113                                             (HGDIOBJ *)&hmf, NULL );
114     if (metaObj)
115     {
116     metaObj->mh = mh;
117         GDI_ReleaseObj( hmf );
118     }
119     return hmf;
120 }
121
122 /******************************************************************
123  *         MF_Create_HMETATFILE16
124  *
125  * Creates a HMETAFILE16 object from a METAHEADER
126  *
127  * HMETAFILE16s are Global memory handles.
128  */
129 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
130 {
131     HMETAFILE16 hmf;
132     DWORD size = mh->mtSize * sizeof(WORD);
133
134     hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
135     if(hmf)
136     {
137         METAHEADER *mh_dest = GlobalLock16(hmf);
138         memcpy(mh_dest, mh, size);
139         GlobalUnlock16(hmf);
140     }
141     HeapFree(GetProcessHeap(), 0, mh);
142     return hmf;
143 }
144
145 /******************************************************************
146  *         MF_GetMetaHeader
147  *
148  * Returns ptr to METAHEADER associated with HMETAFILE
149  */
150 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
151 {
152     METAHEADER *ret = NULL;
153     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
154     if (metaObj)
155     {
156         ret = metaObj->mh;
157         GDI_ReleaseObj( hmf );
158     }
159     return ret;
160 }
161
162 /******************************************************************
163  *         MF_GetMetaHeader16
164  *
165  * Returns ptr to METAHEADER associated with HMETAFILE16
166  * Should be followed by call to MF_ReleaseMetaHeader16
167  */
168 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
169 {
170     return GlobalLock16(hmf);
171 }
172
173 /******************************************************************
174  *         MF_ReleaseMetaHeader16
175  *
176  * Releases METAHEADER associated with HMETAFILE16
177  */
178 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
179 {
180     return GlobalUnlock16( hmf );
181 }
182
183
184 /******************************************************************
185  *         convert_points
186  *
187  * Convert an array of POINT16 to an array of POINT.
188  * Result must be freed by caller.
189  */
190 static POINT *convert_points( UINT count, POINT16 *pt16 )
191 {
192     UINT i;
193     POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
194     if (ret)
195     {
196         for (i = 0; i < count; i++)
197         {
198             ret[i].x = pt16[i].x;
199             ret[i].y = pt16[i].y;
200         }
201     }
202     return ret;
203 }
204
205
206 /******************************************************************
207  *           DeleteMetaFile   (GDI.127)
208  */
209 BOOL16 WINAPI DeleteMetaFile16(  HMETAFILE16 hmf )
210 {
211     return !GlobalFree16( hmf );
212 }
213
214 /******************************************************************
215  *          DeleteMetaFile  (GDI32.@)
216  *
217  *  Delete a memory-based metafile.
218  */
219
220 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
221 {
222     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
223     if (!metaObj) return FALSE;
224     HeapFree( GetProcessHeap(), 0, metaObj->mh );
225     GDI_FreeObject( hmf, metaObj );
226     return TRUE;
227 }
228
229 /******************************************************************
230  *         MF_ReadMetaFile
231  *
232  * Returns a pointer to a memory based METAHEADER read in from file HFILE
233  *
234  */
235 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
236 {
237     METAHEADER *mh;
238     DWORD BytesRead, size;
239
240     size = sizeof(METAHEADER);
241     mh = HeapAlloc( GetProcessHeap(), 0, size );
242     if(!mh) return NULL;
243     if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
244        BytesRead != size) {
245         HeapFree( GetProcessHeap(), 0, mh );
246         return NULL;
247     }
248     size = mh->mtSize * 2;
249     mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
250     if(!mh) return NULL;
251     size -= sizeof(METAHEADER);
252     if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
253                  NULL) == 0 ||
254        BytesRead != size) {
255         HeapFree( GetProcessHeap(), 0, mh );
256         return NULL;
257     }
258
259     if (mh->mtType != METAFILE_MEMORY) {
260         WARN("Disk metafile had mtType = %04x\n", mh->mtType);
261         mh->mtType = METAFILE_MEMORY;
262     }
263     return mh;
264 }
265
266 /******************************************************************
267  *         GetMetaFile   (GDI.124)
268  */
269 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
270 {
271     METAHEADER *mh;
272     HANDLE hFile;
273
274     TRACE("%s\n", lpFilename);
275
276     if(!lpFilename)
277         return 0;
278
279     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
280                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
281         return 0;
282
283     mh = MF_ReadMetaFile(hFile);
284     CloseHandle(hFile);
285     if(!mh) return 0;
286     return MF_Create_HMETAFILE16( mh );
287 }
288
289 /******************************************************************
290  *         GetMetaFileA   (GDI32.@)
291  *
292  *  Read a metafile from a file. Returns handle to a memory-based metafile.
293  */
294 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
295 {
296     METAHEADER *mh;
297     HANDLE hFile;
298
299     TRACE("%s\n", lpFilename);
300
301     if(!lpFilename)
302         return 0;
303
304     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
305                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
306         return 0;
307
308     mh = MF_ReadMetaFile(hFile);
309     CloseHandle(hFile);
310     if(!mh) return 0;
311     return MF_Create_HMETAFILE( mh );
312 }
313
314
315
316 /******************************************************************
317  *         GetMetaFileW   (GDI32.@)
318  */
319 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
320 {
321     METAHEADER *mh;
322     HANDLE hFile;
323
324     TRACE("%s\n", debugstr_w(lpFilename));
325
326     if(!lpFilename)
327         return 0;
328
329     if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
330                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
331         return 0;
332
333     mh = MF_ReadMetaFile(hFile);
334     CloseHandle(hFile);
335     if(!mh) return 0;
336     return MF_Create_HMETAFILE( mh );
337 }
338
339
340 /******************************************************************
341  *         MF_LoadDiskBasedMetaFile
342  *
343  * Creates a new memory-based metafile from a disk-based one.
344  */
345 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
346 {
347     METAHEADERDISK *mhd;
348     HANDLE hfile;
349     METAHEADER *mh2;
350
351     if(mh->mtType != METAFILE_DISK) {
352         ERR("Not a disk based metafile\n");
353         return NULL;
354     }
355     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
356
357     if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
358                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
359         WARN("Can't open file of disk based metafile\n");
360         return NULL;
361     }
362     mh2 = MF_ReadMetaFile(hfile);
363     CloseHandle(hfile);
364     return mh2;
365 }
366
367 /******************************************************************
368  *         MF_CreateMetaHeaderDisk
369  *
370  * Take a memory based METAHEADER and change it to a disk based METAHEADER
371  * assosiated with filename.  Note: Trashes contents of old one.
372  */
373 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
374 {
375     METAHEADERDISK *mhd;
376     DWORD size;
377
378     mh = HeapReAlloc( GetProcessHeap(), 0, mh,
379                       sizeof(METAHEADER) + sizeof(METAHEADERDISK));
380     mh->mtType = METAFILE_DISK;
381     size = HeapSize( GetProcessHeap(), 0, mh );
382     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
383
384     if( uni )
385         WideCharToMultiByte(CP_ACP, 0, filename, -1, 
386                    mhd->filename, sizeof mhd->filename, NULL, NULL);
387     else
388         lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
389     return mh;
390 }
391
392 /******************************************************************
393  *         CopyMetaFile   (GDI.151)
394  */
395 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
396 {
397     METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
398     METAHEADER *mh2 = NULL;
399     HANDLE hFile;
400
401     TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
402
403     if(!mh) return 0;
404
405     if(mh->mtType == METAFILE_DISK)
406         mh2 = MF_LoadDiskBasedMetaFile(mh);
407     else {
408         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
409         memcpy( mh2, mh, mh->mtSize * 2 );
410     }
411     MF_ReleaseMetaHeader16( hSrcMetaFile );
412
413     if(lpFilename) {         /* disk based metafile */
414         if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
415                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
416             HeapFree( GetProcessHeap(), 0, mh2 );
417             return 0;
418         }
419         WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
420         CloseHandle(hFile);
421         mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, FALSE);
422     }
423
424     return MF_Create_HMETAFILE16( mh2 );
425 }
426
427
428 /******************************************************************
429  *         CopyMetaFileW   (GDI32.@)
430  *
431  *  Copies the metafile corresponding to hSrcMetaFile to either
432  *  a disk file, if a filename is given, or to a new memory based
433  *  metafile, if lpFileName is NULL.
434  *
435  * RETURNS
436  *
437  *  Handle to metafile copy on success, NULL on failure.
438  *
439  * BUGS
440  *
441  *  Copying to disk returns NULL even if successful.
442  */
443 HMETAFILE WINAPI CopyMetaFileW(
444                    HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
445                    LPCWSTR lpFilename      /* [in] filename if copying to a file */)
446 {
447     METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
448     METAHEADER *mh2 = NULL;
449     HANDLE hFile;
450
451     TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
452
453     if(!mh) return 0;
454
455     if(mh->mtType == METAFILE_DISK)
456         mh2 = MF_LoadDiskBasedMetaFile(mh);
457     else {
458         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
459         memcpy( mh2, mh, mh->mtSize * 2 );
460     }
461
462     if(lpFilename) {         /* disk based metafile */
463         if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
464                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
465             HeapFree( GetProcessHeap(), 0, mh2 );
466             return 0;
467         }
468         WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
469         CloseHandle(hFile);
470         mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, TRUE);
471     }
472
473     return MF_Create_HMETAFILE( mh2 );
474 }
475
476
477 /******************************************************************
478  *         CopyMetaFileA   (GDI32.@)
479  */
480 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile,
481                                     LPCSTR lpFilename )
482 {
483     UNICODE_STRING lpFilenameW;
484     HMETAFILE ret = 0;
485
486     if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
487     else lpFilenameW.Buffer = NULL;
488
489     if (lpFilenameW.Buffer) {
490         ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
491     }
492     RtlFreeUnicodeString(&lpFilenameW);
493     return ret;
494 }
495
496
497 /******************************************************************
498  *         IsValidMetaFile   (GDI.410)
499  *
500  *  Attempts to check if a given metafile is correctly formatted.
501  *  Currently, the only things verified are several properties of the
502  *  header.
503  *
504  * RETURNS
505  *  TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
506  *
507  * BUGS
508  *  This is not exactly what windows does, see _Undocumented_Windows_
509  *  for details.
510  */
511 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
512 {
513     BOOL16 res=FALSE;
514     METAHEADER *mh = MF_GetMetaHeader16(hmf);
515     if (mh) {
516         if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
517             if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
518                 if (mh->mtVersion == MFVERSION)
519                     res=TRUE;
520         MF_ReleaseMetaHeader16(hmf);
521     }
522     TRACE("IsValidMetaFile %x => %d\n",hmf,res);
523     return res;
524 }
525
526
527 /*******************************************************************
528  *         MF_PlayMetaFile
529  *
530  * Helper for PlayMetaFile
531  */
532 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
533 {
534
535     METARECORD *mr;
536     HANDLETABLE *ht;
537     unsigned int offset = 0;
538     WORD i;
539     HPEN hPen;
540     HBRUSH hBrush;
541     HFONT hFont;
542     BOOL loaded = FALSE;
543
544     if (!mh) return FALSE;
545     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
546         mh = MF_LoadDiskBasedMetaFile(mh);
547         if(!mh) return FALSE;
548         loaded = TRUE;
549     }
550
551     /* save the current pen, brush and font */
552     hPen = GetCurrentObject(hdc, OBJ_PEN);
553     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
554     hFont = GetCurrentObject(hdc, OBJ_FONT);
555
556     /* create the handle table */
557     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
558                     sizeof(HANDLETABLE) * mh->mtNoObjects);
559     if(!ht) return FALSE;
560
561     /* loop through metafile playing records */
562     offset = mh->mtHeaderSize * 2;
563     while (offset < mh->mtSize * 2)
564     {
565         mr = (METARECORD *)((char *)mh + offset);
566         TRACE("offset=%04x,size=%08lx\n",
567             offset, mr->rdSize);
568         if (!mr->rdSize) {
569             TRACE(
570                   "Entry got size 0 at offset %d, total mf length is %ld\n",
571                   offset,mh->mtSize*2);
572                 break; /* would loop endlessly otherwise */
573         }
574         offset += mr->rdSize * 2;
575         PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
576     }
577
578     SelectObject(hdc, hBrush);
579     SelectObject(hdc, hPen);
580     SelectObject(hdc, hFont);
581
582     /* free objects in handle table */
583     for(i = 0; i < mh->mtNoObjects; i++)
584       if(*(ht->objectHandle + i) != 0)
585         DeleteObject(*(ht->objectHandle + i));
586
587     /* free handle table */
588     HeapFree( GetProcessHeap(), 0, ht );
589     if(loaded)
590         HeapFree( GetProcessHeap(), 0, mh );
591     return TRUE;
592 }
593
594 /******************************************************************
595  *         PlayMetaFile   (GDI.123)
596  *
597  */
598 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
599 {
600     BOOL16 ret;
601     METAHEADER *mh = MF_GetMetaHeader16( hmf );
602     ret = MF_PlayMetaFile( HDC_32(hdc), mh );
603     MF_ReleaseMetaHeader16( hmf );
604     return ret;
605 }
606
607 /******************************************************************
608  *         PlayMetaFile   (GDI32.@)
609  *
610  *  Renders the metafile specified by hmf in the DC specified by
611  *  hdc. Returns FALSE on failure, TRUE on success.
612  */
613 BOOL WINAPI PlayMetaFile(
614                              HDC hdc,      /* [in] handle of DC to render in */
615                              HMETAFILE hmf /* [in] handle of metafile to render */
616 )
617 {
618     METAHEADER *mh = MF_GetMetaHeader( hmf );
619     return MF_PlayMetaFile( hdc, mh );
620 }
621
622
623 /******************************************************************
624  *            EnumMetaFile   (GDI.175)
625  *
626  */
627 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
628                               MFENUMPROC16 lpEnumFunc, LPARAM lpData )
629 {
630     METAHEADER *mh = MF_GetMetaHeader16(hmf);
631     METARECORD *mr;
632     HANDLETABLE16 *ht;
633     HDC hdc = HDC_32(hdc16);
634     HGLOBAL16 hHT;
635     SEGPTR spht;
636     unsigned int offset = 0;
637     WORD i, seg;
638     HPEN hPen;
639     HBRUSH hBrush;
640     HFONT hFont;
641     WORD args[8];
642     BOOL16 result = TRUE, loaded = FALSE;
643
644     TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
645
646     if(!mh) return FALSE;
647     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
648         mh = MF_LoadDiskBasedMetaFile(mh);
649         if(!mh) return FALSE;
650         loaded = TRUE;
651     }
652
653     /* save the current pen, brush and font */
654     hPen = GetCurrentObject(hdc, OBJ_PEN);
655     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
656     hFont = GetCurrentObject(hdc, OBJ_FONT);
657
658     /* create the handle table */
659
660     hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
661                      sizeof(HANDLETABLE16) * mh->mtNoObjects);
662     spht = K32WOWGlobalLock16(hHT);
663
664     seg = hmf | 7;
665     offset = mh->mtHeaderSize * 2;
666
667     /* loop through metafile records */
668
669     args[7] = hdc16;
670     args[6] = SELECTOROF(spht);
671     args[5] = OFFSETOF(spht);
672     args[4] = seg + (HIWORD(offset) << __AHSHIFT);
673     args[3] = LOWORD(offset);
674     args[2] = mh->mtNoObjects;
675     args[1] = HIWORD(lpData);
676     args[0] = LOWORD(lpData);
677
678     while (offset < (mh->mtSize * 2))
679     {
680         DWORD ret;
681
682         mr = (METARECORD *)((char *)mh + offset);
683
684         WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
685         if (!LOWORD(ret))
686         {
687             result = FALSE;
688             break;
689         }
690
691         offset += (mr->rdSize * 2);
692         args[4] = seg + (HIWORD(offset) << __AHSHIFT);
693         args[3] = LOWORD(offset);
694     }
695
696     SelectObject(hdc, hBrush);
697     SelectObject(hdc, hPen);
698     SelectObject(hdc, hFont);
699
700     ht = (HANDLETABLE16 *)GlobalLock16(hHT);
701
702     /* free objects in handle table */
703     for(i = 0; i < mh->mtNoObjects; i++)
704       if(*(ht->objectHandle + i) != 0)
705         DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
706
707     /* free handle table */
708     GlobalFree16(hHT);
709     if(loaded)
710         HeapFree( GetProcessHeap(), 0, mh );
711     MF_ReleaseMetaHeader16(hmf);
712     return result;
713 }
714
715 /******************************************************************
716  *            EnumMetaFile   (GDI32.@)
717  *
718  *  Loop through the metafile records in hmf, calling the user-specified
719  *  function for each one, stopping when the user's function returns FALSE
720  *  (which is considered to be failure)
721  *  or when no records are left (which is considered to be success).
722  *
723  * RETURNS
724  *  TRUE on success, FALSE on failure.
725  *
726  * HISTORY
727  *   Niels de carpentier, april 1996
728  */
729 BOOL WINAPI EnumMetaFile(
730                              HDC hdc,
731                              HMETAFILE hmf,
732                              MFENUMPROC lpEnumFunc,
733                              LPARAM lpData)
734 {
735     METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
736     METARECORD *mr;
737     HANDLETABLE *ht;
738     BOOL result = TRUE;
739     int i;
740     unsigned int offset = 0;
741     HPEN hPen;
742     HBRUSH hBrush;
743     HFONT hFont;
744
745     TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
746     if (!mh) return 0;
747     if(mh->mtType == METAFILE_DISK)
748     {
749         /* Create a memory-based copy */
750         if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
751         mh = mhTemp;
752     }
753
754     /* save the current pen, brush and font */
755     hPen = GetCurrentObject(hdc, OBJ_PEN);
756     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
757     hFont = GetCurrentObject(hdc, OBJ_FONT);
758
759     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
760                             sizeof(HANDLETABLE) * mh->mtNoObjects);
761
762     /* loop through metafile records */
763     offset = mh->mtHeaderSize * 2;
764
765     while (offset < (mh->mtSize * 2))
766     {
767         mr = (METARECORD *)((char *)mh + offset);
768         if(mr->rdFunction == META_EOF) {
769             TRACE("Got META_EOF so stopping\n");
770             break;
771         }
772         TRACE("Calling EnumFunc with record type %x\n",
773               mr->rdFunction);
774         if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
775         {
776             result = FALSE;
777             break;
778         }
779
780         offset += (mr->rdSize * 2);
781     }
782
783     /* restore pen, brush and font */
784     SelectObject(hdc, hBrush);
785     SelectObject(hdc, hPen);
786     SelectObject(hdc, hFont);
787
788     /* free objects in handle table */
789     for(i = 0; i < mh->mtNoObjects; i++)
790       if(*(ht->objectHandle + i) != 0)
791         DeleteObject(*(ht->objectHandle + i));
792
793     /* free handle table */
794     HeapFree( GetProcessHeap(), 0, ht);
795     /* free a copy of metafile */
796     if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
797     return result;
798 }
799
800 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
801 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
802 /******************************************************************
803  *         PlayMetaFileRecord   (GDI32.@)
804  *
805  *   Render a single metafile record specified by *mr in the DC hdc, while
806  *   using the handle table *ht, of length handles,
807  *   to store metafile objects.
808  *
809  * BUGS
810  *  The following metafile records are unimplemented:
811  *
812  *  DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
813  *  RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
814  *  ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
815  */
816 BOOL WINAPI PlayMetaFileRecord( HDC hdc,  HANDLETABLE *ht, METARECORD *mr, UINT handles )
817 {
818     short s1;
819     POINT *pt;
820     BITMAPINFOHEADER *infohdr;
821
822     TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
823
824     switch (mr->rdFunction)
825     {
826     case META_EOF:
827         break;
828
829     case META_DELETEOBJECT:
830         DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
831         *(ht->objectHandle + mr->rdParm[0]) = 0;
832         break;
833
834     case META_SETBKCOLOR:
835         SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
836         break;
837
838     case META_SETBKMODE:
839         SetBkMode(hdc, mr->rdParm[0]);
840         break;
841
842     case META_SETMAPMODE:
843         SetMapMode(hdc, mr->rdParm[0]);
844         break;
845
846     case META_SETROP2:
847         SetROP2(hdc, mr->rdParm[0]);
848         break;
849
850     case META_SETRELABS:
851         SetRelAbs(hdc, mr->rdParm[0]);
852         break;
853
854     case META_SETPOLYFILLMODE:
855         SetPolyFillMode(hdc, mr->rdParm[0]);
856         break;
857
858     case META_SETSTRETCHBLTMODE:
859         SetStretchBltMode(hdc, mr->rdParm[0]);
860         break;
861
862     case META_SETTEXTCOLOR:
863         SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
864         break;
865
866     case META_SETWINDOWORG:
867         SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
868         break;
869
870     case META_SETWINDOWEXT:
871         SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
872         break;
873
874     case META_SETVIEWPORTORG:
875         SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
876         break;
877
878     case META_SETVIEWPORTEXT:
879         SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
880         break;
881
882     case META_OFFSETWINDOWORG:
883         OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
884         break;
885
886     case META_SCALEWINDOWEXT:
887         ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
888                               (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
889         break;
890
891     case META_OFFSETVIEWPORTORG:
892         OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
893         break;
894
895     case META_SCALEVIEWPORTEXT:
896         ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
897                                 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
898         break;
899
900     case META_LINETO:
901         LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
902         break;
903
904     case META_MOVETO:
905         MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
906         break;
907
908     case META_EXCLUDECLIPRECT:
909         ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
910                               (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
911         break;
912
913     case META_INTERSECTCLIPRECT:
914         IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
915                                 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
916         break;
917
918     case META_ARC:
919         Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
920                  (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
921                  (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
922                  (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
923         break;
924
925     case META_ELLIPSE:
926         Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
927                      (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
928         break;
929
930     case META_FLOODFILL:
931         FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
932                     MAKELONG(mr->rdParm[0], mr->rdParm[1]));
933         break;
934
935     case META_PIE:
936         Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
937                  (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
938                  (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
939                  (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
940         break;
941
942     case META_RECTANGLE:
943         Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
944                        (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
945         break;
946
947     case META_ROUNDRECT:
948         RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
949                        (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
950                        (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
951         break;
952
953     case META_PATBLT:
954         PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
955                     (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
956                     MAKELONG(mr->rdParm[0], mr->rdParm[1]));
957         break;
958
959     case META_SAVEDC:
960         SaveDC(hdc);
961         break;
962
963     case META_SETPIXEL:
964         SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
965                  MAKELONG(mr->rdParm[0], mr->rdParm[1]));
966         break;
967
968     case META_OFFSETCLIPRGN:
969         OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
970         break;
971
972     case META_TEXTOUT:
973         s1 = mr->rdParm[0];
974         TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
975                  (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
976                  (char *)(mr->rdParm + 1), s1);
977         break;
978
979     case META_POLYGON:
980         if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
981         {
982             Polygon(hdc, pt, mr->rdParm[0]);
983             HeapFree( GetProcessHeap(), 0, pt );
984         }
985         break;
986
987     case META_POLYPOLYGON:
988         {
989             UINT i, total;
990             SHORT *counts = (SHORT *)(mr->rdParm + 1);
991
992             for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
993             pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
994             if (pt)
995             {
996                 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
997                 if (cnt32)
998                 {
999                     for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
1000                     PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
1001                     HeapFree( GetProcessHeap(), 0, cnt32 );
1002                 }
1003             }
1004             HeapFree( GetProcessHeap(), 0, pt );
1005         }
1006         break;
1007
1008     case META_POLYLINE:
1009         if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
1010         {
1011             Polyline( hdc, pt, mr->rdParm[0] );
1012             HeapFree( GetProcessHeap(), 0, pt );
1013         }
1014         break;
1015
1016     case META_RESTOREDC:
1017         RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1018         break;
1019
1020     case META_SELECTOBJECT:
1021         SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1022         break;
1023
1024     case META_CHORD:
1025         Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1026                    (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1027                    (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1028                    (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1029         break;
1030
1031     case META_CREATEPATTERNBRUSH:
1032         switch (mr->rdParm[0])
1033         {
1034         case BS_PATTERN:
1035             infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1036             MF_AddHandle(ht, handles,
1037                          CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1038                                       infohdr->biHeight,
1039                                       infohdr->biPlanes,
1040                                       infohdr->biBitCount,
1041                                       (LPSTR)(mr->rdParm +
1042                                       (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1043             break;
1044
1045         case BS_DIBPATTERN:
1046             infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1047             MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1048             break;
1049
1050         default:
1051             ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1052                 mr->rdParm[0]);
1053             break;
1054         }
1055         break;
1056
1057     case META_CREATEPENINDIRECT:
1058         {
1059             LOGPEN pen;
1060             pen.lopnStyle = mr->rdParm[0];
1061             pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1062             pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1063             pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1064             MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1065         }
1066         break;
1067
1068     case META_CREATEFONTINDIRECT:
1069         {
1070             LOGFONTA font;
1071             font.lfHeight         = (SHORT)mr->rdParm[0];
1072             font.lfWidth          = (SHORT)mr->rdParm[1];
1073             font.lfEscapement     = (SHORT)mr->rdParm[2];
1074             font.lfOrientation    = (SHORT)mr->rdParm[3];
1075             font.lfWeight         = (SHORT)mr->rdParm[4];
1076             font.lfItalic         = LOBYTE(mr->rdParm[5]);
1077             font.lfUnderline      = HIBYTE(mr->rdParm[5]);
1078             font.lfStrikeOut      = LOBYTE(mr->rdParm[6]);
1079             font.lfCharSet        = HIBYTE(mr->rdParm[6]);
1080             font.lfOutPrecision   = LOBYTE(mr->rdParm[7]);
1081             font.lfClipPrecision  = HIBYTE(mr->rdParm[7]);
1082             font.lfQuality        = LOBYTE(mr->rdParm[8]);
1083             font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1084             memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1085             MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1086         }
1087         break;
1088
1089     case META_CREATEBRUSHINDIRECT:
1090         {
1091             LOGBRUSH brush;
1092             brush.lbStyle = mr->rdParm[0];
1093             brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1094             brush.lbHatch = mr->rdParm[3];
1095             MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1096         }
1097         break;
1098
1099     case META_CREATEPALETTE:
1100         MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1101         break;
1102
1103     case META_SETTEXTALIGN:
1104         SetTextAlign(hdc, mr->rdParm[0]);
1105         break;
1106
1107     case META_SELECTPALETTE:
1108         GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1109         break;
1110
1111     case META_SETMAPPERFLAGS:
1112         SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1113         break;
1114
1115     case META_REALIZEPALETTE:
1116         GDIRealizePalette(hdc);
1117         break;
1118
1119     case META_ESCAPE:
1120         Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
1121         break;
1122
1123     case META_EXTTEXTOUT:
1124         MF_Play_MetaExtTextOut( hdc, mr );
1125         break;
1126
1127     case META_STRETCHDIB:
1128       {
1129         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1130         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1131         StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1132                        (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1133                        (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1134                        mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1135       }
1136       break;
1137
1138     case META_DIBSTRETCHBLT:
1139       {
1140         LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1141         LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1142         StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1143                        (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1144                        (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1145                        DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1146       }
1147       break;
1148
1149     case META_STRETCHBLT:
1150       {
1151         HDC hdcSrc = CreateCompatibleDC(hdc);
1152         HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1153                                        mr->rdParm[11], /*Height*/
1154                                        mr->rdParm[13], /*Planes*/
1155                                        mr->rdParm[14], /*BitsPixel*/
1156                                        (LPSTR)&mr->rdParm[15]);  /*bits*/
1157         SelectObject(hdcSrc,hbitmap);
1158         StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1159                    (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1160                    hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1161                    (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1162                    MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1163         DeleteDC(hdcSrc);
1164       }
1165       break;
1166
1167     case META_BITBLT:
1168       {
1169         HDC hdcSrc = CreateCompatibleDC(hdc);
1170         HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1171                                         mr->rdParm[8]/*Height*/,
1172                                         mr->rdParm[10]/*Planes*/,
1173                                         mr->rdParm[11]/*BitsPixel*/,
1174                                         (LPSTR)&mr->rdParm[12]/*bits*/);
1175         SelectObject(hdcSrc,hbitmap);
1176         BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1177                 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1178                 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1179                 MAKELONG(0,mr->rdParm[0]));
1180         DeleteDC(hdcSrc);
1181       }
1182       break;
1183
1184     case META_CREATEREGION:
1185       {
1186         HRGN hrgn = CreateRectRgn(0,0,0,0);
1187
1188         MF_Play_MetaCreateRegion(mr, hrgn);
1189         MF_AddHandle(ht, handles, hrgn);
1190       }
1191       break;
1192
1193     case META_FILLREGION:
1194         FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1195                 *(ht->objectHandle + mr->rdParm[0]));
1196         break;
1197
1198     case META_FRAMEREGION:
1199         FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1200                  *(ht->objectHandle + mr->rdParm[2]),
1201                  (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1202         break;
1203
1204     case META_INVERTREGION:
1205         InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1206         break;
1207
1208     case META_PAINTREGION:
1209         PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1210         break;
1211
1212     case META_SELECTCLIPREGION:
1213         SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1214         break;
1215
1216     case META_DIBCREATEPATTERNBRUSH:
1217         /*  mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1218             but there's no difference */
1219         MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1220         break;
1221
1222     case META_DIBBITBLT:
1223       /* In practice I've found that there are two layouts for
1224          META_DIBBITBLT, one (the first here) is the usual one when a src
1225          dc is actually passed to it, the second occurs when the src dc is
1226          passed in as NULL to the creating BitBlt. As the second case has
1227          no dib, a size check will suffice to distinguish.
1228
1229          Caolan.McNamara@ul.ie */
1230
1231         if (mr->rdSize > 12) {
1232             LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1233             LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1234
1235             StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1236                           (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1237                           (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1238                           DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1239         }
1240         else /* equivalent to a PatBlt */
1241             PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1242                    (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1243                    MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1244         break;
1245
1246     case META_SETTEXTCHAREXTRA:
1247         SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1248         break;
1249
1250     case META_SETTEXTJUSTIFICATION:
1251         SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1252         break;
1253
1254     case META_EXTFLOODFILL:
1255         ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1256                      MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1257                      mr->rdParm[0]);
1258         break;
1259
1260     case META_SETDIBTODEV:
1261         {
1262             BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1263             char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1264             SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1265                               (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1266                               (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1267                               mr->rdParm[2], mr->rdParm[1], bits, info,
1268                               mr->rdParm[0]);
1269             break;
1270         }
1271
1272 #define META_UNIMP(x) case x: \
1273 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1274 break;
1275     META_UNIMP(META_DRAWTEXT)
1276     META_UNIMP(META_ANIMATEPALETTE)
1277     META_UNIMP(META_SETPALENTRIES)
1278     META_UNIMP(META_RESIZEPALETTE)
1279     META_UNIMP(META_RESETDC)
1280     META_UNIMP(META_STARTDOC)
1281     META_UNIMP(META_STARTPAGE)
1282     META_UNIMP(META_ENDPAGE)
1283     META_UNIMP(META_ABORTDOC)
1284     META_UNIMP(META_ENDDOC)
1285     META_UNIMP(META_CREATEBRUSH)
1286     META_UNIMP(META_CREATEBITMAPINDIRECT)
1287     META_UNIMP(META_CREATEBITMAP)
1288 #undef META_UNIMP
1289
1290     default:
1291         WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1292         return FALSE;
1293     }
1294     return TRUE;
1295 }
1296
1297 /******************************************************************
1298  *         GetMetaFileBits   (GDI.159)
1299  *
1300  * Trade in a metafile object handle for a handle to the metafile memory.
1301  *
1302  */
1303
1304 HGLOBAL16 WINAPI GetMetaFileBits16(
1305                                  HMETAFILE16 hmf /* [in] metafile handle */
1306                                  )
1307 {
1308     TRACE("hMem out: %04x\n", hmf);
1309     return hmf;
1310 }
1311
1312 /******************************************************************
1313  *         SetMetaFileBits   (GDI.160)
1314  *
1315  * Trade in a metafile memory handle for a handle to a metafile object.
1316  * The memory region should hold a proper metafile, otherwise
1317  * problems will occur when it is used. Validity of the memory is not
1318  * checked. The function is essentially just the identity function.
1319  */
1320 HMETAFILE16 WINAPI SetMetaFileBits16(
1321                                    HGLOBAL16 hMem
1322                         /* [in] handle to a memory region holding a metafile */
1323 )
1324 {
1325     TRACE("hmf out: %04x\n", hMem);
1326
1327     return hMem;
1328 }
1329
1330 /******************************************************************
1331  *         SetMetaFileBitsBetter   (GDI.196)
1332  *
1333  * Trade in a metafile memory handle for a handle to a metafile object,
1334  * making a cursory check (using IsValidMetaFile()) that the memory
1335  * handle points to a valid metafile.
1336  *
1337  * RETURNS
1338  *  Handle to a metafile on success, NULL on failure..
1339  */
1340 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1341 {
1342     if( IsValidMetaFile16( hMeta ) )
1343         return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1344                            GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1345     return (HMETAFILE16)0;
1346 }
1347
1348 /******************************************************************
1349  *         SetMetaFileBitsEx    (GDI32.@)
1350  *
1351  *  Create a metafile from raw data. No checking of the data is performed.
1352  *  Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1353  */
1354 HMETAFILE WINAPI SetMetaFileBitsEx(
1355      UINT size,         /* [in] size of metafile, in bytes */
1356      const BYTE *lpData /* [in] pointer to metafile data */
1357     )
1358 {
1359     METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1360     if (!mh) return 0;
1361     memcpy(mh, lpData, size);
1362     return MF_Create_HMETAFILE(mh);
1363 }
1364
1365 /*****************************************************************
1366  *  GetMetaFileBitsEx     (GDI32.@)
1367  *
1368  * Get raw metafile data.
1369  *
1370  *  Copies the data from metafile _hmf_ into the buffer _buf_.
1371  *  If _buf_ is zero, returns size of buffer required. Otherwise,
1372  *  returns number of bytes copied.
1373  */
1374 UINT WINAPI GetMetaFileBitsEx(
1375      HMETAFILE hmf, /* [in] metafile */
1376      UINT nSize,    /* [in] size of buf */
1377      LPVOID buf     /* [out] buffer to receive raw metafile data */)
1378 {
1379     METAHEADER *mh = MF_GetMetaHeader(hmf);
1380     UINT mfSize;
1381
1382     TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1383     if (!mh) return 0;  /* FIXME: error code */
1384     if(mh->mtType == METAFILE_DISK)
1385         FIXME("Disk-based metafile?\n");
1386     mfSize = mh->mtSize * 2;
1387     if (!buf) {
1388         TRACE("returning size %d\n", mfSize);
1389         return mfSize;
1390     }
1391     if(mfSize > nSize) mfSize = nSize;
1392     memmove(buf, mh, mfSize);
1393     return mfSize;
1394 }
1395
1396 /******************************************************************
1397  *         GetWinMetaFileBits [GDI32.@]
1398  */
1399 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1400                                 UINT cbBuffer, LPBYTE lpbBuffer,
1401                                 INT fnMapMode, HDC hdcRef)
1402 {
1403     HDC hdcmf;
1404     HMETAFILE hmf;
1405     UINT ret;
1406     RECT rc;
1407     INT oldMapMode;
1408
1409     GetClipBox(hdcRef, &rc);
1410     oldMapMode = SetMapMode(hdcRef, fnMapMode);
1411
1412     TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1413         fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1414
1415     hdcmf = CreateMetaFileA(NULL);
1416     PlayEnhMetaFile(hdcmf, hemf, &rc);
1417     hmf = CloseMetaFile(hdcmf);
1418     ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1419     DeleteMetaFile(hmf);
1420
1421     SetMapMode(hdcRef, oldMapMode);
1422
1423     return ret;
1424 }
1425
1426 /******************************************************************
1427  *         MF_Play_MetaCreateRegion
1428  *
1429  *  Handles META_CREATEREGION for PlayMetaFileRecord().
1430  */
1431
1432 /*
1433  *      The layout of the record looks something like this:
1434  *
1435  *       rdParm meaning
1436  *       0              Always 0?
1437  *       1              Always 6?
1438  *       2              Looks like a handle? - not constant
1439  *       3              0 or 1 ??
1440  *       4              Total number of bytes
1441  *       5              No. of separate bands = n [see below]
1442  *       6              Largest number of x co-ords in a band
1443  *       7-10           Bounding box x1 y1 x2 y2
1444  *       11-...         n bands
1445  *
1446  *       Regions are divided into bands that are uniform in the
1447  *       y-direction. Each band consists of pairs of on/off x-coords and is
1448  *       written as
1449  *              m y0 y1 x1 x2 x3 ... xm m
1450  *       into successive rdParm[]s.
1451  *
1452  *       This is probably just a dump of the internal RGNOBJ?
1453  *
1454  *       HDMD - 18/12/97
1455  *
1456  */
1457
1458 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1459 {
1460     WORD band, pair;
1461     WORD *start, *end;
1462     INT16 y0, y1;
1463     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1464
1465     for(band  = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1466                                                 band++, start = end + 1) {
1467         if(*start / 2 != (*start + 1) / 2) {
1468             WARN("Delimiter not even.\n");
1469             DeleteObject( hrgn2 );
1470             return FALSE;
1471         }
1472
1473         end = start + *start + 3;
1474         if(end > (WORD *)mr + mr->rdSize) {
1475             WARN("End points outside record.\n");
1476             DeleteObject( hrgn2 );
1477             return FALSE;
1478         }
1479
1480         if(*start != *end) {
1481             WARN("Mismatched delimiters.\n");
1482             DeleteObject( hrgn2 );
1483             return FALSE;
1484         }
1485
1486         y0 = *(INT16 *)(start + 1);
1487         y1 = *(INT16 *)(start + 2);
1488         for(pair = 0; pair < *start / 2; pair++) {
1489             SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1490                                  *(INT16 *)(start + 4 + 2*pair), y1 );
1491             CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1492         }
1493     }
1494     DeleteObject( hrgn2 );
1495     return TRUE;
1496  }
1497
1498
1499 /******************************************************************
1500  *         MF_Play_MetaExtTextOut
1501  *
1502  *  Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1503  */
1504
1505 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1506 {
1507     INT *dx = NULL;
1508     int i;
1509     LPINT16 dxx;
1510     LPSTR sot;
1511     DWORD len;
1512     WORD s1;
1513     RECT rect;
1514     BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1515
1516     s1 = mr->rdParm[2];                              /* String length */
1517     len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1518       + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1519                                            /* rec len without dx array */
1520
1521     sot = (LPSTR)&mr->rdParm[4];                      /* start_of_text */
1522     if (isrect)
1523     {
1524         rect.left   = (SHORT)mr->rdParm[4];
1525         rect.top    = (SHORT)mr->rdParm[5];
1526         rect.right  = (SHORT)mr->rdParm[6];
1527         rect.bottom = (SHORT)mr->rdParm[7];
1528         sot += sizeof(RECT16);  /* there is a rectangle, so add offset */
1529     }
1530
1531     if (mr->rdSize == len / 2)
1532         dxx = NULL;                      /* determine if array present */
1533     else
1534         if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1535         {
1536             dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1537             dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1538             if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1539         }
1540         else {
1541             TRACE("%s  len: %ld\n",  sot, mr->rdSize);
1542             WARN(
1543              "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1544                  len, s1, mr->rdSize, mr->rdParm[3]);
1545             dxx = NULL; /* should't happen -- but if, we continue with NULL */
1546         }
1547     ExtTextOutA( hdc,
1548                  (SHORT)mr->rdParm[1],       /* X position */
1549                  (SHORT)mr->rdParm[0],       /* Y position */
1550                  mr->rdParm[3],              /* options */
1551                  &rect,                      /* rectangle */
1552                  sot,                        /* string */
1553                  s1, dx);                   /* length, dx array */
1554     if (dx)
1555     {
1556         TRACE("%s  len: %ld  dx0: %d\n", sot, mr->rdSize, dx[0]);
1557         HeapFree( GetProcessHeap(), 0, dx );
1558     }
1559     return TRUE;
1560 }