GetMetaFile checks both the version and the header size when it tries
[wine/wine64.git] / dlls / gdi / metafile.c
blobac623b58f87eb7b70e09ff911c79b4e97b3137cf
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 if(mh->mtVersion != MFVERSION || mh->mtHeaderSize != size / 2) {
249 HeapFree( GetProcessHeap(), 0, mh );
250 return NULL;
252 size = mh->mtSize * 2;
253 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
254 if(!mh) return NULL;
255 size -= sizeof(METAHEADER);
256 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
257 NULL) == 0 ||
258 BytesRead != size) {
259 HeapFree( GetProcessHeap(), 0, mh );
260 return NULL;
263 if (mh->mtType != METAFILE_MEMORY) {
264 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
265 mh->mtType = METAFILE_MEMORY;
267 return mh;
270 /******************************************************************
271 * GetMetaFile (GDI.124)
273 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
275 METAHEADER *mh;
276 HANDLE hFile;
278 TRACE("%s\n", lpFilename);
280 if(!lpFilename)
281 return 0;
283 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
284 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
285 return 0;
287 mh = MF_ReadMetaFile(hFile);
288 CloseHandle(hFile);
289 if(!mh) return 0;
290 return MF_Create_HMETAFILE16( mh );
293 /******************************************************************
294 * GetMetaFileA (GDI32.@)
296 * Read a metafile from a file. Returns handle to a memory-based metafile.
298 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
300 METAHEADER *mh;
301 HANDLE hFile;
303 TRACE("%s\n", lpFilename);
305 if(!lpFilename)
306 return 0;
308 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
309 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
310 return 0;
312 mh = MF_ReadMetaFile(hFile);
313 CloseHandle(hFile);
314 if(!mh) return 0;
315 return MF_Create_HMETAFILE( mh );
320 /******************************************************************
321 * GetMetaFileW (GDI32.@)
323 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
325 METAHEADER *mh;
326 HANDLE hFile;
328 TRACE("%s\n", debugstr_w(lpFilename));
330 if(!lpFilename)
331 return 0;
333 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
334 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
335 return 0;
337 mh = MF_ReadMetaFile(hFile);
338 CloseHandle(hFile);
339 if(!mh) return 0;
340 return MF_Create_HMETAFILE( mh );
344 /******************************************************************
345 * MF_LoadDiskBasedMetaFile
347 * Creates a new memory-based metafile from a disk-based one.
349 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
351 METAHEADERDISK *mhd;
352 HANDLE hfile;
353 METAHEADER *mh2;
355 if(mh->mtType != METAFILE_DISK) {
356 ERR("Not a disk based metafile\n");
357 return NULL;
359 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
361 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
362 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
363 WARN("Can't open file of disk based metafile\n");
364 return NULL;
366 mh2 = MF_ReadMetaFile(hfile);
367 CloseHandle(hfile);
368 return mh2;
371 /******************************************************************
372 * MF_CreateMetaHeaderDisk
374 * Take a memory based METAHEADER and change it to a disk based METAHEADER
375 * assosiated with filename. Note: Trashes contents of old one.
377 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
379 METAHEADERDISK *mhd;
380 DWORD size;
382 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
383 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
384 mh->mtType = METAFILE_DISK;
385 size = HeapSize( GetProcessHeap(), 0, mh );
386 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
388 if( uni )
389 WideCharToMultiByte(CP_ACP, 0, filename, -1,
390 mhd->filename, sizeof mhd->filename, NULL, NULL);
391 else
392 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
393 return mh;
396 /******************************************************************
397 * CopyMetaFile (GDI.151)
399 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
401 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
402 METAHEADER *mh2 = NULL;
403 HANDLE hFile;
405 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
407 if(!mh) return 0;
409 if(mh->mtType == METAFILE_DISK)
410 mh2 = MF_LoadDiskBasedMetaFile(mh);
411 else {
412 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
413 memcpy( mh2, mh, mh->mtSize * 2 );
415 MF_ReleaseMetaHeader16( hSrcMetaFile );
417 if(lpFilename) { /* disk based metafile */
418 DWORD w;
419 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
420 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
421 HeapFree( GetProcessHeap(), 0, mh2 );
422 return 0;
424 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
425 CloseHandle(hFile);
426 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, FALSE);
429 return MF_Create_HMETAFILE16( mh2 );
433 /******************************************************************
434 * CopyMetaFileW (GDI32.@)
436 * Copies the metafile corresponding to hSrcMetaFile to either
437 * a disk file, if a filename is given, or to a new memory based
438 * metafile, if lpFileName is NULL.
440 * RETURNS
442 * Handle to metafile copy on success, NULL on failure.
444 * BUGS
446 * Copying to disk returns NULL even if successful.
448 HMETAFILE WINAPI CopyMetaFileW(
449 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
450 LPCWSTR lpFilename /* [in] filename if copying to a file */)
452 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
453 METAHEADER *mh2 = NULL;
454 HANDLE hFile;
456 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
458 if(!mh) return 0;
460 if(mh->mtType == METAFILE_DISK)
461 mh2 = MF_LoadDiskBasedMetaFile(mh);
462 else {
463 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
464 memcpy( mh2, mh, mh->mtSize * 2 );
467 if(lpFilename) { /* disk based metafile */
468 DWORD w;
469 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
470 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
471 HeapFree( GetProcessHeap(), 0, mh2 );
472 return 0;
474 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
475 CloseHandle(hFile);
476 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename, TRUE);
479 return MF_Create_HMETAFILE( mh2 );
483 /******************************************************************
484 * CopyMetaFileA (GDI32.@)
486 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile,
487 LPCSTR lpFilename )
489 UNICODE_STRING lpFilenameW;
490 HMETAFILE ret = 0;
492 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
493 else lpFilenameW.Buffer = NULL;
495 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
496 if (lpFilenameW.Buffer)
497 RtlFreeUnicodeString(&lpFilenameW);
498 return ret;
502 /******************************************************************
503 * IsValidMetaFile (GDI.410)
505 * Attempts to check if a given metafile is correctly formatted.
506 * Currently, the only things verified are several properties of the
507 * header.
509 * RETURNS
510 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
512 * BUGS
513 * This is not exactly what windows does, see _Undocumented_Windows_
514 * for details.
516 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
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);
527 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
528 return res;
532 /*******************************************************************
533 * MF_PlayMetaFile
535 * Helper for PlayMetaFile
537 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
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;
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;
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);
561 /* create the handle table */
562 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
563 sizeof(HANDLETABLE) * mh->mtNoObjects);
564 if(!ht) return FALSE;
566 /* loop through metafile playing records */
567 offset = mh->mtHeaderSize * 2;
568 while (offset < mh->mtSize * 2)
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 */
579 offset += mr->rdSize * 2;
580 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
583 SelectObject(hdc, hBrush);
584 SelectObject(hdc, hPen);
585 SelectObject(hdc, hFont);
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));
592 /* free handle table */
593 HeapFree( GetProcessHeap(), 0, ht );
594 if(loaded)
595 HeapFree( GetProcessHeap(), 0, mh );
596 return TRUE;
599 /******************************************************************
600 * PlayMetaFile (GDI.123)
603 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
605 BOOL16 ret;
606 METAHEADER *mh = MF_GetMetaHeader16( hmf );
607 ret = MF_PlayMetaFile( HDC_32(hdc), mh );
608 MF_ReleaseMetaHeader16( hmf );
609 return ret;
612 /******************************************************************
613 * PlayMetaFile (GDI32.@)
615 * Renders the metafile specified by hmf in the DC specified by
616 * hdc. Returns FALSE on failure, TRUE on success.
618 BOOL WINAPI PlayMetaFile(
619 HDC hdc, /* [in] handle of DC to render in */
620 HMETAFILE hmf /* [in] handle of metafile to render */
623 METAHEADER *mh = MF_GetMetaHeader( hmf );
624 return MF_PlayMetaFile( hdc, mh );
628 /******************************************************************
629 * EnumMetaFile (GDI.175)
632 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
633 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
635 METAHEADER *mh = MF_GetMetaHeader16(hmf);
636 METARECORD *mr;
637 HANDLETABLE16 *ht;
638 HDC hdc = HDC_32(hdc16);
639 HGLOBAL16 hHT;
640 SEGPTR spht;
641 unsigned int offset = 0;
642 WORD i, seg;
643 HPEN hPen;
644 HBRUSH hBrush;
645 HFONT hFont;
646 WORD args[8];
647 BOOL16 result = TRUE, loaded = FALSE;
649 TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
651 if(!mh) return FALSE;
652 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
653 mh = MF_LoadDiskBasedMetaFile(mh);
654 if(!mh) return FALSE;
655 loaded = TRUE;
658 /* save the current pen, brush and font */
659 hPen = GetCurrentObject(hdc, OBJ_PEN);
660 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
661 hFont = GetCurrentObject(hdc, OBJ_FONT);
663 /* create the handle table */
665 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
666 sizeof(HANDLETABLE16) * mh->mtNoObjects);
667 spht = K32WOWGlobalLock16(hHT);
669 seg = hmf | 7;
670 offset = mh->mtHeaderSize * 2;
672 /* loop through metafile records */
674 args[7] = hdc16;
675 args[6] = SELECTOROF(spht);
676 args[5] = OFFSETOF(spht);
677 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
678 args[3] = LOWORD(offset);
679 args[2] = mh->mtNoObjects;
680 args[1] = HIWORD(lpData);
681 args[0] = LOWORD(lpData);
683 while (offset < (mh->mtSize * 2))
685 DWORD ret;
687 mr = (METARECORD *)((char *)mh + offset);
689 WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
690 if (!LOWORD(ret))
692 result = FALSE;
693 break;
696 offset += (mr->rdSize * 2);
697 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
698 args[3] = LOWORD(offset);
701 SelectObject(hdc, hBrush);
702 SelectObject(hdc, hPen);
703 SelectObject(hdc, hFont);
705 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
707 /* free objects in handle table */
708 for(i = 0; i < mh->mtNoObjects; i++)
709 if(*(ht->objectHandle + i) != 0)
710 DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
712 /* free handle table */
713 GlobalFree16(hHT);
714 if(loaded)
715 HeapFree( GetProcessHeap(), 0, mh );
716 MF_ReleaseMetaHeader16(hmf);
717 return result;
720 /******************************************************************
721 * EnumMetaFile (GDI32.@)
723 * Loop through the metafile records in hmf, calling the user-specified
724 * function for each one, stopping when the user's function returns FALSE
725 * (which is considered to be failure)
726 * or when no records are left (which is considered to be success).
728 * RETURNS
729 * TRUE on success, FALSE on failure.
731 * HISTORY
732 * Niels de carpentier, april 1996
734 BOOL WINAPI EnumMetaFile(
735 HDC hdc,
736 HMETAFILE hmf,
737 MFENUMPROC lpEnumFunc,
738 LPARAM lpData)
740 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
741 METARECORD *mr;
742 HANDLETABLE *ht;
743 BOOL result = TRUE;
744 int i;
745 unsigned int offset = 0;
746 HPEN hPen;
747 HBRUSH hBrush;
748 HFONT hFont;
750 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
751 if (!mh) return 0;
752 if(mh->mtType == METAFILE_DISK)
754 /* Create a memory-based copy */
755 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
756 mh = mhTemp;
759 /* save the current pen, brush and font */
760 hPen = GetCurrentObject(hdc, OBJ_PEN);
761 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
762 hFont = GetCurrentObject(hdc, OBJ_FONT);
764 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
765 sizeof(HANDLETABLE) * mh->mtNoObjects);
767 /* loop through metafile records */
768 offset = mh->mtHeaderSize * 2;
770 while (offset < (mh->mtSize * 2))
772 mr = (METARECORD *)((char *)mh + offset);
773 if(mr->rdFunction == META_EOF) {
774 TRACE("Got META_EOF so stopping\n");
775 break;
777 TRACE("Calling EnumFunc with record type %x\n",
778 mr->rdFunction);
779 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
781 result = FALSE;
782 break;
785 offset += (mr->rdSize * 2);
788 /* restore pen, brush and font */
789 SelectObject(hdc, hBrush);
790 SelectObject(hdc, hPen);
791 SelectObject(hdc, hFont);
793 /* free objects in handle table */
794 for(i = 0; i < mh->mtNoObjects; i++)
795 if(*(ht->objectHandle + i) != 0)
796 DeleteObject(*(ht->objectHandle + i));
798 /* free handle table */
799 HeapFree( GetProcessHeap(), 0, ht);
800 /* free a copy of metafile */
801 HeapFree( GetProcessHeap(), 0, mhTemp );
802 return result;
805 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
806 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
807 /******************************************************************
808 * PlayMetaFileRecord (GDI32.@)
810 * Render a single metafile record specified by *mr in the DC hdc, while
811 * using the handle table *ht, of length handles,
812 * to store metafile objects.
814 * BUGS
815 * The following metafile records are unimplemented:
817 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
818 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
819 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
821 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
823 short s1;
824 POINT *pt;
825 BITMAPINFOHEADER *infohdr;
827 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
829 switch (mr->rdFunction)
831 case META_EOF:
832 break;
834 case META_DELETEOBJECT:
835 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
836 *(ht->objectHandle + mr->rdParm[0]) = 0;
837 break;
839 case META_SETBKCOLOR:
840 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
841 break;
843 case META_SETBKMODE:
844 SetBkMode(hdc, mr->rdParm[0]);
845 break;
847 case META_SETMAPMODE:
848 SetMapMode(hdc, mr->rdParm[0]);
849 break;
851 case META_SETROP2:
852 SetROP2(hdc, mr->rdParm[0]);
853 break;
855 case META_SETRELABS:
856 SetRelAbs(hdc, mr->rdParm[0]);
857 break;
859 case META_SETPOLYFILLMODE:
860 SetPolyFillMode(hdc, mr->rdParm[0]);
861 break;
863 case META_SETSTRETCHBLTMODE:
864 SetStretchBltMode(hdc, mr->rdParm[0]);
865 break;
867 case META_SETTEXTCOLOR:
868 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
869 break;
871 case META_SETWINDOWORG:
872 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
873 break;
875 case META_SETWINDOWEXT:
876 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
877 break;
879 case META_SETVIEWPORTORG:
880 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
881 break;
883 case META_SETVIEWPORTEXT:
884 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
885 break;
887 case META_OFFSETWINDOWORG:
888 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
889 break;
891 case META_SCALEWINDOWEXT:
892 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
893 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
894 break;
896 case META_OFFSETVIEWPORTORG:
897 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
898 break;
900 case META_SCALEVIEWPORTEXT:
901 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
902 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
903 break;
905 case META_LINETO:
906 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
907 break;
909 case META_MOVETO:
910 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
911 break;
913 case META_EXCLUDECLIPRECT:
914 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
915 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
916 break;
918 case META_INTERSECTCLIPRECT:
919 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
920 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
921 break;
923 case META_ARC:
924 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
925 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
926 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
927 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
928 break;
930 case META_ELLIPSE:
931 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
932 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
933 break;
935 case META_FLOODFILL:
936 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
937 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
938 break;
940 case META_PIE:
941 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
942 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
943 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
944 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
945 break;
947 case META_RECTANGLE:
948 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
949 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
950 break;
952 case META_ROUNDRECT:
953 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
954 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
955 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
956 break;
958 case META_PATBLT:
959 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
960 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
961 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
962 break;
964 case META_SAVEDC:
965 SaveDC(hdc);
966 break;
968 case META_SETPIXEL:
969 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
970 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
971 break;
973 case META_OFFSETCLIPRGN:
974 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
975 break;
977 case META_TEXTOUT:
978 s1 = mr->rdParm[0];
979 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
980 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
981 (char *)(mr->rdParm + 1), s1);
982 break;
984 case META_POLYGON:
985 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
987 Polygon(hdc, pt, mr->rdParm[0]);
988 HeapFree( GetProcessHeap(), 0, pt );
990 break;
992 case META_POLYPOLYGON:
994 UINT i, total;
995 SHORT *counts = (SHORT *)(mr->rdParm + 1);
997 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
998 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
999 if (pt)
1001 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
1002 if (cnt32)
1004 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
1005 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
1006 HeapFree( GetProcessHeap(), 0, cnt32 );
1009 HeapFree( GetProcessHeap(), 0, pt );
1011 break;
1013 case META_POLYLINE:
1014 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
1016 Polyline( hdc, pt, mr->rdParm[0] );
1017 HeapFree( GetProcessHeap(), 0, pt );
1019 break;
1021 case META_RESTOREDC:
1022 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1023 break;
1025 case META_SELECTOBJECT:
1026 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1027 break;
1029 case META_CHORD:
1030 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1031 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1032 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1033 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1034 break;
1036 case META_CREATEPATTERNBRUSH:
1037 switch (mr->rdParm[0])
1039 case BS_PATTERN:
1040 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1041 MF_AddHandle(ht, handles,
1042 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1043 infohdr->biHeight,
1044 infohdr->biPlanes,
1045 infohdr->biBitCount,
1046 (LPSTR)(mr->rdParm +
1047 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1048 break;
1050 case BS_DIBPATTERN:
1051 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1052 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1053 break;
1055 default:
1056 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1057 mr->rdParm[0]);
1058 break;
1060 break;
1062 case META_CREATEPENINDIRECT:
1064 LOGPEN pen;
1065 pen.lopnStyle = mr->rdParm[0];
1066 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1067 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1068 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1069 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1071 break;
1073 case META_CREATEFONTINDIRECT:
1075 LOGFONTA font;
1076 font.lfHeight = (SHORT)mr->rdParm[0];
1077 font.lfWidth = (SHORT)mr->rdParm[1];
1078 font.lfEscapement = (SHORT)mr->rdParm[2];
1079 font.lfOrientation = (SHORT)mr->rdParm[3];
1080 font.lfWeight = (SHORT)mr->rdParm[4];
1081 font.lfItalic = LOBYTE(mr->rdParm[5]);
1082 font.lfUnderline = HIBYTE(mr->rdParm[5]);
1083 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
1084 font.lfCharSet = HIBYTE(mr->rdParm[6]);
1085 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
1086 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
1087 font.lfQuality = LOBYTE(mr->rdParm[8]);
1088 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1089 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1090 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1092 break;
1094 case META_CREATEBRUSHINDIRECT:
1096 LOGBRUSH brush;
1097 brush.lbStyle = mr->rdParm[0];
1098 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1099 brush.lbHatch = mr->rdParm[3];
1100 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1102 break;
1104 case META_CREATEPALETTE:
1105 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1106 break;
1108 case META_SETTEXTALIGN:
1109 SetTextAlign(hdc, mr->rdParm[0]);
1110 break;
1112 case META_SELECTPALETTE:
1113 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1114 break;
1116 case META_SETMAPPERFLAGS:
1117 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1118 break;
1120 case META_REALIZEPALETTE:
1121 GDIRealizePalette(hdc);
1122 break;
1124 case META_ESCAPE:
1125 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
1126 break;
1128 case META_EXTTEXTOUT:
1129 MF_Play_MetaExtTextOut( hdc, mr );
1130 break;
1132 case META_STRETCHDIB:
1134 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1135 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1136 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1137 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1138 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1139 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1141 break;
1143 case META_DIBSTRETCHBLT:
1145 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1146 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1147 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1148 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1149 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1150 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1152 break;
1154 case META_STRETCHBLT:
1156 HDC hdcSrc = CreateCompatibleDC(hdc);
1157 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1158 mr->rdParm[11], /*Height*/
1159 mr->rdParm[13], /*Planes*/
1160 mr->rdParm[14], /*BitsPixel*/
1161 (LPSTR)&mr->rdParm[15]); /*bits*/
1162 SelectObject(hdcSrc,hbitmap);
1163 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1164 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1165 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1166 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1167 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1168 DeleteDC(hdcSrc);
1170 break;
1172 case META_BITBLT:
1174 HDC hdcSrc = CreateCompatibleDC(hdc);
1175 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1176 mr->rdParm[8]/*Height*/,
1177 mr->rdParm[10]/*Planes*/,
1178 mr->rdParm[11]/*BitsPixel*/,
1179 (LPSTR)&mr->rdParm[12]/*bits*/);
1180 SelectObject(hdcSrc,hbitmap);
1181 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1182 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1183 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1184 MAKELONG(0,mr->rdParm[0]));
1185 DeleteDC(hdcSrc);
1187 break;
1189 case META_CREATEREGION:
1191 HRGN hrgn = CreateRectRgn(0,0,0,0);
1193 MF_Play_MetaCreateRegion(mr, hrgn);
1194 MF_AddHandle(ht, handles, hrgn);
1196 break;
1198 case META_FILLREGION:
1199 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1200 *(ht->objectHandle + mr->rdParm[0]));
1201 break;
1203 case META_FRAMEREGION:
1204 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1205 *(ht->objectHandle + mr->rdParm[2]),
1206 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1207 break;
1209 case META_INVERTREGION:
1210 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1211 break;
1213 case META_PAINTREGION:
1214 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1215 break;
1217 case META_SELECTCLIPREGION:
1218 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1219 break;
1221 case META_DIBCREATEPATTERNBRUSH:
1222 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1223 but there's no difference */
1224 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1225 break;
1227 case META_DIBBITBLT:
1228 /* In practice I've found that there are two layouts for
1229 META_DIBBITBLT, one (the first here) is the usual one when a src
1230 dc is actually passed to it, the second occurs when the src dc is
1231 passed in as NULL to the creating BitBlt. As the second case has
1232 no dib, a size check will suffice to distinguish.
1234 Caolan.McNamara@ul.ie */
1236 if (mr->rdSize > 12) {
1237 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1238 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1240 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1241 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1242 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1243 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1245 else /* equivalent to a PatBlt */
1246 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1247 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1248 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1249 break;
1251 case META_SETTEXTCHAREXTRA:
1252 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1253 break;
1255 case META_SETTEXTJUSTIFICATION:
1256 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1257 break;
1259 case META_EXTFLOODFILL:
1260 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1261 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1262 mr->rdParm[0]);
1263 break;
1265 case META_SETDIBTODEV:
1267 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1268 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1269 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1270 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1271 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1272 mr->rdParm[2], mr->rdParm[1], bits, info,
1273 mr->rdParm[0]);
1274 break;
1277 #define META_UNIMP(x) case x: \
1278 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1279 break;
1280 META_UNIMP(META_DRAWTEXT)
1281 META_UNIMP(META_ANIMATEPALETTE)
1282 META_UNIMP(META_SETPALENTRIES)
1283 META_UNIMP(META_RESIZEPALETTE)
1284 META_UNIMP(META_RESETDC)
1285 META_UNIMP(META_STARTDOC)
1286 META_UNIMP(META_STARTPAGE)
1287 META_UNIMP(META_ENDPAGE)
1288 META_UNIMP(META_ABORTDOC)
1289 META_UNIMP(META_ENDDOC)
1290 META_UNIMP(META_CREATEBRUSH)
1291 META_UNIMP(META_CREATEBITMAPINDIRECT)
1292 META_UNIMP(META_CREATEBITMAP)
1293 #undef META_UNIMP
1295 default:
1296 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1297 return FALSE;
1299 return TRUE;
1302 /******************************************************************
1303 * GetMetaFileBits (GDI.159)
1305 * Trade in a metafile object handle for a handle to the metafile memory.
1309 HGLOBAL16 WINAPI GetMetaFileBits16(
1310 HMETAFILE16 hmf /* [in] metafile handle */
1313 TRACE("hMem out: %04x\n", hmf);
1314 return hmf;
1317 /******************************************************************
1318 * SetMetaFileBits (GDI.160)
1320 * Trade in a metafile memory handle for a handle to a metafile object.
1321 * The memory region should hold a proper metafile, otherwise
1322 * problems will occur when it is used. Validity of the memory is not
1323 * checked. The function is essentially just the identity function.
1325 HMETAFILE16 WINAPI SetMetaFileBits16(
1326 HGLOBAL16 hMem
1327 /* [in] handle to a memory region holding a metafile */
1330 TRACE("hmf out: %04x\n", hMem);
1332 return hMem;
1335 /******************************************************************
1336 * SetMetaFileBitsBetter (GDI.196)
1338 * Trade in a metafile memory handle for a handle to a metafile object,
1339 * making a cursory check (using IsValidMetaFile()) that the memory
1340 * handle points to a valid metafile.
1342 * RETURNS
1343 * Handle to a metafile on success, NULL on failure..
1345 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1347 if( IsValidMetaFile16( hMeta ) )
1348 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1349 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1350 return (HMETAFILE16)0;
1353 /******************************************************************
1354 * SetMetaFileBitsEx (GDI32.@)
1356 * Create a metafile from raw data. No checking of the data is performed.
1357 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1359 HMETAFILE WINAPI SetMetaFileBitsEx(
1360 UINT size, /* [in] size of metafile, in bytes */
1361 const BYTE *lpData /* [in] pointer to metafile data */
1364 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1365 if (!mh) return 0;
1366 memcpy(mh, lpData, size);
1367 return MF_Create_HMETAFILE(mh);
1370 /*****************************************************************
1371 * GetMetaFileBitsEx (GDI32.@)
1373 * Get raw metafile data.
1375 * Copies the data from metafile _hmf_ into the buffer _buf_.
1376 * If _buf_ is zero, returns size of buffer required. Otherwise,
1377 * returns number of bytes copied.
1379 UINT WINAPI GetMetaFileBitsEx(
1380 HMETAFILE hmf, /* [in] metafile */
1381 UINT nSize, /* [in] size of buf */
1382 LPVOID buf /* [out] buffer to receive raw metafile data */)
1384 METAHEADER *mh = MF_GetMetaHeader(hmf);
1385 UINT mfSize;
1387 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1388 if (!mh) return 0; /* FIXME: error code */
1389 if(mh->mtType == METAFILE_DISK)
1390 FIXME("Disk-based metafile?\n");
1391 mfSize = mh->mtSize * 2;
1392 if (!buf) {
1393 TRACE("returning size %d\n", mfSize);
1394 return mfSize;
1396 if(mfSize > nSize) mfSize = nSize;
1397 memmove(buf, mh, mfSize);
1398 return mfSize;
1401 /******************************************************************
1402 * GetWinMetaFileBits [GDI32.@]
1404 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1405 UINT cbBuffer, LPBYTE lpbBuffer,
1406 INT fnMapMode, HDC hdcRef)
1408 HDC hdcmf;
1409 HMETAFILE hmf;
1410 UINT ret;
1411 RECT rc;
1412 INT oldMapMode;
1414 GetClipBox(hdcRef, &rc);
1415 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1417 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1418 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1420 hdcmf = CreateMetaFileA(NULL);
1421 PlayEnhMetaFile(hdcmf, hemf, &rc);
1422 hmf = CloseMetaFile(hdcmf);
1423 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1424 DeleteMetaFile(hmf);
1426 SetMapMode(hdcRef, oldMapMode);
1428 return ret;
1431 /******************************************************************
1432 * MF_Play_MetaCreateRegion
1434 * Handles META_CREATEREGION for PlayMetaFileRecord().
1438 * The layout of the record looks something like this:
1440 * rdParm meaning
1441 * 0 Always 0?
1442 * 1 Always 6?
1443 * 2 Looks like a handle? - not constant
1444 * 3 0 or 1 ??
1445 * 4 Total number of bytes
1446 * 5 No. of separate bands = n [see below]
1447 * 6 Largest number of x co-ords in a band
1448 * 7-10 Bounding box x1 y1 x2 y2
1449 * 11-... n bands
1451 * Regions are divided into bands that are uniform in the
1452 * y-direction. Each band consists of pairs of on/off x-coords and is
1453 * written as
1454 * m y0 y1 x1 x2 x3 ... xm m
1455 * into successive rdParm[]s.
1457 * This is probably just a dump of the internal RGNOBJ?
1459 * HDMD - 18/12/97
1463 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1465 WORD band, pair;
1466 WORD *start, *end;
1467 INT16 y0, y1;
1468 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1470 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1471 band++, start = end + 1) {
1472 if(*start / 2 != (*start + 1) / 2) {
1473 WARN("Delimiter not even.\n");
1474 DeleteObject( hrgn2 );
1475 return FALSE;
1478 end = start + *start + 3;
1479 if(end > (WORD *)mr + mr->rdSize) {
1480 WARN("End points outside record.\n");
1481 DeleteObject( hrgn2 );
1482 return FALSE;
1485 if(*start != *end) {
1486 WARN("Mismatched delimiters.\n");
1487 DeleteObject( hrgn2 );
1488 return FALSE;
1491 y0 = *(INT16 *)(start + 1);
1492 y1 = *(INT16 *)(start + 2);
1493 for(pair = 0; pair < *start / 2; pair++) {
1494 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1495 *(INT16 *)(start + 4 + 2*pair), y1 );
1496 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1499 DeleteObject( hrgn2 );
1500 return TRUE;
1504 /******************************************************************
1505 * MF_Play_MetaExtTextOut
1507 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1510 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1512 INT *dx = NULL;
1513 int i;
1514 LPINT16 dxx;
1515 LPSTR sot;
1516 DWORD len;
1517 WORD s1;
1518 RECT rect;
1519 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1521 s1 = mr->rdParm[2]; /* String length */
1522 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1523 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1524 /* rec len without dx array */
1526 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1527 if (isrect)
1529 rect.left = (SHORT)mr->rdParm[4];
1530 rect.top = (SHORT)mr->rdParm[5];
1531 rect.right = (SHORT)mr->rdParm[6];
1532 rect.bottom = (SHORT)mr->rdParm[7];
1533 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1536 if (mr->rdSize == len / 2)
1537 dxx = NULL; /* determine if array present */
1538 else
1539 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1541 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1542 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1543 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1545 else {
1546 TRACE("%s len: %ld\n", sot, mr->rdSize);
1547 WARN(
1548 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1549 len, s1, mr->rdSize, mr->rdParm[3]);
1550 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1552 ExtTextOutA( hdc,
1553 (SHORT)mr->rdParm[1], /* X position */
1554 (SHORT)mr->rdParm[0], /* Y position */
1555 mr->rdParm[3], /* options */
1556 &rect, /* rectangle */
1557 sot, /* string */
1558 s1, dx); /* length, dx array */
1559 if (dx)
1561 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1562 HeapFree( GetProcessHeap(), 0, dx );
1564 return TRUE;