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