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