Fixed buffer overflow.
[wine/multimedia.git] / objects / metafile.c
blob9c917eee7ed113fa03c98ef2d157830e278087b3
1 /*
2 * Metafile functions
4 * Copyright David W. Metcalfe, 1994
5 * Niels de Carpentier, Albrecht Kleine, Huw Davies 1996
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * These functions are primarily involved with metafile playback or anything
24 * that touches a HMETAFILE.
25 * For recording of metafiles look in graphics/metafiledrv/
27 * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
28 * global memory handles so these cannot be interchanged.
30 * Memory-based metafiles are just stored as a continuous block of memory with
31 * a METAHEADER at the head with METARECORDs appended to it. mtType is
32 * METAFILE_MEMORY (1). Note this is indentical to the disk image of a
33 * disk-based metafile - even mtType is METAFILE_MEMORY.
34 * 16bit HMETAFILE16s are global handles to this block
35 * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
36 * the memory.
37 * Disk-based metafiles are rather different. HMETAFILE16s point to a
38 * METAHEADER which has mtType equal to METAFILE_DISK (2). Following the 9
39 * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
40 * more 0, then 2 which may be a time stamp of the file and then the path of
41 * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
43 * HDMD - 14/4/1999
46 #include "config.h"
48 #include <string.h>
49 #include <fcntl.h>
51 #include "wine/winbase16.h"
52 #include "wine/wingdi16.h"
53 #include "gdi.h"
54 #include "wownt32.h"
55 #include "winreg.h"
56 #include "winternl.h"
57 #include "gdi_private.h"
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
62 #include "pshpack1.h"
63 typedef struct
65 DWORD dw1, dw2, dw3;
66 WORD w4;
67 CHAR filename[0x100];
68 } METAHEADERDISK;
69 #include "poppack.h"
71 typedef struct
73 GDIOBJHDR header;
74 METAHEADER *mh;
75 } METAFILEOBJ;
77 #define MFHEADERSIZE (sizeof(METAHEADER))
78 #define MFVERSION 0x300
81 /******************************************************************
82 * MF_AddHandle
84 * Add a handle to an external handle table and return the index
86 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
88 int i;
90 for (i = 0; i < htlen; i++)
92 if (*(ht->objectHandle + i) == 0)
94 *(ht->objectHandle + i) = hobj;
95 return i;
98 return -1;
102 /******************************************************************
103 * MF_Create_HMETATFILE
105 * Creates a (32 bit) HMETAFILE object from a METAHEADER
107 * HMETAFILEs are GDI objects.
109 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
111 HMETAFILE hmf = 0;
112 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
113 (HGDIOBJ *)&hmf, NULL );
114 if (metaObj)
116 metaObj->mh = mh;
117 GDI_ReleaseObj( hmf );
119 return hmf;
122 /******************************************************************
123 * MF_Create_HMETATFILE16
125 * Creates a HMETAFILE16 object from a METAHEADER
127 * HMETAFILE16s are Global memory handles.
129 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
131 HMETAFILE16 hmf;
132 DWORD size = mh->mtSize * sizeof(WORD);
134 hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
135 if(hmf)
137 METAHEADER *mh_dest = GlobalLock16(hmf);
138 memcpy(mh_dest, mh, size);
139 GlobalUnlock16(hmf);
141 HeapFree(GetProcessHeap(), 0, mh);
142 return hmf;
145 /******************************************************************
146 * MF_GetMetaHeader
148 * Returns ptr to METAHEADER associated with HMETAFILE
150 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
152 METAHEADER *ret = NULL;
153 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
154 if (metaObj)
156 ret = metaObj->mh;
157 GDI_ReleaseObj( hmf );
159 return ret;
162 /******************************************************************
163 * MF_GetMetaHeader16
165 * Returns ptr to METAHEADER associated with HMETAFILE16
166 * Should be followed by call to MF_ReleaseMetaHeader16
168 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
170 return GlobalLock16(hmf);
173 /******************************************************************
174 * MF_ReleaseMetaHeader16
176 * Releases METAHEADER associated with HMETAFILE16
178 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
180 return GlobalUnlock16( hmf );
184 /******************************************************************
185 * convert_points
187 * Convert an array of POINT16 to an array of POINT.
188 * Result must be freed by caller.
190 static POINT *convert_points( UINT count, POINT16 *pt16 )
192 UINT i;
193 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
194 if (ret)
196 for (i = 0; i < count; i++)
198 ret[i].x = pt16[i].x;
199 ret[i].y = pt16[i].y;
202 return ret;
206 /******************************************************************
207 * DeleteMetaFile (GDI.127)
209 BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
211 return !GlobalFree16( hmf );
214 /******************************************************************
215 * DeleteMetaFile (GDI32.@)
217 * Delete a memory-based metafile.
220 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
222 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
223 if (!metaObj) return FALSE;
224 HeapFree( GetProcessHeap(), 0, metaObj->mh );
225 GDI_FreeObject( hmf, metaObj );
226 return TRUE;
229 /******************************************************************
230 * MF_ReadMetaFile
232 * Returns a pointer to a memory based METAHEADER read in from file HFILE
235 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
237 METAHEADER *mh;
238 DWORD BytesRead, size;
240 size = sizeof(METAHEADER);
241 mh = HeapAlloc( GetProcessHeap(), 0, size );
242 if(!mh) return NULL;
243 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
244 BytesRead != size) {
245 HeapFree( GetProcessHeap(), 0, mh );
246 return NULL;
248 size = mh->mtSize * 2;
249 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
250 if(!mh) return NULL;
251 size -= sizeof(METAHEADER);
252 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
253 NULL) == 0 ||
254 BytesRead != size) {
255 HeapFree( GetProcessHeap(), 0, mh );
256 return NULL;
259 if (mh->mtType != METAFILE_MEMORY) {
260 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
261 mh->mtType = METAFILE_MEMORY;
263 return mh;
266 /******************************************************************
267 * GetMetaFile (GDI.124)
269 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
271 METAHEADER *mh;
272 HANDLE hFile;
274 TRACE("%s\n", lpFilename);
276 if(!lpFilename)
277 return 0;
279 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
280 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
281 return 0;
283 mh = MF_ReadMetaFile(hFile);
284 CloseHandle(hFile);
285 if(!mh) return 0;
286 return MF_Create_HMETAFILE16( mh );
289 /******************************************************************
290 * GetMetaFileA (GDI32.@)
292 * Read a metafile from a file. Returns handle to a memory-based metafile.
294 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
296 METAHEADER *mh;
297 HANDLE hFile;
299 TRACE("%s\n", lpFilename);
301 if(!lpFilename)
302 return 0;
304 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
305 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
306 return 0;
308 mh = MF_ReadMetaFile(hFile);
309 CloseHandle(hFile);
310 if(!mh) return 0;
311 return MF_Create_HMETAFILE( mh );
316 /******************************************************************
317 * GetMetaFileW (GDI32.@)
319 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
321 METAHEADER *mh;
322 HANDLE hFile;
324 TRACE("%s\n", debugstr_w(lpFilename));
326 if(!lpFilename)
327 return 0;
329 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
330 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
331 return 0;
333 mh = MF_ReadMetaFile(hFile);
334 CloseHandle(hFile);
335 if(!mh) return 0;
336 return MF_Create_HMETAFILE( mh );
340 /******************************************************************
341 * MF_LoadDiskBasedMetaFile
343 * Creates a new memory-based metafile from a disk-based one.
345 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
347 METAHEADERDISK *mhd;
348 HANDLE hfile;
349 METAHEADER *mh2;
351 if(mh->mtType != METAFILE_DISK) {
352 ERR("Not a disk based metafile\n");
353 return NULL;
355 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
357 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
358 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
359 WARN("Can't open file of disk based metafile\n");
360 return NULL;
362 mh2 = MF_ReadMetaFile(hfile);
363 CloseHandle(hfile);
364 return mh2;
367 /******************************************************************
368 * MF_CreateMetaHeaderDisk
370 * Take a memory based METAHEADER and change it to a disk based METAHEADER
371 * assosiated with filename. Note: Trashes contents of old one.
373 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
375 METAHEADERDISK *mhd;
376 DWORD size;
378 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
379 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
380 mh->mtType = METAFILE_DISK;
381 size = HeapSize( GetProcessHeap(), 0, mh );
382 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
384 if( uni )
385 WideCharToMultiByte(CP_ACP, 0, filename, -1,
386 mhd->filename, sizeof mhd->filename, NULL, NULL);
387 else
388 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
389 return mh;
392 /******************************************************************
393 * CopyMetaFile (GDI.151)
395 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
397 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
398 METAHEADER *mh2 = NULL;
399 HANDLE hFile;
401 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
403 if(!mh) return 0;
405 if(mh->mtType == METAFILE_DISK)
406 mh2 = MF_LoadDiskBasedMetaFile(mh);
407 else {
408 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
409 memcpy( mh2, mh, mh->mtSize * 2 );
411 MF_ReleaseMetaHeader16( hSrcMetaFile );
413 if(lpFilename) { /* disk based metafile */
414 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
415 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
416 HeapFree( GetProcessHeap(), 0, mh2 );
417 return 0;
419 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
420 CloseHandle(hFile);
421 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, FALSE);
424 return MF_Create_HMETAFILE16( mh2 );
428 /******************************************************************
429 * CopyMetaFileW (GDI32.@)
431 * Copies the metafile corresponding to hSrcMetaFile to either
432 * a disk file, if a filename is given, or to a new memory based
433 * metafile, if lpFileName is NULL.
435 * RETURNS
437 * Handle to metafile copy on success, NULL on failure.
439 * BUGS
441 * Copying to disk returns NULL even if successful.
443 HMETAFILE WINAPI CopyMetaFileW(
444 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
445 LPCWSTR lpFilename /* [in] filename if copying to a file */)
447 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
448 METAHEADER *mh2 = NULL;
449 HANDLE hFile;
451 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
453 if(!mh) return 0;
455 if(mh->mtType == METAFILE_DISK)
456 mh2 = MF_LoadDiskBasedMetaFile(mh);
457 else {
458 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
459 memcpy( mh2, mh, mh->mtSize * 2 );
462 if(lpFilename) { /* disk based metafile */
463 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
464 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
465 HeapFree( GetProcessHeap(), 0, mh2 );
466 return 0;
468 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
469 CloseHandle(hFile);
470 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, TRUE);
473 return MF_Create_HMETAFILE( mh2 );
477 /******************************************************************
478 * CopyMetaFileA (GDI32.@)
480 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile,
481 LPCSTR lpFilename )
483 UNICODE_STRING lpFilenameW;
484 HMETAFILE ret = 0;
486 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
487 else lpFilenameW.Buffer = NULL;
489 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
490 if (lpFilenameW.Buffer)
491 RtlFreeUnicodeString(&lpFilenameW);
492 return ret;
496 /******************************************************************
497 * IsValidMetaFile (GDI.410)
499 * Attempts to check if a given metafile is correctly formatted.
500 * Currently, the only things verified are several properties of the
501 * header.
503 * RETURNS
504 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
506 * BUGS
507 * This is not exactly what windows does, see _Undocumented_Windows_
508 * for details.
510 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
512 BOOL16 res=FALSE;
513 METAHEADER *mh = MF_GetMetaHeader16(hmf);
514 if (mh) {
515 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
516 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
517 if (mh->mtVersion == MFVERSION)
518 res=TRUE;
519 MF_ReleaseMetaHeader16(hmf);
521 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
522 return res;
526 /*******************************************************************
527 * MF_PlayMetaFile
529 * Helper for PlayMetaFile
531 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
534 METARECORD *mr;
535 HANDLETABLE *ht;
536 unsigned int offset = 0;
537 WORD i;
538 HPEN hPen;
539 HBRUSH hBrush;
540 HFONT hFont;
541 BOOL loaded = FALSE;
543 if (!mh) return FALSE;
544 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
545 mh = MF_LoadDiskBasedMetaFile(mh);
546 if(!mh) return FALSE;
547 loaded = TRUE;
550 /* save the current pen, brush and font */
551 hPen = GetCurrentObject(hdc, OBJ_PEN);
552 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
553 hFont = GetCurrentObject(hdc, OBJ_FONT);
555 /* create the handle table */
556 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
557 sizeof(HANDLETABLE) * mh->mtNoObjects);
558 if(!ht) return FALSE;
560 /* loop through metafile playing records */
561 offset = mh->mtHeaderSize * 2;
562 while (offset < mh->mtSize * 2)
564 mr = (METARECORD *)((char *)mh + offset);
565 TRACE("offset=%04x,size=%08lx\n",
566 offset, mr->rdSize);
567 if (!mr->rdSize) {
568 TRACE(
569 "Entry got size 0 at offset %d, total mf length is %ld\n",
570 offset,mh->mtSize*2);
571 break; /* would loop endlessly otherwise */
573 offset += mr->rdSize * 2;
574 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
577 SelectObject(hdc, hBrush);
578 SelectObject(hdc, hPen);
579 SelectObject(hdc, hFont);
581 /* free objects in handle table */
582 for(i = 0; i < mh->mtNoObjects; i++)
583 if(*(ht->objectHandle + i) != 0)
584 DeleteObject(*(ht->objectHandle + i));
586 /* free handle table */
587 HeapFree( GetProcessHeap(), 0, ht );
588 if(loaded)
589 HeapFree( GetProcessHeap(), 0, mh );
590 return TRUE;
593 /******************************************************************
594 * PlayMetaFile (GDI.123)
597 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
599 BOOL16 ret;
600 METAHEADER *mh = MF_GetMetaHeader16( hmf );
601 ret = MF_PlayMetaFile( HDC_32(hdc), mh );
602 MF_ReleaseMetaHeader16( hmf );
603 return ret;
606 /******************************************************************
607 * PlayMetaFile (GDI32.@)
609 * Renders the metafile specified by hmf in the DC specified by
610 * hdc. Returns FALSE on failure, TRUE on success.
612 BOOL WINAPI PlayMetaFile(
613 HDC hdc, /* [in] handle of DC to render in */
614 HMETAFILE hmf /* [in] handle of metafile to render */
617 METAHEADER *mh = MF_GetMetaHeader( hmf );
618 return MF_PlayMetaFile( hdc, mh );
622 /******************************************************************
623 * EnumMetaFile (GDI.175)
626 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
627 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
629 METAHEADER *mh = MF_GetMetaHeader16(hmf);
630 METARECORD *mr;
631 HANDLETABLE16 *ht;
632 HDC hdc = HDC_32(hdc16);
633 HGLOBAL16 hHT;
634 SEGPTR spht;
635 unsigned int offset = 0;
636 WORD i, seg;
637 HPEN hPen;
638 HBRUSH hBrush;
639 HFONT hFont;
640 WORD args[8];
641 BOOL16 result = TRUE, loaded = FALSE;
643 TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
645 if(!mh) return FALSE;
646 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
647 mh = MF_LoadDiskBasedMetaFile(mh);
648 if(!mh) return FALSE;
649 loaded = TRUE;
652 /* save the current pen, brush and font */
653 hPen = GetCurrentObject(hdc, OBJ_PEN);
654 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
655 hFont = GetCurrentObject(hdc, OBJ_FONT);
657 /* create the handle table */
659 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
660 sizeof(HANDLETABLE16) * mh->mtNoObjects);
661 spht = K32WOWGlobalLock16(hHT);
663 seg = hmf | 7;
664 offset = mh->mtHeaderSize * 2;
666 /* loop through metafile records */
668 args[7] = hdc16;
669 args[6] = SELECTOROF(spht);
670 args[5] = OFFSETOF(spht);
671 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
672 args[3] = LOWORD(offset);
673 args[2] = mh->mtNoObjects;
674 args[1] = HIWORD(lpData);
675 args[0] = LOWORD(lpData);
677 while (offset < (mh->mtSize * 2))
679 DWORD ret;
681 mr = (METARECORD *)((char *)mh + offset);
683 WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
684 if (!LOWORD(ret))
686 result = FALSE;
687 break;
690 offset += (mr->rdSize * 2);
691 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
692 args[3] = LOWORD(offset);
695 SelectObject(hdc, hBrush);
696 SelectObject(hdc, hPen);
697 SelectObject(hdc, hFont);
699 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
701 /* free objects in handle table */
702 for(i = 0; i < mh->mtNoObjects; i++)
703 if(*(ht->objectHandle + i) != 0)
704 DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
706 /* free handle table */
707 GlobalFree16(hHT);
708 if(loaded)
709 HeapFree( GetProcessHeap(), 0, mh );
710 MF_ReleaseMetaHeader16(hmf);
711 return result;
714 /******************************************************************
715 * EnumMetaFile (GDI32.@)
717 * Loop through the metafile records in hmf, calling the user-specified
718 * function for each one, stopping when the user's function returns FALSE
719 * (which is considered to be failure)
720 * or when no records are left (which is considered to be success).
722 * RETURNS
723 * TRUE on success, FALSE on failure.
725 * HISTORY
726 * Niels de carpentier, april 1996
728 BOOL WINAPI EnumMetaFile(
729 HDC hdc,
730 HMETAFILE hmf,
731 MFENUMPROC lpEnumFunc,
732 LPARAM lpData)
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;
744 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
745 if (!mh) return 0;
746 if(mh->mtType == METAFILE_DISK)
748 /* Create a memory-based copy */
749 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
750 mh = mhTemp;
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);
758 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
759 sizeof(HANDLETABLE) * mh->mtNoObjects);
761 /* loop through metafile records */
762 offset = mh->mtHeaderSize * 2;
764 while (offset < (mh->mtSize * 2))
766 mr = (METARECORD *)((char *)mh + offset);
767 if(mr->rdFunction == META_EOF) {
768 TRACE("Got META_EOF so stopping\n");
769 break;
771 TRACE("Calling EnumFunc with record type %x\n",
772 mr->rdFunction);
773 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
775 result = FALSE;
776 break;
779 offset += (mr->rdSize * 2);
782 /* restore pen, brush and font */
783 SelectObject(hdc, hBrush);
784 SelectObject(hdc, hPen);
785 SelectObject(hdc, hFont);
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));
792 /* free handle table */
793 HeapFree( GetProcessHeap(), 0, ht);
794 /* free a copy of metafile */
795 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
796 return result;
799 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
800 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
801 /******************************************************************
802 * PlayMetaFileRecord (GDI32.@)
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.
808 * BUGS
809 * The following metafile records are unimplemented:
811 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
812 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
813 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
815 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
817 short s1;
818 POINT *pt;
819 BITMAPINFOHEADER *infohdr;
821 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
823 switch (mr->rdFunction)
825 case META_EOF:
826 break;
828 case META_DELETEOBJECT:
829 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
830 *(ht->objectHandle + mr->rdParm[0]) = 0;
831 break;
833 case META_SETBKCOLOR:
834 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
835 break;
837 case META_SETBKMODE:
838 SetBkMode(hdc, mr->rdParm[0]);
839 break;
841 case META_SETMAPMODE:
842 SetMapMode(hdc, mr->rdParm[0]);
843 break;
845 case META_SETROP2:
846 SetROP2(hdc, mr->rdParm[0]);
847 break;
849 case META_SETRELABS:
850 SetRelAbs(hdc, mr->rdParm[0]);
851 break;
853 case META_SETPOLYFILLMODE:
854 SetPolyFillMode(hdc, mr->rdParm[0]);
855 break;
857 case META_SETSTRETCHBLTMODE:
858 SetStretchBltMode(hdc, mr->rdParm[0]);
859 break;
861 case META_SETTEXTCOLOR:
862 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
863 break;
865 case META_SETWINDOWORG:
866 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
867 break;
869 case META_SETWINDOWEXT:
870 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
871 break;
873 case META_SETVIEWPORTORG:
874 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
875 break;
877 case META_SETVIEWPORTEXT:
878 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
879 break;
881 case META_OFFSETWINDOWORG:
882 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
883 break;
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;
890 case META_OFFSETVIEWPORTORG:
891 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
892 break;
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;
899 case META_LINETO:
900 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
901 break;
903 case META_MOVETO:
904 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
905 break;
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;
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;
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;
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;
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;
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;
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;
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;
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;
958 case META_SAVEDC:
959 SaveDC(hdc);
960 break;
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;
967 case META_OFFSETCLIPRGN:
968 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
969 break;
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;
978 case META_POLYGON:
979 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
981 Polygon(hdc, pt, mr->rdParm[0]);
982 HeapFree( GetProcessHeap(), 0, pt );
984 break;
986 case META_POLYPOLYGON:
988 UINT i, total;
989 SHORT *counts = (SHORT *)(mr->rdParm + 1);
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)
995 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
996 if (cnt32)
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 );
1003 HeapFree( GetProcessHeap(), 0, pt );
1005 break;
1007 case META_POLYLINE:
1008 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
1010 Polyline( hdc, pt, mr->rdParm[0] );
1011 HeapFree( GetProcessHeap(), 0, pt );
1013 break;
1015 case META_RESTOREDC:
1016 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1017 break;
1019 case META_SELECTOBJECT:
1020 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1021 break;
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;
1030 case META_CREATEPATTERNBRUSH:
1031 switch (mr->rdParm[0])
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;
1044 case BS_DIBPATTERN:
1045 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1046 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1047 break;
1049 default:
1050 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1051 mr->rdParm[0]);
1052 break;
1054 break;
1056 case META_CREATEPENINDIRECT:
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 ));
1065 break;
1067 case META_CREATEFONTINDIRECT:
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 ));
1086 break;
1088 case META_CREATEBRUSHINDIRECT:
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 ));
1096 break;
1098 case META_CREATEPALETTE:
1099 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1100 break;
1102 case META_SETTEXTALIGN:
1103 SetTextAlign(hdc, mr->rdParm[0]);
1104 break;
1106 case META_SELECTPALETTE:
1107 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1108 break;
1110 case META_SETMAPPERFLAGS:
1111 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1112 break;
1114 case META_REALIZEPALETTE:
1115 GDIRealizePalette(hdc);
1116 break;
1118 case META_ESCAPE:
1119 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
1120 break;
1122 case META_EXTTEXTOUT:
1123 MF_Play_MetaExtTextOut( hdc, mr );
1124 break;
1126 case META_STRETCHDIB:
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]));
1135 break;
1137 case META_DIBSTRETCHBLT:
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]));
1146 break;
1148 case META_STRETCHBLT:
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);
1164 break;
1166 case META_BITBLT:
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);
1181 break;
1183 case META_CREATEREGION:
1185 HRGN hrgn = CreateRectRgn(0,0,0,0);
1187 MF_Play_MetaCreateRegion(mr, hrgn);
1188 MF_AddHandle(ht, handles, hrgn);
1190 break;
1192 case META_FILLREGION:
1193 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1194 *(ht->objectHandle + mr->rdParm[0]));
1195 break;
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;
1203 case META_INVERTREGION:
1204 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1205 break;
1207 case META_PAINTREGION:
1208 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1209 break;
1211 case META_SELECTCLIPREGION:
1212 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1213 break;
1215 case META_DIBCREATEPATTERNBRUSH:
1216 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1217 but there's no difference */
1218 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1219 break;
1221 case META_DIBBITBLT:
1222 /* In practice I've found that there are two layouts for
1223 META_DIBBITBLT, one (the first here) is the usual one when a src
1224 dc is actually passed to it, the second occurs when the src dc is
1225 passed in as NULL to the creating BitBlt. As the second case has
1226 no dib, a size check will suffice to distinguish.
1228 Caolan.McNamara@ul.ie */
1230 if (mr->rdSize > 12) {
1231 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1232 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1234 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1235 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1236 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1237 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1239 else /* equivalent to a PatBlt */
1240 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1241 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1242 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1243 break;
1245 case META_SETTEXTCHAREXTRA:
1246 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1247 break;
1249 case META_SETTEXTJUSTIFICATION:
1250 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1251 break;
1253 case META_EXTFLOODFILL:
1254 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1255 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1256 mr->rdParm[0]);
1257 break;
1259 case META_SETDIBTODEV:
1261 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1262 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1263 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1264 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1265 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1266 mr->rdParm[2], mr->rdParm[1], bits, info,
1267 mr->rdParm[0]);
1268 break;
1271 #define META_UNIMP(x) case x: \
1272 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1273 break;
1274 META_UNIMP(META_DRAWTEXT)
1275 META_UNIMP(META_ANIMATEPALETTE)
1276 META_UNIMP(META_SETPALENTRIES)
1277 META_UNIMP(META_RESIZEPALETTE)
1278 META_UNIMP(META_RESETDC)
1279 META_UNIMP(META_STARTDOC)
1280 META_UNIMP(META_STARTPAGE)
1281 META_UNIMP(META_ENDPAGE)
1282 META_UNIMP(META_ABORTDOC)
1283 META_UNIMP(META_ENDDOC)
1284 META_UNIMP(META_CREATEBRUSH)
1285 META_UNIMP(META_CREATEBITMAPINDIRECT)
1286 META_UNIMP(META_CREATEBITMAP)
1287 #undef META_UNIMP
1289 default:
1290 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1291 return FALSE;
1293 return TRUE;
1296 /******************************************************************
1297 * GetMetaFileBits (GDI.159)
1299 * Trade in a metafile object handle for a handle to the metafile memory.
1303 HGLOBAL16 WINAPI GetMetaFileBits16(
1304 HMETAFILE16 hmf /* [in] metafile handle */
1307 TRACE("hMem out: %04x\n", hmf);
1308 return hmf;
1311 /******************************************************************
1312 * SetMetaFileBits (GDI.160)
1314 * Trade in a metafile memory handle for a handle to a metafile object.
1315 * The memory region should hold a proper metafile, otherwise
1316 * problems will occur when it is used. Validity of the memory is not
1317 * checked. The function is essentially just the identity function.
1319 HMETAFILE16 WINAPI SetMetaFileBits16(
1320 HGLOBAL16 hMem
1321 /* [in] handle to a memory region holding a metafile */
1324 TRACE("hmf out: %04x\n", hMem);
1326 return hMem;
1329 /******************************************************************
1330 * SetMetaFileBitsBetter (GDI.196)
1332 * Trade in a metafile memory handle for a handle to a metafile object,
1333 * making a cursory check (using IsValidMetaFile()) that the memory
1334 * handle points to a valid metafile.
1336 * RETURNS
1337 * Handle to a metafile on success, NULL on failure..
1339 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1341 if( IsValidMetaFile16( hMeta ) )
1342 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1343 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1344 return (HMETAFILE16)0;
1347 /******************************************************************
1348 * SetMetaFileBitsEx (GDI32.@)
1350 * Create a metafile from raw data. No checking of the data is performed.
1351 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1353 HMETAFILE WINAPI SetMetaFileBitsEx(
1354 UINT size, /* [in] size of metafile, in bytes */
1355 const BYTE *lpData /* [in] pointer to metafile data */
1358 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1359 if (!mh) return 0;
1360 memcpy(mh, lpData, size);
1361 return MF_Create_HMETAFILE(mh);
1364 /*****************************************************************
1365 * GetMetaFileBitsEx (GDI32.@)
1367 * Get raw metafile data.
1369 * Copies the data from metafile _hmf_ into the buffer _buf_.
1370 * If _buf_ is zero, returns size of buffer required. Otherwise,
1371 * returns number of bytes copied.
1373 UINT WINAPI GetMetaFileBitsEx(
1374 HMETAFILE hmf, /* [in] metafile */
1375 UINT nSize, /* [in] size of buf */
1376 LPVOID buf /* [out] buffer to receive raw metafile data */)
1378 METAHEADER *mh = MF_GetMetaHeader(hmf);
1379 UINT mfSize;
1381 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1382 if (!mh) return 0; /* FIXME: error code */
1383 if(mh->mtType == METAFILE_DISK)
1384 FIXME("Disk-based metafile?\n");
1385 mfSize = mh->mtSize * 2;
1386 if (!buf) {
1387 TRACE("returning size %d\n", mfSize);
1388 return mfSize;
1390 if(mfSize > nSize) mfSize = nSize;
1391 memmove(buf, mh, mfSize);
1392 return mfSize;
1395 /******************************************************************
1396 * GetWinMetaFileBits [GDI32.@]
1398 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1399 UINT cbBuffer, LPBYTE lpbBuffer,
1400 INT fnMapMode, HDC hdcRef)
1402 HDC hdcmf;
1403 HMETAFILE hmf;
1404 UINT ret;
1405 RECT rc;
1406 INT oldMapMode;
1408 GetClipBox(hdcRef, &rc);
1409 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1411 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1412 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1414 hdcmf = CreateMetaFileA(NULL);
1415 PlayEnhMetaFile(hdcmf, hemf, &rc);
1416 hmf = CloseMetaFile(hdcmf);
1417 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1418 DeleteMetaFile(hmf);
1420 SetMapMode(hdcRef, oldMapMode);
1422 return ret;
1425 /******************************************************************
1426 * MF_Play_MetaCreateRegion
1428 * Handles META_CREATEREGION for PlayMetaFileRecord().
1432 * The layout of the record looks something like this:
1434 * rdParm meaning
1435 * 0 Always 0?
1436 * 1 Always 6?
1437 * 2 Looks like a handle? - not constant
1438 * 3 0 or 1 ??
1439 * 4 Total number of bytes
1440 * 5 No. of separate bands = n [see below]
1441 * 6 Largest number of x co-ords in a band
1442 * 7-10 Bounding box x1 y1 x2 y2
1443 * 11-... n bands
1445 * Regions are divided into bands that are uniform in the
1446 * y-direction. Each band consists of pairs of on/off x-coords and is
1447 * written as
1448 * m y0 y1 x1 x2 x3 ... xm m
1449 * into successive rdParm[]s.
1451 * This is probably just a dump of the internal RGNOBJ?
1453 * HDMD - 18/12/97
1457 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1459 WORD band, pair;
1460 WORD *start, *end;
1461 INT16 y0, y1;
1462 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1464 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1465 band++, start = end + 1) {
1466 if(*start / 2 != (*start + 1) / 2) {
1467 WARN("Delimiter not even.\n");
1468 DeleteObject( hrgn2 );
1469 return FALSE;
1472 end = start + *start + 3;
1473 if(end > (WORD *)mr + mr->rdSize) {
1474 WARN("End points outside record.\n");
1475 DeleteObject( hrgn2 );
1476 return FALSE;
1479 if(*start != *end) {
1480 WARN("Mismatched delimiters.\n");
1481 DeleteObject( hrgn2 );
1482 return FALSE;
1485 y0 = *(INT16 *)(start + 1);
1486 y1 = *(INT16 *)(start + 2);
1487 for(pair = 0; pair < *start / 2; pair++) {
1488 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1489 *(INT16 *)(start + 4 + 2*pair), y1 );
1490 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1493 DeleteObject( hrgn2 );
1494 return TRUE;
1498 /******************************************************************
1499 * MF_Play_MetaExtTextOut
1501 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1504 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1506 INT *dx = NULL;
1507 int i;
1508 LPINT16 dxx;
1509 LPSTR sot;
1510 DWORD len;
1511 WORD s1;
1512 RECT rect;
1513 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1515 s1 = mr->rdParm[2]; /* String length */
1516 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1517 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1518 /* rec len without dx array */
1520 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1521 if (isrect)
1523 rect.left = (SHORT)mr->rdParm[4];
1524 rect.top = (SHORT)mr->rdParm[5];
1525 rect.right = (SHORT)mr->rdParm[6];
1526 rect.bottom = (SHORT)mr->rdParm[7];
1527 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1530 if (mr->rdSize == len / 2)
1531 dxx = NULL; /* determine if array present */
1532 else
1533 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1535 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1536 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1537 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1539 else {
1540 TRACE("%s len: %ld\n", sot, mr->rdSize);
1541 WARN(
1542 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1543 len, s1, mr->rdSize, mr->rdParm[3]);
1544 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1546 ExtTextOutA( hdc,
1547 (SHORT)mr->rdParm[1], /* X position */
1548 (SHORT)mr->rdParm[0], /* Y position */
1549 mr->rdParm[3], /* options */
1550 &rect, /* rectangle */
1551 sot, /* string */
1552 s1, dx); /* length, dx array */
1553 if (dx)
1555 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1556 HeapFree( GetProcessHeap(), 0, dx );
1558 return TRUE;