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