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