Roll loop back up to avoid code duplication.
[wine.git] / objects / metafile.c
blob1499c376be4fb731567d9f7a7263a92b9af772fa
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
78 /* ### start build ### */
79 extern WORD CALLBACK MF_CallTo16_word_wllwl(MFENUMPROC16,WORD,LONG,LONG,WORD,LONG);
80 /* ### stop build ### */
82 /******************************************************************
83 * MF_AddHandle
85 * Add a handle to an external handle table and return the index
87 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
89 int i;
91 for (i = 0; i < htlen; i++)
93 if (*(ht->objectHandle + i) == 0)
95 *(ht->objectHandle + i) = hobj;
96 return i;
99 return -1;
103 /******************************************************************
104 * MF_Create_HMETATFILE
106 * Creates a (32 bit) HMETAFILE object from a METAHEADER
108 * HMETAFILEs are GDI objects.
110 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
112 HMETAFILE hmf = 0;
113 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
114 (HGDIOBJ *)&hmf, NULL );
115 if (metaObj)
117 metaObj->mh = mh;
118 GDI_ReleaseObj( hmf );
120 return hmf;
123 /******************************************************************
124 * MF_Create_HMETATFILE16
126 * Creates a HMETAFILE16 object from a METAHEADER
128 * HMETAFILE16s are Global memory handles.
130 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
132 HMETAFILE16 hmf;
133 DWORD size = mh->mtSize * sizeof(WORD);
135 hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
136 if(hmf)
138 METAHEADER *mh_dest = GlobalLock16(hmf);
139 memcpy(mh_dest, mh, size);
140 GlobalUnlock16(hmf);
142 HeapFree(GetProcessHeap(), 0, mh);
143 return hmf;
146 /******************************************************************
147 * MF_GetMetaHeader
149 * Returns ptr to METAHEADER associated with HMETAFILE
151 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
153 METAHEADER *ret = NULL;
154 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
155 if (metaObj)
157 ret = metaObj->mh;
158 GDI_ReleaseObj( hmf );
160 return ret;
163 /******************************************************************
164 * MF_GetMetaHeader16
166 * Returns ptr to METAHEADER associated with HMETAFILE16
167 * Should be followed by call to MF_ReleaseMetaHeader16
169 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
171 return GlobalLock16(hmf);
174 /******************************************************************
175 * MF_ReleaseMetaHeader16
177 * Releases METAHEADER associated with HMETAFILE16
179 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
181 return GlobalUnlock16( hmf );
185 /******************************************************************
186 * convert_points
188 * Convert an array of POINT16 to an array of POINT.
189 * Result must be freed by caller.
191 static POINT *convert_points( UINT count, POINT16 *pt16 )
193 UINT i;
194 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
195 if (ret)
197 for (i = 0; i < count; i++)
199 ret[i].x = pt16[i].x;
200 ret[i].y = pt16[i].y;
203 return ret;
207 /******************************************************************
208 * DeleteMetaFile (GDI.127)
210 BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
212 return !GlobalFree16( hmf );
215 /******************************************************************
216 * DeleteMetaFile (GDI32.@)
218 * Delete a memory-based metafile.
221 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
223 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
224 if (!metaObj) return FALSE;
225 HeapFree( GetProcessHeap(), 0, metaObj->mh );
226 GDI_FreeObject( hmf, metaObj );
227 return TRUE;
230 /******************************************************************
231 * MF_ReadMetaFile
233 * Returns a pointer to a memory based METAHEADER read in from file HFILE
236 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
238 METAHEADER *mh;
239 DWORD BytesRead, size;
241 size = sizeof(METAHEADER);
242 mh = HeapAlloc( GetProcessHeap(), 0, size );
243 if(!mh) return NULL;
244 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
245 BytesRead != size) {
246 HeapFree( GetProcessHeap(), 0, mh );
247 return NULL;
249 size = mh->mtSize * 2;
250 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
251 if(!mh) return NULL;
252 size -= sizeof(METAHEADER);
253 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
254 NULL) == 0 ||
255 BytesRead != size) {
256 HeapFree( GetProcessHeap(), 0, mh );
257 return NULL;
260 if (mh->mtType != METAFILE_MEMORY) {
261 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
262 mh->mtType = METAFILE_MEMORY;
264 return mh;
267 /******************************************************************
268 * GetMetaFile (GDI.124)
270 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
272 METAHEADER *mh;
273 HANDLE hFile;
275 TRACE("%s\n", lpFilename);
277 if(!lpFilename)
278 return 0;
280 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
281 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
282 return 0;
284 mh = MF_ReadMetaFile(hFile);
285 CloseHandle(hFile);
286 if(!mh) return 0;
287 return MF_Create_HMETAFILE16( mh );
290 /******************************************************************
291 * GetMetaFileA (GDI32.@)
293 * Read a metafile from a file. Returns handle to a memory-based metafile.
295 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
297 METAHEADER *mh;
298 HANDLE hFile;
300 TRACE("%s\n", lpFilename);
302 if(!lpFilename)
303 return 0;
305 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
306 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
307 return 0;
309 mh = MF_ReadMetaFile(hFile);
310 CloseHandle(hFile);
311 if(!mh) return 0;
312 return MF_Create_HMETAFILE( mh );
317 /******************************************************************
318 * GetMetaFileW (GDI32.@)
320 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
322 METAHEADER *mh;
323 HANDLE hFile;
325 TRACE("%s\n", debugstr_w(lpFilename));
327 if(!lpFilename)
328 return 0;
330 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
331 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
332 return 0;
334 mh = MF_ReadMetaFile(hFile);
335 CloseHandle(hFile);
336 if(!mh) return 0;
337 return MF_Create_HMETAFILE( mh );
341 /******************************************************************
342 * MF_LoadDiskBasedMetaFile
344 * Creates a new memory-based metafile from a disk-based one.
346 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
348 METAHEADERDISK *mhd;
349 HANDLE hfile;
350 METAHEADER *mh2;
352 if(mh->mtType != METAFILE_DISK) {
353 ERR("Not a disk based metafile\n");
354 return NULL;
356 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
358 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
359 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
360 WARN("Can't open file of disk based metafile\n");
361 return NULL;
363 mh2 = MF_ReadMetaFile(hfile);
364 CloseHandle(hfile);
365 return mh2;
368 /******************************************************************
369 * MF_CreateMetaHeaderDisk
371 * Take a memory based METAHEADER and change it to a disk based METAHEADER
372 * assosiated with filename. Note: Trashes contents of old one.
374 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
376 METAHEADERDISK *mhd;
377 DWORD size;
379 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
380 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
381 mh->mtType = METAFILE_DISK;
382 size = HeapSize( GetProcessHeap(), 0, mh );
383 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
384 strcpy(mhd->filename, filename);
385 return mh;
388 /******************************************************************
389 * CopyMetaFile (GDI.151)
391 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
393 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
394 METAHEADER *mh2 = NULL;
395 HANDLE hFile;
397 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
399 if(!mh) return 0;
401 if(mh->mtType == METAFILE_DISK)
402 mh2 = MF_LoadDiskBasedMetaFile(mh);
403 else {
404 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
405 memcpy( mh2, mh, mh->mtSize * 2 );
407 MF_ReleaseMetaHeader16( hSrcMetaFile );
409 if(lpFilename) { /* disk based metafile */
410 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
411 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
412 HeapFree( GetProcessHeap(), 0, mh2 );
413 return 0;
415 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
416 CloseHandle(hFile);
417 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
420 return MF_Create_HMETAFILE16( mh2 );
424 /******************************************************************
425 * CopyMetaFileA (GDI32.@)
427 * Copies the metafile corresponding to hSrcMetaFile to either
428 * a disk file, if a filename is given, or to a new memory based
429 * metafile, if lpFileName is NULL.
431 * RETURNS
433 * Handle to metafile copy on success, NULL on failure.
435 * BUGS
437 * Copying to disk returns NULL even if successful.
439 HMETAFILE WINAPI CopyMetaFileA(
440 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
441 LPCSTR lpFilename /* [in] filename if copying to a file */
443 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
444 METAHEADER *mh2 = NULL;
445 HANDLE hFile;
447 TRACE("(%p,%s)\n", hSrcMetaFile, lpFilename);
449 if(!mh) return 0;
451 if(mh->mtType == METAFILE_DISK)
452 mh2 = MF_LoadDiskBasedMetaFile(mh);
453 else {
454 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
455 memcpy( mh2, mh, mh->mtSize * 2 );
458 if(lpFilename) { /* disk based metafile */
459 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
460 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
461 HeapFree( GetProcessHeap(), 0, mh2 );
462 return 0;
464 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
465 CloseHandle(hFile);
466 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
469 return MF_Create_HMETAFILE( mh2 );
473 /******************************************************************
474 * CopyMetaFileW (GDI32.@)
476 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile,
477 LPCWSTR lpFilename )
479 HMETAFILE ret = 0;
480 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, NULL, 0, NULL, NULL );
481 LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
483 if (p)
485 WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, p, len, NULL, NULL );
486 ret = CopyMetaFileA( hSrcMetaFile, p );
487 HeapFree( GetProcessHeap(), 0, p );
489 return ret;
493 /******************************************************************
494 * IsValidMetaFile (GDI.410)
496 * Attempts to check if a given metafile is correctly formatted.
497 * Currently, the only things verified are several properties of the
498 * header.
500 * RETURNS
501 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
503 * BUGS
504 * This is not exactly what windows does, see _Undocumented_Windows_
505 * for details.
507 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
509 BOOL16 res=FALSE;
510 METAHEADER *mh = MF_GetMetaHeader16(hmf);
511 if (mh) {
512 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
513 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
514 if (mh->mtVersion == MFVERSION)
515 res=TRUE;
516 MF_ReleaseMetaHeader16(hmf);
518 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
519 return res;
523 /*******************************************************************
524 * MF_PlayMetaFile
526 * Helper for PlayMetaFile
528 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
531 METARECORD *mr;
532 HANDLETABLE *ht;
533 unsigned int offset = 0;
534 WORD i;
535 HPEN hPen;
536 HBRUSH hBrush;
537 HFONT hFont;
538 BOOL loaded = FALSE;
540 if (!mh) return FALSE;
541 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
542 mh = MF_LoadDiskBasedMetaFile(mh);
543 if(!mh) return FALSE;
544 loaded = TRUE;
547 /* save the current pen, brush and font */
548 hPen = GetCurrentObject(hdc, OBJ_PEN);
549 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
550 hFont = GetCurrentObject(hdc, OBJ_FONT);
552 /* create the handle table */
553 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
554 sizeof(HANDLETABLE) * mh->mtNoObjects);
555 if(!ht) return FALSE;
557 /* loop through metafile playing records */
558 offset = mh->mtHeaderSize * 2;
559 while (offset < mh->mtSize * 2)
561 mr = (METARECORD *)((char *)mh + offset);
562 TRACE("offset=%04x,size=%08lx\n",
563 offset, mr->rdSize);
564 if (!mr->rdSize) {
565 TRACE(
566 "Entry got size 0 at offset %d, total mf length is %ld\n",
567 offset,mh->mtSize*2);
568 break; /* would loop endlessly otherwise */
570 offset += mr->rdSize * 2;
571 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
574 SelectObject(hdc, hBrush);
575 SelectObject(hdc, hPen);
576 SelectObject(hdc, hFont);
578 /* free objects in handle table */
579 for(i = 0; i < mh->mtNoObjects; i++)
580 if(*(ht->objectHandle + i) != 0)
581 DeleteObject(*(ht->objectHandle + i));
583 /* free handle table */
584 HeapFree( GetProcessHeap(), 0, ht );
585 if(loaded)
586 HeapFree( GetProcessHeap(), 0, mh );
587 return TRUE;
590 /******************************************************************
591 * PlayMetaFile (GDI.123)
594 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
596 BOOL16 ret;
597 METAHEADER *mh = MF_GetMetaHeader16( hmf );
598 ret = MF_PlayMetaFile( HDC_32(hdc), mh );
599 MF_ReleaseMetaHeader16( hmf );
600 return ret;
603 /******************************************************************
604 * PlayMetaFile (GDI32.@)
606 * Renders the metafile specified by hmf in the DC specified by
607 * hdc. Returns FALSE on failure, TRUE on success.
609 BOOL WINAPI PlayMetaFile(
610 HDC hdc, /* [in] handle of DC to render in */
611 HMETAFILE hmf /* [in] handle of metafile to render */
614 METAHEADER *mh = MF_GetMetaHeader( hmf );
615 return MF_PlayMetaFile( hdc, mh );
619 /******************************************************************
620 * EnumMetaFile (GDI.175)
623 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
624 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
626 METAHEADER *mh = MF_GetMetaHeader16(hmf);
627 METARECORD *mr;
628 HANDLETABLE16 *ht;
629 HDC hdc = HDC_32(hdc16);
630 HGLOBAL16 hHT;
631 SEGPTR spht;
632 unsigned int offset = 0;
633 WORD i, seg;
634 HPEN hPen;
635 HBRUSH hBrush;
636 HFONT hFont;
637 BOOL16 result = TRUE, loaded = FALSE;
639 TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
641 if(!mh) return FALSE;
642 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
643 mh = MF_LoadDiskBasedMetaFile(mh);
644 if(!mh) return FALSE;
645 loaded = TRUE;
648 /* save the current pen, brush and font */
649 hPen = GetCurrentObject(hdc, OBJ_PEN);
650 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
651 hFont = GetCurrentObject(hdc, OBJ_FONT);
653 /* create the handle table */
655 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
656 sizeof(HANDLETABLE16) * mh->mtNoObjects);
657 spht = K32WOWGlobalLock16(hHT);
659 seg = hmf | 7;
660 offset = mh->mtHeaderSize * 2;
662 /* loop through metafile records */
664 while (offset < (mh->mtSize * 2))
666 mr = (METARECORD *)((char *)mh + offset);
668 if (!MF_CallTo16_word_wllwl( lpEnumFunc, hdc16, spht,
669 MAKESEGPTR( seg + (HIWORD(offset) << __AHSHIFT), LOWORD(offset) ),
670 mh->mtNoObjects, (LONG)lpData ))
672 result = FALSE;
673 break;
677 offset += (mr->rdSize * 2);
680 SelectObject(hdc, hBrush);
681 SelectObject(hdc, hPen);
682 SelectObject(hdc, hFont);
684 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
686 /* free objects in handle table */
687 for(i = 0; i < mh->mtNoObjects; i++)
688 if(*(ht->objectHandle + i) != 0)
689 DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
691 /* free handle table */
692 GlobalFree16(hHT);
693 if(loaded)
694 HeapFree( GetProcessHeap(), 0, mh );
695 MF_ReleaseMetaHeader16(hmf);
696 return result;
699 /******************************************************************
700 * EnumMetaFile (GDI32.@)
702 * Loop through the metafile records in hmf, calling the user-specified
703 * function for each one, stopping when the user's function returns FALSE
704 * (which is considered to be failure)
705 * or when no records are left (which is considered to be success).
707 * RETURNS
708 * TRUE on success, FALSE on failure.
710 * HISTORY
711 * Niels de carpentier, april 1996
713 BOOL WINAPI EnumMetaFile(
714 HDC hdc,
715 HMETAFILE hmf,
716 MFENUMPROC lpEnumFunc,
717 LPARAM lpData
719 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
720 METARECORD *mr;
721 HANDLETABLE *ht;
722 BOOL result = TRUE;
723 int i;
724 unsigned int offset = 0;
725 HPEN hPen;
726 HBRUSH hBrush;
727 HFONT hFont;
729 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
730 if (!mh) return 0;
731 if(mh->mtType == METAFILE_DISK)
733 /* Create a memory-based copy */
734 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
735 mh = mhTemp;
738 /* save the current pen, brush and font */
739 hPen = GetCurrentObject(hdc, OBJ_PEN);
740 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
741 hFont = GetCurrentObject(hdc, OBJ_FONT);
743 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
744 sizeof(HANDLETABLE) * mh->mtNoObjects);
746 /* loop through metafile records */
747 offset = mh->mtHeaderSize * 2;
749 while (offset < (mh->mtSize * 2))
751 mr = (METARECORD *)((char *)mh + offset);
752 if(mr->rdFunction == META_EOF) {
753 TRACE("Got META_EOF so stopping\n");
754 break;
756 TRACE("Calling EnumFunc with record type %x\n",
757 mr->rdFunction);
758 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
760 result = FALSE;
761 break;
764 offset += (mr->rdSize * 2);
767 /* restore pen, brush and font */
768 SelectObject(hdc, hBrush);
769 SelectObject(hdc, hPen);
770 SelectObject(hdc, hFont);
772 /* free objects in handle table */
773 for(i = 0; i < mh->mtNoObjects; i++)
774 if(*(ht->objectHandle + i) != 0)
775 DeleteObject(*(ht->objectHandle + i));
777 /* free handle table */
778 HeapFree( GetProcessHeap(), 0, ht);
779 /* free a copy of metafile */
780 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
781 return result;
784 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
785 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
786 /******************************************************************
787 * PlayMetaFileRecord (GDI32.@)
789 * Render a single metafile record specified by *mr in the DC hdc, while
790 * using the handle table *ht, of length handles,
791 * to store metafile objects.
793 * BUGS
794 * The following metafile records are unimplemented:
796 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
797 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
798 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
800 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
802 short s1;
803 POINT *pt;
804 BITMAPINFOHEADER *infohdr;
806 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
808 switch (mr->rdFunction)
810 case META_EOF:
811 break;
813 case META_DELETEOBJECT:
814 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
815 *(ht->objectHandle + mr->rdParm[0]) = 0;
816 break;
818 case META_SETBKCOLOR:
819 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
820 break;
822 case META_SETBKMODE:
823 SetBkMode(hdc, mr->rdParm[0]);
824 break;
826 case META_SETMAPMODE:
827 SetMapMode(hdc, mr->rdParm[0]);
828 break;
830 case META_SETROP2:
831 SetROP2(hdc, mr->rdParm[0]);
832 break;
834 case META_SETRELABS:
835 SetRelAbs(hdc, mr->rdParm[0]);
836 break;
838 case META_SETPOLYFILLMODE:
839 SetPolyFillMode(hdc, mr->rdParm[0]);
840 break;
842 case META_SETSTRETCHBLTMODE:
843 SetStretchBltMode(hdc, mr->rdParm[0]);
844 break;
846 case META_SETTEXTCOLOR:
847 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
848 break;
850 case META_SETWINDOWORG:
851 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
852 break;
854 case META_SETWINDOWEXT:
855 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
856 break;
858 case META_SETVIEWPORTORG:
859 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
860 break;
862 case META_SETVIEWPORTEXT:
863 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
864 break;
866 case META_OFFSETWINDOWORG:
867 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
868 break;
870 case META_SCALEWINDOWEXT:
871 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
872 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
873 break;
875 case META_OFFSETVIEWPORTORG:
876 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
877 break;
879 case META_SCALEVIEWPORTEXT:
880 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
881 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
882 break;
884 case META_LINETO:
885 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
886 break;
888 case META_MOVETO:
889 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
890 break;
892 case META_EXCLUDECLIPRECT:
893 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
894 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
895 break;
897 case META_INTERSECTCLIPRECT:
898 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
899 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
900 break;
902 case META_ARC:
903 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
904 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
905 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
906 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
907 break;
909 case META_ELLIPSE:
910 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
911 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
912 break;
914 case META_FLOODFILL:
915 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
916 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
917 break;
919 case META_PIE:
920 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
921 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
922 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
923 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
924 break;
926 case META_RECTANGLE:
927 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
928 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
929 break;
931 case META_ROUNDRECT:
932 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
933 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
934 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
935 break;
937 case META_PATBLT:
938 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
939 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
940 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
941 break;
943 case META_SAVEDC:
944 SaveDC(hdc);
945 break;
947 case META_SETPIXEL:
948 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
949 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
950 break;
952 case META_OFFSETCLIPRGN:
953 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
954 break;
956 case META_TEXTOUT:
957 s1 = mr->rdParm[0];
958 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
959 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
960 (char *)(mr->rdParm + 1), s1);
961 break;
963 case META_POLYGON:
964 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
966 Polygon(hdc, pt, mr->rdParm[0]);
967 HeapFree( GetProcessHeap(), 0, pt );
969 break;
971 case META_POLYPOLYGON:
973 UINT i, total;
974 SHORT *counts = (SHORT *)(mr->rdParm + 1);
976 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
977 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
978 if (pt)
980 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
981 if (cnt32)
983 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
984 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
985 HeapFree( GetProcessHeap(), 0, cnt32 );
988 HeapFree( GetProcessHeap(), 0, pt );
990 break;
992 case META_POLYLINE:
993 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
995 Polyline( hdc, pt, mr->rdParm[0] );
996 HeapFree( GetProcessHeap(), 0, pt );
998 break;
1000 case META_RESTOREDC:
1001 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1002 break;
1004 case META_SELECTOBJECT:
1005 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1006 break;
1008 case META_CHORD:
1009 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1010 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1011 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1012 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1013 break;
1015 case META_CREATEPATTERNBRUSH:
1016 switch (mr->rdParm[0])
1018 case BS_PATTERN:
1019 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1020 MF_AddHandle(ht, handles,
1021 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1022 infohdr->biHeight,
1023 infohdr->biPlanes,
1024 infohdr->biBitCount,
1025 (LPSTR)(mr->rdParm +
1026 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1027 break;
1029 case BS_DIBPATTERN:
1030 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1031 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1032 break;
1034 default:
1035 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1036 mr->rdParm[0]);
1037 break;
1039 break;
1041 case META_CREATEPENINDIRECT:
1043 LOGPEN pen;
1044 pen.lopnStyle = mr->rdParm[0];
1045 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1046 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1047 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1048 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1050 break;
1052 case META_CREATEFONTINDIRECT:
1054 LOGFONTA font;
1055 font.lfHeight = (SHORT)mr->rdParm[0];
1056 font.lfWidth = (SHORT)mr->rdParm[1];
1057 font.lfEscapement = (SHORT)mr->rdParm[2];
1058 font.lfOrientation = (SHORT)mr->rdParm[3];
1059 font.lfWeight = (SHORT)mr->rdParm[4];
1060 font.lfItalic = LOBYTE(mr->rdParm[5]);
1061 font.lfUnderline = HIBYTE(mr->rdParm[5]);
1062 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
1063 font.lfCharSet = HIBYTE(mr->rdParm[6]);
1064 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
1065 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
1066 font.lfQuality = LOBYTE(mr->rdParm[8]);
1067 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1068 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1069 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1071 break;
1073 case META_CREATEBRUSHINDIRECT:
1075 LOGBRUSH brush;
1076 brush.lbStyle = mr->rdParm[0];
1077 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1078 brush.lbHatch = mr->rdParm[3];
1079 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1081 break;
1083 case META_CREATEPALETTE:
1084 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1085 break;
1087 case META_SETTEXTALIGN:
1088 SetTextAlign(hdc, mr->rdParm[0]);
1089 break;
1091 case META_SELECTPALETTE:
1092 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1093 break;
1095 case META_SETMAPPERFLAGS:
1096 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1097 break;
1099 case META_REALIZEPALETTE:
1100 GDIRealizePalette(hdc);
1101 break;
1103 case META_ESCAPE:
1104 FIXME("META_ESCAPE unimplemented.\n");
1105 break;
1107 case META_EXTTEXTOUT:
1108 MF_Play_MetaExtTextOut( hdc, mr );
1109 break;
1111 case META_STRETCHDIB:
1113 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1114 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1115 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1116 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1117 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1118 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1120 break;
1122 case META_DIBSTRETCHBLT:
1124 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1125 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1126 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1127 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1128 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1129 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1131 break;
1133 case META_STRETCHBLT:
1135 HDC hdcSrc = CreateCompatibleDC(hdc);
1136 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1137 mr->rdParm[11], /*Height*/
1138 mr->rdParm[13], /*Planes*/
1139 mr->rdParm[14], /*BitsPixel*/
1140 (LPSTR)&mr->rdParm[15]); /*bits*/
1141 SelectObject(hdcSrc,hbitmap);
1142 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1143 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1144 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1145 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1146 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1147 DeleteDC(hdcSrc);
1149 break;
1151 case META_BITBLT:
1153 HDC hdcSrc = CreateCompatibleDC(hdc);
1154 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1155 mr->rdParm[8]/*Height*/,
1156 mr->rdParm[10]/*Planes*/,
1157 mr->rdParm[11]/*BitsPixel*/,
1158 (LPSTR)&mr->rdParm[12]/*bits*/);
1159 SelectObject(hdcSrc,hbitmap);
1160 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1161 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1162 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1163 MAKELONG(0,mr->rdParm[0]));
1164 DeleteDC(hdcSrc);
1166 break;
1168 case META_CREATEREGION:
1170 HRGN hrgn = CreateRectRgn(0,0,0,0);
1172 MF_Play_MetaCreateRegion(mr, hrgn);
1173 MF_AddHandle(ht, handles, hrgn);
1175 break;
1177 case META_FILLREGION:
1178 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1179 *(ht->objectHandle + mr->rdParm[0]));
1180 break;
1182 case META_FRAMEREGION:
1183 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1184 *(ht->objectHandle + mr->rdParm[2]),
1185 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1186 break;
1188 case META_INVERTREGION:
1189 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1190 break;
1192 case META_PAINTREGION:
1193 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1194 break;
1196 case META_SELECTCLIPREGION:
1197 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1198 break;
1200 case META_DIBCREATEPATTERNBRUSH:
1201 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1202 but there's no difference */
1203 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1204 break;
1206 case META_DIBBITBLT:
1207 /* In practice I've found that there are two layouts for
1208 META_DIBBITBLT, one (the first here) is the usual one when a src
1209 dc is actually passed to it, the second occurs when the src dc is
1210 passed in as NULL to the creating BitBlt. As the second case has
1211 no dib, a size check will suffice to distinguish.
1213 Caolan.McNamara@ul.ie */
1215 if (mr->rdSize > 12) {
1216 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1217 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1219 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1220 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1221 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1222 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1224 else /* equivalent to a PatBlt */
1225 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1226 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1227 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1228 break;
1230 case META_SETTEXTCHAREXTRA:
1231 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1232 break;
1234 case META_SETTEXTJUSTIFICATION:
1235 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1236 break;
1238 case META_EXTFLOODFILL:
1239 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1240 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1241 mr->rdParm[0]);
1242 break;
1244 case META_SETDIBTODEV:
1246 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1247 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1248 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1249 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1250 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1251 mr->rdParm[2], mr->rdParm[1], bits, info,
1252 mr->rdParm[0]);
1253 break;
1256 #define META_UNIMP(x) case x: \
1257 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1258 break;
1259 META_UNIMP(META_DRAWTEXT)
1260 META_UNIMP(META_ANIMATEPALETTE)
1261 META_UNIMP(META_SETPALENTRIES)
1262 META_UNIMP(META_RESIZEPALETTE)
1263 META_UNIMP(META_RESETDC)
1264 META_UNIMP(META_STARTDOC)
1265 META_UNIMP(META_STARTPAGE)
1266 META_UNIMP(META_ENDPAGE)
1267 META_UNIMP(META_ABORTDOC)
1268 META_UNIMP(META_ENDDOC)
1269 META_UNIMP(META_CREATEBRUSH)
1270 META_UNIMP(META_CREATEBITMAPINDIRECT)
1271 META_UNIMP(META_CREATEBITMAP)
1272 #undef META_UNIMP
1274 default:
1275 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1276 return FALSE;
1278 return TRUE;
1281 /******************************************************************
1282 * GetMetaFileBits (GDI.159)
1284 * Trade in a metafile object handle for a handle to the metafile memory.
1288 HGLOBAL16 WINAPI GetMetaFileBits16(
1289 HMETAFILE16 hmf /* [in] metafile handle */
1292 TRACE("hMem out: %04x\n", hmf);
1293 return hmf;
1296 /******************************************************************
1297 * SetMetaFileBits (GDI.160)
1299 * Trade in a metafile memory handle for a handle to a metafile object.
1300 * The memory region should hold a proper metafile, otherwise
1301 * problems will occur when it is used. Validity of the memory is not
1302 * checked. The function is essentially just the identity function.
1304 HMETAFILE16 WINAPI SetMetaFileBits16(
1305 HGLOBAL16 hMem
1306 /* [in] handle to a memory region holding a metafile */
1309 TRACE("hmf out: %04x\n", hMem);
1311 return hMem;
1314 /******************************************************************
1315 * SetMetaFileBitsBetter (GDI.196)
1317 * Trade in a metafile memory handle for a handle to a metafile object,
1318 * making a cursory check (using IsValidMetaFile()) that the memory
1319 * handle points to a valid metafile.
1321 * RETURNS
1322 * Handle to a metafile on success, NULL on failure..
1324 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1326 if( IsValidMetaFile16( hMeta ) )
1327 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1328 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1329 return (HMETAFILE16)0;
1332 /******************************************************************
1333 * SetMetaFileBitsEx (GDI32.@)
1335 * Create a metafile from raw data. No checking of the data is performed.
1336 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1338 HMETAFILE WINAPI SetMetaFileBitsEx(
1339 UINT size, /* [in] size of metafile, in bytes */
1340 const BYTE *lpData /* [in] pointer to metafile data */
1343 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1344 if (!mh) return 0;
1345 memcpy(mh, lpData, size);
1346 return MF_Create_HMETAFILE(mh);
1349 /*****************************************************************
1350 * GetMetaFileBitsEx (GDI32.@) Get raw metafile data
1352 * Copies the data from metafile _hmf_ into the buffer _buf_.
1353 * If _buf_ is zero, returns size of buffer required. Otherwise,
1354 * returns number of bytes copied.
1356 UINT WINAPI GetMetaFileBitsEx(
1357 HMETAFILE hmf, /* [in] metafile */
1358 UINT nSize, /* [in] size of buf */
1359 LPVOID buf /* [out] buffer to receive raw metafile data */
1361 METAHEADER *mh = MF_GetMetaHeader(hmf);
1362 UINT mfSize;
1364 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1365 if (!mh) return 0; /* FIXME: error code */
1366 if(mh->mtType == METAFILE_DISK)
1367 FIXME("Disk-based metafile?\n");
1368 mfSize = mh->mtSize * 2;
1369 if (!buf) {
1370 TRACE("returning size %d\n", mfSize);
1371 return mfSize;
1373 if(mfSize > nSize) mfSize = nSize;
1374 memmove(buf, mh, mfSize);
1375 return mfSize;
1378 /******************************************************************
1379 * GetWinMetaFileBits [GDI32.@]
1381 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1382 UINT cbBuffer, LPBYTE lpbBuffer,
1383 INT fnMapMode, HDC hdcRef)
1385 HDC hdcmf;
1386 HMETAFILE hmf;
1387 UINT ret;
1389 FIXME("(%p,%d,%p,%d,%p): stub\n", 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;