Automatically detect whether the entry point is main or WinMain
[wine/multimedia.git] / objects / metafile.c
bloba94f0f9c7390c5ebf6ba088705e11bfea5cee943
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 if (lpFilenameW.Buffer) {
490 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
492 RtlFreeUnicodeString(&lpFilenameW);
493 return ret;
497 /******************************************************************
498 * IsValidMetaFile (GDI.410)
500 * Attempts to check if a given metafile is correctly formatted.
501 * Currently, the only things verified are several properties of the
502 * header.
504 * RETURNS
505 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
507 * BUGS
508 * This is not exactly what windows does, see _Undocumented_Windows_
509 * for details.
511 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
513 BOOL16 res=FALSE;
514 METAHEADER *mh = MF_GetMetaHeader16(hmf);
515 if (mh) {
516 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
517 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
518 if (mh->mtVersion == MFVERSION)
519 res=TRUE;
520 MF_ReleaseMetaHeader16(hmf);
522 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
523 return res;
527 /*******************************************************************
528 * MF_PlayMetaFile
530 * Helper for PlayMetaFile
532 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
535 METARECORD *mr;
536 HANDLETABLE *ht;
537 unsigned int offset = 0;
538 WORD i;
539 HPEN hPen;
540 HBRUSH hBrush;
541 HFONT hFont;
542 BOOL loaded = FALSE;
544 if (!mh) return FALSE;
545 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
546 mh = MF_LoadDiskBasedMetaFile(mh);
547 if(!mh) return FALSE;
548 loaded = TRUE;
551 /* save the current pen, brush and font */
552 hPen = GetCurrentObject(hdc, OBJ_PEN);
553 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
554 hFont = GetCurrentObject(hdc, OBJ_FONT);
556 /* create the handle table */
557 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
558 sizeof(HANDLETABLE) * mh->mtNoObjects);
559 if(!ht) return FALSE;
561 /* loop through metafile playing records */
562 offset = mh->mtHeaderSize * 2;
563 while (offset < mh->mtSize * 2)
565 mr = (METARECORD *)((char *)mh + offset);
566 TRACE("offset=%04x,size=%08lx\n",
567 offset, mr->rdSize);
568 if (!mr->rdSize) {
569 TRACE(
570 "Entry got size 0 at offset %d, total mf length is %ld\n",
571 offset,mh->mtSize*2);
572 break; /* would loop endlessly otherwise */
574 offset += mr->rdSize * 2;
575 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
578 SelectObject(hdc, hBrush);
579 SelectObject(hdc, hPen);
580 SelectObject(hdc, hFont);
582 /* free objects in handle table */
583 for(i = 0; i < mh->mtNoObjects; i++)
584 if(*(ht->objectHandle + i) != 0)
585 DeleteObject(*(ht->objectHandle + i));
587 /* free handle table */
588 HeapFree( GetProcessHeap(), 0, ht );
589 if(loaded)
590 HeapFree( GetProcessHeap(), 0, mh );
591 return TRUE;
594 /******************************************************************
595 * PlayMetaFile (GDI.123)
598 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
600 BOOL16 ret;
601 METAHEADER *mh = MF_GetMetaHeader16( hmf );
602 ret = MF_PlayMetaFile( HDC_32(hdc), mh );
603 MF_ReleaseMetaHeader16( hmf );
604 return ret;
607 /******************************************************************
608 * PlayMetaFile (GDI32.@)
610 * Renders the metafile specified by hmf in the DC specified by
611 * hdc. Returns FALSE on failure, TRUE on success.
613 BOOL WINAPI PlayMetaFile(
614 HDC hdc, /* [in] handle of DC to render in */
615 HMETAFILE hmf /* [in] handle of metafile to render */
618 METAHEADER *mh = MF_GetMetaHeader( hmf );
619 return MF_PlayMetaFile( hdc, mh );
623 /******************************************************************
624 * EnumMetaFile (GDI.175)
627 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
628 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
630 METAHEADER *mh = MF_GetMetaHeader16(hmf);
631 METARECORD *mr;
632 HANDLETABLE16 *ht;
633 HDC hdc = HDC_32(hdc16);
634 HGLOBAL16 hHT;
635 SEGPTR spht;
636 unsigned int offset = 0;
637 WORD i, seg;
638 HPEN hPen;
639 HBRUSH hBrush;
640 HFONT hFont;
641 WORD args[8];
642 BOOL16 result = TRUE, loaded = FALSE;
644 TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
646 if(!mh) return FALSE;
647 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
648 mh = MF_LoadDiskBasedMetaFile(mh);
649 if(!mh) return FALSE;
650 loaded = TRUE;
653 /* save the current pen, brush and font */
654 hPen = GetCurrentObject(hdc, OBJ_PEN);
655 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
656 hFont = GetCurrentObject(hdc, OBJ_FONT);
658 /* create the handle table */
660 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
661 sizeof(HANDLETABLE16) * mh->mtNoObjects);
662 spht = K32WOWGlobalLock16(hHT);
664 seg = hmf | 7;
665 offset = mh->mtHeaderSize * 2;
667 /* loop through metafile records */
669 args[7] = hdc16;
670 args[6] = SELECTOROF(spht);
671 args[5] = OFFSETOF(spht);
672 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
673 args[3] = LOWORD(offset);
674 args[2] = mh->mtNoObjects;
675 args[1] = HIWORD(lpData);
676 args[0] = LOWORD(lpData);
678 while (offset < (mh->mtSize * 2))
680 DWORD ret;
682 mr = (METARECORD *)((char *)mh + offset);
684 WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
685 if (!LOWORD(ret))
687 result = FALSE;
688 break;
691 offset += (mr->rdSize * 2);
692 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
693 args[3] = LOWORD(offset);
696 SelectObject(hdc, hBrush);
697 SelectObject(hdc, hPen);
698 SelectObject(hdc, hFont);
700 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
702 /* free objects in handle table */
703 for(i = 0; i < mh->mtNoObjects; i++)
704 if(*(ht->objectHandle + i) != 0)
705 DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
707 /* free handle table */
708 GlobalFree16(hHT);
709 if(loaded)
710 HeapFree( GetProcessHeap(), 0, mh );
711 MF_ReleaseMetaHeader16(hmf);
712 return result;
715 /******************************************************************
716 * EnumMetaFile (GDI32.@)
718 * Loop through the metafile records in hmf, calling the user-specified
719 * function for each one, stopping when the user's function returns FALSE
720 * (which is considered to be failure)
721 * or when no records are left (which is considered to be success).
723 * RETURNS
724 * TRUE on success, FALSE on failure.
726 * HISTORY
727 * Niels de carpentier, april 1996
729 BOOL WINAPI EnumMetaFile(
730 HDC hdc,
731 HMETAFILE hmf,
732 MFENUMPROC lpEnumFunc,
733 LPARAM lpData)
735 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
736 METARECORD *mr;
737 HANDLETABLE *ht;
738 BOOL result = TRUE;
739 int i;
740 unsigned int offset = 0;
741 HPEN hPen;
742 HBRUSH hBrush;
743 HFONT hFont;
745 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
746 if (!mh) return 0;
747 if(mh->mtType == METAFILE_DISK)
749 /* Create a memory-based copy */
750 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
751 mh = mhTemp;
754 /* save the current pen, brush and font */
755 hPen = GetCurrentObject(hdc, OBJ_PEN);
756 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
757 hFont = GetCurrentObject(hdc, OBJ_FONT);
759 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
760 sizeof(HANDLETABLE) * mh->mtNoObjects);
762 /* loop through metafile records */
763 offset = mh->mtHeaderSize * 2;
765 while (offset < (mh->mtSize * 2))
767 mr = (METARECORD *)((char *)mh + offset);
768 if(mr->rdFunction == META_EOF) {
769 TRACE("Got META_EOF so stopping\n");
770 break;
772 TRACE("Calling EnumFunc with record type %x\n",
773 mr->rdFunction);
774 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
776 result = FALSE;
777 break;
780 offset += (mr->rdSize * 2);
783 /* restore pen, brush and font */
784 SelectObject(hdc, hBrush);
785 SelectObject(hdc, hPen);
786 SelectObject(hdc, hFont);
788 /* free objects in handle table */
789 for(i = 0; i < mh->mtNoObjects; i++)
790 if(*(ht->objectHandle + i) != 0)
791 DeleteObject(*(ht->objectHandle + i));
793 /* free handle table */
794 HeapFree( GetProcessHeap(), 0, ht);
795 /* free a copy of metafile */
796 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
797 return result;
800 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
801 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
802 /******************************************************************
803 * PlayMetaFileRecord (GDI32.@)
805 * Render a single metafile record specified by *mr in the DC hdc, while
806 * using the handle table *ht, of length handles,
807 * to store metafile objects.
809 * BUGS
810 * The following metafile records are unimplemented:
812 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
813 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
814 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
816 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
818 short s1;
819 POINT *pt;
820 BITMAPINFOHEADER *infohdr;
822 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
824 switch (mr->rdFunction)
826 case META_EOF:
827 break;
829 case META_DELETEOBJECT:
830 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
831 *(ht->objectHandle + mr->rdParm[0]) = 0;
832 break;
834 case META_SETBKCOLOR:
835 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
836 break;
838 case META_SETBKMODE:
839 SetBkMode(hdc, mr->rdParm[0]);
840 break;
842 case META_SETMAPMODE:
843 SetMapMode(hdc, mr->rdParm[0]);
844 break;
846 case META_SETROP2:
847 SetROP2(hdc, mr->rdParm[0]);
848 break;
850 case META_SETRELABS:
851 SetRelAbs(hdc, mr->rdParm[0]);
852 break;
854 case META_SETPOLYFILLMODE:
855 SetPolyFillMode(hdc, mr->rdParm[0]);
856 break;
858 case META_SETSTRETCHBLTMODE:
859 SetStretchBltMode(hdc, mr->rdParm[0]);
860 break;
862 case META_SETTEXTCOLOR:
863 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
864 break;
866 case META_SETWINDOWORG:
867 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
868 break;
870 case META_SETWINDOWEXT:
871 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
872 break;
874 case META_SETVIEWPORTORG:
875 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
876 break;
878 case META_SETVIEWPORTEXT:
879 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
880 break;
882 case META_OFFSETWINDOWORG:
883 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
884 break;
886 case META_SCALEWINDOWEXT:
887 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
888 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
889 break;
891 case META_OFFSETVIEWPORTORG:
892 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
893 break;
895 case META_SCALEVIEWPORTEXT:
896 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
897 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
898 break;
900 case META_LINETO:
901 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
902 break;
904 case META_MOVETO:
905 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
906 break;
908 case META_EXCLUDECLIPRECT:
909 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
910 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
911 break;
913 case META_INTERSECTCLIPRECT:
914 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
915 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
916 break;
918 case META_ARC:
919 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
920 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
921 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
922 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
923 break;
925 case META_ELLIPSE:
926 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
927 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
928 break;
930 case META_FLOODFILL:
931 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
932 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
933 break;
935 case META_PIE:
936 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
937 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
938 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
939 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
940 break;
942 case META_RECTANGLE:
943 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
944 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
945 break;
947 case META_ROUNDRECT:
948 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
949 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
950 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
951 break;
953 case META_PATBLT:
954 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
955 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
956 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
957 break;
959 case META_SAVEDC:
960 SaveDC(hdc);
961 break;
963 case META_SETPIXEL:
964 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
965 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
966 break;
968 case META_OFFSETCLIPRGN:
969 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
970 break;
972 case META_TEXTOUT:
973 s1 = mr->rdParm[0];
974 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
975 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
976 (char *)(mr->rdParm + 1), s1);
977 break;
979 case META_POLYGON:
980 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
982 Polygon(hdc, pt, mr->rdParm[0]);
983 HeapFree( GetProcessHeap(), 0, pt );
985 break;
987 case META_POLYPOLYGON:
989 UINT i, total;
990 SHORT *counts = (SHORT *)(mr->rdParm + 1);
992 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
993 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
994 if (pt)
996 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
997 if (cnt32)
999 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
1000 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
1001 HeapFree( GetProcessHeap(), 0, cnt32 );
1004 HeapFree( GetProcessHeap(), 0, pt );
1006 break;
1008 case META_POLYLINE:
1009 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
1011 Polyline( hdc, pt, mr->rdParm[0] );
1012 HeapFree( GetProcessHeap(), 0, pt );
1014 break;
1016 case META_RESTOREDC:
1017 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1018 break;
1020 case META_SELECTOBJECT:
1021 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1022 break;
1024 case META_CHORD:
1025 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1026 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1027 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1028 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1029 break;
1031 case META_CREATEPATTERNBRUSH:
1032 switch (mr->rdParm[0])
1034 case BS_PATTERN:
1035 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1036 MF_AddHandle(ht, handles,
1037 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1038 infohdr->biHeight,
1039 infohdr->biPlanes,
1040 infohdr->biBitCount,
1041 (LPSTR)(mr->rdParm +
1042 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1043 break;
1045 case BS_DIBPATTERN:
1046 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1047 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1048 break;
1050 default:
1051 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1052 mr->rdParm[0]);
1053 break;
1055 break;
1057 case META_CREATEPENINDIRECT:
1059 LOGPEN pen;
1060 pen.lopnStyle = mr->rdParm[0];
1061 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1062 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1063 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1064 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1066 break;
1068 case META_CREATEFONTINDIRECT:
1070 LOGFONTA font;
1071 font.lfHeight = (SHORT)mr->rdParm[0];
1072 font.lfWidth = (SHORT)mr->rdParm[1];
1073 font.lfEscapement = (SHORT)mr->rdParm[2];
1074 font.lfOrientation = (SHORT)mr->rdParm[3];
1075 font.lfWeight = (SHORT)mr->rdParm[4];
1076 font.lfItalic = LOBYTE(mr->rdParm[5]);
1077 font.lfUnderline = HIBYTE(mr->rdParm[5]);
1078 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
1079 font.lfCharSet = HIBYTE(mr->rdParm[6]);
1080 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
1081 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
1082 font.lfQuality = LOBYTE(mr->rdParm[8]);
1083 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1084 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1085 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1087 break;
1089 case META_CREATEBRUSHINDIRECT:
1091 LOGBRUSH brush;
1092 brush.lbStyle = mr->rdParm[0];
1093 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1094 brush.lbHatch = mr->rdParm[3];
1095 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1097 break;
1099 case META_CREATEPALETTE:
1100 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1101 break;
1103 case META_SETTEXTALIGN:
1104 SetTextAlign(hdc, mr->rdParm[0]);
1105 break;
1107 case META_SELECTPALETTE:
1108 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1109 break;
1111 case META_SETMAPPERFLAGS:
1112 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1113 break;
1115 case META_REALIZEPALETTE:
1116 GDIRealizePalette(hdc);
1117 break;
1119 case META_ESCAPE:
1120 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
1121 break;
1123 case META_EXTTEXTOUT:
1124 MF_Play_MetaExtTextOut( hdc, mr );
1125 break;
1127 case META_STRETCHDIB:
1129 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1130 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1131 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1132 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1133 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1134 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1136 break;
1138 case META_DIBSTRETCHBLT:
1140 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1141 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1142 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1143 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1144 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1145 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1147 break;
1149 case META_STRETCHBLT:
1151 HDC hdcSrc = CreateCompatibleDC(hdc);
1152 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1153 mr->rdParm[11], /*Height*/
1154 mr->rdParm[13], /*Planes*/
1155 mr->rdParm[14], /*BitsPixel*/
1156 (LPSTR)&mr->rdParm[15]); /*bits*/
1157 SelectObject(hdcSrc,hbitmap);
1158 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1159 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1160 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1161 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1162 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1163 DeleteDC(hdcSrc);
1165 break;
1167 case META_BITBLT:
1169 HDC hdcSrc = CreateCompatibleDC(hdc);
1170 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1171 mr->rdParm[8]/*Height*/,
1172 mr->rdParm[10]/*Planes*/,
1173 mr->rdParm[11]/*BitsPixel*/,
1174 (LPSTR)&mr->rdParm[12]/*bits*/);
1175 SelectObject(hdcSrc,hbitmap);
1176 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1177 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1178 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1179 MAKELONG(0,mr->rdParm[0]));
1180 DeleteDC(hdcSrc);
1182 break;
1184 case META_CREATEREGION:
1186 HRGN hrgn = CreateRectRgn(0,0,0,0);
1188 MF_Play_MetaCreateRegion(mr, hrgn);
1189 MF_AddHandle(ht, handles, hrgn);
1191 break;
1193 case META_FILLREGION:
1194 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1195 *(ht->objectHandle + mr->rdParm[0]));
1196 break;
1198 case META_FRAMEREGION:
1199 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1200 *(ht->objectHandle + mr->rdParm[2]),
1201 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1202 break;
1204 case META_INVERTREGION:
1205 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1206 break;
1208 case META_PAINTREGION:
1209 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1210 break;
1212 case META_SELECTCLIPREGION:
1213 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1214 break;
1216 case META_DIBCREATEPATTERNBRUSH:
1217 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1218 but there's no difference */
1219 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1220 break;
1222 case META_DIBBITBLT:
1223 /* In practice I've found that there are two layouts for
1224 META_DIBBITBLT, one (the first here) is the usual one when a src
1225 dc is actually passed to it, the second occurs when the src dc is
1226 passed in as NULL to the creating BitBlt. As the second case has
1227 no dib, a size check will suffice to distinguish.
1229 Caolan.McNamara@ul.ie */
1231 if (mr->rdSize > 12) {
1232 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1233 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1235 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1236 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1237 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1238 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1240 else /* equivalent to a PatBlt */
1241 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1242 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1243 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1244 break;
1246 case META_SETTEXTCHAREXTRA:
1247 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1248 break;
1250 case META_SETTEXTJUSTIFICATION:
1251 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1252 break;
1254 case META_EXTFLOODFILL:
1255 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1256 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1257 mr->rdParm[0]);
1258 break;
1260 case META_SETDIBTODEV:
1262 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1263 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1264 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1265 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1266 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1267 mr->rdParm[2], mr->rdParm[1], bits, info,
1268 mr->rdParm[0]);
1269 break;
1272 #define META_UNIMP(x) case x: \
1273 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1274 break;
1275 META_UNIMP(META_DRAWTEXT)
1276 META_UNIMP(META_ANIMATEPALETTE)
1277 META_UNIMP(META_SETPALENTRIES)
1278 META_UNIMP(META_RESIZEPALETTE)
1279 META_UNIMP(META_RESETDC)
1280 META_UNIMP(META_STARTDOC)
1281 META_UNIMP(META_STARTPAGE)
1282 META_UNIMP(META_ENDPAGE)
1283 META_UNIMP(META_ABORTDOC)
1284 META_UNIMP(META_ENDDOC)
1285 META_UNIMP(META_CREATEBRUSH)
1286 META_UNIMP(META_CREATEBITMAPINDIRECT)
1287 META_UNIMP(META_CREATEBITMAP)
1288 #undef META_UNIMP
1290 default:
1291 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1292 return FALSE;
1294 return TRUE;
1297 /******************************************************************
1298 * GetMetaFileBits (GDI.159)
1300 * Trade in a metafile object handle for a handle to the metafile memory.
1304 HGLOBAL16 WINAPI GetMetaFileBits16(
1305 HMETAFILE16 hmf /* [in] metafile handle */
1308 TRACE("hMem out: %04x\n", hmf);
1309 return hmf;
1312 /******************************************************************
1313 * SetMetaFileBits (GDI.160)
1315 * Trade in a metafile memory handle for a handle to a metafile object.
1316 * The memory region should hold a proper metafile, otherwise
1317 * problems will occur when it is used. Validity of the memory is not
1318 * checked. The function is essentially just the identity function.
1320 HMETAFILE16 WINAPI SetMetaFileBits16(
1321 HGLOBAL16 hMem
1322 /* [in] handle to a memory region holding a metafile */
1325 TRACE("hmf out: %04x\n", hMem);
1327 return hMem;
1330 /******************************************************************
1331 * SetMetaFileBitsBetter (GDI.196)
1333 * Trade in a metafile memory handle for a handle to a metafile object,
1334 * making a cursory check (using IsValidMetaFile()) that the memory
1335 * handle points to a valid metafile.
1337 * RETURNS
1338 * Handle to a metafile on success, NULL on failure..
1340 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1342 if( IsValidMetaFile16( hMeta ) )
1343 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1344 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1345 return (HMETAFILE16)0;
1348 /******************************************************************
1349 * SetMetaFileBitsEx (GDI32.@)
1351 * Create a metafile from raw data. No checking of the data is performed.
1352 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1354 HMETAFILE WINAPI SetMetaFileBitsEx(
1355 UINT size, /* [in] size of metafile, in bytes */
1356 const BYTE *lpData /* [in] pointer to metafile data */
1359 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1360 if (!mh) return 0;
1361 memcpy(mh, lpData, size);
1362 return MF_Create_HMETAFILE(mh);
1365 /*****************************************************************
1366 * GetMetaFileBitsEx (GDI32.@)
1368 * Get raw metafile data.
1370 * Copies the data from metafile _hmf_ into the buffer _buf_.
1371 * If _buf_ is zero, returns size of buffer required. Otherwise,
1372 * returns number of bytes copied.
1374 UINT WINAPI GetMetaFileBitsEx(
1375 HMETAFILE hmf, /* [in] metafile */
1376 UINT nSize, /* [in] size of buf */
1377 LPVOID buf /* [out] buffer to receive raw metafile data */)
1379 METAHEADER *mh = MF_GetMetaHeader(hmf);
1380 UINT mfSize;
1382 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1383 if (!mh) return 0; /* FIXME: error code */
1384 if(mh->mtType == METAFILE_DISK)
1385 FIXME("Disk-based metafile?\n");
1386 mfSize = mh->mtSize * 2;
1387 if (!buf) {
1388 TRACE("returning size %d\n", mfSize);
1389 return mfSize;
1391 if(mfSize > nSize) mfSize = nSize;
1392 memmove(buf, mh, mfSize);
1393 return mfSize;
1396 /******************************************************************
1397 * GetWinMetaFileBits [GDI32.@]
1399 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1400 UINT cbBuffer, LPBYTE lpbBuffer,
1401 INT fnMapMode, HDC hdcRef)
1403 HDC hdcmf;
1404 HMETAFILE hmf;
1405 UINT ret;
1406 RECT rc;
1407 INT oldMapMode;
1409 GetClipBox(hdcRef, &rc);
1410 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1412 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1413 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1415 hdcmf = CreateMetaFileA(NULL);
1416 PlayEnhMetaFile(hdcmf, hemf, &rc);
1417 hmf = CloseMetaFile(hdcmf);
1418 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1419 DeleteMetaFile(hmf);
1421 SetMapMode(hdcRef, oldMapMode);
1423 return ret;
1426 /******************************************************************
1427 * MF_Play_MetaCreateRegion
1429 * Handles META_CREATEREGION for PlayMetaFileRecord().
1433 * The layout of the record looks something like this:
1435 * rdParm meaning
1436 * 0 Always 0?
1437 * 1 Always 6?
1438 * 2 Looks like a handle? - not constant
1439 * 3 0 or 1 ??
1440 * 4 Total number of bytes
1441 * 5 No. of separate bands = n [see below]
1442 * 6 Largest number of x co-ords in a band
1443 * 7-10 Bounding box x1 y1 x2 y2
1444 * 11-... n bands
1446 * Regions are divided into bands that are uniform in the
1447 * y-direction. Each band consists of pairs of on/off x-coords and is
1448 * written as
1449 * m y0 y1 x1 x2 x3 ... xm m
1450 * into successive rdParm[]s.
1452 * This is probably just a dump of the internal RGNOBJ?
1454 * HDMD - 18/12/97
1458 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1460 WORD band, pair;
1461 WORD *start, *end;
1462 INT16 y0, y1;
1463 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1465 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1466 band++, start = end + 1) {
1467 if(*start / 2 != (*start + 1) / 2) {
1468 WARN("Delimiter not even.\n");
1469 DeleteObject( hrgn2 );
1470 return FALSE;
1473 end = start + *start + 3;
1474 if(end > (WORD *)mr + mr->rdSize) {
1475 WARN("End points outside record.\n");
1476 DeleteObject( hrgn2 );
1477 return FALSE;
1480 if(*start != *end) {
1481 WARN("Mismatched delimiters.\n");
1482 DeleteObject( hrgn2 );
1483 return FALSE;
1486 y0 = *(INT16 *)(start + 1);
1487 y1 = *(INT16 *)(start + 2);
1488 for(pair = 0; pair < *start / 2; pair++) {
1489 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1490 *(INT16 *)(start + 4 + 2*pair), y1 );
1491 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1494 DeleteObject( hrgn2 );
1495 return TRUE;
1499 /******************************************************************
1500 * MF_Play_MetaExtTextOut
1502 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1505 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1507 INT *dx = NULL;
1508 int i;
1509 LPINT16 dxx;
1510 LPSTR sot;
1511 DWORD len;
1512 WORD s1;
1513 RECT rect;
1514 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1516 s1 = mr->rdParm[2]; /* String length */
1517 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1518 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1519 /* rec len without dx array */
1521 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1522 if (isrect)
1524 rect.left = (SHORT)mr->rdParm[4];
1525 rect.top = (SHORT)mr->rdParm[5];
1526 rect.right = (SHORT)mr->rdParm[6];
1527 rect.bottom = (SHORT)mr->rdParm[7];
1528 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1531 if (mr->rdSize == len / 2)
1532 dxx = NULL; /* determine if array present */
1533 else
1534 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1536 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1537 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1538 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1540 else {
1541 TRACE("%s len: %ld\n", sot, mr->rdSize);
1542 WARN(
1543 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1544 len, s1, mr->rdSize, mr->rdParm[3]);
1545 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1547 ExtTextOutA( hdc,
1548 (SHORT)mr->rdParm[1], /* X position */
1549 (SHORT)mr->rdParm[0], /* Y position */
1550 mr->rdParm[3], /* options */
1551 &rect, /* rectangle */
1552 sot, /* string */
1553 s1, dx); /* length, dx array */
1554 if (dx)
1556 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1557 HeapFree( GetProcessHeap(), 0, dx );
1559 return TRUE;