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