4 * Copyright David W. Metcalfe, 1994
5 * Copyright Niels de Carpentier, 1996
6 * Copyright Albrecht Kleine, 1996
7 * Copyright Huw Davies, 1996
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * These functions are primarily involved with metafile playback or anything
26 * that touches a HMETAFILE.
27 * For recording of metafiles look in graphics/metafiledrv/
29 * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
30 * global memory handles so these cannot be interchanged.
32 * Memory-based metafiles are just stored as a continuous block of memory with
33 * a METAHEADER at the head with METARECORDs appended to it. mtType is
34 * METAFILE_MEMORY (1). Note this is indentical to the disk image of a
35 * disk-based metafile - even mtType is METAFILE_MEMORY.
36 * 16bit HMETAFILE16s are global handles to this block
37 * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
39 * Disk-based metafiles are rather different. HMETAFILE16s point to a
40 * METAHEADER which has mtType equal to METAFILE_DISK (2). Following the 9
41 * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
42 * more 0, then 2 which may be a time stamp of the file and then the path of
43 * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
56 #include "gdi_private.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
77 /******************************************************************
80 * Add a handle to an external handle table and return the index
82 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
86 for (i = 0; i < htlen; i++)
88 if (*(ht->objectHandle + i) == 0)
90 *(ht->objectHandle + i) = hobj;
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)
108 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
109 (HGDIOBJ *)&hmf, NULL );
113 GDI_ReleaseObj( hmf );
118 /******************************************************************
121 * Returns ptr to METAHEADER associated with HMETAFILE
123 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
125 METAHEADER *ret = NULL;
126 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
130 GDI_ReleaseObj( hmf );
135 /******************************************************************
138 * Convert an array of POINT16 to an array of POINT.
139 * Result must be freed by caller.
141 static POINT *convert_points( UINT count, POINT16 *pt16 )
144 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
147 for (i = 0; i < count; i++)
149 ret[i].x = pt16[i].x;
150 ret[i].y = pt16[i].y;
156 /******************************************************************
157 * DeleteMetaFile (GDI32.@)
159 * Delete a memory-based metafile.
162 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
164 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
165 if (!metaObj) return FALSE;
166 HeapFree( GetProcessHeap(), 0, metaObj->mh );
167 GDI_FreeObject( hmf, metaObj );
171 /******************************************************************
174 * Returns a pointer to a memory based METAHEADER read in from file HFILE
177 METAHEADER *MF_ReadMetaFile(HANDLE hfile)
180 DWORD BytesRead, size;
182 size = sizeof(METAHEADER);
183 mh = HeapAlloc( GetProcessHeap(), 0, size );
185 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
187 HeapFree( GetProcessHeap(), 0, mh );
190 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
191 mh->mtHeaderSize != size / 2)
193 HeapFree( GetProcessHeap(), 0, mh );
196 size = mh->mtSize * 2;
197 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
199 size -= sizeof(METAHEADER);
200 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
203 HeapFree( GetProcessHeap(), 0, mh );
207 if (mh->mtType != METAFILE_MEMORY) {
208 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
209 mh->mtType = METAFILE_MEMORY;
214 /******************************************************************
215 * GetMetaFileA (GDI32.@)
217 * Read a metafile from a file. Returns handle to a memory-based metafile.
219 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
224 TRACE("%s\n", lpFilename);
229 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
230 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
233 mh = MF_ReadMetaFile(hFile);
236 return MF_Create_HMETAFILE( mh );
239 /******************************************************************
240 * GetMetaFileW (GDI32.@)
242 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
247 TRACE("%s\n", debugstr_w(lpFilename));
252 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
253 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
256 mh = MF_ReadMetaFile(hFile);
259 return MF_Create_HMETAFILE( mh );
263 /******************************************************************
264 * MF_LoadDiskBasedMetaFile
266 * Creates a new memory-based metafile from a disk-based one.
268 METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
274 if(mh->mtType != METAFILE_DISK) {
275 ERR("Not a disk based metafile\n");
278 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
280 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
281 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
282 WARN("Can't open file of disk based metafile\n");
285 mh2 = MF_ReadMetaFile(hfile);
290 /******************************************************************
291 * MF_CreateMetaHeaderDisk
293 * Take a memory based METAHEADER and change it to a disk based METAHEADER
294 * assosiated with filename. Note: Trashes contents of old one.
296 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
300 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
301 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
302 mh->mtType = METAFILE_DISK;
303 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
306 WideCharToMultiByte(CP_ACP, 0, filename, -1,
307 mhd->filename, sizeof mhd->filename, NULL, NULL);
309 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
313 /******************************************************************
314 * CopyMetaFileW (GDI32.@)
316 * Copies the metafile corresponding to hSrcMetaFile to either
317 * a disk file, if a filename is given, or to a new memory based
318 * metafile, if lpFileName is NULL.
321 * hSrcMetaFile [I] handle of metafile to copy
322 * lpFilename [I] filename if copying to a file
325 * Handle to metafile copy on success, NULL on failure.
328 * Copying to disk returns NULL even if successful.
330 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
332 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
333 METAHEADER *mh2 = NULL;
336 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
340 if(mh->mtType == METAFILE_DISK)
341 mh2 = MF_LoadDiskBasedMetaFile(mh);
343 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
344 memcpy( mh2, mh, mh->mtSize * 2 );
347 if(lpFilename) { /* disk based metafile */
349 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
350 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
351 HeapFree( GetProcessHeap(), 0, mh2 );
354 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
358 return MF_Create_HMETAFILE( mh2 );
362 /******************************************************************
363 * CopyMetaFileA (GDI32.@)
367 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
369 UNICODE_STRING lpFilenameW;
372 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
373 else lpFilenameW.Buffer = NULL;
375 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
376 if (lpFilenameW.Buffer)
377 RtlFreeUnicodeString(&lpFilenameW);
381 /*******************************************************************
384 * Helper for PlayMetaFile
386 BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
391 unsigned int offset = 0;
398 if (!mh) return FALSE;
399 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
400 mh = MF_LoadDiskBasedMetaFile(mh);
401 if(!mh) return FALSE;
405 /* save the current pen, brush and font */
406 hPen = GetCurrentObject(hdc, OBJ_PEN);
407 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
408 hFont = GetCurrentObject(hdc, OBJ_FONT);
410 /* create the handle table */
411 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
412 sizeof(HANDLETABLE) * mh->mtNoObjects);
413 if(!ht) return FALSE;
415 /* loop through metafile playing records */
416 offset = mh->mtHeaderSize * 2;
417 while (offset < mh->mtSize * 2)
419 mr = (METARECORD *)((char *)mh + offset);
420 TRACE("offset=%04x,size=%08x\n",
422 if (mr->rdSize < 3) { /* catch illegal record sizes */
423 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
424 mr->rdSize,offset,mh->mtSize*2);
427 offset += mr->rdSize * 2;
428 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
431 SelectObject(hdc, hBrush);
432 SelectObject(hdc, hPen);
433 SelectObject(hdc, hFont);
435 /* free objects in handle table */
436 for(i = 0; i < mh->mtNoObjects; i++)
437 if(*(ht->objectHandle + i) != 0)
438 DeleteObject(*(ht->objectHandle + i));
440 /* free handle table */
441 HeapFree( GetProcessHeap(), 0, ht );
443 HeapFree( GetProcessHeap(), 0, mh );
447 /******************************************************************
448 * PlayMetaFile (GDI32.@)
450 * Renders the metafile specified by hmf in the DC specified by
451 * hdc. Returns FALSE on failure, TRUE on success.
454 * hdc [I] handle of DC to render in
455 * hmf [I] handle of metafile to render
461 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
463 METAHEADER *mh = MF_GetMetaHeader( hmf );
464 return MF_PlayMetaFile( hdc, mh );
467 /******************************************************************
468 * EnumMetaFile (GDI32.@)
470 * Loop through the metafile records in hmf, calling the user-specified
471 * function for each one, stopping when the user's function returns FALSE
472 * (which is considered to be failure)
473 * or when no records are left (which is considered to be success).
476 * TRUE on success, FALSE on failure.
478 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
480 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
485 unsigned int offset = 0;
490 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
492 if(mh->mtType == METAFILE_DISK)
494 /* Create a memory-based copy */
495 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
499 /* save the current pen, brush and font */
500 hPen = GetCurrentObject(hdc, OBJ_PEN);
501 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
502 hFont = GetCurrentObject(hdc, OBJ_FONT);
504 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
505 sizeof(HANDLETABLE) * mh->mtNoObjects);
507 /* loop through metafile records */
508 offset = mh->mtHeaderSize * 2;
510 while (offset < (mh->mtSize * 2))
512 mr = (METARECORD *)((char *)mh + offset);
513 if(mr->rdFunction == META_EOF) {
514 TRACE("Got META_EOF so stopping\n");
517 TRACE("Calling EnumFunc with record type %x\n",
519 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
525 offset += (mr->rdSize * 2);
528 /* restore pen, brush and font */
529 SelectObject(hdc, hBrush);
530 SelectObject(hdc, hPen);
531 SelectObject(hdc, hFont);
533 /* free objects in handle table */
534 for(i = 0; i < mh->mtNoObjects; i++)
535 if(*(ht->objectHandle + i) != 0)
536 DeleteObject(*(ht->objectHandle + i));
538 /* free handle table */
539 HeapFree( GetProcessHeap(), 0, ht);
540 /* free a copy of metafile */
541 HeapFree( GetProcessHeap(), 0, mhTemp );
545 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
546 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
547 /******************************************************************
548 * PlayMetaFileRecord (GDI32.@)
550 * Render a single metafile record specified by *mr in the DC hdc, while
551 * using the handle table *ht, of length handles,
552 * to store metafile objects.
555 * The following metafile records are unimplemented:
557 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
558 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
559 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
561 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
565 BITMAPINFOHEADER *infohdr;
567 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
569 switch (mr->rdFunction)
574 case META_DELETEOBJECT:
575 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
576 *(ht->objectHandle + mr->rdParm[0]) = 0;
579 case META_SETBKCOLOR:
580 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
584 SetBkMode(hdc, mr->rdParm[0]);
587 case META_SETMAPMODE:
588 SetMapMode(hdc, mr->rdParm[0]);
592 SetROP2(hdc, mr->rdParm[0]);
596 SetRelAbs(hdc, mr->rdParm[0]);
599 case META_SETPOLYFILLMODE:
600 SetPolyFillMode(hdc, mr->rdParm[0]);
603 case META_SETSTRETCHBLTMODE:
604 SetStretchBltMode(hdc, mr->rdParm[0]);
607 case META_SETTEXTCOLOR:
608 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
611 case META_SETWINDOWORG:
612 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
615 case META_SETWINDOWEXT:
616 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
619 case META_SETVIEWPORTORG:
620 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
623 case META_SETVIEWPORTEXT:
624 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
627 case META_OFFSETWINDOWORG:
628 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
631 case META_SCALEWINDOWEXT:
632 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
633 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
636 case META_OFFSETVIEWPORTORG:
637 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
640 case META_SCALEVIEWPORTEXT:
641 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
642 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
646 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
650 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
653 case META_EXCLUDECLIPRECT:
654 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
655 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
658 case META_INTERSECTCLIPRECT:
659 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
660 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
664 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
665 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
666 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
667 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
671 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
672 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
676 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
677 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
681 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
682 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
683 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
684 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
688 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
689 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
693 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
694 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
695 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
699 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
700 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
701 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
709 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
710 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
713 case META_OFFSETCLIPRGN:
714 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
719 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
720 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
721 (char *)(mr->rdParm + 1), s1);
725 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
727 Polygon(hdc, pt, mr->rdParm[0]);
728 HeapFree( GetProcessHeap(), 0, pt );
732 case META_POLYPOLYGON:
735 SHORT *counts = (SHORT *)(mr->rdParm + 1);
737 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
738 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
741 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
744 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
745 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
746 HeapFree( GetProcessHeap(), 0, cnt32 );
749 HeapFree( GetProcessHeap(), 0, pt );
754 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
756 Polyline( hdc, pt, mr->rdParm[0] );
757 HeapFree( GetProcessHeap(), 0, pt );
762 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
765 case META_SELECTOBJECT:
766 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
770 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
771 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
772 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
773 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
776 case META_CREATEPATTERNBRUSH:
777 switch (mr->rdParm[0])
780 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
781 MF_AddHandle(ht, handles,
782 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
787 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
791 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
792 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
796 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
802 case META_CREATEPENINDIRECT:
805 pen.lopnStyle = mr->rdParm[0];
806 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
807 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
808 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
809 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
813 case META_CREATEFONTINDIRECT:
816 font.lfHeight = (SHORT)mr->rdParm[0];
817 font.lfWidth = (SHORT)mr->rdParm[1];
818 font.lfEscapement = (SHORT)mr->rdParm[2];
819 font.lfOrientation = (SHORT)mr->rdParm[3];
820 font.lfWeight = (SHORT)mr->rdParm[4];
821 font.lfItalic = LOBYTE(mr->rdParm[5]);
822 font.lfUnderline = HIBYTE(mr->rdParm[5]);
823 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
824 font.lfCharSet = HIBYTE(mr->rdParm[6]);
825 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
826 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
827 font.lfQuality = LOBYTE(mr->rdParm[8]);
828 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
829 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
830 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
834 case META_CREATEBRUSHINDIRECT:
837 brush.lbStyle = mr->rdParm[0];
838 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
839 brush.lbHatch = mr->rdParm[3];
840 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
844 case META_CREATEPALETTE:
845 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
848 case META_SETTEXTALIGN:
849 SetTextAlign(hdc, mr->rdParm[0]);
852 case META_SELECTPALETTE:
853 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
856 case META_SETMAPPERFLAGS:
857 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
860 case META_REALIZEPALETTE:
861 GDIRealizePalette(hdc);
865 switch (mr->rdParm[0]) {
866 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
867 case GETPHYSPAGESIZE:
868 case GETPRINTINGOFFSET:
871 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
874 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
877 case META_EXTTEXTOUT:
878 MF_Play_MetaExtTextOut( hdc, mr );
881 case META_STRETCHDIB:
883 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
884 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
885 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
886 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
887 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
888 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
892 case META_DIBSTRETCHBLT:
894 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
895 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
896 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
897 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
898 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
899 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
903 case META_STRETCHBLT:
905 HDC hdcSrc = CreateCompatibleDC(hdc);
906 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
907 mr->rdParm[11], /*Height*/
908 mr->rdParm[13], /*Planes*/
909 mr->rdParm[14], /*BitsPixel*/
910 (LPSTR)&mr->rdParm[15]); /*bits*/
911 SelectObject(hdcSrc,hbitmap);
912 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
913 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
914 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
915 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
916 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
923 HDC hdcSrc = CreateCompatibleDC(hdc);
924 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
925 mr->rdParm[8]/*Height*/,
926 mr->rdParm[10]/*Planes*/,
927 mr->rdParm[11]/*BitsPixel*/,
928 (LPSTR)&mr->rdParm[12]/*bits*/);
929 SelectObject(hdcSrc,hbitmap);
930 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
931 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
932 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
933 MAKELONG(0,mr->rdParm[0]));
938 case META_CREATEREGION:
940 HRGN hrgn = CreateRectRgn(0,0,0,0);
942 MF_Play_MetaCreateRegion(mr, hrgn);
943 MF_AddHandle(ht, handles, hrgn);
947 case META_FILLREGION:
948 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
949 *(ht->objectHandle + mr->rdParm[0]));
952 case META_FRAMEREGION:
953 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
954 *(ht->objectHandle + mr->rdParm[2]),
955 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
958 case META_INVERTREGION:
959 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
962 case META_PAINTREGION:
963 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
966 case META_SELECTCLIPREGION:
970 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
971 SelectClipRgn(hdc, hrgn);
975 case META_DIBCREATEPATTERNBRUSH:
976 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
977 but there's no difference */
978 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
982 /* In practice I've found that there are two layouts for
983 META_DIBBITBLT, one (the first here) is the usual one when a src
984 dc is actually passed to it, the second occurs when the src dc is
985 passed in as NULL to the creating BitBlt. As the second case has
986 no dib, a size check will suffice to distinguish.
988 Caolan.McNamara@ul.ie */
990 if (mr->rdSize > 12) {
991 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
992 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
994 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
995 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
996 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
997 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
999 else /* equivalent to a PatBlt */
1000 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1001 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1002 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1005 case META_SETTEXTCHAREXTRA:
1006 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1009 case META_SETTEXTJUSTIFICATION:
1010 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1013 case META_EXTFLOODFILL:
1014 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1015 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1019 case META_SETDIBTODEV:
1021 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1022 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1023 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1024 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1025 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1026 mr->rdParm[2], mr->rdParm[1], bits, info,
1031 #define META_UNIMP(x) case x: \
1032 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1034 META_UNIMP(META_DRAWTEXT)
1035 META_UNIMP(META_ANIMATEPALETTE)
1036 META_UNIMP(META_SETPALENTRIES)
1037 META_UNIMP(META_RESIZEPALETTE)
1038 META_UNIMP(META_RESETDC)
1039 META_UNIMP(META_STARTDOC)
1040 META_UNIMP(META_STARTPAGE)
1041 META_UNIMP(META_ENDPAGE)
1042 META_UNIMP(META_ABORTDOC)
1043 META_UNIMP(META_ENDDOC)
1044 META_UNIMP(META_CREATEBRUSH)
1045 META_UNIMP(META_CREATEBITMAPINDIRECT)
1046 META_UNIMP(META_CREATEBITMAP)
1050 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1056 /******************************************************************
1057 * SetMetaFileBitsEx (GDI32.@)
1059 * Create a metafile from raw data. No checking of the data is performed.
1060 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1063 * size [I] size of metafile, in bytes
1064 * lpData [I] pointer to metafile data
1067 * Success: Handle to metafile.
1070 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1072 METAHEADER *mh = (METAHEADER *)lpData;
1074 if (size & 1) return 0;
1076 if (!size || mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
1077 mh->mtHeaderSize != sizeof(METAHEADER) / 2)
1079 SetLastError(ERROR_INVALID_DATA);
1083 mh = HeapAlloc( GetProcessHeap(), 0, size );
1086 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1090 memcpy(mh, lpData, size);
1091 mh->mtSize = size / 2;
1092 return MF_Create_HMETAFILE(mh);
1095 /*****************************************************************
1096 * GetMetaFileBitsEx (GDI32.@)
1098 * Get raw metafile data.
1100 * Copies the data from metafile _hmf_ into the buffer _buf_.
1104 * nSize [I] size of buf
1105 * buf [O] buffer to receive raw metafile data
1108 * If _buf_ is zero, returns size of buffer required. Otherwise,
1109 * returns number of bytes copied.
1111 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1113 METAHEADER *mh = MF_GetMetaHeader(hmf);
1116 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1117 if (!mh) return 0; /* FIXME: error code */
1118 if(mh->mtType == METAFILE_DISK)
1119 FIXME("Disk-based metafile?\n");
1120 mfSize = mh->mtSize * 2;
1122 TRACE("returning size %d\n", mfSize);
1125 if(mfSize > nSize) mfSize = nSize;
1126 memmove(buf, mh, mfSize);
1130 /******************************************************************
1131 * GetWinMetaFileBits [GDI32.@]
1133 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1134 UINT cbBuffer, LPBYTE lpbBuffer,
1135 INT fnMapMode, HDC hdcRef)
1143 GetClipBox(hdcRef, &rc);
1144 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1146 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1147 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1149 hdcmf = CreateMetaFileA(NULL);
1150 PlayEnhMetaFile(hdcmf, hemf, &rc);
1151 hmf = CloseMetaFile(hdcmf);
1152 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1153 DeleteMetaFile(hmf);
1155 SetMapMode(hdcRef, oldMapMode);
1160 /******************************************************************
1161 * MF_Play_MetaCreateRegion
1163 * Handles META_CREATEREGION for PlayMetaFileRecord().
1165 * The layout of the record looks something like this:
1170 * 2 Looks like a handle? - not constant
1172 * 4 Total number of bytes
1173 * 5 No. of separate bands = n [see below]
1174 * 6 Largest number of x co-ords in a band
1175 * 7-10 Bounding box x1 y1 x2 y2
1178 * Regions are divided into bands that are uniform in the
1179 * y-direction. Each band consists of pairs of on/off x-coords and is
1181 * m y0 y1 x1 x2 x3 ... xm m
1182 * into successive rdParm[]s.
1184 * This is probably just a dump of the internal RGNOBJ?
1190 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1195 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1197 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1198 band++, start = end + 1) {
1199 if(*start / 2 != (*start + 1) / 2) {
1200 WARN("Delimiter not even.\n");
1201 DeleteObject( hrgn2 );
1205 end = start + *start + 3;
1206 if(end > (WORD *)mr + mr->rdSize) {
1207 WARN("End points outside record.\n");
1208 DeleteObject( hrgn2 );
1212 if(*start != *end) {
1213 WARN("Mismatched delimiters.\n");
1214 DeleteObject( hrgn2 );
1218 y0 = *(INT16 *)(start + 1);
1219 y1 = *(INT16 *)(start + 2);
1220 for(pair = 0; pair < *start / 2; pair++) {
1221 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1222 *(INT16 *)(start + 4 + 2*pair), y1 );
1223 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1226 DeleteObject( hrgn2 );
1231 /******************************************************************
1232 * MF_Play_MetaExtTextOut
1234 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1237 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1246 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1248 s1 = mr->rdParm[2]; /* String length */
1249 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1250 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1251 /* rec len without dx array */
1253 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1256 rect.left = (SHORT)mr->rdParm[4];
1257 rect.top = (SHORT)mr->rdParm[5];
1258 rect.right = (SHORT)mr->rdParm[6];
1259 rect.bottom = (SHORT)mr->rdParm[7];
1260 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1263 if (mr->rdSize == len / 2)
1264 dxx = NULL; /* determine if array present */
1266 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1268 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1269 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1270 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1273 TRACE("%s len: %d\n", sot, mr->rdSize);
1274 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1275 len, s1, mr->rdSize, mr->rdParm[3]);
1276 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1279 (SHORT)mr->rdParm[1], /* X position */
1280 (SHORT)mr->rdParm[0], /* Y position */
1281 mr->rdParm[3], /* options */
1282 &rect, /* rectangle */
1284 s1, dx); /* length, dx array */
1287 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1288 HeapFree( GetProcessHeap(), 0, dx );