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