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