Implement ldap_create_vlv_control{A,W},
[wine] / dlls / gdi / metafile.c
1 /*
2  * Metafile functions
3  *
4  * Copyright  David W. Metcalfe, 1994
5  * Copyright  Niels de Carpentier, 1996
6  * Copyright  Albrecht Kleine, 1996
7  * Copyright  Huw Davies, 1996
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * NOTES
24  *
25  * These functions are primarily involved with metafile playback or anything
26  * that touches a HMETAFILE.
27  * For recording of metafiles look in graphics/metafiledrv/
28  *
29  * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
30  * global memory handles so these cannot be interchanged.
31  *
32  * Memory-based metafiles are just stored as a continuous block of memory with
33  * a METAHEADER at the head with METARECORDs appended to it.  mtType is
34  * METAFILE_MEMORY (1).  Note this is indentical to the disk image of a
35  * disk-based metafile - even mtType is METAFILE_MEMORY.
36  * 16bit HMETAFILE16s are global handles to this block
37  * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
38  * the memory.
39  * Disk-based metafiles are rather different. HMETAFILE16s point to a
40  * METAHEADER which has mtType equal to METAFILE_DISK (2).  Following the 9
41  * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
42  * more 0, then 2 which may be a time stamp of the file and then the path of
43  * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
44  *
45  * HDMD - 14/4/1999
46  */
47
48 #include "config.h"
49
50 #include <string.h>
51 #include <fcntl.h>
52
53 #include "wine/winbase16.h"
54 #include "wine/wingdi16.h"
55 #include "gdi.h"
56 #include "wownt32.h"
57 #include "winreg.h"
58 #include "winternl.h"
59 #include "gdi_private.h"
60 #include "wine/debug.h"
61
62 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
63
64 #include "pshpack1.h"
65 typedef struct
66 {
67     DWORD dw1, dw2, dw3;
68     WORD w4;
69     CHAR filename[0x100];
70 } METAHEADERDISK;
71 #include "poppack.h"
72
73 typedef struct
74 {
75     GDIOBJHDR   header;
76     METAHEADER  *mh;
77 } METAFILEOBJ;
78
79 #define MFHEADERSIZE (sizeof(METAHEADER))
80 #define MFVERSION 0x300
81
82
83 /******************************************************************
84  *         MF_AddHandle
85  *
86  *    Add a handle to an external handle table and return the index
87  */
88 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
89 {
90     int i;
91
92     for (i = 0; i < htlen; i++)
93     {
94         if (*(ht->objectHandle + i) == 0)
95         {
96             *(ht->objectHandle + i) = hobj;
97             return i;
98         }
99     }
100     return -1;
101 }
102
103
104 /******************************************************************
105  *         MF_Create_HMETATFILE
106  *
107  * Creates a (32 bit) HMETAFILE object from a METAHEADER
108  *
109  * HMETAFILEs are GDI objects.
110  */
111 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
112 {
113     HMETAFILE hmf = 0;
114     METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
115                                             (HGDIOBJ *)&hmf, NULL );
116     if (metaObj)
117     {
118         metaObj->mh = mh;
119         GDI_ReleaseObj( hmf );
120     }
121     return hmf;
122 }
123
124 /******************************************************************
125  *         MF_Create_HMETATFILE16
126  *
127  * Creates a HMETAFILE16 object from a METAHEADER
128  *
129  * HMETAFILE16s are Global memory handles.
130  */
131 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
132 {
133     HMETAFILE16 hmf;
134     DWORD size = mh->mtSize * sizeof(WORD);
135
136     hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
137     if(hmf)
138     {
139         METAHEADER *mh_dest = GlobalLock16(hmf);
140         memcpy(mh_dest, mh, size);
141         GlobalUnlock16(hmf);
142     }
143     HeapFree(GetProcessHeap(), 0, mh);
144     return hmf;
145 }
146
147 /******************************************************************
148  *         MF_GetMetaHeader
149  *
150  * Returns ptr to METAHEADER associated with HMETAFILE
151  */
152 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
153 {
154     METAHEADER *ret = NULL;
155     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
156     if (metaObj)
157     {
158         ret = metaObj->mh;
159         GDI_ReleaseObj( hmf );
160     }
161     return ret;
162 }
163
164 /******************************************************************
165  *         MF_GetMetaHeader16
166  *
167  * Returns ptr to METAHEADER associated with HMETAFILE16
168  * Should be followed by call to MF_ReleaseMetaHeader16
169  */
170 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
171 {
172     return GlobalLock16(hmf);
173 }
174
175 /******************************************************************
176  *         MF_ReleaseMetaHeader16
177  *
178  * Releases METAHEADER associated with HMETAFILE16
179  */
180 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
181 {
182     return GlobalUnlock16( hmf );
183 }
184
185
186 /******************************************************************
187  *         convert_points
188  *
189  * Convert an array of POINT16 to an array of POINT.
190  * Result must be freed by caller.
191  */
192 static POINT *convert_points( UINT count, POINT16 *pt16 )
193 {
194     UINT i;
195     POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
196     if (ret)
197     {
198         for (i = 0; i < count; i++)
199         {
200             ret[i].x = pt16[i].x;
201             ret[i].y = pt16[i].y;
202         }
203     }
204     return ret;
205 }
206
207
208 /******************************************************************
209  *           DeleteMetaFile   (GDI.127)
210  */
211 BOOL16 WINAPI DeleteMetaFile16(  HMETAFILE16 hmf )
212 {
213     return !GlobalFree16( hmf );
214 }
215
216 /******************************************************************
217  *          DeleteMetaFile  (GDI32.@)
218  *
219  *  Delete a memory-based metafile.
220  */
221
222 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
223 {
224     METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
225     if (!metaObj) return FALSE;
226     HeapFree( GetProcessHeap(), 0, metaObj->mh );
227     GDI_FreeObject( hmf, metaObj );
228     return TRUE;
229 }
230
231 /******************************************************************
232  *         MF_ReadMetaFile
233  *
234  * Returns a pointer to a memory based METAHEADER read in from file HFILE
235  *
236  */
237 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
238 {
239     METAHEADER *mh;
240     DWORD BytesRead, size;
241
242     size = sizeof(METAHEADER);
243     mh = HeapAlloc( GetProcessHeap(), 0, size );
244     if(!mh) return NULL;
245     if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
246        BytesRead != size) {
247         HeapFree( GetProcessHeap(), 0, mh );
248         return NULL;
249     }
250     if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
251         mh->mtHeaderSize != size / 2)
252     {
253         HeapFree( GetProcessHeap(), 0, mh );
254         return NULL;
255     }
256     size = mh->mtSize * 2;
257     mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
258     if(!mh) return NULL;
259     size -= sizeof(METAHEADER);
260     if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
261                  NULL) == 0 ||
262        BytesRead != size) {
263         HeapFree( GetProcessHeap(), 0, mh );
264         return NULL;
265     }
266
267     if (mh->mtType != METAFILE_MEMORY) {
268         WARN("Disk metafile had mtType = %04x\n", mh->mtType);
269         mh->mtType = METAFILE_MEMORY;
270     }
271     return mh;
272 }
273
274 /******************************************************************
275  *         GetMetaFile   (GDI.124)
276  */
277 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
278 {
279     METAHEADER *mh;
280     HANDLE hFile;
281
282     TRACE("%s\n", lpFilename);
283
284     if(!lpFilename)
285         return 0;
286
287     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
288                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
289         return 0;
290
291     mh = MF_ReadMetaFile(hFile);
292     CloseHandle(hFile);
293     if(!mh) return 0;
294     return MF_Create_HMETAFILE16( mh );
295 }
296
297 /******************************************************************
298  *         GetMetaFileA   (GDI32.@)
299  *
300  *  Read a metafile from a file. Returns handle to a memory-based metafile.
301  */
302 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
303 {
304     METAHEADER *mh;
305     HANDLE hFile;
306
307     TRACE("%s\n", lpFilename);
308
309     if(!lpFilename)
310         return 0;
311
312     if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
313                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
314         return 0;
315
316     mh = MF_ReadMetaFile(hFile);
317     CloseHandle(hFile);
318     if(!mh) return 0;
319     return MF_Create_HMETAFILE( mh );
320 }
321
322
323
324 /******************************************************************
325  *         GetMetaFileW   (GDI32.@)
326  */
327 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
328 {
329     METAHEADER *mh;
330     HANDLE hFile;
331
332     TRACE("%s\n", debugstr_w(lpFilename));
333
334     if(!lpFilename)
335         return 0;
336
337     if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
338                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
339         return 0;
340
341     mh = MF_ReadMetaFile(hFile);
342     CloseHandle(hFile);
343     if(!mh) return 0;
344     return MF_Create_HMETAFILE( mh );
345 }
346
347
348 /******************************************************************
349  *         MF_LoadDiskBasedMetaFile
350  *
351  * Creates a new memory-based metafile from a disk-based one.
352  */
353 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
354 {
355     METAHEADERDISK *mhd;
356     HANDLE hfile;
357     METAHEADER *mh2;
358
359     if(mh->mtType != METAFILE_DISK) {
360         ERR("Not a disk based metafile\n");
361         return NULL;
362     }
363     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
364
365     if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
366                             OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
367         WARN("Can't open file of disk based metafile\n");
368         return NULL;
369     }
370     mh2 = MF_ReadMetaFile(hfile);
371     CloseHandle(hfile);
372     return mh2;
373 }
374
375 /******************************************************************
376  *         MF_CreateMetaHeaderDisk
377  *
378  * Take a memory based METAHEADER and change it to a disk based METAHEADER
379  * assosiated with filename.  Note: Trashes contents of old one.
380  */
381 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
382 {
383     METAHEADERDISK *mhd;
384
385     mh = HeapReAlloc( GetProcessHeap(), 0, mh,
386                       sizeof(METAHEADER) + sizeof(METAHEADERDISK));
387     mh->mtType = METAFILE_DISK;
388     mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
389
390     if( uni )
391         WideCharToMultiByte(CP_ACP, 0, filename, -1, 
392                    mhd->filename, sizeof mhd->filename, NULL, NULL);
393     else
394         lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
395     return mh;
396 }
397
398 /******************************************************************
399  *         CopyMetaFile   (GDI.151)
400  */
401 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
402 {
403     METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
404     METAHEADER *mh2 = NULL;
405     HANDLE hFile;
406
407     TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
408
409     if(!mh) return 0;
410
411     if(mh->mtType == METAFILE_DISK)
412         mh2 = MF_LoadDiskBasedMetaFile(mh);
413     else {
414         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
415         memcpy( mh2, mh, mh->mtSize * 2 );
416     }
417     MF_ReleaseMetaHeader16( hSrcMetaFile );
418
419     if(lpFilename) {         /* disk based metafile */
420         DWORD w;
421         if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
422                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
423             HeapFree( GetProcessHeap(), 0, mh2 );
424             return 0;
425         }
426         WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
427         CloseHandle(hFile);
428         mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, FALSE);
429     }
430
431     return MF_Create_HMETAFILE16( mh2 );
432 }
433
434
435 /******************************************************************
436  *         CopyMetaFileW   (GDI32.@)
437  *
438  *  Copies the metafile corresponding to hSrcMetaFile to either
439  *  a disk file, if a filename is given, or to a new memory based
440  *  metafile, if lpFileName is NULL.
441  *
442  * PARAMS
443  *  hSrcMetaFile [I] handle of metafile to copy
444  *  lpFilename   [I] filename if copying to a file
445  *
446  * RETURNS
447  *  Handle to metafile copy on success, NULL on failure.
448  *
449  * BUGS
450  *  Copying to disk returns NULL even if successful.
451  */
452 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
453 {
454     METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
455     METAHEADER *mh2 = NULL;
456     HANDLE hFile;
457
458     TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
459
460     if(!mh) return 0;
461
462     if(mh->mtType == METAFILE_DISK)
463         mh2 = MF_LoadDiskBasedMetaFile(mh);
464     else {
465         mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
466         memcpy( mh2, mh, mh->mtSize * 2 );
467     }
468
469     if(lpFilename) {         /* disk based metafile */
470         DWORD w;
471         if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
472                                 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
473             HeapFree( GetProcessHeap(), 0, mh2 );
474             return 0;
475         }
476         WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
477         CloseHandle(hFile);
478     }
479
480     return MF_Create_HMETAFILE( mh2 );
481 }
482
483
484 /******************************************************************
485  *         CopyMetaFileA   (GDI32.@)
486  *
487  * See CopyMetaFileW.
488  */
489 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
490 {
491     UNICODE_STRING lpFilenameW;
492     HMETAFILE ret = 0;
493
494     if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
495     else lpFilenameW.Buffer = NULL;
496
497     ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
498     if (lpFilenameW.Buffer)
499         RtlFreeUnicodeString(&lpFilenameW);
500     return ret;
501 }
502
503
504 /******************************************************************
505  *         IsValidMetaFile   (GDI.410)
506  *
507  *  Attempts to check if a given metafile is correctly formatted.
508  *  Currently, the only things verified are several properties of the
509  *  header.
510  *
511  * RETURNS
512  *  TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
513  *
514  * BUGS
515  *  This is not exactly what windows does, see _Undocumented_Windows_
516  *  for details.
517  */
518 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
519 {
520     BOOL16 res=FALSE;
521     METAHEADER *mh = MF_GetMetaHeader16(hmf);
522     if (mh) {
523         if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
524             if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
525                 if (mh->mtVersion == MFVERSION)
526                     res=TRUE;
527         MF_ReleaseMetaHeader16(hmf);
528     }
529     TRACE("IsValidMetaFile %x => %d\n",hmf,res);
530     return res;
531 }
532
533
534 /*******************************************************************
535  *         MF_PlayMetaFile
536  *
537  * Helper for PlayMetaFile
538  */
539 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
540 {
541
542     METARECORD *mr;
543     HANDLETABLE *ht;
544     unsigned int offset = 0;
545     WORD i;
546     HPEN hPen;
547     HBRUSH hBrush;
548     HFONT hFont;
549     BOOL loaded = FALSE;
550
551     if (!mh) return FALSE;
552     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
553         mh = MF_LoadDiskBasedMetaFile(mh);
554         if(!mh) return FALSE;
555         loaded = TRUE;
556     }
557
558     /* save the current pen, brush and font */
559     hPen = GetCurrentObject(hdc, OBJ_PEN);
560     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
561     hFont = GetCurrentObject(hdc, OBJ_FONT);
562
563     /* create the handle table */
564     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
565                     sizeof(HANDLETABLE) * mh->mtNoObjects);
566     if(!ht) return FALSE;
567
568     /* loop through metafile playing records */
569     offset = mh->mtHeaderSize * 2;
570     while (offset < mh->mtSize * 2)
571     {
572         mr = (METARECORD *)((char *)mh + offset);
573         TRACE("offset=%04x,size=%08lx\n",
574             offset, mr->rdSize);
575         if (!mr->rdSize) {
576             TRACE(
577                   "Entry got size 0 at offset %d, total mf length is %ld\n",
578                   offset,mh->mtSize*2);
579                 break; /* would loop endlessly otherwise */
580         }
581         offset += mr->rdSize * 2;
582         PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
583     }
584
585     SelectObject(hdc, hBrush);
586     SelectObject(hdc, hPen);
587     SelectObject(hdc, hFont);
588
589     /* free objects in handle table */
590     for(i = 0; i < mh->mtNoObjects; i++)
591       if(*(ht->objectHandle + i) != 0)
592         DeleteObject(*(ht->objectHandle + i));
593
594     /* free handle table */
595     HeapFree( GetProcessHeap(), 0, ht );
596     if(loaded)
597         HeapFree( GetProcessHeap(), 0, mh );
598     return TRUE;
599 }
600
601 /******************************************************************
602  *         PlayMetaFile   (GDI.123)
603  *
604  */
605 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
606 {
607     BOOL16 ret;
608     METAHEADER *mh = MF_GetMetaHeader16( hmf );
609     ret = MF_PlayMetaFile( HDC_32(hdc), mh );
610     MF_ReleaseMetaHeader16( hmf );
611     return ret;
612 }
613
614 /******************************************************************
615  *         PlayMetaFile   (GDI32.@)
616  *
617  *  Renders the metafile specified by hmf in the DC specified by
618  *  hdc. Returns FALSE on failure, TRUE on success.
619  *
620  * PARAMS
621  *  hdc [I] handle of DC to render in
622  *  hmf [I] handle of metafile to render
623  *
624  * RETURNS
625  *  Success: TRUE
626  *  Failure: FALSE
627  */
628 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
629 {
630     METAHEADER *mh = MF_GetMetaHeader( hmf );
631     return MF_PlayMetaFile( hdc, mh );
632 }
633
634
635 /******************************************************************
636  *            EnumMetaFile   (GDI.175)
637  *
638  */
639 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
640                               MFENUMPROC16 lpEnumFunc, LPARAM lpData )
641 {
642     METAHEADER *mh = MF_GetMetaHeader16(hmf);
643     METARECORD *mr;
644     HANDLETABLE16 *ht;
645     HDC hdc = HDC_32(hdc16);
646     HGLOBAL16 hHT;
647     SEGPTR spht;
648     unsigned int offset = 0;
649     WORD i, seg;
650     HPEN hPen;
651     HBRUSH hBrush;
652     HFONT hFont;
653     WORD args[8];
654     BOOL16 result = TRUE, loaded = FALSE;
655
656     TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
657
658     if(!mh) return FALSE;
659     if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
660         mh = MF_LoadDiskBasedMetaFile(mh);
661         if(!mh) return FALSE;
662         loaded = TRUE;
663     }
664
665     /* save the current pen, brush and font */
666     hPen = GetCurrentObject(hdc, OBJ_PEN);
667     hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
668     hFont = GetCurrentObject(hdc, OBJ_FONT);
669
670     /* create the handle table */
671
672     hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
673                      sizeof(HANDLETABLE16) * mh->mtNoObjects);
674     spht = WOWGlobalLock16(hHT);
675
676     seg = hmf | 7;
677     offset = mh->mtHeaderSize * 2;
678
679     /* loop through metafile records */
680
681     args[7] = hdc16;
682     args[6] = SELECTOROF(spht);
683     args[5] = OFFSETOF(spht);
684     args[4] = seg + (HIWORD(offset) << __AHSHIFT);
685     args[3] = LOWORD(offset);
686     args[2] = mh->mtNoObjects;
687     args[1] = HIWORD(lpData);
688     args[0] = LOWORD(lpData);
689
690     while (offset < (mh->mtSize * 2))
691     {
692         DWORD ret;
693
694         mr = (METARECORD *)((char *)mh + offset);
695
696         WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
697         if (!LOWORD(ret))
698         {
699             result = FALSE;
700             break;
701         }
702
703         offset += (mr->rdSize * 2);
704         args[4] = seg + (HIWORD(offset) << __AHSHIFT);
705         args[3] = LOWORD(offset);
706     }
707
708     SelectObject(hdc, hBrush);
709     SelectObject(hdc, hPen);
710     SelectObject(hdc, hFont);
711
712     ht = (HANDLETABLE16 *)GlobalLock16(hHT);
713
714     /* free objects in handle table */
715     for(i = 0; i < mh->mtNoObjects; i++)
716       if(*(ht->objectHandle + i) != 0)
717         DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
718
719     /* free handle table */
720     GlobalFree16(hHT);
721     if(loaded)
722         HeapFree( GetProcessHeap(), 0, mh );
723     MF_ReleaseMetaHeader16(hmf);
724     return result;
725 }
726
727 /******************************************************************
728  *            EnumMetaFile   (GDI32.@)
729  *
730  *  Loop through the metafile records in hmf, calling the user-specified
731  *  function for each one, stopping when the user's function returns FALSE
732  *  (which is considered to be failure)
733  *  or when no records are left (which is considered to be success).
734  *
735  * RETURNS
736  *  TRUE on success, FALSE on failure.
737  */
738 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, 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  * PARAMS
1313  *  hmf [I] metafile handle
1314  */
1315
1316 HGLOBAL16 WINAPI GetMetaFileBits16( HMETAFILE16 hmf )
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  * PARAMS
1331  *  hMem [I] handle to a memory region holding a metafile
1332  *
1333  * RETURNS
1334  *  Handle to a metafile on success, NULL on failure..
1335  */
1336 HMETAFILE16 WINAPI SetMetaFileBits16( HGLOBAL16 hMem )
1337 {
1338     TRACE("hmf out: %04x\n", hMem);
1339
1340     return hMem;
1341 }
1342
1343 /******************************************************************
1344  *         SetMetaFileBitsBetter   (GDI.196)
1345  *
1346  * Trade in a metafile memory handle for a handle to a metafile object,
1347  * making a cursory check (using IsValidMetaFile()) that the memory
1348  * handle points to a valid metafile.
1349  *
1350  * RETURNS
1351  *  Handle to a metafile on success, NULL on failure..
1352  */
1353 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1354 {
1355     if( IsValidMetaFile16( hMeta ) )
1356         return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1357                            GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1358     return (HMETAFILE16)0;
1359 }
1360
1361 /******************************************************************
1362  *         SetMetaFileBitsEx    (GDI32.@)
1363  *
1364  *  Create a metafile from raw data. No checking of the data is performed.
1365  *  Use GetMetaFileBitsEx() to get raw data from a metafile.
1366  *
1367  * PARAMS
1368  *  size   [I] size of metafile, in bytes
1369  *  lpData [I] pointer to metafile data
1370  *
1371  * RETURNS
1372  *  Success: Handle to metafile.
1373  *  Failure: NULL.
1374  */
1375 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1376 {
1377     METAHEADER *mh = (METAHEADER *)lpData;
1378
1379     if (size & 1) return 0;
1380
1381     if (!size || mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
1382         mh->mtHeaderSize != sizeof(METAHEADER) / 2)
1383     {
1384         SetLastError(ERROR_INVALID_DATA);
1385         return 0;
1386     }
1387
1388     mh = HeapAlloc( GetProcessHeap(), 0, size );
1389     if (!mh)
1390     {
1391         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1392         return 0;
1393     }
1394
1395     memcpy(mh, lpData, size);
1396     mh->mtSize = size / 2;
1397     return MF_Create_HMETAFILE(mh);
1398 }
1399
1400 /*****************************************************************
1401  *  GetMetaFileBitsEx     (GDI32.@)
1402  *
1403  * Get raw metafile data.
1404  *
1405  *  Copies the data from metafile _hmf_ into the buffer _buf_.
1406  *
1407  * PARAMS
1408  *  hmf   [I] metafile
1409  *  nSize [I] size of buf
1410  *  buf   [O] buffer to receive raw metafile data
1411  *
1412  * RETURNS
1413  *  If _buf_ is zero, returns size of buffer required. Otherwise,
1414  *  returns number of bytes copied.
1415  */
1416 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1417 {
1418     METAHEADER *mh = MF_GetMetaHeader(hmf);
1419     UINT mfSize;
1420
1421     TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1422     if (!mh) return 0;  /* FIXME: error code */
1423     if(mh->mtType == METAFILE_DISK)
1424         FIXME("Disk-based metafile?\n");
1425     mfSize = mh->mtSize * 2;
1426     if (!buf) {
1427         TRACE("returning size %d\n", mfSize);
1428         return mfSize;
1429     }
1430     if(mfSize > nSize) mfSize = nSize;
1431     memmove(buf, mh, mfSize);
1432     return mfSize;
1433 }
1434
1435 /******************************************************************
1436  *         GetWinMetaFileBits [GDI32.@]
1437  */
1438 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1439                                 UINT cbBuffer, LPBYTE lpbBuffer,
1440                                 INT fnMapMode, HDC hdcRef)
1441 {
1442     HDC hdcmf;
1443     HMETAFILE hmf;
1444     UINT ret;
1445     RECT rc;
1446     INT oldMapMode;
1447
1448     GetClipBox(hdcRef, &rc);
1449     oldMapMode = SetMapMode(hdcRef, fnMapMode);
1450
1451     TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1452         fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1453
1454     hdcmf = CreateMetaFileA(NULL);
1455     PlayEnhMetaFile(hdcmf, hemf, &rc);
1456     hmf = CloseMetaFile(hdcmf);
1457     ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1458     DeleteMetaFile(hmf);
1459
1460     SetMapMode(hdcRef, oldMapMode);
1461
1462     return ret;
1463 }
1464
1465 /******************************************************************
1466  *         MF_Play_MetaCreateRegion
1467  *
1468  *  Handles META_CREATEREGION for PlayMetaFileRecord().
1469  *
1470  *      The layout of the record looks something like this:
1471  *
1472  *       rdParm meaning
1473  *       0              Always 0?
1474  *       1              Always 6?
1475  *       2              Looks like a handle? - not constant
1476  *       3              0 or 1 ??
1477  *       4              Total number of bytes
1478  *       5              No. of separate bands = n [see below]
1479  *       6              Largest number of x co-ords in a band
1480  *       7-10           Bounding box x1 y1 x2 y2
1481  *       11-...         n bands
1482  *
1483  *       Regions are divided into bands that are uniform in the
1484  *       y-direction. Each band consists of pairs of on/off x-coords and is
1485  *       written as
1486  *              m y0 y1 x1 x2 x3 ... xm m
1487  *       into successive rdParm[]s.
1488  *
1489  *       This is probably just a dump of the internal RGNOBJ?
1490  *
1491  *       HDMD - 18/12/97
1492  *
1493  */
1494
1495 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1496 {
1497     WORD band, pair;
1498     WORD *start, *end;
1499     INT16 y0, y1;
1500     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1501
1502     for(band  = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1503                                                 band++, start = end + 1) {
1504         if(*start / 2 != (*start + 1) / 2) {
1505             WARN("Delimiter not even.\n");
1506             DeleteObject( hrgn2 );
1507             return FALSE;
1508         }
1509
1510         end = start + *start + 3;
1511         if(end > (WORD *)mr + mr->rdSize) {
1512             WARN("End points outside record.\n");
1513             DeleteObject( hrgn2 );
1514             return FALSE;
1515         }
1516
1517         if(*start != *end) {
1518             WARN("Mismatched delimiters.\n");
1519             DeleteObject( hrgn2 );
1520             return FALSE;
1521         }
1522
1523         y0 = *(INT16 *)(start + 1);
1524         y1 = *(INT16 *)(start + 2);
1525         for(pair = 0; pair < *start / 2; pair++) {
1526             SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1527                                  *(INT16 *)(start + 4 + 2*pair), y1 );
1528             CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1529         }
1530     }
1531     DeleteObject( hrgn2 );
1532     return TRUE;
1533  }
1534
1535
1536 /******************************************************************
1537  *         MF_Play_MetaExtTextOut
1538  *
1539  *  Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1540  */
1541
1542 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1543 {
1544     INT *dx = NULL;
1545     int i;
1546     LPINT16 dxx;
1547     LPSTR sot;
1548     DWORD len;
1549     WORD s1;
1550     RECT rect;
1551     BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1552
1553     s1 = mr->rdParm[2];                              /* String length */
1554     len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1555       + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1556                                            /* rec len without dx array */
1557
1558     sot = (LPSTR)&mr->rdParm[4];                      /* start_of_text */
1559     if (isrect)
1560     {
1561         rect.left   = (SHORT)mr->rdParm[4];
1562         rect.top    = (SHORT)mr->rdParm[5];
1563         rect.right  = (SHORT)mr->rdParm[6];
1564         rect.bottom = (SHORT)mr->rdParm[7];
1565         sot += sizeof(RECT16);  /* there is a rectangle, so add offset */
1566     }
1567
1568     if (mr->rdSize == len / 2)
1569         dxx = NULL;                      /* determine if array present */
1570     else
1571         if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1572         {
1573             dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1574             dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1575             if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1576         }
1577         else {
1578             TRACE("%s  len: %ld\n",  sot, mr->rdSize);
1579             WARN("Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1580                  len, s1, mr->rdSize, mr->rdParm[3]);
1581             dxx = NULL; /* should't happen -- but if, we continue with NULL */
1582         }
1583     ExtTextOutA( hdc,
1584                  (SHORT)mr->rdParm[1],       /* X position */
1585                  (SHORT)mr->rdParm[0],       /* Y position */
1586                  mr->rdParm[3],              /* options */
1587                  &rect,                      /* rectangle */
1588                  sot,                        /* string */
1589                  s1, dx);                    /* length, dx array */
1590     if (dx)
1591     {
1592         TRACE("%s  len: %ld  dx0: %d\n", sot, mr->rdSize, dx[0]);
1593         HeapFree( GetProcessHeap(), 0, dx );
1594     }
1595     return TRUE;
1596 }