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