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