- Clean up and add some comments.
[wine/multimedia.git] / objects / metafile.c
blob4ade939d3c5ffee462d3cb9df7a205ae9c6dd431
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 "bitmap.h"
54 #include "global.h"
55 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
59 #include "pshpack1.h"
60 typedef struct
62 DWORD dw1, dw2, dw3;
63 WORD w4;
64 CHAR filename[0x100];
65 } METAHEADERDISK;
66 #include "poppack.h"
68 typedef struct
70 GDIOBJHDR header;
71 METAHEADER *mh;
72 } METAFILEOBJ;
74 #define MFHEADERSIZE (sizeof(METAHEADER))
75 #define MFVERSION 0x300
77 /* ### start build ### */
78 extern WORD CALLBACK MF_CallTo16_word_wllwl(MFENUMPROC16,WORD,LONG,LONG,WORD,LONG);
79 /* ### stop build ### */
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, &hmf, NULL );
113 if (metaObj)
115 metaObj->mh = mh;
116 GDI_ReleaseObj( hmf );
118 return hmf;
121 /******************************************************************
122 * MF_Create_HMETATFILE16
124 * Creates a HMETAFILE16 object from a METAHEADER
126 * HMETAFILE16s are Global memory handles.
128 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
130 HMETAFILE16 hmf;
131 DWORD size = mh->mtSize * sizeof(WORD);
133 hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
134 if(hmf)
136 METAHEADER *mh_dest = GlobalLock16(hmf);
137 memcpy(mh_dest, mh, size);
138 GlobalUnlock16(hmf);
140 HeapFree(GetProcessHeap(), 0, mh);
141 return hmf;
144 /******************************************************************
145 * MF_GetMetaHeader
147 * Returns ptr to METAHEADER associated with HMETAFILE
149 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
151 METAHEADER *ret = NULL;
152 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
153 if (metaObj)
155 ret = metaObj->mh;
156 GDI_ReleaseObj( hmf );
158 return ret;
161 /******************************************************************
162 * MF_GetMetaHeader16
164 * Returns ptr to METAHEADER associated with HMETAFILE16
165 * Should be followed by call to MF_ReleaseMetaHeader16
167 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
169 return GlobalLock16(hmf);
172 /******************************************************************
173 * MF_ReleaseMetaHeader16
175 * Releases METAHEADER associated with HMETAFILE16
177 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
179 return GlobalUnlock16( hmf );
183 /******************************************************************
184 * convert_points
186 * Convert an array of POINT16 to an array of POINT.
187 * Result must be freed by caller.
189 static POINT *convert_points( UINT count, POINT16 *pt16 )
191 UINT i;
192 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
193 if (ret)
195 for (i = 0; i < count; i++)
197 ret[i].x = pt16[i].x;
198 ret[i].y = pt16[i].y;
201 return ret;
205 /******************************************************************
206 * DeleteMetaFile (GDI.127)
208 BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
210 return !GlobalFree16( hmf );
213 /******************************************************************
214 * DeleteMetaFile (GDI32.@)
216 * Delete a memory-based metafile.
219 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
221 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
222 if (!metaObj) return FALSE;
223 HeapFree( GetProcessHeap(), 0, metaObj->mh );
224 GDI_FreeObject( hmf, metaObj );
225 return TRUE;
228 /******************************************************************
229 * MF_ReadMetaFile
231 * Returns a pointer to a memory based METAHEADER read in from file HFILE
234 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
236 METAHEADER *mh;
237 DWORD BytesRead, size;
239 size = sizeof(METAHEADER);
240 mh = HeapAlloc( GetProcessHeap(), 0, size );
241 if(!mh) return NULL;
242 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
243 BytesRead != size) {
244 HeapFree( GetProcessHeap(), 0, mh );
245 return NULL;
247 size = mh->mtSize * 2;
248 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
249 if(!mh) return NULL;
250 size -= sizeof(METAHEADER);
251 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
252 NULL) == 0 ||
253 BytesRead != size) {
254 HeapFree( GetProcessHeap(), 0, mh );
255 return NULL;
258 if (mh->mtType != METAFILE_MEMORY) {
259 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
260 mh->mtType = METAFILE_MEMORY;
262 return mh;
265 /******************************************************************
266 * GetMetaFile (GDI.124)
268 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
270 METAHEADER *mh;
271 HANDLE hFile;
273 TRACE("%s\n", lpFilename);
275 if(!lpFilename)
276 return 0;
278 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
279 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
280 return 0;
282 mh = MF_ReadMetaFile(hFile);
283 CloseHandle(hFile);
284 if(!mh) return 0;
285 return MF_Create_HMETAFILE16( mh );
288 /******************************************************************
289 * GetMetaFileA (GDI32.@)
291 * Read a metafile from a file. Returns handle to a memory-based metafile.
293 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
295 METAHEADER *mh;
296 HANDLE hFile;
298 TRACE("%s\n", lpFilename);
300 if(!lpFilename)
301 return 0;
303 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
304 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
305 return 0;
307 mh = MF_ReadMetaFile(hFile);
308 CloseHandle(hFile);
309 if(!mh) return 0;
310 return MF_Create_HMETAFILE( mh );
315 /******************************************************************
316 * GetMetaFileW (GDI32.@)
318 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
320 METAHEADER *mh;
321 HANDLE hFile;
323 TRACE("%s\n", debugstr_w(lpFilename));
325 if(!lpFilename)
326 return 0;
328 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
329 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
330 return 0;
332 mh = MF_ReadMetaFile(hFile);
333 CloseHandle(hFile);
334 if(!mh) return 0;
335 return MF_Create_HMETAFILE( mh );
339 /******************************************************************
340 * MF_LoadDiskBasedMetaFile
342 * Creates a new memory-based metafile from a disk-based one.
344 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
346 METAHEADERDISK *mhd;
347 HANDLE hfile;
348 METAHEADER *mh2;
350 if(mh->mtType != METAFILE_DISK) {
351 ERR("Not a disk based metafile\n");
352 return NULL;
354 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
356 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
357 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
358 WARN("Can't open file of disk based metafile\n");
359 return NULL;
361 mh2 = MF_ReadMetaFile(hfile);
362 CloseHandle(hfile);
363 return mh2;
366 /******************************************************************
367 * MF_CreateMetaHeaderDisk
369 * Take a memory based METAHEADER and change it to a disk based METAHEADER
370 * assosiated with filename. Note: Trashes contents of old one.
372 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
374 METAHEADERDISK *mhd;
375 DWORD size;
377 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
378 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
379 mh->mtType = METAFILE_DISK;
380 size = HeapSize( GetProcessHeap(), 0, mh );
381 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
382 strcpy(mhd->filename, filename);
383 return mh;
386 /******************************************************************
387 * CopyMetaFile (GDI.151)
389 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
391 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
392 METAHEADER *mh2 = NULL;
393 HANDLE hFile;
395 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
397 if(!mh) return 0;
399 if(mh->mtType == METAFILE_DISK)
400 mh2 = MF_LoadDiskBasedMetaFile(mh);
401 else {
402 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
403 memcpy( mh2, mh, mh->mtSize * 2 );
405 MF_ReleaseMetaHeader16( hSrcMetaFile );
407 if(lpFilename) { /* disk based metafile */
408 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
409 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
410 HeapFree( GetProcessHeap(), 0, mh2 );
411 return 0;
413 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
414 CloseHandle(hFile);
415 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
418 return MF_Create_HMETAFILE16( mh2 );
422 /******************************************************************
423 * CopyMetaFileA (GDI32.@)
425 * Copies the metafile corresponding to hSrcMetaFile to either
426 * a disk file, if a filename is given, or to a new memory based
427 * metafile, if lpFileName is NULL.
429 * RETURNS
431 * Handle to metafile copy on success, NULL on failure.
433 * BUGS
435 * Copying to disk returns NULL even if successful.
437 HMETAFILE WINAPI CopyMetaFileA(
438 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
439 LPCSTR lpFilename /* [in] filename if copying to a file */
441 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
442 METAHEADER *mh2 = NULL;
443 HANDLE hFile;
445 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
447 if(!mh) return 0;
449 if(mh->mtType == METAFILE_DISK)
450 mh2 = MF_LoadDiskBasedMetaFile(mh);
451 else {
452 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
453 memcpy( mh2, mh, mh->mtSize * 2 );
456 if(lpFilename) { /* disk based metafile */
457 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
458 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
459 HeapFree( GetProcessHeap(), 0, mh2 );
460 return 0;
462 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
463 CloseHandle(hFile);
464 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
467 return MF_Create_HMETAFILE( mh2 );
471 /******************************************************************
472 * CopyMetaFileW (GDI32.@)
474 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile,
475 LPCWSTR lpFilename )
477 HMETAFILE ret = 0;
478 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, NULL, 0, NULL, NULL );
479 LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
481 if (p)
483 WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, p, len, NULL, NULL );
484 ret = CopyMetaFileA( hSrcMetaFile, p );
485 HeapFree( GetProcessHeap(), 0, p );
487 return ret;
491 /******************************************************************
492 * IsValidMetaFile (GDI.410)
494 * Attempts to check if a given metafile is correctly formatted.
495 * Currently, the only things verified are several properties of the
496 * header.
498 * RETURNS
499 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
501 * BUGS
502 * This is not exactly what windows does, see _Undocumented_Windows_
503 * for details.
505 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
507 BOOL16 res=FALSE;
508 METAHEADER *mh = MF_GetMetaHeader16(hmf);
509 if (mh) {
510 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
511 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
512 if (mh->mtVersion == MFVERSION)
513 res=TRUE;
514 MF_ReleaseMetaHeader16(hmf);
516 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
517 return res;
521 /*******************************************************************
522 * MF_PlayMetaFile
524 * Helper for PlayMetaFile
526 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
529 METARECORD *mr;
530 HANDLETABLE *ht;
531 unsigned int offset = 0;
532 WORD i;
533 HPEN hPen;
534 HBRUSH hBrush;
535 HFONT hFont;
536 BOOL loaded = FALSE;
538 if (!mh) return FALSE;
539 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
540 mh = MF_LoadDiskBasedMetaFile(mh);
541 if(!mh) return FALSE;
542 loaded = TRUE;
545 /* save the current pen, brush and font */
546 hPen = GetCurrentObject(hdc, OBJ_PEN);
547 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
548 hFont = GetCurrentObject(hdc, OBJ_FONT);
550 /* create the handle table */
551 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
552 sizeof(HANDLETABLE) * mh->mtNoObjects);
553 if(!ht) return FALSE;
555 /* loop through metafile playing records */
556 offset = mh->mtHeaderSize * 2;
557 while (offset < mh->mtSize * 2)
559 mr = (METARECORD *)((char *)mh + offset);
560 TRACE("offset=%04x,size=%08lx\n",
561 offset, mr->rdSize);
562 if (!mr->rdSize) {
563 TRACE(
564 "Entry got size 0 at offset %d, total mf length is %ld\n",
565 offset,mh->mtSize*2);
566 break; /* would loop endlessly otherwise */
568 offset += mr->rdSize * 2;
569 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
572 SelectObject(hdc, hBrush);
573 SelectObject(hdc, hPen);
574 SelectObject(hdc, hFont);
576 /* free objects in handle table */
577 for(i = 0; i < mh->mtNoObjects; i++)
578 if(*(ht->objectHandle + i) != 0)
579 DeleteObject(*(ht->objectHandle + i));
581 /* free handle table */
582 HeapFree( GetProcessHeap(), 0, ht );
583 if(loaded)
584 HeapFree( GetProcessHeap(), 0, mh );
585 return TRUE;
588 /******************************************************************
589 * PlayMetaFile (GDI.123)
592 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
594 BOOL16 ret;
595 METAHEADER *mh = MF_GetMetaHeader16( hmf );
596 ret = MF_PlayMetaFile( hdc, mh );
597 MF_ReleaseMetaHeader16( hmf );
598 return ret;
601 /******************************************************************
602 * PlayMetaFile (GDI32.@)
604 * Renders the metafile specified by hmf in the DC specified by
605 * hdc. Returns FALSE on failure, TRUE on success.
607 BOOL WINAPI PlayMetaFile(
608 HDC hdc, /* [in] handle of DC to render in */
609 HMETAFILE hmf /* [in] handle of metafile to render */
612 METAHEADER *mh = MF_GetMetaHeader( hmf );
613 return MF_PlayMetaFile( hdc, mh );
617 /******************************************************************
618 * EnumMetaFile (GDI.175)
621 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
622 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
624 METAHEADER *mh = MF_GetMetaHeader16(hmf);
625 METARECORD *mr;
626 HANDLETABLE16 *ht;
627 HGLOBAL16 hHT;
628 SEGPTR spht;
629 unsigned int offset = 0;
630 WORD i, seg;
631 HPEN hPen;
632 HBRUSH hBrush;
633 HFONT hFont;
634 BOOL16 result = TRUE, loaded = FALSE;
636 TRACE("(%04x, %04x, %08lx, %08lx)\n",
637 hdc, hmf, (DWORD)lpEnumFunc, lpData);
640 if(!mh) return FALSE;
641 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
642 mh = MF_LoadDiskBasedMetaFile(mh);
643 if(!mh) return FALSE;
644 loaded = TRUE;
647 /* save the current pen, brush and font */
648 hPen = GetCurrentObject(hdc, OBJ_PEN);
649 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
650 hFont = GetCurrentObject(hdc, OBJ_FONT);
652 /* create the handle table */
654 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
655 sizeof(HANDLETABLE16) * mh->mtNoObjects);
656 spht = K32WOWGlobalLock16(hHT);
658 seg = hmf | 7;
659 offset = mh->mtHeaderSize * 2;
661 /* loop through metafile records */
663 while (offset < (mh->mtSize * 2))
665 mr = (METARECORD *)((char *)mh + offset);
667 if (!MF_CallTo16_word_wllwl( lpEnumFunc, hdc, spht,
668 MAKESEGPTR( seg + (HIWORD(offset) << __AHSHIFT), LOWORD(offset) ),
669 mh->mtNoObjects, (LONG)lpData ))
671 result = FALSE;
672 break;
676 offset += (mr->rdSize * 2);
679 SelectObject(hdc, hBrush);
680 SelectObject(hdc, hPen);
681 SelectObject(hdc, hFont);
683 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
685 /* free objects in handle table */
686 for(i = 0; i < mh->mtNoObjects; i++)
687 if(*(ht->objectHandle + i) != 0)
688 DeleteObject(*(ht->objectHandle + i));
690 /* free handle table */
691 GlobalFree16(hHT);
692 if(loaded)
693 HeapFree( GetProcessHeap(), 0, mh );
694 MF_ReleaseMetaHeader16(hmf);
695 return result;
698 /******************************************************************
699 * EnumMetaFile (GDI32.@)
701 * Loop through the metafile records in hmf, calling the user-specified
702 * function for each one, stopping when the user's function returns FALSE
703 * (which is considered to be failure)
704 * or when no records are left (which is considered to be success).
706 * RETURNS
707 * TRUE on success, FALSE on failure.
709 * HISTORY
710 * Niels de carpentier, april 1996
712 BOOL WINAPI EnumMetaFile(
713 HDC hdc,
714 HMETAFILE hmf,
715 MFENUMPROC lpEnumFunc,
716 LPARAM lpData
718 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
719 METARECORD *mr;
720 HANDLETABLE *ht;
721 BOOL result = TRUE;
722 int i;
723 unsigned int offset = 0;
724 HPEN hPen;
725 HBRUSH hBrush;
726 HFONT hFont;
728 TRACE("(%08x,%08x,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
729 if (!mh) return 0;
730 if(mh->mtType == METAFILE_DISK)
732 /* Create a memory-based copy */
733 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
734 mh = mhTemp;
737 /* save the current pen, brush and font */
738 hPen = GetCurrentObject(hdc, OBJ_PEN);
739 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
740 hFont = GetCurrentObject(hdc, OBJ_FONT);
742 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
743 sizeof(HANDLETABLE) * mh->mtNoObjects);
745 /* loop through metafile records */
746 offset = mh->mtHeaderSize * 2;
748 while (offset < (mh->mtSize * 2))
750 mr = (METARECORD *)((char *)mh + offset);
751 if(mr->rdFunction == META_EOF) {
752 TRACE("Got META_EOF so stopping\n");
753 break;
755 TRACE("Calling EnumFunc with record type %x\n",
756 mr->rdFunction);
757 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
759 result = FALSE;
760 break;
763 offset += (mr->rdSize * 2);
766 /* restore pen, brush and font */
767 SelectObject(hdc, hBrush);
768 SelectObject(hdc, hPen);
769 SelectObject(hdc, hFont);
771 /* free objects in handle table */
772 for(i = 0; i < mh->mtNoObjects; i++)
773 if(*(ht->objectHandle + i) != 0)
774 DeleteObject(*(ht->objectHandle + i));
776 /* free handle table */
777 HeapFree( GetProcessHeap(), 0, ht);
778 /* free a copy of metafile */
779 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
780 return result;
783 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
784 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
785 /******************************************************************
786 * PlayMetaFileRecord (GDI32.@)
788 * Render a single metafile record specified by *mr in the DC hdc, while
789 * using the handle table *ht, of length handles,
790 * to store metafile objects.
792 * BUGS
793 * The following metafile records are unimplemented:
795 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
796 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
797 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
799 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
801 short s1;
802 POINT *pt;
803 BITMAPINFOHEADER *infohdr;
805 TRACE("(%04x %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
807 switch (mr->rdFunction)
809 case META_EOF:
810 break;
812 case META_DELETEOBJECT:
813 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
814 *(ht->objectHandle + mr->rdParm[0]) = 0;
815 break;
817 case META_SETBKCOLOR:
818 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
819 break;
821 case META_SETBKMODE:
822 SetBkMode(hdc, mr->rdParm[0]);
823 break;
825 case META_SETMAPMODE:
826 SetMapMode(hdc, mr->rdParm[0]);
827 break;
829 case META_SETROP2:
830 SetROP2(hdc, mr->rdParm[0]);
831 break;
833 case META_SETRELABS:
834 SetRelAbs(hdc, mr->rdParm[0]);
835 break;
837 case META_SETPOLYFILLMODE:
838 SetPolyFillMode(hdc, mr->rdParm[0]);
839 break;
841 case META_SETSTRETCHBLTMODE:
842 SetStretchBltMode(hdc, mr->rdParm[0]);
843 break;
845 case META_SETTEXTCOLOR:
846 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
847 break;
849 case META_SETWINDOWORG:
850 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
851 break;
853 case META_SETWINDOWEXT:
854 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
855 break;
857 case META_SETVIEWPORTORG:
858 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
859 break;
861 case META_SETVIEWPORTEXT:
862 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
863 break;
865 case META_OFFSETWINDOWORG:
866 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
867 break;
869 case META_SCALEWINDOWEXT:
870 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
871 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
872 break;
874 case META_OFFSETVIEWPORTORG:
875 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
876 break;
878 case META_SCALEVIEWPORTEXT:
879 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
880 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
881 break;
883 case META_LINETO:
884 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
885 break;
887 case META_MOVETO:
888 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
889 break;
891 case META_EXCLUDECLIPRECT:
892 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
893 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
894 break;
896 case META_INTERSECTCLIPRECT:
897 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
898 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
899 break;
901 case META_ARC:
902 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
903 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
904 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
905 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
906 break;
908 case META_ELLIPSE:
909 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
910 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
911 break;
913 case META_FLOODFILL:
914 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
915 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
916 break;
918 case META_PIE:
919 Pie(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_RECTANGLE:
926 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
927 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
928 break;
930 case META_ROUNDRECT:
931 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
932 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
933 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
934 break;
936 case META_PATBLT:
937 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
938 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
939 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
940 break;
942 case META_SAVEDC:
943 SaveDC(hdc);
944 break;
946 case META_SETPIXEL:
947 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
948 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
949 break;
951 case META_OFFSETCLIPRGN:
952 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
953 break;
955 case META_TEXTOUT:
956 s1 = mr->rdParm[0];
957 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
958 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
959 (char *)(mr->rdParm + 1), s1);
960 break;
962 case META_POLYGON:
963 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
965 Polygon(hdc, pt, mr->rdParm[0]);
966 HeapFree( GetProcessHeap(), 0, pt );
968 break;
970 case META_POLYPOLYGON:
972 UINT i, total;
973 SHORT *counts = (SHORT *)(mr->rdParm + 1);
975 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
976 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
977 if (pt)
979 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
980 if (cnt32)
982 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
983 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
984 HeapFree( GetProcessHeap(), 0, cnt32 );
987 HeapFree( GetProcessHeap(), 0, pt );
989 break;
991 case META_POLYLINE:
992 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
994 Polyline( hdc, pt, mr->rdParm[0] );
995 HeapFree( GetProcessHeap(), 0, pt );
997 break;
999 case META_RESTOREDC:
1000 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1001 break;
1003 case META_SELECTOBJECT:
1004 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1005 break;
1007 case META_CHORD:
1008 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1009 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1010 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1011 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1012 break;
1014 case META_CREATEPATTERNBRUSH:
1015 switch (mr->rdParm[0])
1017 case BS_PATTERN:
1018 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1019 MF_AddHandle(ht, handles,
1020 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1021 infohdr->biHeight,
1022 infohdr->biPlanes,
1023 infohdr->biBitCount,
1024 (LPSTR)(mr->rdParm +
1025 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1026 break;
1028 case BS_DIBPATTERN:
1029 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1030 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1031 break;
1033 default:
1034 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1035 mr->rdParm[0]);
1036 break;
1038 break;
1040 case META_CREATEPENINDIRECT:
1042 LOGPEN pen;
1043 pen.lopnStyle = mr->rdParm[0];
1044 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1045 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1046 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1047 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1049 break;
1051 case META_CREATEFONTINDIRECT:
1053 LOGFONTA font;
1054 font.lfHeight = (SHORT)mr->rdParm[0];
1055 font.lfWidth = (SHORT)mr->rdParm[1];
1056 font.lfEscapement = (SHORT)mr->rdParm[2];
1057 font.lfOrientation = (SHORT)mr->rdParm[3];
1058 font.lfWeight = (SHORT)mr->rdParm[4];
1059 font.lfItalic = LOBYTE(mr->rdParm[5]);
1060 font.lfUnderline = HIBYTE(mr->rdParm[5]);
1061 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
1062 font.lfCharSet = HIBYTE(mr->rdParm[6]);
1063 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
1064 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
1065 font.lfQuality = LOBYTE(mr->rdParm[8]);
1066 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1067 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1068 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1070 break;
1072 case META_CREATEBRUSHINDIRECT:
1074 LOGBRUSH brush;
1075 brush.lbStyle = mr->rdParm[0];
1076 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1077 brush.lbHatch = mr->rdParm[3];
1078 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1080 break;
1082 case META_CREATEPALETTE:
1083 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1084 break;
1086 case META_SETTEXTALIGN:
1087 SetTextAlign(hdc, mr->rdParm[0]);
1088 break;
1090 case META_SELECTPALETTE:
1091 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1092 break;
1094 case META_SETMAPPERFLAGS:
1095 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1096 break;
1098 case META_REALIZEPALETTE:
1099 GDIRealizePalette(hdc);
1100 break;
1102 case META_ESCAPE:
1103 FIXME("META_ESCAPE unimplemented.\n");
1104 break;
1106 case META_EXTTEXTOUT:
1107 MF_Play_MetaExtTextOut( hdc, mr );
1108 break;
1110 case META_STRETCHDIB:
1112 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1113 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1114 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1115 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1116 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1117 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1119 break;
1121 case META_DIBSTRETCHBLT:
1123 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1124 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1125 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1126 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1127 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1128 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1130 break;
1132 case META_STRETCHBLT:
1134 HDC hdcSrc = CreateCompatibleDC(hdc);
1135 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1136 mr->rdParm[11], /*Height*/
1137 mr->rdParm[13], /*Planes*/
1138 mr->rdParm[14], /*BitsPixel*/
1139 (LPSTR)&mr->rdParm[15]); /*bits*/
1140 SelectObject(hdcSrc,hbitmap);
1141 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1142 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1143 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1144 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1145 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1146 DeleteDC(hdcSrc);
1148 break;
1150 case META_BITBLT:
1152 HDC hdcSrc = CreateCompatibleDC(hdc);
1153 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1154 mr->rdParm[8]/*Height*/,
1155 mr->rdParm[10]/*Planes*/,
1156 mr->rdParm[11]/*BitsPixel*/,
1157 (LPSTR)&mr->rdParm[12]/*bits*/);
1158 SelectObject(hdcSrc,hbitmap);
1159 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1160 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1161 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1162 MAKELONG(0,mr->rdParm[0]));
1163 DeleteDC(hdcSrc);
1165 break;
1167 case META_CREATEREGION:
1169 HRGN hrgn = CreateRectRgn(0,0,0,0);
1171 MF_Play_MetaCreateRegion(mr, hrgn);
1172 MF_AddHandle(ht, handles, hrgn);
1174 break;
1176 case META_FILLREGION:
1177 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1178 *(ht->objectHandle + mr->rdParm[0]));
1179 break;
1181 case META_FRAMEREGION:
1182 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1183 *(ht->objectHandle + mr->rdParm[2]),
1184 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1185 break;
1187 case META_INVERTREGION:
1188 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1189 break;
1191 case META_PAINTREGION:
1192 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1193 break;
1195 case META_SELECTCLIPREGION:
1196 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1197 break;
1199 case META_DIBCREATEPATTERNBRUSH:
1200 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1201 but there's no difference */
1202 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1203 break;
1205 case META_DIBBITBLT:
1206 /* In practice I've found that there are two layouts for
1207 META_DIBBITBLT, one (the first here) is the usual one when a src
1208 dc is actually passed to it, the second occurs when the src dc is
1209 passed in as NULL to the creating BitBlt. As the second case has
1210 no dib, a size check will suffice to distinguish.
1212 Caolan.McNamara@ul.ie */
1214 if (mr->rdSize > 12) {
1215 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1216 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1218 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1219 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1220 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1221 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1223 else /* equivalent to a PatBlt */
1224 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1225 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1226 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1227 break;
1229 case META_SETTEXTCHAREXTRA:
1230 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1231 break;
1233 case META_SETTEXTJUSTIFICATION:
1234 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1235 break;
1237 case META_EXTFLOODFILL:
1238 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1239 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1240 mr->rdParm[0]);
1241 break;
1243 case META_SETDIBTODEV:
1245 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1246 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1247 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1248 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1249 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1250 mr->rdParm[2], mr->rdParm[1], bits, info,
1251 mr->rdParm[0]);
1252 break;
1255 #define META_UNIMP(x) case x: \
1256 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1257 break;
1258 META_UNIMP(META_DRAWTEXT)
1259 META_UNIMP(META_ANIMATEPALETTE)
1260 META_UNIMP(META_SETPALENTRIES)
1261 META_UNIMP(META_RESIZEPALETTE)
1262 META_UNIMP(META_RESETDC)
1263 META_UNIMP(META_STARTDOC)
1264 META_UNIMP(META_STARTPAGE)
1265 META_UNIMP(META_ENDPAGE)
1266 META_UNIMP(META_ABORTDOC)
1267 META_UNIMP(META_ENDDOC)
1268 META_UNIMP(META_CREATEBRUSH)
1269 META_UNIMP(META_CREATEBITMAPINDIRECT)
1270 META_UNIMP(META_CREATEBITMAP)
1271 #undef META_UNIMP
1273 default:
1274 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1275 return FALSE;
1277 return TRUE;
1280 /******************************************************************
1281 * GetMetaFileBits (GDI.159)
1283 * Trade in a metafile object handle for a handle to the metafile memory.
1287 HGLOBAL16 WINAPI GetMetaFileBits16(
1288 HMETAFILE16 hmf /* [in] metafile handle */
1291 TRACE("hMem out: %04x\n", hmf);
1292 return hmf;
1295 /******************************************************************
1296 * SetMetaFileBits (GDI.160)
1298 * Trade in a metafile memory handle for a handle to a metafile object.
1299 * The memory region should hold a proper metafile, otherwise
1300 * problems will occur when it is used. Validity of the memory is not
1301 * checked. The function is essentially just the identity function.
1303 HMETAFILE16 WINAPI SetMetaFileBits16(
1304 HGLOBAL16 hMem
1305 /* [in] handle to a memory region holding a metafile */
1308 TRACE("hmf out: %04x\n", hMem);
1310 return hMem;
1313 /******************************************************************
1314 * SetMetaFileBitsBetter (GDI.196)
1316 * Trade in a metafile memory handle for a handle to a metafile object,
1317 * making a cursory check (using IsValidMetaFile()) that the memory
1318 * handle points to a valid metafile.
1320 * RETURNS
1321 * Handle to a metafile on success, NULL on failure..
1323 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1325 if( IsValidMetaFile16( hMeta ) )
1326 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1327 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1328 return (HMETAFILE16)0;
1331 /******************************************************************
1332 * SetMetaFileBitsEx (GDI32.@)
1334 * Create a metafile from raw data. No checking of the data is performed.
1335 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1337 HMETAFILE WINAPI SetMetaFileBitsEx(
1338 UINT size, /* [in] size of metafile, in bytes */
1339 const BYTE *lpData /* [in] pointer to metafile data */
1342 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1343 if (!mh) return 0;
1344 memcpy(mh, lpData, size);
1345 return MF_Create_HMETAFILE(mh);
1348 /*****************************************************************
1349 * GetMetaFileBitsEx (GDI32.@) Get raw metafile data
1351 * Copies the data from metafile _hmf_ into the buffer _buf_.
1352 * If _buf_ is zero, returns size of buffer required. Otherwise,
1353 * returns number of bytes copied.
1355 UINT WINAPI GetMetaFileBitsEx(
1356 HMETAFILE hmf, /* [in] metafile */
1357 UINT nSize, /* [in] size of buf */
1358 LPVOID buf /* [out] buffer to receive raw metafile data */
1360 METAHEADER *mh = MF_GetMetaHeader(hmf);
1361 UINT mfSize;
1363 TRACE("(%08x,%d,%p)\n", hmf, nSize, buf);
1364 if (!mh) return 0; /* FIXME: error code */
1365 if(mh->mtType == METAFILE_DISK)
1366 FIXME("Disk-based metafile?\n");
1367 mfSize = mh->mtSize * 2;
1368 if (!buf) {
1369 TRACE("returning size %d\n", mfSize);
1370 return mfSize;
1372 if(mfSize > nSize) mfSize = nSize;
1373 memmove(buf, mh, mfSize);
1374 return mfSize;
1377 /******************************************************************
1378 * GetWinMetaFileBits [GDI32.@]
1380 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1381 UINT cbBuffer, LPBYTE lpbBuffer,
1382 INT fnMapMode, HDC hdcRef)
1384 HDC hdcmf;
1385 HMETAFILE hmf;
1386 UINT ret;
1388 FIXME("(%d,%d,%p,%d,%d): stub\n",
1389 hemf, cbBuffer, lpbBuffer, fnMapMode, hdcRef);
1390 hdcmf = CreateMetaFileA(NULL);
1391 /* PlayEnhMetaFile(hdcmf, hemf, lpRect); where does the bounding rect come from? */
1392 hmf = CloseMetaFile(hdcmf);
1393 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1394 DeleteMetaFile(hmf);
1395 return ret;
1398 /******************************************************************
1399 * MF_Play_MetaCreateRegion
1401 * Handles META_CREATEREGION for PlayMetaFileRecord().
1405 * The layout of the record looks something like this:
1407 * rdParm meaning
1408 * 0 Always 0?
1409 * 1 Always 6?
1410 * 2 Looks like a handle? - not constant
1411 * 3 0 or 1 ??
1412 * 4 Total number of bytes
1413 * 5 No. of separate bands = n [see below]
1414 * 6 Largest number of x co-ords in a band
1415 * 7-10 Bounding box x1 y1 x2 y2
1416 * 11-... n bands
1418 * Regions are divided into bands that are uniform in the
1419 * y-direction. Each band consists of pairs of on/off x-coords and is
1420 * written as
1421 * m y0 y1 x1 x2 x3 ... xm m
1422 * into successive rdParm[]s.
1424 * This is probably just a dump of the internal RGNOBJ?
1426 * HDMD - 18/12/97
1430 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1432 WORD band, pair;
1433 WORD *start, *end;
1434 INT16 y0, y1;
1435 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1437 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1438 band++, start = end + 1) {
1439 if(*start / 2 != (*start + 1) / 2) {
1440 WARN("Delimiter not even.\n");
1441 DeleteObject( hrgn2 );
1442 return FALSE;
1445 end = start + *start + 3;
1446 if(end > (WORD *)mr + mr->rdSize) {
1447 WARN("End points outside record.\n");
1448 DeleteObject( hrgn2 );
1449 return FALSE;
1452 if(*start != *end) {
1453 WARN("Mismatched delimiters.\n");
1454 DeleteObject( hrgn2 );
1455 return FALSE;
1458 y0 = *(INT16 *)(start + 1);
1459 y1 = *(INT16 *)(start + 2);
1460 for(pair = 0; pair < *start / 2; pair++) {
1461 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1462 *(INT16 *)(start + 4 + 2*pair), y1 );
1463 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1466 DeleteObject( hrgn2 );
1467 return TRUE;
1471 /******************************************************************
1472 * MF_Play_MetaExtTextOut
1474 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1477 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1479 INT *dx = NULL;
1480 int i;
1481 LPINT16 dxx;
1482 LPSTR sot;
1483 DWORD len;
1484 WORD s1;
1485 RECT rect;
1486 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1488 s1 = mr->rdParm[2]; /* String length */
1489 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1490 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1491 /* rec len without dx array */
1493 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1494 if (isrect)
1496 rect.left = (SHORT)mr->rdParm[4];
1497 rect.top = (SHORT)mr->rdParm[5];
1498 rect.right = (SHORT)mr->rdParm[6];
1499 rect.bottom = (SHORT)mr->rdParm[7];
1500 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1503 if (mr->rdSize == len / 2)
1504 dxx = NULL; /* determine if array present */
1505 else
1506 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1508 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1509 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1510 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1512 else {
1513 TRACE("%s len: %ld\n", sot, mr->rdSize);
1514 WARN(
1515 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1516 len, s1, mr->rdSize, mr->rdParm[3]);
1517 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1519 ExtTextOutA( hdc,
1520 (SHORT)mr->rdParm[1], /* X position */
1521 (SHORT)mr->rdParm[0], /* Y position */
1522 mr->rdParm[3], /* options */
1523 &rect, /* rectangle */
1524 sot, /* string */
1525 s1, dx); /* length, dx array */
1526 if (dx)
1528 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1529 HeapFree( GetProcessHeap(), 0, dx );
1531 return TRUE;