Added function table to GDI objects for better encapsulation.
[wine.git] / objects / metafile.c
blob2953e982e99b8bb0aa0808a69440e865d8b958f5
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
44 */
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 "metafile.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
61 #include "pshpack1.h"
62 typedef struct
64 DWORD dw1, dw2, dw3;
65 WORD w4;
66 CHAR filename[0x100];
67 } METAHEADERDISK;
68 #include "poppack.h"
70 #define MFHEADERSIZE (sizeof(METAHEADER))
71 #define MFVERSION 0x300
73 /* ### start build ### */
74 extern WORD CALLBACK MF_CallTo16_word_wllwl(MFENUMPROC16,WORD,LONG,LONG,WORD,LONG);
75 /* ### stop build ### */
77 /******************************************************************
78 * MF_AddHandle
80 * Add a handle to an external handle table and return the index
82 static int MF_AddHandle(HANDLETABLE16 *ht, WORD htlen, HGDIOBJ16 hobj)
84 int i;
86 for (i = 0; i < htlen; i++)
88 if (*(ht->objectHandle + i) == 0)
90 *(ht->objectHandle + i) = hobj;
91 return i;
94 return -1;
98 /******************************************************************
99 * MF_Create_HMETATFILE
101 * Creates a (32 bit) HMETAFILE object from a METAHEADER
103 * HMETAFILEs are GDI objects.
105 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
107 HMETAFILE hmf = 0;
108 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC, &hmf, NULL );
109 if (metaObj)
111 metaObj->mh = mh;
112 GDI_ReleaseObj( hmf );
114 return hmf;
117 /******************************************************************
118 * MF_Create_HMETATFILE16
120 * Creates a HMETAFILE16 object from a METAHEADER
122 * HMETAFILE16s are Global memory handles.
124 HMETAFILE16 MF_Create_HMETAFILE16(METAHEADER *mh)
126 HMETAFILE16 hmf;
127 DWORD size = mh->mtSize * sizeof(WORD);
129 hmf = GlobalAlloc16(GMEM_MOVEABLE, size);
130 if(hmf)
132 METAHEADER *mh_dest = GlobalLock16(hmf);
133 memcpy(mh_dest, mh, size);
134 GlobalUnlock16(hmf);
136 HeapFree(GetProcessHeap(), 0, mh);
137 return hmf;
140 /******************************************************************
141 * MF_GetMetaHeader
143 * Returns ptr to METAHEADER associated with HMETAFILE
145 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
147 METAHEADER *ret = NULL;
148 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
149 if (metaObj)
151 ret = metaObj->mh;
152 GDI_ReleaseObj( hmf );
154 return ret;
157 /******************************************************************
158 * MF_GetMetaHeader16
160 * Returns ptr to METAHEADER associated with HMETAFILE16
161 * Should be followed by call to MF_ReleaseMetaHeader16
163 static METAHEADER *MF_GetMetaHeader16( HMETAFILE16 hmf )
165 return GlobalLock16(hmf);
168 /******************************************************************
169 * MF_ReleaseMetaHeader16
171 * Releases METAHEADER associated with HMETAFILE16
173 static BOOL16 MF_ReleaseMetaHeader16( HMETAFILE16 hmf )
175 return GlobalUnlock16( hmf );
179 /******************************************************************
180 * DeleteMetaFile (GDI.127)
182 BOOL16 WINAPI DeleteMetaFile16( HMETAFILE16 hmf )
184 return !GlobalFree16( hmf );
187 /******************************************************************
188 * DeleteMetaFile (GDI32.@)
190 * Delete a memory-based metafile.
193 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
195 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
196 if (!metaObj) return FALSE;
197 HeapFree( GetProcessHeap(), 0, metaObj->mh );
198 GDI_FreeObject( hmf, metaObj );
199 return TRUE;
202 /******************************************************************
203 * MF_ReadMetaFile
205 * Returns a pointer to a memory based METAHEADER read in from file HFILE
208 static METAHEADER *MF_ReadMetaFile(HFILE hfile)
210 METAHEADER *mh;
211 DWORD BytesRead, size;
213 size = sizeof(METAHEADER);
214 mh = HeapAlloc( GetProcessHeap(), 0, size );
215 if(!mh) return NULL;
216 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
217 BytesRead != size) {
218 HeapFree( GetProcessHeap(), 0, mh );
219 return NULL;
221 size = mh->mtSize * 2;
222 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
223 if(!mh) return NULL;
224 size -= sizeof(METAHEADER);
225 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
226 NULL) == 0 ||
227 BytesRead != size) {
228 HeapFree( GetProcessHeap(), 0, mh );
229 return NULL;
232 if (mh->mtType != METAFILE_MEMORY) {
233 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
234 mh->mtType = METAFILE_MEMORY;
236 return mh;
239 /******************************************************************
240 * GetMetaFile (GDI.124)
242 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
244 METAHEADER *mh;
245 HANDLE hFile;
247 TRACE("%s\n", lpFilename);
249 if(!lpFilename)
250 return 0;
252 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
253 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
254 return 0;
256 mh = MF_ReadMetaFile(hFile);
257 CloseHandle(hFile);
258 if(!mh) return 0;
259 return MF_Create_HMETAFILE16( mh );
262 /******************************************************************
263 * GetMetaFileA (GDI32.@)
265 * Read a metafile from a file. Returns handle to a memory-based metafile.
267 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
269 METAHEADER *mh;
270 HANDLE hFile;
272 TRACE("%s\n", lpFilename);
274 if(!lpFilename)
275 return 0;
277 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
278 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
279 return 0;
281 mh = MF_ReadMetaFile(hFile);
282 CloseHandle(hFile);
283 if(!mh) return 0;
284 return MF_Create_HMETAFILE( mh );
289 /******************************************************************
290 * GetMetaFileW (GDI32.@)
292 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
294 METAHEADER *mh;
295 HANDLE hFile;
297 TRACE("%s\n", debugstr_w(lpFilename));
299 if(!lpFilename)
300 return 0;
302 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
303 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
304 return 0;
306 mh = MF_ReadMetaFile(hFile);
307 CloseHandle(hFile);
308 if(!mh) return 0;
309 return MF_Create_HMETAFILE( mh );
313 /******************************************************************
314 * MF_LoadDiskBasedMetaFile
316 * Creates a new memory-based metafile from a disk-based one.
318 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
320 METAHEADERDISK *mhd;
321 HANDLE hfile;
322 METAHEADER *mh2;
324 if(mh->mtType != METAFILE_DISK) {
325 ERR("Not a disk based metafile\n");
326 return NULL;
328 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
330 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
331 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
332 WARN("Can't open file of disk based metafile\n");
333 return NULL;
335 mh2 = MF_ReadMetaFile(hfile);
336 CloseHandle(hfile);
337 return mh2;
340 /******************************************************************
341 * MF_CreateMetaHeaderDisk
343 * Take a memory based METAHEADER and change it to a disk based METAHEADER
344 * assosiated with filename. Note: Trashes contents of old one.
346 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCSTR filename)
348 METAHEADERDISK *mhd;
349 DWORD size;
351 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
352 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
353 mh->mtType = METAFILE_DISK;
354 size = HeapSize( GetProcessHeap(), 0, mh );
355 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
356 strcpy(mhd->filename, filename);
357 return mh;
360 /******************************************************************
361 * CopyMetaFile (GDI.151)
363 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename)
365 METAHEADER *mh = MF_GetMetaHeader16( hSrcMetaFile );
366 METAHEADER *mh2 = NULL;
367 HANDLE hFile;
369 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
371 if(!mh) return 0;
373 if(mh->mtType == METAFILE_DISK)
374 mh2 = MF_LoadDiskBasedMetaFile(mh);
375 else {
376 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
377 memcpy( mh2, mh, mh->mtSize * 2 );
379 MF_ReleaseMetaHeader16( hSrcMetaFile );
381 if(lpFilename) { /* disk based metafile */
382 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
383 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
384 HeapFree( GetProcessHeap(), 0, mh2 );
385 return 0;
387 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
388 CloseHandle(hFile);
389 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
392 return MF_Create_HMETAFILE16( mh2 );
396 /******************************************************************
397 * CopyMetaFileA (GDI32.@)
399 * Copies the metafile corresponding to hSrcMetaFile to either
400 * a disk file, if a filename is given, or to a new memory based
401 * metafile, if lpFileName is NULL.
403 * RETURNS
405 * Handle to metafile copy on success, NULL on failure.
407 * BUGS
409 * Copying to disk returns NULL even if successful.
411 HMETAFILE WINAPI CopyMetaFileA(
412 HMETAFILE hSrcMetaFile, /* [in] handle of metafile to copy */
413 LPCSTR lpFilename /* [in] filename if copying to a file */
415 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
416 METAHEADER *mh2 = NULL;
417 HANDLE hFile;
419 TRACE("(%08x,%s)\n", hSrcMetaFile, lpFilename);
421 if(!mh) return 0;
423 if(mh->mtType == METAFILE_DISK)
424 mh2 = MF_LoadDiskBasedMetaFile(mh);
425 else {
426 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
427 memcpy( mh2, mh, mh->mtSize * 2 );
430 if(lpFilename) { /* disk based metafile */
431 if((hFile = CreateFileA(lpFilename, GENERIC_WRITE, 0, NULL,
432 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
433 HeapFree( GetProcessHeap(), 0, mh2 );
434 return 0;
436 WriteFile(hFile, mh2, mh2->mtSize * 2, NULL, NULL);
437 CloseHandle(hFile);
438 mh2 = MF_CreateMetaHeaderDisk(mh2, lpFilename);
441 return MF_Create_HMETAFILE( mh2 );
445 /******************************************************************
446 * CopyMetaFileW (GDI32.@)
448 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile,
449 LPCWSTR lpFilename )
451 HMETAFILE ret = 0;
452 DWORD len = WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, NULL, 0, NULL, NULL );
453 LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
455 if (p)
457 WideCharToMultiByte( CP_ACP, 0, lpFilename, -1, p, len, NULL, NULL );
458 ret = CopyMetaFileA( hSrcMetaFile, p );
459 HeapFree( GetProcessHeap(), 0, p );
461 return ret;
465 /******************************************************************
466 * IsValidMetaFile (GDI.410)
468 * Attempts to check if a given metafile is correctly formatted.
469 * Currently, the only things verified are several properties of the
470 * header.
472 * RETURNS
473 * TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
475 * BUGS
476 * This is not exactly what windows does, see _Undocumented_Windows_
477 * for details.
479 BOOL16 WINAPI IsValidMetaFile16(HMETAFILE16 hmf)
481 BOOL16 res=FALSE;
482 METAHEADER *mh = MF_GetMetaHeader16(hmf);
483 if (mh) {
484 if (mh->mtType == METAFILE_MEMORY || mh->mtType == METAFILE_DISK)
485 if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
486 if (mh->mtVersion == MFVERSION)
487 res=TRUE;
488 MF_ReleaseMetaHeader16(hmf);
490 TRACE("IsValidMetaFile %x => %d\n",hmf,res);
491 return res;
495 /*******************************************************************
496 * MF_PlayMetaFile
498 * Helper for PlayMetaFile
500 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
503 METARECORD *mr;
504 HANDLETABLE16 *ht;
505 unsigned int offset = 0;
506 WORD i;
507 HPEN hPen;
508 HBRUSH hBrush;
509 HFONT hFont;
510 BOOL loaded = FALSE;
512 if (!mh) return FALSE;
513 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
514 mh = MF_LoadDiskBasedMetaFile(mh);
515 if(!mh) return FALSE;
516 loaded = TRUE;
519 /* save the current pen, brush and font */
520 hPen = GetCurrentObject(hdc, OBJ_PEN);
521 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
522 hFont = GetCurrentObject(hdc, OBJ_FONT);
524 /* create the handle table */
525 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
526 sizeof(HANDLETABLE16) * mh->mtNoObjects);
527 if(!ht) return FALSE;
529 /* loop through metafile playing records */
530 offset = mh->mtHeaderSize * 2;
531 while (offset < mh->mtSize * 2)
533 mr = (METARECORD *)((char *)mh + offset);
534 TRACE("offset=%04x,size=%08lx\n",
535 offset, mr->rdSize);
536 if (!mr->rdSize) {
537 TRACE(
538 "Entry got size 0 at offset %d, total mf length is %ld\n",
539 offset,mh->mtSize*2);
540 break; /* would loop endlessly otherwise */
542 offset += mr->rdSize * 2;
543 PlayMetaFileRecord16( hdc, ht, mr, mh->mtNoObjects );
546 SelectObject(hdc, hBrush);
547 SelectObject(hdc, hPen);
548 SelectObject(hdc, hFont);
550 /* free objects in handle table */
551 for(i = 0; i < mh->mtNoObjects; i++)
552 if(*(ht->objectHandle + i) != 0)
553 DeleteObject(*(ht->objectHandle + i));
555 /* free handle table */
556 HeapFree( GetProcessHeap(), 0, ht );
557 if(loaded)
558 HeapFree( GetProcessHeap(), 0, mh );
559 return TRUE;
562 /******************************************************************
563 * PlayMetaFile (GDI.123)
566 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
568 BOOL16 ret;
569 METAHEADER *mh = MF_GetMetaHeader16( hmf );
570 ret = MF_PlayMetaFile( hdc, mh );
571 MF_ReleaseMetaHeader16( hmf );
572 return ret;
575 /******************************************************************
576 * PlayMetaFile (GDI32.@)
578 * Renders the metafile specified by hmf in the DC specified by
579 * hdc. Returns FALSE on failure, TRUE on success.
581 BOOL WINAPI PlayMetaFile(
582 HDC hdc, /* [in] handle of DC to render in */
583 HMETAFILE hmf /* [in] handle of metafile to render */
586 METAHEADER *mh = MF_GetMetaHeader( hmf );
587 return MF_PlayMetaFile( hdc, mh );
591 /******************************************************************
592 * EnumMetaFile (GDI.175)
595 BOOL16 WINAPI EnumMetaFile16( HDC16 hdc, HMETAFILE16 hmf,
596 MFENUMPROC16 lpEnumFunc, LPARAM lpData )
598 METAHEADER *mh = MF_GetMetaHeader16(hmf);
599 METARECORD *mr;
600 HANDLETABLE16 *ht;
601 HGLOBAL16 hHT;
602 SEGPTR spht;
603 unsigned int offset = 0;
604 WORD i, seg;
605 HPEN hPen;
606 HBRUSH hBrush;
607 HFONT hFont;
608 BOOL16 result = TRUE, loaded = FALSE;
610 TRACE("(%04x, %04x, %08lx, %08lx)\n",
611 hdc, hmf, (DWORD)lpEnumFunc, lpData);
614 if(!mh) return FALSE;
615 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
616 mh = MF_LoadDiskBasedMetaFile(mh);
617 if(!mh) return FALSE;
618 loaded = TRUE;
621 /* save the current pen, brush and font */
622 hPen = GetCurrentObject(hdc, OBJ_PEN);
623 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
624 hFont = GetCurrentObject(hdc, OBJ_FONT);
626 /* create the handle table */
628 hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
629 sizeof(HANDLETABLE16) * mh->mtNoObjects);
630 spht = K32WOWGlobalLock16(hHT);
632 seg = hmf | 7;
633 offset = mh->mtHeaderSize * 2;
635 /* loop through metafile records */
637 while (offset < (mh->mtSize * 2))
639 mr = (METARECORD *)((char *)mh + offset);
641 if (!MF_CallTo16_word_wllwl( lpEnumFunc, hdc, spht,
642 MAKESEGPTR( seg + (HIWORD(offset) << __AHSHIFT), LOWORD(offset) ),
643 mh->mtNoObjects, (LONG)lpData ))
645 result = FALSE;
646 break;
650 offset += (mr->rdSize * 2);
653 SelectObject(hdc, hBrush);
654 SelectObject(hdc, hPen);
655 SelectObject(hdc, hFont);
657 ht = (HANDLETABLE16 *)GlobalLock16(hHT);
659 /* free objects in handle table */
660 for(i = 0; i < mh->mtNoObjects; i++)
661 if(*(ht->objectHandle + i) != 0)
662 DeleteObject(*(ht->objectHandle + i));
664 /* free handle table */
665 GlobalFree16(hHT);
666 if(loaded)
667 HeapFree( GetProcessHeap(), 0, mh );
668 MF_ReleaseMetaHeader16(hmf);
669 return result;
672 /******************************************************************
673 * EnumMetaFile (GDI32.@)
675 * Loop through the metafile records in hmf, calling the user-specified
676 * function for each one, stopping when the user's function returns FALSE
677 * (which is considered to be failure)
678 * or when no records are left (which is considered to be success).
680 * RETURNS
681 * TRUE on success, FALSE on failure.
683 * HISTORY
684 * Niels de carpentier, april 1996
686 BOOL WINAPI EnumMetaFile(
687 HDC hdc,
688 HMETAFILE hmf,
689 MFENUMPROC lpEnumFunc,
690 LPARAM lpData
692 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
693 METARECORD *mr;
694 HANDLETABLE *ht;
695 BOOL result = TRUE;
696 int i;
697 unsigned int offset = 0;
698 HPEN hPen;
699 HBRUSH hBrush;
700 HFONT hFont;
702 TRACE("(%08x,%08x,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
703 if (!mh) return 0;
704 if(mh->mtType == METAFILE_DISK)
706 /* Create a memory-based copy */
707 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
708 mh = mhTemp;
711 /* save the current pen, brush and font */
712 hPen = GetCurrentObject(hdc, OBJ_PEN);
713 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
714 hFont = GetCurrentObject(hdc, OBJ_FONT);
716 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
717 sizeof(HANDLETABLE) * mh->mtNoObjects);
719 /* loop through metafile records */
720 offset = mh->mtHeaderSize * 2;
722 while (offset < (mh->mtSize * 2))
724 mr = (METARECORD *)((char *)mh + offset);
725 if(mr->rdFunction == META_EOF) {
726 TRACE("Got META_EOF so stopping\n");
727 break;
729 TRACE("Calling EnumFunc with record type %x\n",
730 mr->rdFunction);
731 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
733 result = FALSE;
734 break;
737 offset += (mr->rdSize * 2);
740 /* restore pen, brush and font */
741 SelectObject(hdc, hBrush);
742 SelectObject(hdc, hPen);
743 SelectObject(hdc, hFont);
745 /* free objects in handle table */
746 for(i = 0; i < mh->mtNoObjects; i++)
747 if(*(ht->objectHandle + i) != 0)
748 DeleteObject(*(ht->objectHandle + i));
750 /* free handle table */
751 HeapFree( GetProcessHeap(), 0, ht);
752 /* free a copy of metafile */
753 if (mhTemp) HeapFree( GetProcessHeap(), 0, mhTemp );
754 return result;
757 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
758 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr);
759 /******************************************************************
760 * PlayMetaFileRecord (GDI.176)
762 * Render a single metafile record specified by *mr in the DC hdc, while
763 * using the handle table *ht, of length nHandles,
764 * to store metafile objects.
766 * BUGS
767 * The following metafile records are unimplemented:
769 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
770 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
771 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
774 void WINAPI PlayMetaFileRecord16(
775 HDC16 hdc, /* [in] DC to render metafile into */
776 HANDLETABLE16 *ht, /* [in] pointer to handle table for metafile objects */
777 METARECORD *mr, /* [in] pointer to metafile record to render */
778 UINT16 nHandles /* [in] size of handle table */
780 short s1;
781 HANDLE16 hndl;
782 char *ptr;
783 BITMAPINFOHEADER *infohdr;
785 TRACE("(%04x %08lx %08lx %04x) function %04x\n",
786 hdc,(LONG)ht, (LONG)mr, nHandles, mr->rdFunction);
788 switch (mr->rdFunction)
790 case META_EOF:
791 break;
793 case META_DELETEOBJECT:
794 DeleteObject(*(ht->objectHandle + *(mr->rdParm)));
795 *(ht->objectHandle + *(mr->rdParm)) = 0;
796 break;
798 case META_SETBKCOLOR:
799 SetBkColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
800 break;
802 case META_SETBKMODE:
803 SetBkMode16(hdc, *(mr->rdParm));
804 break;
806 case META_SETMAPMODE:
807 SetMapMode16(hdc, *(mr->rdParm));
808 break;
810 case META_SETROP2:
811 SetROP216(hdc, *(mr->rdParm));
812 break;
814 case META_SETRELABS:
815 SetRelAbs16(hdc, *(mr->rdParm));
816 break;
818 case META_SETPOLYFILLMODE:
819 SetPolyFillMode16(hdc, *(mr->rdParm));
820 break;
822 case META_SETSTRETCHBLTMODE:
823 SetStretchBltMode16(hdc, *(mr->rdParm));
824 break;
826 case META_SETTEXTCOLOR:
827 SetTextColor16(hdc, MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
828 break;
830 case META_SETWINDOWORG:
831 SetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
832 break;
834 case META_SETWINDOWEXT:
835 SetWindowExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
836 break;
838 case META_SETVIEWPORTORG:
839 SetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
840 break;
842 case META_SETVIEWPORTEXT:
843 SetViewportExt16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
844 break;
846 case META_OFFSETWINDOWORG:
847 OffsetWindowOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
848 break;
850 case META_SCALEWINDOWEXT:
851 ScaleWindowExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
852 *(mr->rdParm + 1), *(mr->rdParm));
853 break;
855 case META_OFFSETVIEWPORTORG:
856 OffsetViewportOrg16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
857 break;
859 case META_SCALEVIEWPORTEXT:
860 ScaleViewportExt16(hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
861 *(mr->rdParm + 1), *(mr->rdParm));
862 break;
864 case META_LINETO:
865 LineTo(hdc, (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
866 break;
868 case META_MOVETO:
869 MoveTo16(hdc, *(mr->rdParm + 1), *(mr->rdParm));
870 break;
872 case META_EXCLUDECLIPRECT:
873 ExcludeClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
874 *(mr->rdParm + 1), *(mr->rdParm) );
875 break;
877 case META_INTERSECTCLIPRECT:
878 IntersectClipRect16( hdc, *(mr->rdParm + 3), *(mr->rdParm + 2),
879 *(mr->rdParm + 1), *(mr->rdParm) );
880 break;
882 case META_ARC:
883 Arc(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
884 (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
885 (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
886 (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
887 break;
889 case META_ELLIPSE:
890 Ellipse(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
891 (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
892 break;
894 case META_FLOODFILL:
895 FloodFill(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
896 MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
897 break;
899 case META_PIE:
900 Pie(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
901 (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
902 (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
903 (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
904 break;
906 case META_RECTANGLE:
907 Rectangle(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
908 (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
909 break;
911 case META_ROUNDRECT:
912 RoundRect(hdc, (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
913 (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
914 (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
915 break;
917 case META_PATBLT:
918 PatBlt16(hdc, *(mr->rdParm + 5), *(mr->rdParm + 4),
919 *(mr->rdParm + 3), *(mr->rdParm + 2),
920 MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
921 break;
923 case META_SAVEDC:
924 SaveDC(hdc);
925 break;
927 case META_SETPIXEL:
928 SetPixel(hdc, (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
929 MAKELONG(*(mr->rdParm), *(mr->rdParm + 1)));
930 break;
932 case META_OFFSETCLIPRGN:
933 OffsetClipRgn16( hdc, *(mr->rdParm + 1), *(mr->rdParm) );
934 break;
936 case META_TEXTOUT:
937 s1 = *(mr->rdParm);
938 TextOut16(hdc, *(mr->rdParm + ((s1 + 1) >> 1) + 2),
939 *(mr->rdParm + ((s1 + 1) >> 1) + 1),
940 (char *)(mr->rdParm + 1), s1);
941 break;
943 case META_POLYGON:
944 Polygon16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
945 break;
947 case META_POLYPOLYGON:
948 PolyPolygon16(hdc, (LPPOINT16)(mr->rdParm + *(mr->rdParm) + 1),
949 (LPINT16)(mr->rdParm + 1), *(mr->rdParm));
950 break;
952 case META_POLYLINE:
953 Polyline16(hdc, (LPPOINT16)(mr->rdParm + 1), *(mr->rdParm));
954 break;
956 case META_RESTOREDC:
957 RestoreDC(hdc, (INT16)*(mr->rdParm));
958 break;
960 case META_SELECTOBJECT:
961 SelectObject(hdc, *(ht->objectHandle + *(mr->rdParm)));
962 break;
964 case META_CHORD:
965 Chord(hdc, (INT16)*(mr->rdParm + 7), (INT16)*(mr->rdParm + 6),
966 (INT16)*(mr->rdParm + 5), (INT16)*(mr->rdParm + 4),
967 (INT16)*(mr->rdParm + 3), (INT16)*(mr->rdParm + 2),
968 (INT16)*(mr->rdParm + 1), (INT16)*(mr->rdParm));
969 break;
971 case META_CREATEPATTERNBRUSH:
972 switch (*(mr->rdParm))
974 case BS_PATTERN:
975 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
976 MF_AddHandle(ht, nHandles,
977 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
978 infohdr->biHeight,
979 infohdr->biPlanes,
980 infohdr->biBitCount,
981 (LPSTR)(mr->rdParm +
982 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
983 break;
985 case BS_DIBPATTERN:
986 s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
987 hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
988 ptr = GlobalLock16(hndl);
989 memcpy(ptr, mr->rdParm + 2, s1);
990 GlobalUnlock16(hndl);
991 MF_AddHandle(ht, nHandles,
992 CreateDIBPatternBrush(hndl, *(mr->rdParm + 1)));
993 GlobalFree16(hndl);
994 break;
996 default:
997 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
998 mr->rdParm[0]);
999 break;
1001 break;
1003 case META_CREATEPENINDIRECT:
1004 MF_AddHandle(ht, nHandles,
1005 CreatePenIndirect16((LOGPEN16 *)(&(mr->rdParm))));
1006 break;
1008 case META_CREATEFONTINDIRECT:
1009 MF_AddHandle(ht, nHandles,
1010 CreateFontIndirect16((LOGFONT16 *)(&(mr->rdParm))));
1011 break;
1013 case META_CREATEBRUSHINDIRECT:
1014 MF_AddHandle(ht, nHandles,
1015 CreateBrushIndirect16((LOGBRUSH16 *)(&(mr->rdParm))));
1016 break;
1018 case META_CREATEPALETTE:
1019 MF_AddHandle(ht, nHandles,
1020 CreatePalette16((LPLOGPALETTE)mr->rdParm));
1021 break;
1023 case META_SETTEXTALIGN:
1024 SetTextAlign16(hdc, *(mr->rdParm));
1025 break;
1027 case META_SELECTPALETTE:
1028 GDISelectPalette16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1029 *(mr->rdParm));
1030 break;
1032 case META_SETMAPPERFLAGS:
1033 SetMapperFlags16(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1034 break;
1036 case META_REALIZEPALETTE:
1037 GDIRealizePalette16(hdc);
1038 break;
1040 case META_ESCAPE:
1041 FIXME("META_ESCAPE unimplemented.\n");
1042 break;
1044 case META_EXTTEXTOUT:
1045 MF_Play_MetaExtTextOut( hdc, mr );
1046 break;
1048 case META_STRETCHDIB:
1050 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
1051 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1052 StretchDIBits16(hdc,mr->rdParm[10],mr->rdParm[9],mr->rdParm[8],
1053 mr->rdParm[7],mr->rdParm[6],mr->rdParm[5],
1054 mr->rdParm[4],mr->rdParm[3],bits,info,
1055 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1057 break;
1059 case META_DIBSTRETCHBLT:
1061 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
1062 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
1063 StretchDIBits16(hdc,mr->rdParm[9],mr->rdParm[8],mr->rdParm[7],
1064 mr->rdParm[6],mr->rdParm[5],mr->rdParm[4],
1065 mr->rdParm[3],mr->rdParm[2],bits,info,
1066 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1068 break;
1070 case META_STRETCHBLT:
1072 HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1073 HBITMAP hbitmap=CreateBitmap(mr->rdParm[10], /*Width */
1074 mr->rdParm[11], /*Height*/
1075 mr->rdParm[13], /*Planes*/
1076 mr->rdParm[14], /*BitsPixel*/
1077 (LPSTR)&mr->rdParm[15]); /*bits*/
1078 SelectObject(hdcSrc,hbitmap);
1079 StretchBlt16(hdc,mr->rdParm[9],mr->rdParm[8],
1080 mr->rdParm[7],mr->rdParm[6],
1081 hdcSrc,mr->rdParm[5],mr->rdParm[4],
1082 mr->rdParm[3],mr->rdParm[2],
1083 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
1084 DeleteDC(hdcSrc);
1086 break;
1088 case META_BITBLT:
1090 HDC16 hdcSrc=CreateCompatibleDC16(hdc);
1091 HBITMAP hbitmap=CreateBitmap(mr->rdParm[7]/*Width */,
1092 mr->rdParm[8]/*Height*/,
1093 mr->rdParm[10]/*Planes*/,
1094 mr->rdParm[11]/*BitsPixel*/,
1095 (LPSTR)&mr->rdParm[12]/*bits*/);
1096 SelectObject(hdcSrc,hbitmap);
1097 BitBlt(hdc,(INT16)mr->rdParm[6],(INT16)mr->rdParm[5],
1098 (INT16)mr->rdParm[4],(INT16)mr->rdParm[3],
1099 hdcSrc, (INT16)mr->rdParm[2],(INT16)mr->rdParm[1],
1100 MAKELONG(0,mr->rdParm[0]));
1101 DeleteDC(hdcSrc);
1103 break;
1105 case META_CREATEREGION:
1107 HRGN hrgn = CreateRectRgn(0,0,0,0);
1109 MF_Play_MetaCreateRegion(mr, hrgn);
1110 MF_AddHandle(ht, nHandles, hrgn);
1112 break;
1114 case META_FILLREGION:
1115 FillRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+1)),
1116 *(ht->objectHandle + *(mr->rdParm)));
1117 break;
1119 case META_FRAMEREGION:
1120 FrameRgn16(hdc, *(ht->objectHandle + *(mr->rdParm+3)),
1121 *(ht->objectHandle + *(mr->rdParm+2)),
1122 *(mr->rdParm+1), *(mr->rdParm));
1123 break;
1125 case META_INVERTREGION:
1126 InvertRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1127 break;
1129 case META_PAINTREGION:
1130 PaintRgn16(hdc, *(ht->objectHandle + *(mr->rdParm)));
1131 break;
1133 case META_SELECTCLIPREGION:
1134 SelectClipRgn(hdc, *(ht->objectHandle + *(mr->rdParm)));
1135 break;
1137 case META_DIBCREATEPATTERNBRUSH:
1138 /* *(mr->rdParm) may be BS_PATTERN or BS_DIBPATTERN:
1139 but there's no difference */
1141 TRACE("%d\n",*(mr->rdParm));
1142 s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
1143 hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
1144 ptr = GlobalLock16(hndl);
1145 memcpy(ptr, mr->rdParm + 2, s1);
1146 GlobalUnlock16(hndl);
1147 MF_AddHandle(ht, nHandles,
1148 CreateDIBPatternBrush16(hndl, *(mr->rdParm + 1)));
1149 GlobalFree16(hndl);
1150 break;
1152 case META_DIBBITBLT:
1153 /* In practice I've found that there are two layouts for
1154 META_DIBBITBLT, one (the first here) is the usual one when a src
1155 dc is actually passed to it, the second occurs when the src dc is
1156 passed in as NULL to the creating BitBlt. As the second case has
1157 no dib, a size check will suffice to distinguish.
1159 Caolan.McNamara@ul.ie */
1161 if (mr->rdSize > 12) {
1162 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1163 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1165 StretchDIBits16(hdc, mr->rdParm[7], mr->rdParm[6], mr->rdParm[5],
1166 mr->rdParm[4], mr->rdParm[3], mr->rdParm[2],
1167 mr->rdParm[5], mr->rdParm[4], bits, info,
1168 DIB_RGB_COLORS,
1169 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1170 } else { /* equivalent to a PatBlt */
1171 PatBlt16(hdc, mr->rdParm[8], mr->rdParm[7],
1172 mr->rdParm[6], mr->rdParm[5],
1173 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1175 break;
1177 case META_SETTEXTCHAREXTRA:
1178 SetTextCharacterExtra16(hdc, (INT16)*(mr->rdParm));
1179 break;
1181 case META_SETTEXTJUSTIFICATION:
1182 SetTextJustification(hdc, *(mr->rdParm + 1), *(mr->rdParm));
1183 break;
1185 case META_EXTFLOODFILL:
1186 ExtFloodFill(hdc, (INT16)*(mr->rdParm + 4), (INT16)*(mr->rdParm + 3),
1187 MAKELONG(*(mr->rdParm+1), *(mr->rdParm + 2)),
1188 *(mr->rdParm));
1189 break;
1191 case META_SETDIBTODEV:
1193 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1194 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1195 SetDIBitsToDevice(hdc, (INT16)mr->rdParm[8], (INT16)mr->rdParm[7],
1196 (INT16)mr->rdParm[6], (INT16)mr->rdParm[5],
1197 (INT16)mr->rdParm[4], (INT16)mr->rdParm[3],
1198 mr->rdParm[2], mr->rdParm[1], bits, info,
1199 mr->rdParm[0]);
1200 break;
1203 #define META_UNIMP(x) case x: \
1204 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1205 break;
1206 META_UNIMP(META_DRAWTEXT)
1207 META_UNIMP(META_ANIMATEPALETTE)
1208 META_UNIMP(META_SETPALENTRIES)
1209 META_UNIMP(META_RESIZEPALETTE)
1210 META_UNIMP(META_RESETDC)
1211 META_UNIMP(META_STARTDOC)
1212 META_UNIMP(META_STARTPAGE)
1213 META_UNIMP(META_ENDPAGE)
1214 META_UNIMP(META_ABORTDOC)
1215 META_UNIMP(META_ENDDOC)
1216 META_UNIMP(META_CREATEBRUSH)
1217 META_UNIMP(META_CREATEBITMAPINDIRECT)
1218 META_UNIMP(META_CREATEBITMAP)
1219 #undef META_UNIMP
1221 default:
1222 WARN("PlayMetaFileRecord: Unknown record type %x\n",
1223 mr->rdFunction);
1227 /******************************************************************
1228 * PlayMetaFileRecord (GDI32.@)
1230 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *handletable,
1231 METARECORD *metarecord, UINT handles )
1233 HANDLETABLE16 * ht = (void *)GlobalAlloc(GPTR,
1234 handles*sizeof(HANDLETABLE16));
1235 unsigned int i = 0;
1236 TRACE("(%08x,%p,%p,%d)\n", hdc, handletable, metarecord,
1237 handles);
1238 for (i=0; i<handles; i++)
1239 ht->objectHandle[i] = handletable->objectHandle[i];
1240 PlayMetaFileRecord16(hdc, ht, metarecord, handles);
1241 for (i=0; i<handles; i++)
1242 handletable->objectHandle[i] = ht->objectHandle[i];
1243 GlobalFree((HGLOBAL)ht);
1244 return TRUE;
1247 /******************************************************************
1248 * GetMetaFileBits (GDI.159)
1250 * Trade in a metafile object handle for a handle to the metafile memory.
1254 HGLOBAL16 WINAPI GetMetaFileBits16(
1255 HMETAFILE16 hmf /* [in] metafile handle */
1258 TRACE("hMem out: %04x\n", hmf);
1259 return hmf;
1262 /******************************************************************
1263 * SetMetaFileBits (GDI.160)
1265 * Trade in a metafile memory handle for a handle to a metafile object.
1266 * The memory region should hold a proper metafile, otherwise
1267 * problems will occur when it is used. Validity of the memory is not
1268 * checked. The function is essentially just the identity function.
1270 HMETAFILE16 WINAPI SetMetaFileBits16(
1271 HGLOBAL16 hMem
1272 /* [in] handle to a memory region holding a metafile */
1275 TRACE("hmf out: %04x\n", hMem);
1277 return hMem;
1280 /******************************************************************
1281 * SetMetaFileBitsBetter (GDI.196)
1283 * Trade in a metafile memory handle for a handle to a metafile object,
1284 * making a cursory check (using IsValidMetaFile()) that the memory
1285 * handle points to a valid metafile.
1287 * RETURNS
1288 * Handle to a metafile on success, NULL on failure..
1290 HMETAFILE16 WINAPI SetMetaFileBitsBetter16( HMETAFILE16 hMeta )
1292 if( IsValidMetaFile16( hMeta ) )
1293 return (HMETAFILE16)GlobalReAlloc16( hMeta, 0,
1294 GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1295 return (HMETAFILE16)0;
1298 /******************************************************************
1299 * SetMetaFileBitsEx (GDI32.@)
1301 * Create a metafile from raw data. No checking of the data is performed.
1302 * Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1304 HMETAFILE WINAPI SetMetaFileBitsEx(
1305 UINT size, /* [in] size of metafile, in bytes */
1306 const BYTE *lpData /* [in] pointer to metafile data */
1309 METAHEADER *mh = HeapAlloc( GetProcessHeap(), 0, size );
1310 if (!mh) return 0;
1311 memcpy(mh, lpData, size);
1312 return MF_Create_HMETAFILE(mh);
1315 /*****************************************************************
1316 * GetMetaFileBitsEx (GDI32.@) Get raw metafile data
1318 * Copies the data from metafile _hmf_ into the buffer _buf_.
1319 * If _buf_ is zero, returns size of buffer required. Otherwise,
1320 * returns number of bytes copied.
1322 UINT WINAPI GetMetaFileBitsEx(
1323 HMETAFILE hmf, /* [in] metafile */
1324 UINT nSize, /* [in] size of buf */
1325 LPVOID buf /* [out] buffer to receive raw metafile data */
1327 METAHEADER *mh = MF_GetMetaHeader(hmf);
1328 UINT mfSize;
1330 TRACE("(%08x,%d,%p)\n", hmf, nSize, buf);
1331 if (!mh) return 0; /* FIXME: error code */
1332 if(mh->mtType == METAFILE_DISK)
1333 FIXME("Disk-based metafile?\n");
1334 mfSize = mh->mtSize * 2;
1335 if (!buf) {
1336 TRACE("returning size %d\n", mfSize);
1337 return mfSize;
1339 if(mfSize > nSize) mfSize = nSize;
1340 memmove(buf, mh, mfSize);
1341 return mfSize;
1344 /******************************************************************
1345 * GetWinMetaFileBits [GDI32.@]
1347 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1348 UINT cbBuffer, LPBYTE lpbBuffer,
1349 INT fnMapMode, HDC hdcRef)
1351 FIXME("(%d,%d,%p,%d,%d): stub\n",
1352 hemf, cbBuffer, lpbBuffer, fnMapMode, hdcRef);
1353 return 0;
1356 /******************************************************************
1357 * MF_Play_MetaCreateRegion
1359 * Handles META_CREATEREGION for PlayMetaFileRecord().
1363 * The layout of the record looks something like this:
1365 * rdParm meaning
1366 * 0 Always 0?
1367 * 1 Always 6?
1368 * 2 Looks like a handle? - not constant
1369 * 3 0 or 1 ??
1370 * 4 Total number of bytes
1371 * 5 No. of separate bands = n [see below]
1372 * 6 Largest number of x co-ords in a band
1373 * 7-10 Bounding box x1 y1 x2 y2
1374 * 11-... n bands
1376 * Regions are divided into bands that are uniform in the
1377 * y-direction. Each band consists of pairs of on/off x-coords and is
1378 * written as
1379 * m y0 y1 x1 x2 x3 ... xm m
1380 * into successive rdParm[]s.
1382 * This is probably just a dump of the internal RGNOBJ?
1384 * HDMD - 18/12/97
1388 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1390 WORD band, pair;
1391 WORD *start, *end;
1392 INT16 y0, y1;
1393 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1395 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1396 band++, start = end + 1) {
1397 if(*start / 2 != (*start + 1) / 2) {
1398 WARN("Delimiter not even.\n");
1399 DeleteObject( hrgn2 );
1400 return FALSE;
1403 end = start + *start + 3;
1404 if(end > (WORD *)mr + mr->rdSize) {
1405 WARN("End points outside record.\n");
1406 DeleteObject( hrgn2 );
1407 return FALSE;
1410 if(*start != *end) {
1411 WARN("Mismatched delimiters.\n");
1412 DeleteObject( hrgn2 );
1413 return FALSE;
1416 y0 = *(INT16 *)(start + 1);
1417 y1 = *(INT16 *)(start + 2);
1418 for(pair = 0; pair < *start / 2; pair++) {
1419 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1420 *(INT16 *)(start + 4 + 2*pair), y1 );
1421 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1424 DeleteObject( hrgn2 );
1425 return TRUE;
1429 /******************************************************************
1430 * MF_Play_MetaExtTextOut
1432 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1435 static BOOL MF_Play_MetaExtTextOut(HDC16 hdc, METARECORD *mr)
1437 LPINT16 dxx;
1438 LPSTR sot;
1439 DWORD len;
1440 WORD s1;
1442 s1 = mr->rdParm[2]; /* String length */
1443 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1444 + sizeof(UINT16) + (mr->rdParm[3] ? sizeof(RECT16) : 0);
1445 /* rec len without dx array */
1447 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1448 if (mr->rdParm[3])
1449 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1451 if (mr->rdSize == len / 2)
1452 dxx = NULL; /* determine if array present */
1453 else
1454 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1455 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1456 else {
1457 TRACE("%s len: %ld\n", sot, mr->rdSize);
1458 WARN(
1459 "Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1460 len, s1, mr->rdSize, mr->rdParm[3]);
1461 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1463 ExtTextOut16( hdc, mr->rdParm[1], /* X position */
1464 mr->rdParm[0], /* Y position */
1465 mr->rdParm[3], /* options */
1466 mr->rdParm[3] ? (LPRECT16) &mr->rdParm[4]:NULL,
1467 /* rectangle */
1468 sot, /* string */
1469 s1, dxx); /* length, dx array */
1470 if (dxx)
1471 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dxx[0]);
1472 return TRUE;