Fixed a reference counting bug I introduced.
[wine/wine-kai.git] / objects / metafile.c
blob5ed4e20afef9714cb1fd497d9b129086908e6fd8
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 "wownt32.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
60 #include "pshpack1.h"
61 typedef struct
63 DWORD dw1, dw2, dw3;
64 WORD w4;
65 CHAR filename[0x100];
66 } METAHEADERDISK;
67 #include "poppack.h"
69 typedef struct
71 GDIOBJHDR header;
72 METAHEADER *mh;
73 } METAFILEOBJ;
75 #define MFHEADERSIZE (sizeof(METAHEADER))
76 #define MFVERSION 0x300
79 /******************************************************************
80 * MF_AddHandle
82 * Add a handle to an external handle table and return the index
84 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
86 int i;
88 for (i = 0; i < htlen; i++)
90 if (*(ht->objectHandle + i) == 0)
92 *(ht->objectHandle + i) = hobj;
93 return i;
96 return -1;
100 /******************************************************************
101 * MF_Create_HMETATFILE
103 * Creates a (32 bit) HMETAFILE object from a METAHEADER
105 * HMETAFILEs are GDI objects.
107 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
109 HMETAFILE hmf = 0;
110 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
111 (HGDIOBJ *)&hmf, NULL );
112 if (metaObj)
114 metaObj->mh = mh;
115 GDI_ReleaseObj( hmf );
117 return hmf;
120 /******************************************************************
121 * MF_Create_HMETATFILE16
123 * Creates a HMETAFILE16 object from a METAHEADER
125 * HMETAFILE16s are Global memory handles.
127 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
129 HMETAFILE16 hmf;
130 DWORD size = mh->mtSize * sizeof(WORD);
132 hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
133 if(hmf)
135 METAHEADER *mh_dest = GlobalLock16(hmf);
136 memcpy(mh_dest, mh, size);
137 GlobalUnlock16(hmf);
139 HeapFree(GetProcessHeap(), 0, mh);
140 return hmf;
143 /******************************************************************
144 * MF_GetMetaHeader
146 * Returns ptr to METAHEADER associated with HMETAFILE
148 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
150 METAHEADER *ret = NULL;
151 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
152 if (metaObj)
154 ret = metaObj->mh;
155 GDI_ReleaseObj( hmf );
157 return ret;
160 /******************************************************************
161 * MF_GetMetaHeader16
163 * Returns ptr to METAHEADER associated with HMETAFILE16
164 * Should be followed by call to MF_ReleaseMetaHeader16
166 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
168 return GlobalLock16(hmf);
171 /******************************************************************
172 * MF_ReleaseMetaHeader16
174 * Releases METAHEADER associated with HMETAFILE16
176 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
178 return GlobalUnlock16( hmf );
182 /******************************************************************
183 * convert_points
185 * Convert an array of POINT16 to an array of POINT.
186 * Result must be freed by caller.
188 static POINT *convert_points( UINT count, POINT16 *pt16 )
190 UINT i;
191 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
192 if (ret)
194 for (i = 0; i < count; i++)
196 ret[i].x = pt16[i].x;
197 ret[i].y = pt16[i].y;
200 return ret;
204 /******************************************************************
205 * DeleteMetaFile (GDI.127)
207 BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
209 return !GlobalFree16( hmf );
212 /******************************************************************
213 * DeleteMetaFile (GDI32.@)
215 * Delete a memory-based metafile.
218 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
220 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
221 if (!metaObj) return FALSE;
222 HeapFree( GetProcessHeap(), 0, metaObj->mh );
223 GDI_FreeObject( hmf, metaObj );
224 return TRUE;
227 /******************************************************************
228 * MF_ReadMetaFile
230 * Returns a pointer to a memory based METAHEADER read in from file HFILE
233 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
235 METAHEADER *mh;
236 DWORD BytesRead, size;
238 size = sizeof(METAHEADER);
239 mh = HeapAlloc( GetProcessHeap(), 0, size );
240 if(!mh) return NULL;
241 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
242 BytesRead != size) {
243 HeapFree( GetProcessHeap(), 0, mh );
244 return NULL;
246 size = mh->mtSize * 2;
247 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
248 if(!mh) return NULL;
249 size -= sizeof(METAHEADER);
250 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
251 NULL) == 0 ||
252 BytesRead != size) {
253 HeapFree( GetProcessHeap(), 0, mh );
254 return NULL;
257 if (mh->mtType != METAFILE_MEMORY) {
258 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
259 mh->mtType = METAFILE_MEMORY;
261 return mh;
264 /******************************************************************
265 * GetMetaFile (GDI.124)
267 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
269 METAHEADER *mh;
270 HANDLE hFile;
272 TRACE("%s\n", lpFilename);
274 if(!lpFilename)
275 return 0;
277 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
278 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
279 return 0;
281 mh = MF_ReadMetaFile(hFile);
282 CloseHandle(hFile);
283 if(!mh) return 0;
284 return MF_Create_HMETAFILE16( mh );
287 /******************************************************************
288 * GetMetaFileA (GDI32.@)
290 * Read a metafile from a file. Returns handle to a memory-based metafile.
292 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
294 METAHEADER *mh;
295 HANDLE hFile;
297 TRACE("%s\n", lpFilename);
299 if(!lpFilename)
300 return 0;
302 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
303 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
304 return 0;
306 mh = MF_ReadMetaFile(hFile);
307 CloseHandle(hFile);
308 if(!mh) return 0;
309 return MF_Create_HMETAFILE( mh );
314 /******************************************************************
315 * GetMetaFileW (GDI32.@)
317 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
319 METAHEADER *mh;
320 HANDLE hFile;
322 TRACE("%s\n", debugstr_w(lpFilename));
324 if(!lpFilename)
325 return 0;
327 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
328 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
329 return 0;
331 mh = MF_ReadMetaFile(hFile);
332 CloseHandle(hFile);
333 if(!mh) return 0;
334 return MF_Create_HMETAFILE( mh );
338 /******************************************************************
339 * MF_LoadDiskBasedMetaFile
341 * Creates a new memory-based metafile from a disk-based one.
343 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
345 METAHEADERDISK *mhd;
346 HANDLE hfile;
347 METAHEADER *mh2;
349 if(mh->mtType != METAFILE_DISK) {
350 ERR("Not a disk based metafile\n");
351 return NULL;
353 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
355 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
356 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
357 WARN("Can't open file of disk based metafile\n");
358 return NULL;
360 mh2 = MF_ReadMetaFile(hfile);
361 CloseHandle(hfile);
362 return mh2;
365 /******************************************************************
366 * MF_CreateMetaHeaderDisk
368 * Take a memory based METAHEADER and change it to a disk based METAHEADER
369 * assosiated with filename. Note: Trashes contents of old one.
371 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
373 METAHEADERDISK *mhd;
374 DWORD size;
376 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
377 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
378 mh->mtType = METAFILE_DISK;
379 size = HeapSize( GetProcessHeap(), 0, mh );
380 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
381 strcpy(mhd->filename, filename);
382 return mh;
385 /******************************************************************
386 * CopyMetaFile (GDI.151)
388 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
390 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
391 METAHEADER *mh2 = NULL;
392 HANDLE hFile;
394 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
396 if(!mh) return 0;
398 if(mh->mtType == METAFILE_DISK)
399 mh2 = MF_LoadDiskBasedMetaFile(mh);
400 else {
401 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
402 memcpy( mh2, mh, mh->mtSize * 2 );
404 MF_ReleaseMetaHeader16( hSrcMetaFile );
406 if(lpFilename) { /* disk based metafile */
407 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
408 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
409 HeapFree( GetProcessHeap(), 0, mh2 );
410 return 0;
412 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
413 CloseHandle(hFile);
414 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
417 return MF_Create_HMETAFILE16( mh2 );
421 /******************************************************************
422 * CopyMetaFileA (GDI32.@)
424 * Copies the metafile corresponding to hSrcMetaFile to either
425 * a disk file, if a filename is given, or to a new memory based
426 * metafile, if lpFileName is NULL.
428 * RETURNS
430 * Handle to metafile copy on success, NULL on failure.
432 * BUGS
434 * Copying to disk returns NULL even if successful.
436 HMETAFILE WINAPI CopyMetaFileA(
437 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
438 LPCSTR lpFilename /* [in] filename if copying to a file */
440 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
441 METAHEADER *mh2 = NULL;
442 HANDLE hFile;
444 TRACE("(%p,%s)\n", hSrcMetaFile, lpFilename);
446 if(!mh) return 0;
448 if(mh->mtType == METAFILE_DISK)
449 mh2 = MF_LoadDiskBasedMetaFile(mh);
450 else {
451 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
452 memcpy( mh2, mh, mh->mtSize * 2 );
455 if(lpFilename) { /* disk based metafile */
456 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
457 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
458 HeapFree( GetProcessHeap(), 0, mh2 );
459 return 0;
461 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
462 CloseHandle(hFile);
463 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
466 return MF_Create_HMETAFILE( mh2 );
470 /******************************************************************
471 * CopyMetaFileW (GDI32.@)
473 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile,
474 LPCWSTR lpFilename )
476 HMETAFILE ret = 0;
477 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, NULL, 0, NULL, NULL );
478 LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
480 if (p)
482 WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, p, len, NULL, NULL );
483 ret = CopyMetaFileA( hSrcMetaFile, p );
484 HeapFree( GetProcessHeap(), 0, p );
486 return ret;
490 /******************************************************************
491 * IsValidMetaFile (GDI.410)
493 * Attempts to check if a given metafile is correctly formatted.
494 * Currently, the only things verified are several properties of the
495 * header.
497 * RETURNS
498 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
500 * BUGS
501 * This is not exactly what windows does, see _Undocumented_Windows_
502 * for details.
504 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
506 BOOL16 res=FALSE;
507 METAHEADER *mh = MF_GetMetaHeader16(hmf);
508 if (mh) {
509 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
510 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
511 if (mh->mtVersion == MFVERSION)
512 res=TRUE;
513 MF_ReleaseMetaHeader16(hmf);
515 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
516 return res;
520 /*******************************************************************
521 * MF_PlayMetaFile
523 * Helper for PlayMetaFile
525 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
528 METARECORD *mr;
529 HANDLETABLE *ht;
530 unsigned int offset = 0;
531 WORD i;
532 HPEN hPen;
533 HBRUSH hBrush;
534 HFONT hFont;
535 BOOL loaded = FALSE;
537 if (!mh) return FALSE;
538 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
539 mh = MF_LoadDiskBasedMetaFile(mh);
540 if(!mh) return FALSE;
541 loaded = TRUE;
544 /* save the current pen, brush and font */
545 hPen = GetCurrentObject(hdc, OBJ_PEN);
546 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
547 hFont = GetCurrentObject(hdc, OBJ_FONT);
549 /* create the handle table */
550 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
551 sizeof(HANDLETABLE) * mh->mtNoObjects);
552 if(!ht) return FALSE;
554 /* loop through metafile playing records */
555 offset = mh->mtHeaderSize * 2;
556 while (offset < mh->mtSize * 2)
558 mr = (METARECORD *)((char *)mh + offset);
559 TRACE("offset=%04x,size=%08lx\n",
560 offset, mr->rdSize);
561 if (!mr->rdSize) {
562 TRACE(
563 "Entry got size 0 at offset %d, total mf length is %ld\n",
564 offset,mh->mtSize*2);
565 break; /* would loop endlessly otherwise */
567 offset += mr->rdSize * 2;
568 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
571 SelectObject(hdc, hBrush);
572 SelectObject(hdc, hPen);
573 SelectObject(hdc, hFont);
575 /* free objects in handle table */
576 for(i = 0; i < mh->mtNoObjects; i++)
577 if(*(ht->objectHandle + i) != 0)
578 DeleteObject(*(ht->objectHandle + i));
580 /* free handle table */
581 HeapFree( GetProcessHeap(), 0, ht );
582 if(loaded)
583 HeapFree( GetProcessHeap(), 0, mh );
584 return TRUE;
587 /******************************************************************
588 * PlayMetaFile (GDI.123)
591 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
593 BOOL16 ret;
594 METAHEADER *mh = MF_GetMetaHeader16( hmf );
595 ret = MF_PlayMetaFile( HDC_32(hdc), mh );
596 MF_ReleaseMetaHeader16( hmf );
597 return ret;
600 /******************************************************************
601 * PlayMetaFile (GDI32.@)
603 * Renders the metafile specified by hmf in the DC specified by
604 * hdc. Returns FALSE on failure, TRUE on success.
606 BOOL WINAPI PlayMetaFile(
607 HDC hdc, /* [in] handle of DC to render in */
608 HMETAFILE hmf /* [in] handle of metafile to render */
611 METAHEADER *mh = MF_GetMetaHeader( hmf );
612 return MF_PlayMetaFile( hdc, mh );
616 /******************************************************************
617 * EnumMetaFile (GDI.175)
620 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
621 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
623 METAHEADER *mh = MF_GetMetaHeader16(hmf);
624 METARECORD *mr;
625 HANDLETABLE16 *ht;
626 HDC hdc = HDC_32(hdc16);
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 WORD args[8];
635 BOOL16 result = TRUE, loaded = FALSE;
637 TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
639 if(!mh) return FALSE;
640 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
641 mh = MF_LoadDiskBasedMetaFile(mh);
642 if(!mh) return FALSE;
643 loaded = TRUE;
646 /* save the current pen, brush and font */
647 hPen = GetCurrentObject(hdc, OBJ_PEN);
648 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
649 hFont = GetCurrentObject(hdc, OBJ_FONT);
651 /* create the handle table */
653 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
654 sizeof(HANDLETABLE16) * mh->mtNoObjects);
655 spht = K32WOWGlobalLock16(hHT);
657 seg = hmf | 7;
658 offset = mh->mtHeaderSize * 2;
660 /* loop through metafile records */
662 args[7] = hdc16;
663 args[6] = SELECTOROF(spht);
664 args[5] = OFFSETOF(spht);
665 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
666 args[3] = LOWORD(offset);
667 args[2] = mh->mtNoObjects;
668 args[1] = HIWORD(lpData);
669 args[0] = LOWORD(lpData);
671 while (offset < (mh->mtSize * 2))
673 DWORD ret;
675 mr = (METARECORD *)((char *)mh + offset);
677 WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
678 if (!LOWORD(ret))
680 result = FALSE;
681 break;
684 offset += (mr->rdSize * 2);
685 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
686 args[3] = LOWORD(offset);
689 SelectObject(hdc, hBrush);
690 SelectObject(hdc, hPen);
691 SelectObject(hdc, hFont);
693 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
695 /* free objects in handle table */
696 for(i = 0; i < mh->mtNoObjects; i++)
697 if(*(ht->objectHandle + i) != 0)
698 DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
700 /* free handle table */
701 GlobalFree16(hHT);
702 if(loaded)
703 HeapFree( GetProcessHeap(), 0, mh );
704 MF_ReleaseMetaHeader16(hmf);
705 return result;
708 /******************************************************************
709 * EnumMetaFile (GDI32.@)
711 * Loop through the metafile records in hmf, calling the user-specified
712 * function for each one, stopping when the user's function returns FALSE
713 * (which is considered to be failure)
714 * or when no records are left (which is considered to be success).
716 * RETURNS
717 * TRUE on success, FALSE on failure.
719 * HISTORY
720 * Niels de carpentier, april 1996
722 BOOL WINAPI EnumMetaFile(
723 HDC hdc,
724 HMETAFILE hmf,
725 MFENUMPROC lpEnumFunc,
726 LPARAM lpData
728 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
729 METARECORD *mr;
730 HANDLETABLE *ht;
731 BOOL result = TRUE;
732 int i;
733 unsigned int offset = 0;
734 HPEN hPen;
735 HBRUSH hBrush;
736 HFONT hFont;
738 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
739 if (!mh) return 0;
740 if(mh->mtType == METAFILE_DISK)
742 /* Create a memory-based copy */
743 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
744 mh = mhTemp;
747 /* save the current pen, brush and font */
748 hPen = GetCurrentObject(hdc, OBJ_PEN);
749 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
750 hFont = GetCurrentObject(hdc, OBJ_FONT);
752 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
753 sizeof(HANDLETABLE) * mh->mtNoObjects);
755 /* loop through metafile records */
756 offset = mh->mtHeaderSize * 2;
758 while (offset < (mh->mtSize * 2))
760 mr = (METARECORD *)((char *)mh + offset);
761 if(mr->rdFunction == META_EOF) {
762 TRACE("Got META_EOF so stopping\n");
763 break;
765 TRACE("Calling EnumFunc with record type %x\n",
766 mr->rdFunction);
767 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
769 result = FALSE;
770 break;
773 offset += (mr->rdSize * 2);
776 /* restore pen, brush and font */
777 SelectObject(hdc, hBrush);
778 SelectObject(hdc, hPen);
779 SelectObject(hdc, hFont);
781 /* free objects in handle table */
782 for(i = 0; i < mh->mtNoObjects; i++)
783 if(*(ht->objectHandle + i) != 0)
784 DeleteObject(*(ht->objectHandle + i));
786 /* free handle table */
787 HeapFree( GetProcessHeap(), 0, ht);
788 /* free a copy of metafile */
789 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
790 return result;
793 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
794 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
795 /******************************************************************
796 * PlayMetaFileRecord (GDI32.@)
798 * Render a single metafile record specified by *mr in the DC hdc, while
799 * using the handle table *ht, of length handles,
800 * to store metafile objects.
802 * BUGS
803 * The following metafile records are unimplemented:
805 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
806 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
807 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
809 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
811 short s1;
812 POINT *pt;
813 BITMAPINFOHEADER *infohdr;
815 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
817 switch (mr->rdFunction)
819 case META_EOF:
820 break;
822 case META_DELETEOBJECT:
823 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
824 *(ht->objectHandle + mr->rdParm[0]) = 0;
825 break;
827 case META_SETBKCOLOR:
828 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
829 break;
831 case META_SETBKMODE:
832 SetBkMode(hdc, mr->rdParm[0]);
833 break;
835 case META_SETMAPMODE:
836 SetMapMode(hdc, mr->rdParm[0]);
837 break;
839 case META_SETROP2:
840 SetROP2(hdc, mr->rdParm[0]);
841 break;
843 case META_SETRELABS:
844 SetRelAbs(hdc, mr->rdParm[0]);
845 break;
847 case META_SETPOLYFILLMODE:
848 SetPolyFillMode(hdc, mr->rdParm[0]);
849 break;
851 case META_SETSTRETCHBLTMODE:
852 SetStretchBltMode(hdc, mr->rdParm[0]);
853 break;
855 case META_SETTEXTCOLOR:
856 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
857 break;
859 case META_SETWINDOWORG:
860 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
861 break;
863 case META_SETWINDOWEXT:
864 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
865 break;
867 case META_SETVIEWPORTORG:
868 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
869 break;
871 case META_SETVIEWPORTEXT:
872 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
873 break;
875 case META_OFFSETWINDOWORG:
876 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
877 break;
879 case META_SCALEWINDOWEXT:
880 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
881 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
882 break;
884 case META_OFFSETVIEWPORTORG:
885 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
886 break;
888 case META_SCALEVIEWPORTEXT:
889 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
890 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
891 break;
893 case META_LINETO:
894 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
895 break;
897 case META_MOVETO:
898 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
899 break;
901 case META_EXCLUDECLIPRECT:
902 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
903 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
904 break;
906 case META_INTERSECTCLIPRECT:
907 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
908 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
909 break;
911 case META_ARC:
912 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
913 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
914 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
915 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
916 break;
918 case META_ELLIPSE:
919 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
920 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
921 break;
923 case META_FLOODFILL:
924 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
925 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
926 break;
928 case META_PIE:
929 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
930 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
931 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
932 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
933 break;
935 case META_RECTANGLE:
936 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
937 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
938 break;
940 case META_ROUNDRECT:
941 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
942 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
943 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
944 break;
946 case META_PATBLT:
947 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
948 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
949 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
950 break;
952 case META_SAVEDC:
953 SaveDC(hdc);
954 break;
956 case META_SETPIXEL:
957 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
958 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
959 break;
961 case META_OFFSETCLIPRGN:
962 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
963 break;
965 case META_TEXTOUT:
966 s1 = mr->rdParm[0];
967 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
968 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
969 (char *)(mr->rdParm + 1), s1);
970 break;
972 case META_POLYGON:
973 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
975 Polygon(hdc, pt, mr->rdParm[0]);
976 HeapFree( GetProcessHeap(), 0, pt );
978 break;
980 case META_POLYPOLYGON:
982 UINT i, total;
983 SHORT *counts = (SHORT *)(mr->rdParm + 1);
985 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
986 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
987 if (pt)
989 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
990 if (cnt32)
992 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
993 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
994 HeapFree( GetProcessHeap(), 0, cnt32 );
997 HeapFree( GetProcessHeap(), 0, pt );
999 break;
1001 case META_POLYLINE:
1002 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
1004 Polyline( hdc, pt, mr->rdParm[0] );
1005 HeapFree( GetProcessHeap(), 0, pt );
1007 break;
1009 case META_RESTOREDC:
1010 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1011 break;
1013 case META_SELECTOBJECT:
1014 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1015 break;
1017 case META_CHORD:
1018 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1019 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1020 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1021 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1022 break;
1024 case META_CREATEPATTERNBRUSH:
1025 switch (mr->rdParm[0])
1027 case BS_PATTERN:
1028 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1029 MF_AddHandle(ht, handles,
1030 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1031 infohdr->biHeight,
1032 infohdr->biPlanes,
1033 infohdr->biBitCount,
1034 (LPSTR)(mr->rdParm +
1035 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1036 break;
1038 case BS_DIBPATTERN:
1039 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1040 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1041 break;
1043 default:
1044 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1045 mr->rdParm[0]);
1046 break;
1048 break;
1050 case META_CREATEPENINDIRECT:
1052 LOGPEN pen;
1053 pen.lopnStyle = mr->rdParm[0];
1054 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1055 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1056 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1057 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1059 break;
1061 case META_CREATEFONTINDIRECT:
1063 LOGFONTA font;
1064 font.lfHeight = (SHORT)mr->rdParm[0];
1065 font.lfWidth = (SHORT)mr->rdParm[1];
1066 font.lfEscapement = (SHORT)mr->rdParm[2];
1067 font.lfOrientation = (SHORT)mr->rdParm[3];
1068 font.lfWeight = (SHORT)mr->rdParm[4];
1069 font.lfItalic = LOBYTE(mr->rdParm[5]);
1070 font.lfUnderline = HIBYTE(mr->rdParm[5]);
1071 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
1072 font.lfCharSet = HIBYTE(mr->rdParm[6]);
1073 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
1074 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
1075 font.lfQuality = LOBYTE(mr->rdParm[8]);
1076 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1077 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1078 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1080 break;
1082 case META_CREATEBRUSHINDIRECT:
1084 LOGBRUSH brush;
1085 brush.lbStyle = mr->rdParm[0];
1086 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1087 brush.lbHatch = mr->rdParm[3];
1088 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1090 break;
1092 case META_CREATEPALETTE:
1093 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1094 break;
1096 case META_SETTEXTALIGN:
1097 SetTextAlign(hdc, mr->rdParm[0]);
1098 break;
1100 case META_SELECTPALETTE:
1101 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1102 break;
1104 case META_SETMAPPERFLAGS:
1105 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1106 break;
1108 case META_REALIZEPALETTE:
1109 GDIRealizePalette(hdc);
1110 break;
1112 case META_ESCAPE:
1113 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
1114 break;
1116 case META_EXTTEXTOUT:
1117 MF_Play_MetaExtTextOut( hdc, mr );
1118 break;
1120 case META_STRETCHDIB:
1122 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1123 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1124 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1125 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1126 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1127 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1129 break;
1131 case META_DIBSTRETCHBLT:
1133 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1134 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1135 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1136 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1137 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1138 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1140 break;
1142 case META_STRETCHBLT:
1144 HDC hdcSrc = CreateCompatibleDC(hdc);
1145 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1146 mr->rdParm[11], /*Height*/
1147 mr->rdParm[13], /*Planes*/
1148 mr->rdParm[14], /*BitsPixel*/
1149 (LPSTR)&mr->rdParm[15]); /*bits*/
1150 SelectObject(hdcSrc,hbitmap);
1151 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1152 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1153 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1154 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1155 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1156 DeleteDC(hdcSrc);
1158 break;
1160 case META_BITBLT:
1162 HDC hdcSrc = CreateCompatibleDC(hdc);
1163 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1164 mr->rdParm[8]/*Height*/,
1165 mr->rdParm[10]/*Planes*/,
1166 mr->rdParm[11]/*BitsPixel*/,
1167 (LPSTR)&mr->rdParm[12]/*bits*/);
1168 SelectObject(hdcSrc,hbitmap);
1169 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1170 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1171 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1172 MAKELONG(0,mr->rdParm[0]));
1173 DeleteDC(hdcSrc);
1175 break;
1177 case META_CREATEREGION:
1179 HRGN hrgn = CreateRectRgn(0,0,0,0);
1181 MF_Play_MetaCreateRegion(mr, hrgn);
1182 MF_AddHandle(ht, handles, hrgn);
1184 break;
1186 case META_FILLREGION:
1187 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1188 *(ht->objectHandle + mr->rdParm[0]));
1189 break;
1191 case META_FRAMEREGION:
1192 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1193 *(ht->objectHandle + mr->rdParm[2]),
1194 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1195 break;
1197 case META_INVERTREGION:
1198 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1199 break;
1201 case META_PAINTREGION:
1202 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1203 break;
1205 case META_SELECTCLIPREGION:
1206 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1207 break;
1209 case META_DIBCREATEPATTERNBRUSH:
1210 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1211 but there's no difference */
1212 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1213 break;
1215 case META_DIBBITBLT:
1216 /* In practice I've found that there are two layouts for
1217 META_DIBBITBLT, one (the first here) is the usual one when a src
1218 dc is actually passed to it, the second occurs when the src dc is
1219 passed in as NULL to the creating BitBlt. As the second case has
1220 no dib, a size check will suffice to distinguish.
1222 Caolan.McNamara@ul.ie */
1224 if (mr->rdSize > 12) {
1225 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1226 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1228 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1229 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1230 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1231 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1233 else /* equivalent to a PatBlt */
1234 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1235 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1236 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1237 break;
1239 case META_SETTEXTCHAREXTRA:
1240 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1241 break;
1243 case META_SETTEXTJUSTIFICATION:
1244 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1245 break;
1247 case META_EXTFLOODFILL:
1248 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1249 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1250 mr->rdParm[0]);
1251 break;
1253 case META_SETDIBTODEV:
1255 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1256 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1257 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1258 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1259 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1260 mr->rdParm[2], mr->rdParm[1], bits, info,
1261 mr->rdParm[0]);
1262 break;
1265 #define META_UNIMP(x) case x: \
1266 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1267 break;
1268 META_UNIMP(META_DRAWTEXT)
1269 META_UNIMP(META_ANIMATEPALETTE)
1270 META_UNIMP(META_SETPALENTRIES)
1271 META_UNIMP(META_RESIZEPALETTE)
1272 META_UNIMP(META_RESETDC)
1273 META_UNIMP(META_STARTDOC)
1274 META_UNIMP(META_STARTPAGE)
1275 META_UNIMP(META_ENDPAGE)
1276 META_UNIMP(META_ABORTDOC)
1277 META_UNIMP(META_ENDDOC)
1278 META_UNIMP(META_CREATEBRUSH)
1279 META_UNIMP(META_CREATEBITMAPINDIRECT)
1280 META_UNIMP(META_CREATEBITMAP)
1281 #undef META_UNIMP
1283 default:
1284 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1285 return FALSE;
1287 return TRUE;
1290 /******************************************************************
1291 * GetMetaFileBits (GDI.159)
1293 * Trade in a metafile object handle for a handle to the metafile memory.
1297 HGLOBAL16 WINAPI GetMetaFileBits16(
1298 HMETAFILE16 hmf /* [in] metafile handle */
1301 TRACE("hMem out: %04x\n", hmf);
1302 return hmf;
1305 /******************************************************************
1306 * SetMetaFileBits (GDI.160)
1308 * Trade in a metafile memory handle for a handle to a metafile object.
1309 * The memory region should hold a proper metafile, otherwise
1310 * problems will occur when it is used. Validity of the memory is not
1311 * checked. The function is essentially just the identity function.
1313 HMETAFILE16 WINAPI SetMetaFileBits16(
1314 HGLOBAL16 hMem
1315 /* [in] handle to a memory region holding a metafile */
1318 TRACE("hmf out: %04x\n", hMem);
1320 return hMem;
1323 /******************************************************************
1324 * SetMetaFileBitsBetter (GDI.196)
1326 * Trade in a metafile memory handle for a handle to a metafile object,
1327 * making a cursory check (using IsValidMetaFile()) that the memory
1328 * handle points to a valid metafile.
1330 * RETURNS
1331 * Handle to a metafile on success, NULL on failure..
1333 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1335 if( IsValidMetaFile16( hMeta ) )
1336 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1337 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1338 return (HMETAFILE16)0;
1341 /******************************************************************
1342 * SetMetaFileBitsEx (GDI32.@)
1344 * Create a metafile from raw data. No checking of the data is performed.
1345 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1347 HMETAFILE WINAPI SetMetaFileBitsEx(
1348 UINT size, /* [in] size of metafile, in bytes */
1349 const BYTE *lpData /* [in] pointer to metafile data */
1352 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1353 if (!mh) return 0;
1354 memcpy(mh, lpData, size);
1355 return MF_Create_HMETAFILE(mh);
1358 /*****************************************************************
1359 * GetMetaFileBitsEx (GDI32.@) Get raw metafile data
1361 * Copies the data from metafile _hmf_ into the buffer _buf_.
1362 * If _buf_ is zero, returns size of buffer required. Otherwise,
1363 * returns number of bytes copied.
1365 UINT WINAPI GetMetaFileBitsEx(
1366 HMETAFILE hmf, /* [in] metafile */
1367 UINT nSize, /* [in] size of buf */
1368 LPVOID buf /* [out] buffer to receive raw metafile data */
1370 METAHEADER *mh = MF_GetMetaHeader(hmf);
1371 UINT mfSize;
1373 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1374 if (!mh) return 0; /* FIXME: error code */
1375 if(mh->mtType == METAFILE_DISK)
1376 FIXME("Disk-based metafile?\n");
1377 mfSize = mh->mtSize * 2;
1378 if (!buf) {
1379 TRACE("returning size %d\n", mfSize);
1380 return mfSize;
1382 if(mfSize > nSize) mfSize = nSize;
1383 memmove(buf, mh, mfSize);
1384 return mfSize;
1387 /******************************************************************
1388 * GetWinMetaFileBits [GDI32.@]
1390 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1391 UINT cbBuffer, LPBYTE lpbBuffer,
1392 INT fnMapMode, HDC hdcRef)
1394 HDC hdcmf;
1395 HMETAFILE hmf;
1396 UINT ret;
1398 FIXME("(%p,%d,%p,%d,%p): stub\n", hemf, cbBuffer, lpbBuffer, fnMapMode, hdcRef);
1399 hdcmf = CreateMetaFileA(NULL);
1400 /* PlayEnhMetaFile(hdcmf, hemf, lpRect); where does the bounding rect come from? */
1401 hmf = CloseMetaFile(hdcmf);
1402 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1403 DeleteMetaFile(hmf);
1404 return ret;
1407 /******************************************************************
1408 * MF_Play_MetaCreateRegion
1410 * Handles META_CREATEREGION for PlayMetaFileRecord().
1414 * The layout of the record looks something like this:
1416 * rdParm meaning
1417 * 0 Always 0?
1418 * 1 Always 6?
1419 * 2 Looks like a handle? - not constant
1420 * 3 0 or 1 ??
1421 * 4 Total number of bytes
1422 * 5 No. of separate bands = n [see below]
1423 * 6 Largest number of x co-ords in a band
1424 * 7-10 Bounding box x1 y1 x2 y2
1425 * 11-... n bands
1427 * Regions are divided into bands that are uniform in the
1428 * y-direction. Each band consists of pairs of on/off x-coords and is
1429 * written as
1430 * m y0 y1 x1 x2 x3 ... xm m
1431 * into successive rdParm[]s.
1433 * This is probably just a dump of the internal RGNOBJ?
1435 * HDMD - 18/12/97
1439 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1441 WORD band, pair;
1442 WORD *start, *end;
1443 INT16 y0, y1;
1444 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1446 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1447 band++, start = end + 1) {
1448 if(*start / 2 != (*start + 1) / 2) {
1449 WARN("Delimiter not even.\n");
1450 DeleteObject( hrgn2 );
1451 return FALSE;
1454 end = start + *start + 3;
1455 if(end > (WORD *)mr + mr->rdSize) {
1456 WARN("End points outside record.\n");
1457 DeleteObject( hrgn2 );
1458 return FALSE;
1461 if(*start != *end) {
1462 WARN("Mismatched delimiters.\n");
1463 DeleteObject( hrgn2 );
1464 return FALSE;
1467 y0 = *(INT16 *)(start + 1);
1468 y1 = *(INT16 *)(start + 2);
1469 for(pair = 0; pair < *start / 2; pair++) {
1470 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1471 *(INT16 *)(start + 4 + 2*pair), y1 );
1472 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1475 DeleteObject( hrgn2 );
1476 return TRUE;
1480 /******************************************************************
1481 * MF_Play_MetaExtTextOut
1483 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1486 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1488 INT *dx = NULL;
1489 int i;
1490 LPINT16 dxx;
1491 LPSTR sot;
1492 DWORD len;
1493 WORD s1;
1494 RECT rect;
1495 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1497 s1 = mr->rdParm[2]; /* String length */
1498 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1499 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1500 /* rec len without dx array */
1502 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1503 if (isrect)
1505 rect.left = (SHORT)mr->rdParm[4];
1506 rect.top = (SHORT)mr->rdParm[5];
1507 rect.right = (SHORT)mr->rdParm[6];
1508 rect.bottom = (SHORT)mr->rdParm[7];
1509 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1512 if (mr->rdSize == len / 2)
1513 dxx = NULL; /* determine if array present */
1514 else
1515 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1517 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1518 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1519 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1521 else {
1522 TRACE("%s len: %ld\n", sot, mr->rdSize);
1523 WARN(
1524 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1525 len, s1, mr->rdSize, mr->rdParm[3]);
1526 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1528 ExtTextOutA( hdc,
1529 (SHORT)mr->rdParm[1], /* X position */
1530 (SHORT)mr->rdParm[0], /* Y position */
1531 mr->rdParm[3], /* options */
1532 &rect, /* rectangle */
1533 sot, /* string */
1534 s1, dx); /* length, dx array */
1535 if (dx)
1537 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1538 HeapFree( GetProcessHeap(), 0, dx );
1540 return TRUE;