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 identical 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.
59 #include "gdi_private.h"
60 #include "wine/debug.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
80 /******************************************************************
83 * Add a handle to an external handle table and return the index
85 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
89 for (i = 0; i < htlen; i++)
91 if (*(ht->objectHandle + i) == 0)
93 *(ht->objectHandle + i) = hobj;
101 /******************************************************************
102 * MF_Create_HMETATFILE
104 * Creates a (32 bit) HMETAFILE object from a METAHEADER
106 * HMETAFILEs are GDI objects.
108 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
111 METAFILEOBJ *metaObj;
113 if (!(metaObj = HeapAlloc( GetProcessHeap(), 0, sizeof(*metaObj) ))) return 0;
115 if (!(hmf = alloc_gdi_handle( &metaObj->header, OBJ_METAFILE, NULL )))
116 HeapFree( GetProcessHeap(), 0, metaObj );
120 /******************************************************************
123 * Returns ptr to METAHEADER associated with HMETAFILE
125 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
127 METAHEADER *ret = NULL;
128 METAFILEOBJ * metaObj = GDI_GetObjPtr( hmf, OBJ_METAFILE );
132 GDI_ReleaseObj( hmf );
137 /******************************************************************
140 * Convert an array of POINT16 to an array of POINT.
141 * Result must be freed by caller.
143 static POINT *convert_points( UINT count, POINT16 *pt16 )
146 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
149 for (i = 0; i < count; i++)
151 ret[i].x = pt16[i].x;
152 ret[i].y = pt16[i].y;
158 /******************************************************************
159 * DeleteMetaFile (GDI32.@)
161 * Delete a memory-based metafile.
164 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
166 METAFILEOBJ * metaObj = free_gdi_handle( hmf );
167 if (!metaObj) return FALSE;
168 HeapFree( GetProcessHeap(), 0, metaObj->mh );
169 return HeapFree( GetProcessHeap(), 0, metaObj );
172 /******************************************************************
175 * Returns a pointer to a memory based METAHEADER read in from file HFILE
178 METAHEADER *MF_ReadMetaFile(HANDLE hfile)
181 DWORD BytesRead, size;
183 size = sizeof(METAHEADER);
184 mh = HeapAlloc( GetProcessHeap(), 0, size );
186 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
188 HeapFree( GetProcessHeap(), 0, mh );
191 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
192 mh->mtHeaderSize != size / 2)
194 HeapFree( GetProcessHeap(), 0, mh );
197 size = mh->mtSize * 2;
198 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
200 size -= sizeof(METAHEADER);
201 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
204 HeapFree( GetProcessHeap(), 0, mh );
208 if (mh->mtType != METAFILE_MEMORY) {
209 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
210 mh->mtType = METAFILE_MEMORY;
215 /******************************************************************
216 * GetMetaFileA (GDI32.@)
218 * Read a metafile from a file. Returns handle to a memory-based metafile.
220 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
225 TRACE("%s\n", lpFilename);
230 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
231 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
234 mh = MF_ReadMetaFile(hFile);
237 return MF_Create_HMETAFILE( mh );
240 /******************************************************************
241 * GetMetaFileW (GDI32.@)
243 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
248 TRACE("%s\n", debugstr_w(lpFilename));
253 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
254 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
257 mh = MF_ReadMetaFile(hFile);
260 return MF_Create_HMETAFILE( mh );
264 /******************************************************************
265 * MF_LoadDiskBasedMetaFile
267 * Creates a new memory-based metafile from a disk-based one.
269 METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
275 if(mh->mtType != METAFILE_DISK) {
276 ERR("Not a disk based metafile\n");
279 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
281 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
282 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
283 WARN("Can't open file of disk based metafile\n");
286 mh2 = MF_ReadMetaFile(hfile);
291 /******************************************************************
292 * MF_CreateMetaHeaderDisk
294 * Take a memory based METAHEADER and change it to a disk based METAHEADER
295 * associated with filename. Note: Trashes contents of old one.
297 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
301 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
302 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
303 mh->mtType = METAFILE_DISK;
304 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
307 WideCharToMultiByte(CP_ACP, 0, filename, -1,
308 mhd->filename, sizeof mhd->filename, NULL, NULL);
310 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
314 /******************************************************************
315 * CopyMetaFileW (GDI32.@)
317 * Copies the metafile corresponding to hSrcMetaFile to either
318 * a disk file, if a filename is given, or to a new memory based
319 * metafile, if lpFileName is NULL.
322 * hSrcMetaFile [I] handle of metafile to copy
323 * lpFilename [I] filename if copying to a file
326 * Handle to metafile copy on success, NULL on failure.
329 * Copying to disk returns NULL even if successful.
331 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
333 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
334 METAHEADER *mh2 = NULL;
337 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
341 if(mh->mtType == METAFILE_DISK)
342 mh2 = MF_LoadDiskBasedMetaFile(mh);
344 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
345 memcpy( mh2, mh, mh->mtSize * 2 );
348 if(lpFilename) { /* disk based metafile */
350 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
351 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
352 HeapFree( GetProcessHeap(), 0, mh2 );
355 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
359 return MF_Create_HMETAFILE( mh2 );
363 /******************************************************************
364 * CopyMetaFileA (GDI32.@)
368 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
370 UNICODE_STRING lpFilenameW;
373 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
374 else lpFilenameW.Buffer = NULL;
376 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
377 if (lpFilenameW.Buffer)
378 RtlFreeUnicodeString(&lpFilenameW);
382 /*******************************************************************
385 * Helper for PlayMetaFile
387 BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
392 unsigned int offset = 0;
401 if (!mh) return FALSE;
402 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
403 mh = MF_LoadDiskBasedMetaFile(mh);
404 if(!mh) return FALSE;
409 hPen = GetCurrentObject(hdc, OBJ_PEN);
410 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
411 hFont = GetCurrentObject(hdc, OBJ_FONT);
412 hPal = GetCurrentObject(hdc, OBJ_PAL);
414 hRgn = CreateRectRgn(0, 0, 0, 0);
415 if (!GetClipRgn(hdc, hRgn))
421 /* create the handle table */
422 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
423 sizeof(HANDLETABLE) * mh->mtNoObjects);
424 if(!ht) return FALSE;
426 /* loop through metafile playing records */
427 offset = mh->mtHeaderSize * 2;
428 while (offset < mh->mtSize * 2)
430 mr = (METARECORD *)((char *)mh + offset);
431 TRACE("offset=%04x,size=%08x\n",
433 if (mr->rdSize < 3) { /* catch illegal record sizes */
434 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
435 mr->rdSize,offset,mh->mtSize*2);
439 offset += mr->rdSize * 2;
440 if (mr->rdFunction == META_EOF) {
441 TRACE("Got META_EOF so stopping\n");
444 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
448 SelectObject(hdc, hPen);
449 SelectObject(hdc, hBrush);
450 SelectPalette(hdc, hPal, FALSE);
451 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
454 /* free objects in handle table */
455 for(i = 0; i < mh->mtNoObjects; i++)
456 if(*(ht->objectHandle + i) != 0)
457 DeleteObject(*(ht->objectHandle + i));
459 /* free handle table */
460 HeapFree( GetProcessHeap(), 0, ht );
462 HeapFree( GetProcessHeap(), 0, mh );
466 /******************************************************************
467 * PlayMetaFile (GDI32.@)
469 * Renders the metafile specified by hmf in the DC specified by
470 * hdc. Returns FALSE on failure, TRUE on success.
473 * hdc [I] handle of DC to render in
474 * hmf [I] handle of metafile to render
480 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
482 METAHEADER *mh = MF_GetMetaHeader( hmf );
483 return MF_PlayMetaFile( hdc, mh );
486 /******************************************************************
487 * EnumMetaFile (GDI32.@)
489 * Loop through the metafile records in hmf, calling the user-specified
490 * function for each one, stopping when the user's function returns FALSE
491 * (which is considered to be failure)
492 * or when no records are left (which is considered to be success).
495 * TRUE on success, FALSE on failure.
497 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
499 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
504 unsigned int offset = 0;
509 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
511 if(mh->mtType == METAFILE_DISK)
513 /* Create a memory-based copy */
514 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
518 /* save the current pen, brush and font */
519 hPen = GetCurrentObject(hdc, OBJ_PEN);
520 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
521 hFont = GetCurrentObject(hdc, OBJ_FONT);
523 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
524 sizeof(HANDLETABLE) * mh->mtNoObjects);
526 /* loop through metafile records */
527 offset = mh->mtHeaderSize * 2;
529 while (offset < (mh->mtSize * 2))
531 mr = (METARECORD *)((char *)mh + offset);
532 if(mr->rdFunction == META_EOF) {
533 TRACE("Got META_EOF so stopping\n");
536 TRACE("Calling EnumFunc with record type %x\n",
538 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
544 offset += (mr->rdSize * 2);
547 /* restore pen, brush and font */
548 SelectObject(hdc, hBrush);
549 SelectObject(hdc, hPen);
550 SelectObject(hdc, hFont);
552 /* free objects in handle table */
553 for(i = 0; i < mh->mtNoObjects; i++)
554 if(*(ht->objectHandle + i) != 0)
555 DeleteObject(*(ht->objectHandle + i));
557 /* free handle table */
558 HeapFree( GetProcessHeap(), 0, ht);
559 /* free a copy of metafile */
560 HeapFree( GetProcessHeap(), 0, mhTemp );
564 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
565 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
566 /******************************************************************
567 * PlayMetaFileRecord (GDI32.@)
569 * Render a single metafile record specified by *mr in the DC hdc, while
570 * using the handle table *ht, of length handles,
571 * to store metafile objects.
574 * The following metafile records are unimplemented:
576 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
577 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
578 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
580 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
584 BITMAPINFOHEADER *infohdr;
586 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
588 switch (mr->rdFunction)
593 case META_DELETEOBJECT:
594 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
595 *(ht->objectHandle + mr->rdParm[0]) = 0;
598 case META_SETBKCOLOR:
599 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
603 SetBkMode(hdc, mr->rdParm[0]);
606 case META_SETMAPMODE:
607 SetMapMode(hdc, mr->rdParm[0]);
611 SetROP2(hdc, mr->rdParm[0]);
615 SetRelAbs(hdc, mr->rdParm[0]);
618 case META_SETPOLYFILLMODE:
619 SetPolyFillMode(hdc, mr->rdParm[0]);
622 case META_SETSTRETCHBLTMODE:
623 SetStretchBltMode(hdc, mr->rdParm[0]);
626 case META_SETTEXTCOLOR:
627 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
630 case META_SETWINDOWORG:
631 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
634 case META_SETWINDOWEXT:
635 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
638 case META_SETVIEWPORTORG:
639 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
642 case META_SETVIEWPORTEXT:
643 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
646 case META_OFFSETWINDOWORG:
647 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
650 case META_SCALEWINDOWEXT:
651 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
652 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
655 case META_OFFSETVIEWPORTORG:
656 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
659 case META_SCALEVIEWPORTEXT:
660 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
661 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
665 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
669 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
672 case META_EXCLUDECLIPRECT:
673 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
674 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
677 case META_INTERSECTCLIPRECT:
678 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
679 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
683 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
684 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
685 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
686 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
690 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
691 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
695 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
696 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
700 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
701 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
702 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
703 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
707 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
708 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
712 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
713 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
714 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
718 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
719 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
720 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
728 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
729 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
732 case META_OFFSETCLIPRGN:
733 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
738 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
739 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
740 (char *)(mr->rdParm + 1), s1);
744 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
746 Polygon(hdc, pt, mr->rdParm[0]);
747 HeapFree( GetProcessHeap(), 0, pt );
751 case META_POLYPOLYGON:
754 SHORT *counts = (SHORT *)(mr->rdParm + 1);
756 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
757 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
760 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
763 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
764 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
765 HeapFree( GetProcessHeap(), 0, cnt32 );
768 HeapFree( GetProcessHeap(), 0, pt );
773 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
775 Polyline( hdc, pt, mr->rdParm[0] );
776 HeapFree( GetProcessHeap(), 0, pt );
781 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
784 case META_SELECTOBJECT:
785 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
789 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
790 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
791 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
792 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
795 case META_CREATEPATTERNBRUSH:
796 switch (mr->rdParm[0])
799 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
800 MF_AddHandle(ht, handles,
801 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
806 (sizeof(BITMAPINFOHEADER) / 2) + 4)));
810 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
811 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
815 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
821 case META_CREATEPENINDIRECT:
824 pen.lopnStyle = mr->rdParm[0];
825 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
826 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
827 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
828 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
832 case META_CREATEFONTINDIRECT:
835 font.lfHeight = (SHORT)mr->rdParm[0];
836 font.lfWidth = (SHORT)mr->rdParm[1];
837 font.lfEscapement = (SHORT)mr->rdParm[2];
838 font.lfOrientation = (SHORT)mr->rdParm[3];
839 font.lfWeight = (SHORT)mr->rdParm[4];
840 font.lfItalic = LOBYTE(mr->rdParm[5]);
841 font.lfUnderline = HIBYTE(mr->rdParm[5]);
842 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
843 font.lfCharSet = HIBYTE(mr->rdParm[6]);
844 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
845 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
846 font.lfQuality = LOBYTE(mr->rdParm[8]);
847 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
848 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
849 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
853 case META_CREATEBRUSHINDIRECT:
856 brush.lbStyle = mr->rdParm[0];
857 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
858 brush.lbHatch = mr->rdParm[3];
859 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
863 case META_CREATEPALETTE:
864 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
867 case META_SETTEXTALIGN:
868 SetTextAlign(hdc, mr->rdParm[0]);
871 case META_SELECTPALETTE:
872 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
875 case META_SETMAPPERFLAGS:
876 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
879 case META_REALIZEPALETTE:
880 GDIRealizePalette(hdc);
884 switch (mr->rdParm[0]) {
885 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
886 case GETPHYSPAGESIZE:
887 case GETPRINTINGOFFSET:
890 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
893 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
896 case META_EXTTEXTOUT:
897 MF_Play_MetaExtTextOut( hdc, mr );
900 case META_STRETCHDIB:
902 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
903 LPSTR bits = (LPSTR)info + bitmap_info_size( info, mr->rdParm[2] );
904 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
905 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
906 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
907 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
911 case META_DIBSTRETCHBLT:
913 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
914 LPSTR bits = (LPSTR)info + bitmap_info_size( info, DIB_RGB_COLORS );
915 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
916 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
917 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
918 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
922 case META_STRETCHBLT:
924 HDC hdcSrc = CreateCompatibleDC(hdc);
925 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
926 mr->rdParm[11], /*Height*/
927 mr->rdParm[13], /*Planes*/
928 mr->rdParm[14], /*BitsPixel*/
929 &mr->rdParm[15]); /*bits*/
930 SelectObject(hdcSrc,hbitmap);
931 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
932 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
933 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
934 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
935 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
942 HDC hdcSrc = CreateCompatibleDC(hdc);
943 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
944 mr->rdParm[8]/*Height*/,
945 mr->rdParm[10]/*Planes*/,
946 mr->rdParm[11]/*BitsPixel*/,
947 &mr->rdParm[12]/*bits*/);
948 SelectObject(hdcSrc,hbitmap);
949 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
950 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
951 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
952 MAKELONG(0,mr->rdParm[0]));
957 case META_CREATEREGION:
959 HRGN hrgn = CreateRectRgn(0,0,0,0);
961 MF_Play_MetaCreateRegion(mr, hrgn);
962 MF_AddHandle(ht, handles, hrgn);
966 case META_FILLREGION:
967 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
968 *(ht->objectHandle + mr->rdParm[0]));
971 case META_FRAMEREGION:
972 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
973 *(ht->objectHandle + mr->rdParm[2]),
974 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
977 case META_INVERTREGION:
978 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
981 case META_PAINTREGION:
982 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
985 case META_SELECTCLIPREGION:
989 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
990 SelectClipRgn(hdc, hrgn);
994 case META_DIBCREATEPATTERNBRUSH:
995 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
996 but there's no difference */
997 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
1000 case META_DIBBITBLT:
1001 /* In practice I've found that there are two layouts for
1002 META_DIBBITBLT, one (the first here) is the usual one when a src
1003 dc is actually passed to it, the second occurs when the src dc is
1004 passed in as NULL to the creating BitBlt. As the second case has
1005 no dib, a size check will suffice to distinguish.
1007 Caolan.McNamara@ul.ie */
1009 if (mr->rdSize > 12) {
1010 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1011 LPSTR bits = (LPSTR)info + bitmap_info_size(info, mr->rdParm[0]);
1013 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1014 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1015 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1016 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1018 else /* equivalent to a PatBlt */
1019 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1020 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1021 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1024 case META_SETTEXTCHAREXTRA:
1025 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1028 case META_SETTEXTJUSTIFICATION:
1029 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1032 case META_EXTFLOODFILL:
1033 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1034 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1038 case META_SETDIBTODEV:
1040 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1041 char *bits = (char *)info + bitmap_info_size( info, mr->rdParm[0] );
1042 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1043 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1044 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1045 mr->rdParm[2], mr->rdParm[1], bits, info,
1050 #define META_UNIMP(x) case x: \
1051 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1053 META_UNIMP(META_DRAWTEXT)
1054 META_UNIMP(META_ANIMATEPALETTE)
1055 META_UNIMP(META_SETPALENTRIES)
1056 META_UNIMP(META_RESIZEPALETTE)
1057 META_UNIMP(META_RESETDC)
1058 META_UNIMP(META_STARTDOC)
1059 META_UNIMP(META_STARTPAGE)
1060 META_UNIMP(META_ENDPAGE)
1061 META_UNIMP(META_ABORTDOC)
1062 META_UNIMP(META_ENDDOC)
1063 META_UNIMP(META_CREATEBRUSH)
1064 META_UNIMP(META_CREATEBITMAPINDIRECT)
1065 META_UNIMP(META_CREATEBITMAP)
1069 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1075 /******************************************************************
1076 * SetMetaFileBitsEx (GDI32.@)
1078 * Create a metafile from raw data. No checking of the data is performed.
1079 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1082 * size [I] size of metafile, in bytes
1083 * lpData [I] pointer to metafile data
1086 * Success: Handle to metafile.
1089 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1091 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1094 if (size & 1) return 0;
1096 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1097 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1099 SetLastError(ERROR_INVALID_DATA);
1103 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1106 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1110 memcpy(mh_out, mh_in, size);
1111 mh_out->mtSize = size / 2;
1112 return MF_Create_HMETAFILE(mh_out);
1115 /*****************************************************************
1116 * GetMetaFileBitsEx (GDI32.@)
1118 * Get raw metafile data.
1120 * Copies the data from metafile _hmf_ into the buffer _buf_.
1124 * nSize [I] size of buf
1125 * buf [O] buffer to receive raw metafile data
1128 * If _buf_ is zero, returns size of buffer required. Otherwise,
1129 * returns number of bytes copied.
1131 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1133 METAHEADER *mh = MF_GetMetaHeader(hmf);
1136 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1137 if (!mh) return 0; /* FIXME: error code */
1138 if(mh->mtType == METAFILE_DISK)
1139 FIXME("Disk-based metafile?\n");
1140 mfSize = mh->mtSize * 2;
1142 TRACE("returning size %d\n", mfSize);
1145 if(mfSize > nSize) mfSize = nSize;
1146 memmove(buf, mh, mfSize);
1150 #include <pshpack2.h>
1153 DWORD magic; /* WMFC */
1159 DWORD unk0e; /* 0 */
1162 DWORD remaining_size;
1166 #include <poppack.h>
1168 static const DWORD wmfc_magic = 0x43464d57;
1170 /******************************************************************
1173 * Helper for GetWinMetaFileBits
1175 * Add the MFCOMMENT record[s] which is essentially a copy
1176 * of the original emf.
1178 static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
1180 DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i;
1181 BYTE *bits, *chunk_data;
1182 mf_comment_chunk *chunk = NULL;
1184 static const DWORD max_chunk_size = 0x2000;
1186 if(!size) return FALSE;
1187 chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size);
1188 if(!bits) return FALSE;
1189 if(!GetEnhMetaFileBits(emf, size, bits)) goto end;
1191 chunk = HeapAlloc(GetProcessHeap(), 0, max_chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data));
1192 if(!chunk) goto end;
1194 chunk->magic = wmfc_magic;
1199 chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1201 chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
1202 chunk->chunk_size = max_chunk_size;
1203 chunk->remaining_size = size;
1204 chunk->emf_size = size;
1206 for(i = 0; i < chunk->num_chunks; i++)
1208 if(i == chunk->num_chunks - 1) /* last chunk */
1209 chunk->chunk_size = chunk->remaining_size;
1211 chunk->remaining_size -= chunk->chunk_size;
1212 memcpy(&chunk->emf_data, chunk_data, chunk->chunk_size);
1213 chunk_data += chunk->chunk_size;
1215 if(!Escape(hdc, MFCOMMENT, chunk->chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data), (char*)chunk, NULL))
1220 HeapFree(GetProcessHeap(), 0, chunk);
1221 HeapFree(GetProcessHeap(), 0, bits);
1225 /*******************************************************************
1228 * Behaves somewhat differently to MulDiv when the answer is -ve
1229 * and also rounds n.5 towards zero
1231 static INT muldiv(INT m1, INT m2, INT d)
1235 ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1237 if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1245 /******************************************************************
1248 * Helper for GetWinMetaFileBits
1250 * Add the SetWindowOrg and SetWindowExt records
1252 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1254 ENHMETAHEADER header;
1255 INT horz_res, vert_res, horz_size, vert_size;
1258 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1260 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1261 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1262 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1263 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1269 case MM_ANISOTROPIC:
1270 pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1271 pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
1274 pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1275 pt.x = muldiv( header.rclFrame.left, 1, 10);
1278 pt.y = -header.rclFrame.top + 1;
1279 pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
1282 pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1283 pt.x = muldiv( header.rclFrame.left, 10, 254);
1286 pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1287 pt.x = muldiv( header.rclFrame.left, 100, 254);
1290 pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1291 pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
1294 WARN("Unknown map mode %d\n", map_mode);
1297 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1299 pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1300 pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1301 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1305 /******************************************************************
1306 * GetWinMetaFileBits [GDI32.@]
1308 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1309 UINT cbBuffer, LPBYTE lpbBuffer,
1310 INT map_mode, HDC hdcRef)
1314 UINT ret, full_size;
1317 GetClipBox(hdcRef, &rc);
1319 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1320 map_mode, hdcRef, wine_dbgstr_rect(&rc));
1322 hdcmf = CreateMetaFileW(NULL);
1324 add_mf_comment(hdcmf, hemf);
1325 SetMapMode(hdcmf, map_mode);
1326 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1329 PlayEnhMetaFile(hdcmf, hemf, &rc);
1330 hmf = CloseMetaFile(hdcmf);
1331 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1332 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1333 DeleteMetaFile(hmf);
1335 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1338 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1341 for(i = 0; i < full_size / 2; i++)
1342 checksum += ((WORD*)lpbBuffer)[i];
1343 comment_rec->rdParm[8] = ~checksum + 1;
1348 DeleteMetaFile(CloseMetaFile(hdcmf));
1352 /******************************************************************
1353 * MF_Play_MetaCreateRegion
1355 * Handles META_CREATEREGION for PlayMetaFileRecord().
1357 * The layout of the record looks something like this:
1362 * 2 Looks like a handle? - not constant
1364 * 4 Total number of bytes
1365 * 5 No. of separate bands = n [see below]
1366 * 6 Largest number of x co-ords in a band
1367 * 7-10 Bounding box x1 y1 x2 y2
1370 * Regions are divided into bands that are uniform in the
1371 * y-direction. Each band consists of pairs of on/off x-coords and is
1373 * m y0 y1 x1 x2 x3 ... xm m
1374 * into successive rdParm[]s.
1376 * This is probably just a dump of the internal RGNOBJ?
1382 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1387 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1389 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1390 band++, start = end + 1) {
1391 if(*start / 2 != (*start + 1) / 2) {
1392 WARN("Delimiter not even.\n");
1393 DeleteObject( hrgn2 );
1397 end = start + *start + 3;
1398 if(end > (WORD *)mr + mr->rdSize) {
1399 WARN("End points outside record.\n");
1400 DeleteObject( hrgn2 );
1404 if(*start != *end) {
1405 WARN("Mismatched delimiters.\n");
1406 DeleteObject( hrgn2 );
1410 y0 = *(INT16 *)(start + 1);
1411 y1 = *(INT16 *)(start + 2);
1412 for(pair = 0; pair < *start / 2; pair++) {
1413 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1414 *(INT16 *)(start + 4 + 2*pair), y1 );
1415 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1418 DeleteObject( hrgn2 );
1423 /******************************************************************
1424 * MF_Play_MetaExtTextOut
1426 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1429 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1438 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1440 s1 = mr->rdParm[2]; /* String length */
1441 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1442 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1443 /* rec len without dx array */
1445 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1448 rect.left = (SHORT)mr->rdParm[4];
1449 rect.top = (SHORT)mr->rdParm[5];
1450 rect.right = (SHORT)mr->rdParm[6];
1451 rect.bottom = (SHORT)mr->rdParm[7];
1452 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1455 if (mr->rdSize == len / 2)
1456 dxx = NULL; /* determine if array is present */
1458 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1460 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1461 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1462 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1465 TRACE("%s len: %d\n", sot, mr->rdSize);
1466 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1467 len, s1, mr->rdSize, mr->rdParm[3]);
1468 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1471 (SHORT)mr->rdParm[1], /* X position */
1472 (SHORT)mr->rdParm[0], /* Y position */
1473 mr->rdParm[3], /* options */
1474 &rect, /* rectangle */
1476 s1, dx); /* length, dx array */
1479 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1480 HeapFree( GetProcessHeap(), 0, dx );