Added support for inter-process GetWindowWord.
[wine.git] / objects / metafile.c
blobd61f9d8ea6cc3f413a65d9175f9c506af008a2ef
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 "wownt32.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
78 /******************************************************************
79 * MF_AddHandle
81 * Add a handle to an external handle table and return the index
83 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
85 int i;
87 for (i = 0; i < htlen; i++)
89 if (*(ht->objectHandle + i) == 0)
91 *(ht->objectHandle + i) = hobj;
92 return i;
95 return -1;
99 /******************************************************************
100 * MF_Create_HMETATFILE
102 * Creates a (32 bit) HMETAFILE object from a METAHEADER
104 * HMETAFILEs are GDI objects.
106 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
108 HMETAFILE hmf = 0;
109 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
110 (HGDIOBJ *)&hmf, NULL );
111 if (metaObj)
113 metaObj->mh = mh;
114 GDI_ReleaseObj( hmf );
116 return hmf;
119 /******************************************************************
120 * MF_Create_HMETATFILE16
122 * Creates a HMETAFILE16 object from a METAHEADER
124 * HMETAFILE16s are Global memory handles.
126 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
128 HMETAFILE16 hmf;
129 DWORD size = mh->mtSize * sizeof(WORD);
131 hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
132 if(hmf)
134 METAHEADER *mh_dest = GlobalLock16(hmf);
135 memcpy(mh_dest, mh, size);
136 GlobalUnlock16(hmf);
138 HeapFree(GetProcessHeap(), 0, mh);
139 return hmf;
142 /******************************************************************
143 * MF_GetMetaHeader
145 * Returns ptr to METAHEADER associated with HMETAFILE
147 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
149 METAHEADER *ret = NULL;
150 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
151 if (metaObj)
153 ret = metaObj->mh;
154 GDI_ReleaseObj( hmf );
156 return ret;
159 /******************************************************************
160 * MF_GetMetaHeader16
162 * Returns ptr to METAHEADER associated with HMETAFILE16
163 * Should be followed by call to MF_ReleaseMetaHeader16
165 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
167 return GlobalLock16(hmf);
170 /******************************************************************
171 * MF_ReleaseMetaHeader16
173 * Releases METAHEADER associated with HMETAFILE16
175 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
177 return GlobalUnlock16( hmf );
181 /******************************************************************
182 * convert_points
184 * Convert an array of POINT16 to an array of POINT.
185 * Result must be freed by caller.
187 static POINT *convert_points( UINT count, POINT16 *pt16 )
189 UINT i;
190 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
191 if (ret)
193 for (i = 0; i < count; i++)
195 ret[i].x = pt16[i].x;
196 ret[i].y = pt16[i].y;
199 return ret;
203 /******************************************************************
204 * DeleteMetaFile (GDI.127)
206 BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
208 return !GlobalFree16( hmf );
211 /******************************************************************
212 * DeleteMetaFile (GDI32.@)
214 * Delete a memory-based metafile.
217 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
219 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
220 if (!metaObj) return FALSE;
221 HeapFree( GetProcessHeap(), 0, metaObj->mh );
222 GDI_FreeObject( hmf, metaObj );
223 return TRUE;
226 /******************************************************************
227 * MF_ReadMetaFile
229 * Returns a pointer to a memory based METAHEADER read in from file HFILE
232 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
234 METAHEADER *mh;
235 DWORD BytesRead, size;
237 size = sizeof(METAHEADER);
238 mh = HeapAlloc( GetProcessHeap(), 0, size );
239 if(!mh) return NULL;
240 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
241 BytesRead != size) {
242 HeapFree( GetProcessHeap(), 0, mh );
243 return NULL;
245 size = mh->mtSize * 2;
246 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
247 if(!mh) return NULL;
248 size -= sizeof(METAHEADER);
249 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
250 NULL) == 0 ||
251 BytesRead != size) {
252 HeapFree( GetProcessHeap(), 0, mh );
253 return NULL;
256 if (mh->mtType != METAFILE_MEMORY) {
257 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
258 mh->mtType = METAFILE_MEMORY;
260 return mh;
263 /******************************************************************
264 * GetMetaFile (GDI.124)
266 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
268 METAHEADER *mh;
269 HANDLE hFile;
271 TRACE("%s\n", lpFilename);
273 if(!lpFilename)
274 return 0;
276 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
277 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
278 return 0;
280 mh = MF_ReadMetaFile(hFile);
281 CloseHandle(hFile);
282 if(!mh) return 0;
283 return MF_Create_HMETAFILE16( mh );
286 /******************************************************************
287 * GetMetaFileA (GDI32.@)
289 * Read a metafile from a file. Returns handle to a memory-based metafile.
291 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
293 METAHEADER *mh;
294 HANDLE hFile;
296 TRACE("%s\n", lpFilename);
298 if(!lpFilename)
299 return 0;
301 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
302 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
303 return 0;
305 mh = MF_ReadMetaFile(hFile);
306 CloseHandle(hFile);
307 if(!mh) return 0;
308 return MF_Create_HMETAFILE( mh );
313 /******************************************************************
314 * GetMetaFileW (GDI32.@)
316 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
318 METAHEADER *mh;
319 HANDLE hFile;
321 TRACE("%s\n", debugstr_w(lpFilename));
323 if(!lpFilename)
324 return 0;
326 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
327 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
328 return 0;
330 mh = MF_ReadMetaFile(hFile);
331 CloseHandle(hFile);
332 if(!mh) return 0;
333 return MF_Create_HMETAFILE( mh );
337 /******************************************************************
338 * MF_LoadDiskBasedMetaFile
340 * Creates a new memory-based metafile from a disk-based one.
342 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
344 METAHEADERDISK *mhd;
345 HANDLE hfile;
346 METAHEADER *mh2;
348 if(mh->mtType != METAFILE_DISK) {
349 ERR("Not a disk based metafile\n");
350 return NULL;
352 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
354 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
355 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
356 WARN("Can't open file of disk based metafile\n");
357 return NULL;
359 mh2 = MF_ReadMetaFile(hfile);
360 CloseHandle(hfile);
361 return mh2;
364 /******************************************************************
365 * MF_CreateMetaHeaderDisk
367 * Take a memory based METAHEADER and change it to a disk based METAHEADER
368 * assosiated with filename. Note: Trashes contents of old one.
370 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
372 METAHEADERDISK *mhd;
373 DWORD size;
375 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
376 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
377 mh->mtType = METAFILE_DISK;
378 size = HeapSize( GetProcessHeap(), 0, mh );
379 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
380 strcpy(mhd->filename, filename);
381 return mh;
384 /******************************************************************
385 * CopyMetaFile (GDI.151)
387 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
389 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
390 METAHEADER *mh2 = NULL;
391 HANDLE hFile;
393 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
395 if(!mh) return 0;
397 if(mh->mtType == METAFILE_DISK)
398 mh2 = MF_LoadDiskBasedMetaFile(mh);
399 else {
400 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
401 memcpy( mh2, mh, mh->mtSize * 2 );
403 MF_ReleaseMetaHeader16( hSrcMetaFile );
405 if(lpFilename) { /* disk based metafile */
406 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
407 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
408 HeapFree( GetProcessHeap(), 0, mh2 );
409 return 0;
411 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
412 CloseHandle(hFile);
413 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
416 return MF_Create_HMETAFILE16( mh2 );
420 /******************************************************************
421 * CopyMetaFileA (GDI32.@)
423 * Copies the metafile corresponding to hSrcMetaFile to either
424 * a disk file, if a filename is given, or to a new memory based
425 * metafile, if lpFileName is NULL.
427 * RETURNS
429 * Handle to metafile copy on success, NULL on failure.
431 * BUGS
433 * Copying to disk returns NULL even if successful.
435 HMETAFILE WINAPI CopyMetaFileA(
436 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
437 LPCSTR lpFilename /* [in] filename if copying to a file */
439 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
440 METAHEADER *mh2 = NULL;
441 HANDLE hFile;
443 TRACE("(%p,%s)\n", hSrcMetaFile, lpFilename);
445 if(!mh) return 0;
447 if(mh->mtType == METAFILE_DISK)
448 mh2 = MF_LoadDiskBasedMetaFile(mh);
449 else {
450 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
451 memcpy( mh2, mh, mh->mtSize * 2 );
454 if(lpFilename) { /* disk based metafile */
455 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
456 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
457 HeapFree( GetProcessHeap(), 0, mh2 );
458 return 0;
460 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
461 CloseHandle(hFile);
462 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
465 return MF_Create_HMETAFILE( mh2 );
469 /******************************************************************
470 * CopyMetaFileW (GDI32.@)
472 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile,
473 LPCWSTR lpFilename )
475 HMETAFILE ret = 0;
476 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, NULL, 0, NULL, NULL );
477 LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
479 if (p)
481 WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, p, len, NULL, NULL );
482 ret = CopyMetaFileA( hSrcMetaFile, p );
483 HeapFree( GetProcessHeap(), 0, p );
485 return ret;
489 /******************************************************************
490 * IsValidMetaFile (GDI.410)
492 * Attempts to check if a given metafile is correctly formatted.
493 * Currently, the only things verified are several properties of the
494 * header.
496 * RETURNS
497 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
499 * BUGS
500 * This is not exactly what windows does, see _Undocumented_Windows_
501 * for details.
503 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
505 BOOL16 res=FALSE;
506 METAHEADER *mh = MF_GetMetaHeader16(hmf);
507 if (mh) {
508 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
509 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
510 if (mh->mtVersion == MFVERSION)
511 res=TRUE;
512 MF_ReleaseMetaHeader16(hmf);
514 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
515 return res;
519 /*******************************************************************
520 * MF_PlayMetaFile
522 * Helper for PlayMetaFile
524 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
527 METARECORD *mr;
528 HANDLETABLE *ht;
529 unsigned int offset = 0;
530 WORD i;
531 HPEN hPen;
532 HBRUSH hBrush;
533 HFONT hFont;
534 BOOL loaded = FALSE;
536 if (!mh) return FALSE;
537 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
538 mh = MF_LoadDiskBasedMetaFile(mh);
539 if(!mh) return FALSE;
540 loaded = TRUE;
543 /* save the current pen, brush and font */
544 hPen = GetCurrentObject(hdc, OBJ_PEN);
545 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
546 hFont = GetCurrentObject(hdc, OBJ_FONT);
548 /* create the handle table */
549 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
550 sizeof(HANDLETABLE) * mh->mtNoObjects);
551 if(!ht) return FALSE;
553 /* loop through metafile playing records */
554 offset = mh->mtHeaderSize * 2;
555 while (offset < mh->mtSize * 2)
557 mr = (METARECORD *)((char *)mh + offset);
558 TRACE("offset=%04x,size=%08lx\n",
559 offset, mr->rdSize);
560 if (!mr->rdSize) {
561 TRACE(
562 "Entry got size 0 at offset %d, total mf length is %ld\n",
563 offset,mh->mtSize*2);
564 break; /* would loop endlessly otherwise */
566 offset += mr->rdSize * 2;
567 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
570 SelectObject(hdc, hBrush);
571 SelectObject(hdc, hPen);
572 SelectObject(hdc, hFont);
574 /* free objects in handle table */
575 for(i = 0; i < mh->mtNoObjects; i++)
576 if(*(ht->objectHandle + i) != 0)
577 DeleteObject(*(ht->objectHandle + i));
579 /* free handle table */
580 HeapFree( GetProcessHeap(), 0, ht );
581 if(loaded)
582 HeapFree( GetProcessHeap(), 0, mh );
583 return TRUE;
586 /******************************************************************
587 * PlayMetaFile (GDI.123)
590 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
592 BOOL16 ret;
593 METAHEADER *mh = MF_GetMetaHeader16( hmf );
594 ret = MF_PlayMetaFile( HDC_32(hdc), mh );
595 MF_ReleaseMetaHeader16( hmf );
596 return ret;
599 /******************************************************************
600 * PlayMetaFile (GDI32.@)
602 * Renders the metafile specified by hmf in the DC specified by
603 * hdc. Returns FALSE on failure, TRUE on success.
605 BOOL WINAPI PlayMetaFile(
606 HDC hdc, /* [in] handle of DC to render in */
607 HMETAFILE hmf /* [in] handle of metafile to render */
610 METAHEADER *mh = MF_GetMetaHeader( hmf );
611 return MF_PlayMetaFile( hdc, mh );
615 /******************************************************************
616 * EnumMetaFile (GDI.175)
619 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
620 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
622 METAHEADER *mh = MF_GetMetaHeader16(hmf);
623 METARECORD *mr;
624 HANDLETABLE16 *ht;
625 HDC hdc = HDC_32(hdc16);
626 HGLOBAL16 hHT;
627 SEGPTR spht;
628 unsigned int offset = 0;
629 WORD i, seg;
630 HPEN hPen;
631 HBRUSH hBrush;
632 HFONT hFont;
633 WORD args[8];
634 BOOL16 result = TRUE, loaded = FALSE;
636 TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
638 if(!mh) return FALSE;
639 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
640 mh = MF_LoadDiskBasedMetaFile(mh);
641 if(!mh) return FALSE;
642 loaded = TRUE;
645 /* save the current pen, brush and font */
646 hPen = GetCurrentObject(hdc, OBJ_PEN);
647 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
648 hFont = GetCurrentObject(hdc, OBJ_FONT);
650 /* create the handle table */
652 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
653 sizeof(HANDLETABLE16) * mh->mtNoObjects);
654 spht = K32WOWGlobalLock16(hHT);
656 seg = hmf | 7;
657 offset = mh->mtHeaderSize * 2;
659 /* loop through metafile records */
661 args[7] = hdc16;
662 args[6] = SELECTOROF(spht);
663 args[5] = OFFSETOF(spht);
664 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
665 args[3] = LOWORD(offset);
666 args[2] = mh->mtNoObjects;
667 args[1] = HIWORD(lpData);
668 args[0] = LOWORD(lpData);
670 while (offset < (mh->mtSize * 2))
672 DWORD ret;
674 mr = (METARECORD *)((char *)mh + offset);
676 WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
677 if (!LOWORD(ret))
679 result = FALSE;
680 break;
683 offset += (mr->rdSize * 2);
684 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
685 args[3] = LOWORD(offset);
688 SelectObject(hdc, hBrush);
689 SelectObject(hdc, hPen);
690 SelectObject(hdc, hFont);
692 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
694 /* free objects in handle table */
695 for(i = 0; i < mh->mtNoObjects; i++)
696 if(*(ht->objectHandle + i) != 0)
697 DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
699 /* free handle table */
700 GlobalFree16(hHT);
701 if(loaded)
702 HeapFree( GetProcessHeap(), 0, mh );
703 MF_ReleaseMetaHeader16(hmf);
704 return result;
707 /******************************************************************
708 * EnumMetaFile (GDI32.@)
710 * Loop through the metafile records in hmf, calling the user-specified
711 * function for each one, stopping when the user's function returns FALSE
712 * (which is considered to be failure)
713 * or when no records are left (which is considered to be success).
715 * RETURNS
716 * TRUE on success, FALSE on failure.
718 * HISTORY
719 * Niels de carpentier, april 1996
721 BOOL WINAPI EnumMetaFile(
722 HDC hdc,
723 HMETAFILE hmf,
724 MFENUMPROC lpEnumFunc,
725 LPARAM lpData
727 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
728 METARECORD *mr;
729 HANDLETABLE *ht;
730 BOOL result = TRUE;
731 int i;
732 unsigned int offset = 0;
733 HPEN hPen;
734 HBRUSH hBrush;
735 HFONT hFont;
737 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
738 if (!mh) return 0;
739 if(mh->mtType == METAFILE_DISK)
741 /* Create a memory-based copy */
742 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
743 mh = mhTemp;
746 /* save the current pen, brush and font */
747 hPen = GetCurrentObject(hdc, OBJ_PEN);
748 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
749 hFont = GetCurrentObject(hdc, OBJ_FONT);
751 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
752 sizeof(HANDLETABLE) * mh->mtNoObjects);
754 /* loop through metafile records */
755 offset = mh->mtHeaderSize * 2;
757 while (offset < (mh->mtSize * 2))
759 mr = (METARECORD *)((char *)mh + offset);
760 if(mr->rdFunction == META_EOF) {
761 TRACE("Got META_EOF so stopping\n");
762 break;
764 TRACE("Calling EnumFunc with record type %x\n",
765 mr->rdFunction);
766 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
768 result = FALSE;
769 break;
772 offset += (mr->rdSize * 2);
775 /* restore pen, brush and font */
776 SelectObject(hdc, hBrush);
777 SelectObject(hdc, hPen);
778 SelectObject(hdc, hFont);
780 /* free objects in handle table */
781 for(i = 0; i < mh->mtNoObjects; i++)
782 if(*(ht->objectHandle + i) != 0)
783 DeleteObject(*(ht->objectHandle + i));
785 /* free handle table */
786 HeapFree( GetProcessHeap(), 0, ht);
787 /* free a copy of metafile */
788 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
789 return result;
792 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
793 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
794 /******************************************************************
795 * PlayMetaFileRecord (GDI32.@)
797 * Render a single metafile record specified by *mr in the DC hdc, while
798 * using the handle table *ht, of length handles,
799 * to store metafile objects.
801 * BUGS
802 * The following metafile records are unimplemented:
804 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
805 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
806 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
808 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
810 short s1;
811 POINT *pt;
812 BITMAPINFOHEADER *infohdr;
814 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
816 switch (mr->rdFunction)
818 case META_EOF:
819 break;
821 case META_DELETEOBJECT:
822 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
823 *(ht->objectHandle + mr->rdParm[0]) = 0;
824 break;
826 case META_SETBKCOLOR:
827 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
828 break;
830 case META_SETBKMODE:
831 SetBkMode(hdc, mr->rdParm[0]);
832 break;
834 case META_SETMAPMODE:
835 SetMapMode(hdc, mr->rdParm[0]);
836 break;
838 case META_SETROP2:
839 SetROP2(hdc, mr->rdParm[0]);
840 break;
842 case META_SETRELABS:
843 SetRelAbs(hdc, mr->rdParm[0]);
844 break;
846 case META_SETPOLYFILLMODE:
847 SetPolyFillMode(hdc, mr->rdParm[0]);
848 break;
850 case META_SETSTRETCHBLTMODE:
851 SetStretchBltMode(hdc, mr->rdParm[0]);
852 break;
854 case META_SETTEXTCOLOR:
855 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
856 break;
858 case META_SETWINDOWORG:
859 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
860 break;
862 case META_SETWINDOWEXT:
863 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
864 break;
866 case META_SETVIEWPORTORG:
867 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
868 break;
870 case META_SETVIEWPORTEXT:
871 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
872 break;
874 case META_OFFSETWINDOWORG:
875 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
876 break;
878 case META_SCALEWINDOWEXT:
879 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
880 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
881 break;
883 case META_OFFSETVIEWPORTORG:
884 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
885 break;
887 case META_SCALEVIEWPORTEXT:
888 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
889 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
890 break;
892 case META_LINETO:
893 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
894 break;
896 case META_MOVETO:
897 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
898 break;
900 case META_EXCLUDECLIPRECT:
901 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
902 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
903 break;
905 case META_INTERSECTCLIPRECT:
906 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
907 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
908 break;
910 case META_ARC:
911 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
912 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
913 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
914 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
915 break;
917 case META_ELLIPSE:
918 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
919 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
920 break;
922 case META_FLOODFILL:
923 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
924 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
925 break;
927 case META_PIE:
928 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
929 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
930 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
931 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
932 break;
934 case META_RECTANGLE:
935 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
936 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
937 break;
939 case META_ROUNDRECT:
940 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
941 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
942 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
943 break;
945 case META_PATBLT:
946 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
947 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
948 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
949 break;
951 case META_SAVEDC:
952 SaveDC(hdc);
953 break;
955 case META_SETPIXEL:
956 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
957 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
958 break;
960 case META_OFFSETCLIPRGN:
961 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
962 break;
964 case META_TEXTOUT:
965 s1 = mr->rdParm[0];
966 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
967 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
968 (char *)(mr->rdParm + 1), s1);
969 break;
971 case META_POLYGON:
972 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
974 Polygon(hdc, pt, mr->rdParm[0]);
975 HeapFree( GetProcessHeap(), 0, pt );
977 break;
979 case META_POLYPOLYGON:
981 UINT i, total;
982 SHORT *counts = (SHORT *)(mr->rdParm + 1);
984 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
985 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
986 if (pt)
988 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
989 if (cnt32)
991 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
992 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
993 HeapFree( GetProcessHeap(), 0, cnt32 );
996 HeapFree( GetProcessHeap(), 0, pt );
998 break;
1000 case META_POLYLINE:
1001 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
1003 Polyline( hdc, pt, mr->rdParm[0] );
1004 HeapFree( GetProcessHeap(), 0, pt );
1006 break;
1008 case META_RESTOREDC:
1009 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1010 break;
1012 case META_SELECTOBJECT:
1013 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1014 break;
1016 case META_CHORD:
1017 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1018 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1019 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1020 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1021 break;
1023 case META_CREATEPATTERNBRUSH:
1024 switch (mr->rdParm[0])
1026 case BS_PATTERN:
1027 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1028 MF_AddHandle(ht, handles,
1029 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1030 infohdr->biHeight,
1031 infohdr->biPlanes,
1032 infohdr->biBitCount,
1033 (LPSTR)(mr->rdParm +
1034 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1035 break;
1037 case BS_DIBPATTERN:
1038 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1039 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1040 break;
1042 default:
1043 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1044 mr->rdParm[0]);
1045 break;
1047 break;
1049 case META_CREATEPENINDIRECT:
1051 LOGPEN pen;
1052 pen.lopnStyle = mr->rdParm[0];
1053 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1054 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1055 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1056 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1058 break;
1060 case META_CREATEFONTINDIRECT:
1062 LOGFONTA font;
1063 font.lfHeight = (SHORT)mr->rdParm[0];
1064 font.lfWidth = (SHORT)mr->rdParm[1];
1065 font.lfEscapement = (SHORT)mr->rdParm[2];
1066 font.lfOrientation = (SHORT)mr->rdParm[3];
1067 font.lfWeight = (SHORT)mr->rdParm[4];
1068 font.lfItalic = LOBYTE(mr->rdParm[5]);
1069 font.lfUnderline = HIBYTE(mr->rdParm[5]);
1070 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
1071 font.lfCharSet = HIBYTE(mr->rdParm[6]);
1072 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
1073 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
1074 font.lfQuality = LOBYTE(mr->rdParm[8]);
1075 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1076 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1077 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1079 break;
1081 case META_CREATEBRUSHINDIRECT:
1083 LOGBRUSH brush;
1084 brush.lbStyle = mr->rdParm[0];
1085 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1086 brush.lbHatch = mr->rdParm[3];
1087 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1089 break;
1091 case META_CREATEPALETTE:
1092 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1093 break;
1095 case META_SETTEXTALIGN:
1096 SetTextAlign(hdc, mr->rdParm[0]);
1097 break;
1099 case META_SELECTPALETTE:
1100 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1101 break;
1103 case META_SETMAPPERFLAGS:
1104 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1105 break;
1107 case META_REALIZEPALETTE:
1108 GDIRealizePalette(hdc);
1109 break;
1111 case META_ESCAPE:
1112 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
1113 break;
1115 case META_EXTTEXTOUT:
1116 MF_Play_MetaExtTextOut( hdc, mr );
1117 break;
1119 case META_STRETCHDIB:
1121 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1122 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1123 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1124 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1125 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1126 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1128 break;
1130 case META_DIBSTRETCHBLT:
1132 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1133 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1134 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1135 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1136 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1137 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1139 break;
1141 case META_STRETCHBLT:
1143 HDC hdcSrc = CreateCompatibleDC(hdc);
1144 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1145 mr->rdParm[11], /*Height*/
1146 mr->rdParm[13], /*Planes*/
1147 mr->rdParm[14], /*BitsPixel*/
1148 (LPSTR)&mr->rdParm[15]); /*bits*/
1149 SelectObject(hdcSrc,hbitmap);
1150 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1151 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1152 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1153 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1154 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1155 DeleteDC(hdcSrc);
1157 break;
1159 case META_BITBLT:
1161 HDC hdcSrc = CreateCompatibleDC(hdc);
1162 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1163 mr->rdParm[8]/*Height*/,
1164 mr->rdParm[10]/*Planes*/,
1165 mr->rdParm[11]/*BitsPixel*/,
1166 (LPSTR)&mr->rdParm[12]/*bits*/);
1167 SelectObject(hdcSrc,hbitmap);
1168 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1169 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1170 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1171 MAKELONG(0,mr->rdParm[0]));
1172 DeleteDC(hdcSrc);
1174 break;
1176 case META_CREATEREGION:
1178 HRGN hrgn = CreateRectRgn(0,0,0,0);
1180 MF_Play_MetaCreateRegion(mr, hrgn);
1181 MF_AddHandle(ht, handles, hrgn);
1183 break;
1185 case META_FILLREGION:
1186 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1187 *(ht->objectHandle + mr->rdParm[0]));
1188 break;
1190 case META_FRAMEREGION:
1191 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1192 *(ht->objectHandle + mr->rdParm[2]),
1193 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1194 break;
1196 case META_INVERTREGION:
1197 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1198 break;
1200 case META_PAINTREGION:
1201 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1202 break;
1204 case META_SELECTCLIPREGION:
1205 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1206 break;
1208 case META_DIBCREATEPATTERNBRUSH:
1209 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1210 but there's no difference */
1211 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1212 break;
1214 case META_DIBBITBLT:
1215 /* In practice I've found that there are two layouts for
1216 META_DIBBITBLT, one (the first here) is the usual one when a src
1217 dc is actually passed to it, the second occurs when the src dc is
1218 passed in as NULL to the creating BitBlt. As the second case has
1219 no dib, a size check will suffice to distinguish.
1221 Caolan.McNamara@ul.ie */
1223 if (mr->rdSize > 12) {
1224 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1225 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1227 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1228 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1229 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1230 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1232 else /* equivalent to a PatBlt */
1233 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1234 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1235 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1236 break;
1238 case META_SETTEXTCHAREXTRA:
1239 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1240 break;
1242 case META_SETTEXTJUSTIFICATION:
1243 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1244 break;
1246 case META_EXTFLOODFILL:
1247 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1248 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1249 mr->rdParm[0]);
1250 break;
1252 case META_SETDIBTODEV:
1254 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1255 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1256 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1257 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1258 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1259 mr->rdParm[2], mr->rdParm[1], bits, info,
1260 mr->rdParm[0]);
1261 break;
1264 #define META_UNIMP(x) case x: \
1265 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1266 break;
1267 META_UNIMP(META_DRAWTEXT)
1268 META_UNIMP(META_ANIMATEPALETTE)
1269 META_UNIMP(META_SETPALENTRIES)
1270 META_UNIMP(META_RESIZEPALETTE)
1271 META_UNIMP(META_RESETDC)
1272 META_UNIMP(META_STARTDOC)
1273 META_UNIMP(META_STARTPAGE)
1274 META_UNIMP(META_ENDPAGE)
1275 META_UNIMP(META_ABORTDOC)
1276 META_UNIMP(META_ENDDOC)
1277 META_UNIMP(META_CREATEBRUSH)
1278 META_UNIMP(META_CREATEBITMAPINDIRECT)
1279 META_UNIMP(META_CREATEBITMAP)
1280 #undef META_UNIMP
1282 default:
1283 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1284 return FALSE;
1286 return TRUE;
1289 /******************************************************************
1290 * GetMetaFileBits (GDI.159)
1292 * Trade in a metafile object handle for a handle to the metafile memory.
1296 HGLOBAL16 WINAPI GetMetaFileBits16(
1297 HMETAFILE16 hmf /* [in] metafile handle */
1300 TRACE("hMem out: %04x\n", hmf);
1301 return hmf;
1304 /******************************************************************
1305 * SetMetaFileBits (GDI.160)
1307 * Trade in a metafile memory handle for a handle to a metafile object.
1308 * The memory region should hold a proper metafile, otherwise
1309 * problems will occur when it is used. Validity of the memory is not
1310 * checked. The function is essentially just the identity function.
1312 HMETAFILE16 WINAPI SetMetaFileBits16(
1313 HGLOBAL16 hMem
1314 /* [in] handle to a memory region holding a metafile */
1317 TRACE("hmf out: %04x\n", hMem);
1319 return hMem;
1322 /******************************************************************
1323 * SetMetaFileBitsBetter (GDI.196)
1325 * Trade in a metafile memory handle for a handle to a metafile object,
1326 * making a cursory check (using IsValidMetaFile()) that the memory
1327 * handle points to a valid metafile.
1329 * RETURNS
1330 * Handle to a metafile on success, NULL on failure..
1332 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1334 if( IsValidMetaFile16( hMeta ) )
1335 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1336 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1337 return (HMETAFILE16)0;
1340 /******************************************************************
1341 * SetMetaFileBitsEx (GDI32.@)
1343 * Create a metafile from raw data. No checking of the data is performed.
1344 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1346 HMETAFILE WINAPI SetMetaFileBitsEx(
1347 UINT size, /* [in] size of metafile, in bytes */
1348 const BYTE *lpData /* [in] pointer to metafile data */
1351 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1352 if (!mh) return 0;
1353 memcpy(mh, lpData, size);
1354 return MF_Create_HMETAFILE(mh);
1357 /*****************************************************************
1358 * GetMetaFileBitsEx (GDI32.@) Get raw metafile data
1360 * Copies the data from metafile _hmf_ into the buffer _buf_.
1361 * If _buf_ is zero, returns size of buffer required. Otherwise,
1362 * returns number of bytes copied.
1364 UINT WINAPI GetMetaFileBitsEx(
1365 HMETAFILE hmf, /* [in] metafile */
1366 UINT nSize, /* [in] size of buf */
1367 LPVOID buf /* [out] buffer to receive raw metafile data */
1369 METAHEADER *mh = MF_GetMetaHeader(hmf);
1370 UINT mfSize;
1372 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1373 if (!mh) return 0; /* FIXME: error code */
1374 if(mh->mtType == METAFILE_DISK)
1375 FIXME("Disk-based metafile?\n");
1376 mfSize = mh->mtSize * 2;
1377 if (!buf) {
1378 TRACE("returning size %d\n", mfSize);
1379 return mfSize;
1381 if(mfSize > nSize) mfSize = nSize;
1382 memmove(buf, mh, mfSize);
1383 return mfSize;
1386 /******************************************************************
1387 * GetWinMetaFileBits [GDI32.@]
1389 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1390 UINT cbBuffer, LPBYTE lpbBuffer,
1391 INT fnMapMode, HDC hdcRef)
1393 HDC hdcmf;
1394 HMETAFILE hmf;
1395 UINT ret;
1397 FIXME("(%p,%d,%p,%d,%p): stub\n", hemf, cbBuffer, lpbBuffer, fnMapMode, hdcRef);
1398 hdcmf = CreateMetaFileA(NULL);
1399 /* PlayEnhMetaFile(hdcmf, hemf, lpRect); where does the bounding rect come from? */
1400 hmf = CloseMetaFile(hdcmf);
1401 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1402 DeleteMetaFile(hmf);
1403 return ret;
1406 /******************************************************************
1407 * MF_Play_MetaCreateRegion
1409 * Handles META_CREATEREGION for PlayMetaFileRecord().
1413 * The layout of the record looks something like this:
1415 * rdParm meaning
1416 * 0 Always 0?
1417 * 1 Always 6?
1418 * 2 Looks like a handle? - not constant
1419 * 3 0 or 1 ??
1420 * 4 Total number of bytes
1421 * 5 No. of separate bands = n [see below]
1422 * 6 Largest number of x co-ords in a band
1423 * 7-10 Bounding box x1 y1 x2 y2
1424 * 11-... n bands
1426 * Regions are divided into bands that are uniform in the
1427 * y-direction. Each band consists of pairs of on/off x-coords and is
1428 * written as
1429 * m y0 y1 x1 x2 x3 ... xm m
1430 * into successive rdParm[]s.
1432 * This is probably just a dump of the internal RGNOBJ?
1434 * HDMD - 18/12/97
1438 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1440 WORD band, pair;
1441 WORD *start, *end;
1442 INT16 y0, y1;
1443 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1445 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1446 band++, start = end + 1) {
1447 if(*start / 2 != (*start + 1) / 2) {
1448 WARN("Delimiter not even.\n");
1449 DeleteObject( hrgn2 );
1450 return FALSE;
1453 end = start + *start + 3;
1454 if(end > (WORD *)mr + mr->rdSize) {
1455 WARN("End points outside record.\n");
1456 DeleteObject( hrgn2 );
1457 return FALSE;
1460 if(*start != *end) {
1461 WARN("Mismatched delimiters.\n");
1462 DeleteObject( hrgn2 );
1463 return FALSE;
1466 y0 = *(INT16 *)(start + 1);
1467 y1 = *(INT16 *)(start + 2);
1468 for(pair = 0; pair < *start / 2; pair++) {
1469 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1470 *(INT16 *)(start + 4 + 2*pair), y1 );
1471 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1474 DeleteObject( hrgn2 );
1475 return TRUE;
1479 /******************************************************************
1480 * MF_Play_MetaExtTextOut
1482 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1485 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1487 INT *dx = NULL;
1488 int i;
1489 LPINT16 dxx;
1490 LPSTR sot;
1491 DWORD len;
1492 WORD s1;
1493 RECT rect;
1494 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1496 s1 = mr->rdParm[2]; /* String length */
1497 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1498 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1499 /* rec len without dx array */
1501 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1502 if (isrect)
1504 rect.left = (SHORT)mr->rdParm[4];
1505 rect.top = (SHORT)mr->rdParm[5];
1506 rect.right = (SHORT)mr->rdParm[6];
1507 rect.bottom = (SHORT)mr->rdParm[7];
1508 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1511 if (mr->rdSize == len / 2)
1512 dxx = NULL; /* determine if array present */
1513 else
1514 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1516 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1517 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1518 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1520 else {
1521 TRACE("%s len: %ld\n", sot, mr->rdSize);
1522 WARN(
1523 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1524 len, s1, mr->rdSize, mr->rdParm[3]);
1525 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1527 ExtTextOutA( hdc,
1528 (SHORT)mr->rdParm[1], /* X position */
1529 (SHORT)mr->rdParm[0], /* Y position */
1530 mr->rdParm[3], /* options */
1531 &rect, /* rectangle */
1532 sot, /* string */
1533 s1, dx); /* length, dx array */
1534 if (dx)
1536 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1537 HeapFree( GetProcessHeap(), 0, dx );
1539 return TRUE;