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