Reimplemented GetVolumeInformation and SetVolumeLabel; volume label
[wine.git] / objects / metafile.c
blob1c8e70c4b0ce9259bc4dbd6671a7dddad2da2e3e
1 /*
2 * Metafile functions
4 * Copyright David W. Metcalfe, 1994
5 * Niels de Carpentier, Albrecht Kleine, Huw Davies 1996
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * These functions are primarily involved with metafile playback or anything
24 * that touches a HMETAFILE.
25 * For recording of metafiles look in graphics/metafiledrv/
27 * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
28 * global memory handles so these cannot be interchanged.
30 * Memory-based metafiles are just stored as a continuous block of memory with
31 * a METAHEADER at the head with METARECORDs appended to it. mtType is
32 * METAFILE_MEMORY (1). Note this is indentical to the disk image of a
33 * disk-based metafile - even mtType is METAFILE_MEMORY.
34 * 16bit HMETAFILE16s are global handles to this block
35 * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
36 * the memory.
37 * Disk-based metafiles are rather different. HMETAFILE16s point to a
38 * METAHEADER which has mtType equal to METAFILE_DISK (2). Following the 9
39 * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
40 * more 0, then 2 which may be a time stamp of the file and then the path of
41 * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
43 * HDMD - 14/4/1999
46 #include "config.h"
48 #include <string.h>
49 #include <fcntl.h>
51 #include "wine/winbase16.h"
52 #include "wine/wingdi16.h"
53 #include "gdi.h"
54 #include "wownt32.h"
55 #include "winreg.h"
56 #include "winternl.h"
57 #include "gdi_private.h"
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
62 #include "pshpack1.h"
63 typedef struct
65 DWORD dw1, dw2, dw3;
66 WORD w4;
67 CHAR filename[0x100];
68 } METAHEADERDISK;
69 #include "poppack.h"
71 typedef struct
73 GDIOBJHDR header;
74 METAHEADER *mh;
75 } METAFILEOBJ;
77 #define MFHEADERSIZE (sizeof(METAHEADER))
78 #define MFVERSION 0x300
81 /******************************************************************
82 * MF_AddHandle
84 * Add a handle to an external handle table and return the index
86 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
88 int i;
90 for (i = 0; i < htlen; i++)
92 if (*(ht->objectHandle + i) == 0)
94 *(ht->objectHandle + i) = hobj;
95 return i;
98 return -1;
102 /******************************************************************
103 * MF_Create_HMETATFILE
105 * Creates a (32 bit) HMETAFILE object from a METAHEADER
107 * HMETAFILEs are GDI objects.
109 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
111 HMETAFILE hmf = 0;
112 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
113 (HGDIOBJ *)&hmf, NULL );
114 if (metaObj)
116 metaObj->mh = mh;
117 GDI_ReleaseObj( hmf );
119 return hmf;
122 /******************************************************************
123 * MF_Create_HMETATFILE16
125 * Creates a HMETAFILE16 object from a METAHEADER
127 * HMETAFILE16s are Global memory handles.
129 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
131 HMETAFILE16 hmf;
132 DWORD size = mh->mtSize * sizeof(WORD);
134 hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
135 if(hmf)
137 METAHEADER *mh_dest = GlobalLock16(hmf);
138 memcpy(mh_dest, mh, size);
139 GlobalUnlock16(hmf);
141 HeapFree(GetProcessHeap(), 0, mh);
142 return hmf;
145 /******************************************************************
146 * MF_GetMetaHeader
148 * Returns ptr to METAHEADER associated with HMETAFILE
150 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
152 METAHEADER *ret = NULL;
153 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
154 if (metaObj)
156 ret = metaObj->mh;
157 GDI_ReleaseObj( hmf );
159 return ret;
162 /******************************************************************
163 * MF_GetMetaHeader16
165 * Returns ptr to METAHEADER associated with HMETAFILE16
166 * Should be followed by call to MF_ReleaseMetaHeader16
168 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
170 return GlobalLock16(hmf);
173 /******************************************************************
174 * MF_ReleaseMetaHeader16
176 * Releases METAHEADER associated with HMETAFILE16
178 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
180 return GlobalUnlock16( hmf );
184 /******************************************************************
185 * convert_points
187 * Convert an array of POINT16 to an array of POINT.
188 * Result must be freed by caller.
190 static POINT *convert_points( UINT count, POINT16 *pt16 )
192 UINT i;
193 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
194 if (ret)
196 for (i = 0; i < count; i++)
198 ret[i].x = pt16[i].x;
199 ret[i].y = pt16[i].y;
202 return ret;
206 /******************************************************************
207 * DeleteMetaFile (GDI.127)
209 BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
211 return !GlobalFree16( hmf );
214 /******************************************************************
215 * DeleteMetaFile (GDI32.@)
217 * Delete a memory-based metafile.
220 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
222 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
223 if (!metaObj) return FALSE;
224 HeapFree( GetProcessHeap(), 0, metaObj->mh );
225 GDI_FreeObject( hmf, metaObj );
226 return TRUE;
229 /******************************************************************
230 * MF_ReadMetaFile
232 * Returns a pointer to a memory based METAHEADER read in from file HFILE
235 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
237 METAHEADER *mh;
238 DWORD BytesRead, size;
240 size = sizeof(METAHEADER);
241 mh = HeapAlloc( GetProcessHeap(), 0, size );
242 if(!mh) return NULL;
243 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
244 BytesRead != size) {
245 HeapFree( GetProcessHeap(), 0, mh );
246 return NULL;
248 size = mh->mtSize * 2;
249 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
250 if(!mh) return NULL;
251 size -= sizeof(METAHEADER);
252 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
253 NULL) == 0 ||
254 BytesRead != size) {
255 HeapFree( GetProcessHeap(), 0, mh );
256 return NULL;
259 if (mh->mtType != METAFILE_MEMORY) {
260 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
261 mh->mtType = METAFILE_MEMORY;
263 return mh;
266 /******************************************************************
267 * GetMetaFile (GDI.124)
269 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
271 METAHEADER *mh;
272 HANDLE hFile;
274 TRACE("%s\n", lpFilename);
276 if(!lpFilename)
277 return 0;
279 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
280 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
281 return 0;
283 mh = MF_ReadMetaFile(hFile);
284 CloseHandle(hFile);
285 if(!mh) return 0;
286 return MF_Create_HMETAFILE16( mh );
289 /******************************************************************
290 * GetMetaFileA (GDI32.@)
292 * Read a metafile from a file. Returns handle to a memory-based metafile.
294 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
296 METAHEADER *mh;
297 HANDLE hFile;
299 TRACE("%s\n", lpFilename);
301 if(!lpFilename)
302 return 0;
304 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
305 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
306 return 0;
308 mh = MF_ReadMetaFile(hFile);
309 CloseHandle(hFile);
310 if(!mh) return 0;
311 return MF_Create_HMETAFILE( mh );
316 /******************************************************************
317 * GetMetaFileW (GDI32.@)
319 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
321 METAHEADER *mh;
322 HANDLE hFile;
324 TRACE("%s\n", debugstr_w(lpFilename));
326 if(!lpFilename)
327 return 0;
329 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
330 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
331 return 0;
333 mh = MF_ReadMetaFile(hFile);
334 CloseHandle(hFile);
335 if(!mh) return 0;
336 return MF_Create_HMETAFILE( mh );
340 /******************************************************************
341 * MF_LoadDiskBasedMetaFile
343 * Creates a new memory-based metafile from a disk-based one.
345 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
347 METAHEADERDISK *mhd;
348 HANDLE hfile;
349 METAHEADER *mh2;
351 if(mh->mtType != METAFILE_DISK) {
352 ERR("Not a disk based metafile\n");
353 return NULL;
355 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
357 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
358 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
359 WARN("Can't open file of disk based metafile\n");
360 return NULL;
362 mh2 = MF_ReadMetaFile(hfile);
363 CloseHandle(hfile);
364 return mh2;
367 /******************************************************************
368 * MF_CreateMetaHeaderDisk
370 * Take a memory based METAHEADER and change it to a disk based METAHEADER
371 * assosiated with filename. Note: Trashes contents of old one.
373 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
375 METAHEADERDISK *mhd;
376 DWORD size;
378 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
379 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
380 mh->mtType = METAFILE_DISK;
381 size = HeapSize( GetProcessHeap(), 0, mh );
382 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
383 strcpy(mhd->filename, filename);
384 return mh;
387 /******************************************************************
388 * CopyMetaFile (GDI.151)
390 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
392 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
393 METAHEADER *mh2 = NULL;
394 HANDLE hFile;
396 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
398 if(!mh) return 0;
400 if(mh->mtType == METAFILE_DISK)
401 mh2 = MF_LoadDiskBasedMetaFile(mh);
402 else {
403 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
404 memcpy( mh2, mh, mh->mtSize * 2 );
406 MF_ReleaseMetaHeader16( hSrcMetaFile );
408 if(lpFilename) { /* disk based metafile */
409 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
410 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
411 HeapFree( GetProcessHeap(), 0, mh2 );
412 return 0;
414 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
415 CloseHandle(hFile);
416 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
419 return MF_Create_HMETAFILE16( mh2 );
423 /******************************************************************
424 * CopyMetaFileW (GDI32.@)
426 * Copies the metafile corresponding to hSrcMetaFile to either
427 * a disk file, if a filename is given, or to a new memory based
428 * metafile, if lpFileName is NULL.
430 * RETURNS
432 * Handle to metafile copy on success, NULL on failure.
434 * BUGS
436 * Copying to disk returns NULL even if successful.
438 HMETAFILE WINAPI CopyMetaFileW(
439 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
440 LPCWSTR lpFilename /* [in] filename if copying to a file */)
442 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
443 METAHEADER *mh2 = NULL;
444 HANDLE hFile;
446 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
448 if(!mh) return 0;
450 if(mh->mtType == METAFILE_DISK)
451 mh2 = MF_LoadDiskBasedMetaFile(mh);
452 else {
453 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
454 memcpy( mh2, mh, mh->mtSize * 2 );
457 if(lpFilename) { /* disk based metafile */
458 DWORD len;
459 LPSTR lpFilenameA;
460 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
461 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
462 HeapFree( GetProcessHeap(), 0, mh2 );
463 return 0;
465 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
466 CloseHandle(hFile);
467 len = WideCharToMultiByte(CP_ACP, 0, lpFilename, -1, NULL, 0, NULL, NULL);
468 lpFilenameA = HeapAlloc(GetProcessHeap(), 0, len);
469 WideCharToMultiByte(CP_ACP, 0, lpFilename, -1, lpFilenameA, len, NULL, NULL);
470 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilenameA);
471 HeapFree(GetProcessHeap(), 0, lpFilenameA);
474 return MF_Create_HMETAFILE( mh2 );
478 /******************************************************************
479 * CopyMetaFileA (GDI32.@)
481 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile,
482 LPCSTR lpFilename )
484 UNICODE_STRING lpFilenameW;
485 HMETAFILE ret = 0;
487 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
488 else lpFilenameW.Buffer = NULL;
490 if (lpFilenameW.Buffer) {
491 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
493 RtlFreeUnicodeString(&lpFilenameW);
494 return ret;
498 /******************************************************************
499 * IsValidMetaFile (GDI.410)
501 * Attempts to check if a given metafile is correctly formatted.
502 * Currently, the only things verified are several properties of the
503 * header.
505 * RETURNS
506 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
508 * BUGS
509 * This is not exactly what windows does, see _Undocumented_Windows_
510 * for details.
512 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
514 BOOL16 res=FALSE;
515 METAHEADER *mh = MF_GetMetaHeader16(hmf);
516 if (mh) {
517 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
518 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
519 if (mh->mtVersion == MFVERSION)
520 res=TRUE;
521 MF_ReleaseMetaHeader16(hmf);
523 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
524 return res;
528 /*******************************************************************
529 * MF_PlayMetaFile
531 * Helper for PlayMetaFile
533 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
536 METARECORD *mr;
537 HANDLETABLE *ht;
538 unsigned int offset = 0;
539 WORD i;
540 HPEN hPen;
541 HBRUSH hBrush;
542 HFONT hFont;
543 BOOL loaded = FALSE;
545 if (!mh) return FALSE;
546 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
547 mh = MF_LoadDiskBasedMetaFile(mh);
548 if(!mh) return FALSE;
549 loaded = TRUE;
552 /* save the current pen, brush and font */
553 hPen = GetCurrentObject(hdc, OBJ_PEN);
554 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
555 hFont = GetCurrentObject(hdc, OBJ_FONT);
557 /* create the handle table */
558 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
559 sizeof(HANDLETABLE) * mh->mtNoObjects);
560 if(!ht) return FALSE;
562 /* loop through metafile playing records */
563 offset = mh->mtHeaderSize * 2;
564 while (offset < mh->mtSize * 2)
566 mr = (METARECORD *)((char *)mh + offset);
567 TRACE("offset=%04x,size=%08lx\n",
568 offset, mr->rdSize);
569 if (!mr->rdSize) {
570 TRACE(
571 "Entry got size 0 at offset %d, total mf length is %ld\n",
572 offset,mh->mtSize*2);
573 break; /* would loop endlessly otherwise */
575 offset += mr->rdSize * 2;
576 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
579 SelectObject(hdc, hBrush);
580 SelectObject(hdc, hPen);
581 SelectObject(hdc, hFont);
583 /* free objects in handle table */
584 for(i = 0; i < mh->mtNoObjects; i++)
585 if(*(ht->objectHandle + i) != 0)
586 DeleteObject(*(ht->objectHandle + i));
588 /* free handle table */
589 HeapFree( GetProcessHeap(), 0, ht );
590 if(loaded)
591 HeapFree( GetProcessHeap(), 0, mh );
592 return TRUE;
595 /******************************************************************
596 * PlayMetaFile (GDI.123)
599 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
601 BOOL16 ret;
602 METAHEADER *mh = MF_GetMetaHeader16( hmf );
603 ret = MF_PlayMetaFile( HDC_32(hdc), mh );
604 MF_ReleaseMetaHeader16( hmf );
605 return ret;
608 /******************************************************************
609 * PlayMetaFile (GDI32.@)
611 * Renders the metafile specified by hmf in the DC specified by
612 * hdc. Returns FALSE on failure, TRUE on success.
614 BOOL WINAPI PlayMetaFile(
615 HDC hdc, /* [in] handle of DC to render in */
616 HMETAFILE hmf /* [in] handle of metafile to render */
619 METAHEADER *mh = MF_GetMetaHeader( hmf );
620 return MF_PlayMetaFile( hdc, mh );
624 /******************************************************************
625 * EnumMetaFile (GDI.175)
628 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc16, HMETAFILE16 hmf,
629 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
631 METAHEADER *mh = MF_GetMetaHeader16(hmf);
632 METARECORD *mr;
633 HANDLETABLE16 *ht;
634 HDC hdc = HDC_32(hdc16);
635 HGLOBAL16 hHT;
636 SEGPTR spht;
637 unsigned int offset = 0;
638 WORD i, seg;
639 HPEN hPen;
640 HBRUSH hBrush;
641 HFONT hFont;
642 WORD args[8];
643 BOOL16 result = TRUE, loaded = FALSE;
645 TRACE("(%p, %04x, %p, %08lx)\n", hdc, hmf, lpEnumFunc, lpData);
647 if(!mh) return FALSE;
648 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
649 mh = MF_LoadDiskBasedMetaFile(mh);
650 if(!mh) return FALSE;
651 loaded = TRUE;
654 /* save the current pen, brush and font */
655 hPen = GetCurrentObject(hdc, OBJ_PEN);
656 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
657 hFont = GetCurrentObject(hdc, OBJ_FONT);
659 /* create the handle table */
661 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
662 sizeof(HANDLETABLE16) * mh->mtNoObjects);
663 spht = K32WOWGlobalLock16(hHT);
665 seg = hmf | 7;
666 offset = mh->mtHeaderSize * 2;
668 /* loop through metafile records */
670 args[7] = hdc16;
671 args[6] = SELECTOROF(spht);
672 args[5] = OFFSETOF(spht);
673 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
674 args[3] = LOWORD(offset);
675 args[2] = mh->mtNoObjects;
676 args[1] = HIWORD(lpData);
677 args[0] = LOWORD(lpData);
679 while (offset < (mh->mtSize * 2))
681 DWORD ret;
683 mr = (METARECORD *)((char *)mh + offset);
685 WOWCallback16Ex( (DWORD)lpEnumFunc, WCB16_PASCAL, sizeof(args), args, &ret );
686 if (!LOWORD(ret))
688 result = FALSE;
689 break;
692 offset += (mr->rdSize * 2);
693 args[4] = seg + (HIWORD(offset) << __AHSHIFT);
694 args[3] = LOWORD(offset);
697 SelectObject(hdc, hBrush);
698 SelectObject(hdc, hPen);
699 SelectObject(hdc, hFont);
701 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
703 /* free objects in handle table */
704 for(i = 0; i < mh->mtNoObjects; i++)
705 if(*(ht->objectHandle + i) != 0)
706 DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));
708 /* free handle table */
709 GlobalFree16(hHT);
710 if(loaded)
711 HeapFree( GetProcessHeap(), 0, mh );
712 MF_ReleaseMetaHeader16(hmf);
713 return result;
716 /******************************************************************
717 * EnumMetaFile (GDI32.@)
719 * Loop through the metafile records in hmf, calling the user-specified
720 * function for each one, stopping when the user's function returns FALSE
721 * (which is considered to be failure)
722 * or when no records are left (which is considered to be success).
724 * RETURNS
725 * TRUE on success, FALSE on failure.
727 * HISTORY
728 * Niels de carpentier, april 1996
730 BOOL WINAPI EnumMetaFile(
731 HDC hdc,
732 HMETAFILE hmf,
733 MFENUMPROC lpEnumFunc,
734 LPARAM lpData)
736 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
737 METARECORD *mr;
738 HANDLETABLE *ht;
739 BOOL result = TRUE;
740 int i;
741 unsigned int offset = 0;
742 HPEN hPen;
743 HBRUSH hBrush;
744 HFONT hFont;
746 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
747 if (!mh) return 0;
748 if(mh->mtType == METAFILE_DISK)
750 /* Create a memory-based copy */
751 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
752 mh = mhTemp;
755 /* save the current pen, brush and font */
756 hPen = GetCurrentObject(hdc, OBJ_PEN);
757 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
758 hFont = GetCurrentObject(hdc, OBJ_FONT);
760 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
761 sizeof(HANDLETABLE) * mh->mtNoObjects);
763 /* loop through metafile records */
764 offset = mh->mtHeaderSize * 2;
766 while (offset < (mh->mtSize * 2))
768 mr = (METARECORD *)((char *)mh + offset);
769 if(mr->rdFunction == META_EOF) {
770 TRACE("Got META_EOF so stopping\n");
771 break;
773 TRACE("Calling EnumFunc with record type %x\n",
774 mr->rdFunction);
775 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
777 result = FALSE;
778 break;
781 offset += (mr->rdSize * 2);
784 /* restore pen, brush and font */
785 SelectObject(hdc, hBrush);
786 SelectObject(hdc, hPen);
787 SelectObject(hdc, hFont);
789 /* free objects in handle table */
790 for(i = 0; i < mh->mtNoObjects; i++)
791 if(*(ht->objectHandle + i) != 0)
792 DeleteObject(*(ht->objectHandle + i));
794 /* free handle table */
795 HeapFree( GetProcessHeap(), 0, ht);
796 /* free a copy of metafile */
797 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
798 return result;
801 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
802 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
803 /******************************************************************
804 * PlayMetaFileRecord (GDI32.@)
806 * Render a single metafile record specified by *mr in the DC hdc, while
807 * using the handle table *ht, of length handles,
808 * to store metafile objects.
810 * BUGS
811 * The following metafile records are unimplemented:
813 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
814 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
815 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
817 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
819 short s1;
820 POINT *pt;
821 BITMAPINFOHEADER *infohdr;
823 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
825 switch (mr->rdFunction)
827 case META_EOF:
828 break;
830 case META_DELETEOBJECT:
831 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
832 *(ht->objectHandle + mr->rdParm[0]) = 0;
833 break;
835 case META_SETBKCOLOR:
836 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
837 break;
839 case META_SETBKMODE:
840 SetBkMode(hdc, mr->rdParm[0]);
841 break;
843 case META_SETMAPMODE:
844 SetMapMode(hdc, mr->rdParm[0]);
845 break;
847 case META_SETROP2:
848 SetROP2(hdc, mr->rdParm[0]);
849 break;
851 case META_SETRELABS:
852 SetRelAbs(hdc, mr->rdParm[0]);
853 break;
855 case META_SETPOLYFILLMODE:
856 SetPolyFillMode(hdc, mr->rdParm[0]);
857 break;
859 case META_SETSTRETCHBLTMODE:
860 SetStretchBltMode(hdc, mr->rdParm[0]);
861 break;
863 case META_SETTEXTCOLOR:
864 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
865 break;
867 case META_SETWINDOWORG:
868 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
869 break;
871 case META_SETWINDOWEXT:
872 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
873 break;
875 case META_SETVIEWPORTORG:
876 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
877 break;
879 case META_SETVIEWPORTEXT:
880 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
881 break;
883 case META_OFFSETWINDOWORG:
884 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
885 break;
887 case META_SCALEWINDOWEXT:
888 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
889 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
890 break;
892 case META_OFFSETVIEWPORTORG:
893 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
894 break;
896 case META_SCALEVIEWPORTEXT:
897 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
898 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
899 break;
901 case META_LINETO:
902 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
903 break;
905 case META_MOVETO:
906 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
907 break;
909 case META_EXCLUDECLIPRECT:
910 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
911 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
912 break;
914 case META_INTERSECTCLIPRECT:
915 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
916 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
917 break;
919 case META_ARC:
920 Arc(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_ELLIPSE:
927 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
928 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
929 break;
931 case META_FLOODFILL:
932 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
933 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
934 break;
936 case META_PIE:
937 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
938 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
939 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
940 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
941 break;
943 case META_RECTANGLE:
944 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
945 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
946 break;
948 case META_ROUNDRECT:
949 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
950 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
951 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
952 break;
954 case META_PATBLT:
955 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
956 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
957 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
958 break;
960 case META_SAVEDC:
961 SaveDC(hdc);
962 break;
964 case META_SETPIXEL:
965 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
966 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
967 break;
969 case META_OFFSETCLIPRGN:
970 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
971 break;
973 case META_TEXTOUT:
974 s1 = mr->rdParm[0];
975 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
976 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
977 (char *)(mr->rdParm + 1), s1);
978 break;
980 case META_POLYGON:
981 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
983 Polygon(hdc, pt, mr->rdParm[0]);
984 HeapFree( GetProcessHeap(), 0, pt );
986 break;
988 case META_POLYPOLYGON:
990 UINT i, total;
991 SHORT *counts = (SHORT *)(mr->rdParm + 1);
993 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
994 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
995 if (pt)
997 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
998 if (cnt32)
1000 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
1001 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
1002 HeapFree( GetProcessHeap(), 0, cnt32 );
1005 HeapFree( GetProcessHeap(), 0, pt );
1007 break;
1009 case META_POLYLINE:
1010 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
1012 Polyline( hdc, pt, mr->rdParm[0] );
1013 HeapFree( GetProcessHeap(), 0, pt );
1015 break;
1017 case META_RESTOREDC:
1018 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
1019 break;
1021 case META_SELECTOBJECT:
1022 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
1023 break;
1025 case META_CHORD:
1026 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1027 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1028 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1029 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1030 break;
1032 case META_CREATEPATTERNBRUSH:
1033 switch (mr->rdParm[0])
1035 case BS_PATTERN:
1036 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1037 MF_AddHandle(ht, handles,
1038 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
1039 infohdr->biHeight,
1040 infohdr->biPlanes,
1041 infohdr->biBitCount,
1042 (LPSTR)(mr->rdParm +
1043 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
1044 break;
1046 case BS_DIBPATTERN:
1047 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
1048 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
1049 break;
1051 default:
1052 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
1053 mr->rdParm[0]);
1054 break;
1056 break;
1058 case META_CREATEPENINDIRECT:
1060 LOGPEN pen;
1061 pen.lopnStyle = mr->rdParm[0];
1062 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
1063 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
1064 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
1065 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
1067 break;
1069 case META_CREATEFONTINDIRECT:
1071 LOGFONTA font;
1072 font.lfHeight = (SHORT)mr->rdParm[0];
1073 font.lfWidth = (SHORT)mr->rdParm[1];
1074 font.lfEscapement = (SHORT)mr->rdParm[2];
1075 font.lfOrientation = (SHORT)mr->rdParm[3];
1076 font.lfWeight = (SHORT)mr->rdParm[4];
1077 font.lfItalic = LOBYTE(mr->rdParm[5]);
1078 font.lfUnderline = HIBYTE(mr->rdParm[5]);
1079 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
1080 font.lfCharSet = HIBYTE(mr->rdParm[6]);
1081 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
1082 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
1083 font.lfQuality = LOBYTE(mr->rdParm[8]);
1084 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
1085 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
1086 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
1088 break;
1090 case META_CREATEBRUSHINDIRECT:
1092 LOGBRUSH brush;
1093 brush.lbStyle = mr->rdParm[0];
1094 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
1095 brush.lbHatch = mr->rdParm[3];
1096 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
1098 break;
1100 case META_CREATEPALETTE:
1101 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
1102 break;
1104 case META_SETTEXTALIGN:
1105 SetTextAlign(hdc, mr->rdParm[0]);
1106 break;
1108 case META_SELECTPALETTE:
1109 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
1110 break;
1112 case META_SETMAPPERFLAGS:
1113 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1114 break;
1116 case META_REALIZEPALETTE:
1117 GDIRealizePalette(hdc);
1118 break;
1120 case META_ESCAPE:
1121 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
1122 break;
1124 case META_EXTTEXTOUT:
1125 MF_Play_MetaExtTextOut( hdc, mr );
1126 break;
1128 case META_STRETCHDIB:
1130 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1131 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1132 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1133 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1134 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
1135 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1137 break;
1139 case META_DIBSTRETCHBLT:
1141 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1142 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1143 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1144 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1145 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
1146 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1148 break;
1150 case META_STRETCHBLT:
1152 HDC hdcSrc = CreateCompatibleDC(hdc);
1153 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
1154 mr->rdParm[11], /*Height*/
1155 mr->rdParm[13], /*Planes*/
1156 mr->rdParm[14], /*BitsPixel*/
1157 (LPSTR)&mr->rdParm[15]); /*bits*/
1158 SelectObject(hdcSrc,hbitmap);
1159 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
1160 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
1161 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
1162 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1163 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1164 DeleteDC(hdcSrc);
1166 break;
1168 case META_BITBLT:
1170 HDC hdcSrc = CreateCompatibleDC(hdc);
1171 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
1172 mr->rdParm[8]/*Height*/,
1173 mr->rdParm[10]/*Planes*/,
1174 mr->rdParm[11]/*BitsPixel*/,
1175 (LPSTR)&mr->rdParm[12]/*bits*/);
1176 SelectObject(hdcSrc,hbitmap);
1177 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
1178 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
1179 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
1180 MAKELONG(0,mr->rdParm[0]));
1181 DeleteDC(hdcSrc);
1183 break;
1185 case META_CREATEREGION:
1187 HRGN hrgn = CreateRectRgn(0,0,0,0);
1189 MF_Play_MetaCreateRegion(mr, hrgn);
1190 MF_AddHandle(ht, handles, hrgn);
1192 break;
1194 case META_FILLREGION:
1195 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
1196 *(ht->objectHandle + mr->rdParm[0]));
1197 break;
1199 case META_FRAMEREGION:
1200 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
1201 *(ht->objectHandle + mr->rdParm[2]),
1202 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1203 break;
1205 case META_INVERTREGION:
1206 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1207 break;
1209 case META_PAINTREGION:
1210 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1211 break;
1213 case META_SELECTCLIPREGION:
1214 SelectClipRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
1215 break;
1217 case META_DIBCREATEPATTERNBRUSH:
1218 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
1219 but there's no difference */
1220 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1221 break;
1223 case META_DIBBITBLT:
1224 /* In practice I've found that there are two layouts for
1225 META_DIBBITBLT, one (the first here) is the usual one when a src
1226 dc is actually passed to it, the second occurs when the src dc is
1227 passed in as NULL to the creating BitBlt. As the second case has
1228 no dib, a size check will suffice to distinguish.
1230 Caolan.McNamara@ul.ie */
1232 if (mr->rdSize > 12) {
1233 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1234 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1236 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1237 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1238 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1239 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1241 else /* equivalent to a PatBlt */
1242 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1243 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1244 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1245 break;
1247 case META_SETTEXTCHAREXTRA:
1248 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1249 break;
1251 case META_SETTEXTJUSTIFICATION:
1252 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1253 break;
1255 case META_EXTFLOODFILL:
1256 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1257 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1258 mr->rdParm[0]);
1259 break;
1261 case META_SETDIBTODEV:
1263 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1264 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1265 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1266 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1267 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1268 mr->rdParm[2], mr->rdParm[1], bits, info,
1269 mr->rdParm[0]);
1270 break;
1273 #define META_UNIMP(x) case x: \
1274 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1275 break;
1276 META_UNIMP(META_DRAWTEXT)
1277 META_UNIMP(META_ANIMATEPALETTE)
1278 META_UNIMP(META_SETPALENTRIES)
1279 META_UNIMP(META_RESIZEPALETTE)
1280 META_UNIMP(META_RESETDC)
1281 META_UNIMP(META_STARTDOC)
1282 META_UNIMP(META_STARTPAGE)
1283 META_UNIMP(META_ENDPAGE)
1284 META_UNIMP(META_ABORTDOC)
1285 META_UNIMP(META_ENDDOC)
1286 META_UNIMP(META_CREATEBRUSH)
1287 META_UNIMP(META_CREATEBITMAPINDIRECT)
1288 META_UNIMP(META_CREATEBITMAP)
1289 #undef META_UNIMP
1291 default:
1292 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1293 return FALSE;
1295 return TRUE;
1298 /******************************************************************
1299 * GetMetaFileBits (GDI.159)
1301 * Trade in a metafile object handle for a handle to the metafile memory.
1305 HGLOBAL16 WINAPI GetMetaFileBits16(
1306 HMETAFILE16 hmf /* [in] metafile handle */
1309 TRACE("hMem out: %04x\n", hmf);
1310 return hmf;
1313 /******************************************************************
1314 * SetMetaFileBits (GDI.160)
1316 * Trade in a metafile memory handle for a handle to a metafile object.
1317 * The memory region should hold a proper metafile, otherwise
1318 * problems will occur when it is used. Validity of the memory is not
1319 * checked. The function is essentially just the identity function.
1321 HMETAFILE16 WINAPI SetMetaFileBits16(
1322 HGLOBAL16 hMem
1323 /* [in] handle to a memory region holding a metafile */
1326 TRACE("hmf out: %04x\n", hMem);
1328 return hMem;
1331 /******************************************************************
1332 * SetMetaFileBitsBetter (GDI.196)
1334 * Trade in a metafile memory handle for a handle to a metafile object,
1335 * making a cursory check (using IsValidMetaFile()) that the memory
1336 * handle points to a valid metafile.
1338 * RETURNS
1339 * Handle to a metafile on success, NULL on failure..
1341 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1343 if( IsValidMetaFile16( hMeta ) )
1344 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1345 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1346 return (HMETAFILE16)0;
1349 /******************************************************************
1350 * SetMetaFileBitsEx (GDI32.@)
1352 * Create a metafile from raw data. No checking of the data is performed.
1353 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1355 HMETAFILE WINAPI SetMetaFileBitsEx(
1356 UINT size, /* [in] size of metafile, in bytes */
1357 const BYTE *lpData /* [in] pointer to metafile data */
1360 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1361 if (!mh) return 0;
1362 memcpy(mh, lpData, size);
1363 return MF_Create_HMETAFILE(mh);
1366 /*****************************************************************
1367 * GetMetaFileBitsEx (GDI32.@)
1369 * Get raw metafile data.
1371 * Copies the data from metafile _hmf_ into the buffer _buf_.
1372 * If _buf_ is zero, returns size of buffer required. Otherwise,
1373 * returns number of bytes copied.
1375 UINT WINAPI GetMetaFileBitsEx(
1376 HMETAFILE hmf, /* [in] metafile */
1377 UINT nSize, /* [in] size of buf */
1378 LPVOID buf /* [out] buffer to receive raw metafile data */)
1380 METAHEADER *mh = MF_GetMetaHeader(hmf);
1381 UINT mfSize;
1383 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1384 if (!mh) return 0; /* FIXME: error code */
1385 if(mh->mtType == METAFILE_DISK)
1386 FIXME("Disk-based metafile?\n");
1387 mfSize = mh->mtSize * 2;
1388 if (!buf) {
1389 TRACE("returning size %d\n", mfSize);
1390 return mfSize;
1392 if(mfSize > nSize) mfSize = nSize;
1393 memmove(buf, mh, mfSize);
1394 return mfSize;
1397 /******************************************************************
1398 * GetWinMetaFileBits [GDI32.@]
1400 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1401 UINT cbBuffer, LPBYTE lpbBuffer,
1402 INT fnMapMode, HDC hdcRef)
1404 HDC hdcmf;
1405 HMETAFILE hmf;
1406 UINT ret;
1407 RECT rc;
1408 INT oldMapMode;
1410 GetClipBox(hdcRef, &rc);
1411 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1413 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1414 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1416 hdcmf = CreateMetaFileA(NULL);
1417 PlayEnhMetaFile(hdcmf, hemf, &rc);
1418 hmf = CloseMetaFile(hdcmf);
1419 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1420 DeleteMetaFile(hmf);
1422 SetMapMode(hdcRef, oldMapMode);
1424 return ret;
1427 /******************************************************************
1428 * MF_Play_MetaCreateRegion
1430 * Handles META_CREATEREGION for PlayMetaFileRecord().
1434 * The layout of the record looks something like this:
1436 * rdParm meaning
1437 * 0 Always 0?
1438 * 1 Always 6?
1439 * 2 Looks like a handle? - not constant
1440 * 3 0 or 1 ??
1441 * 4 Total number of bytes
1442 * 5 No. of separate bands = n [see below]
1443 * 6 Largest number of x co-ords in a band
1444 * 7-10 Bounding box x1 y1 x2 y2
1445 * 11-... n bands
1447 * Regions are divided into bands that are uniform in the
1448 * y-direction. Each band consists of pairs of on/off x-coords and is
1449 * written as
1450 * m y0 y1 x1 x2 x3 ... xm m
1451 * into successive rdParm[]s.
1453 * This is probably just a dump of the internal RGNOBJ?
1455 * HDMD - 18/12/97
1459 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1461 WORD band, pair;
1462 WORD *start, *end;
1463 INT16 y0, y1;
1464 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1466 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1467 band++, start = end + 1) {
1468 if(*start / 2 != (*start + 1) / 2) {
1469 WARN("Delimiter not even.\n");
1470 DeleteObject( hrgn2 );
1471 return FALSE;
1474 end = start + *start + 3;
1475 if(end > (WORD *)mr + mr->rdSize) {
1476 WARN("End points outside record.\n");
1477 DeleteObject( hrgn2 );
1478 return FALSE;
1481 if(*start != *end) {
1482 WARN("Mismatched delimiters.\n");
1483 DeleteObject( hrgn2 );
1484 return FALSE;
1487 y0 = *(INT16 *)(start + 1);
1488 y1 = *(INT16 *)(start + 2);
1489 for(pair = 0; pair < *start / 2; pair++) {
1490 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1491 *(INT16 *)(start + 4 + 2*pair), y1 );
1492 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1495 DeleteObject( hrgn2 );
1496 return TRUE;
1500 /******************************************************************
1501 * MF_Play_MetaExtTextOut
1503 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1506 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1508 INT *dx = NULL;
1509 int i;
1510 LPINT16 dxx;
1511 LPSTR sot;
1512 DWORD len;
1513 WORD s1;
1514 RECT rect;
1515 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1517 s1 = mr->rdParm[2]; /* String length */
1518 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1519 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1520 /* rec len without dx array */
1522 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1523 if (isrect)
1525 rect.left = (SHORT)mr->rdParm[4];
1526 rect.top = (SHORT)mr->rdParm[5];
1527 rect.right = (SHORT)mr->rdParm[6];
1528 rect.bottom = (SHORT)mr->rdParm[7];
1529 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1532 if (mr->rdSize == len / 2)
1533 dxx = NULL; /* determine if array present */
1534 else
1535 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1537 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1538 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1539 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1541 else {
1542 TRACE("%s len: %ld\n", sot, mr->rdSize);
1543 WARN(
1544 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1545 len, s1, mr->rdSize, mr->rdParm[3]);
1546 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1548 ExtTextOutA( hdc,
1549 (SHORT)mr->rdParm[1], /* X position */
1550 (SHORT)mr->rdParm[0], /* Y position */
1551 mr->rdParm[3], /* options */
1552 &rect, /* rectangle */
1553 sot, /* string */
1554 s1, dx); /* length, dx array */
1555 if (dx)
1557 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1558 HeapFree( GetProcessHeap(), 0, dx );
1560 return TRUE;