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