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