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