wmp: Add seeking and duration.
[wine.git] / dlls / gdi32 / metafile.c
blob28ad53cf57b38084643ce2bcf97e0560a1b0868e
1 /*
2 * Metafile functions
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
23 * NOTES
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
38 * the memory.
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.
45 * HDMD - 14/4/1999
48 #include "config.h"
50 #include <stdarg.h>
51 #include <string.h>
52 #include <fcntl.h>
54 #include "windef.h"
55 #include "winbase.h"
56 #include "wingdi.h"
57 #include "winreg.h"
58 #include "winnls.h"
59 #include "winternl.h"
60 #include "gdi_private.h"
61 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
65 #include "pshpack1.h"
66 typedef struct
68 DWORD dw1, dw2, dw3;
69 WORD w4;
70 CHAR filename[0x100];
71 } METAHEADERDISK;
72 #include "poppack.h"
75 /******************************************************************
76 * MF_AddHandle
78 * Add a handle to an external handle table and return the index
80 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
82 int i;
84 for (i = 0; i < htlen; i++)
86 if (*(ht->objectHandle + i) == 0)
88 *(ht->objectHandle + i) = hobj;
89 return i;
92 return -1;
96 /******************************************************************
97 * MF_Create_HMETATFILE
99 * Creates a (32 bit) HMETAFILE object from a METAHEADER
101 * HMETAFILEs are GDI objects.
103 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
105 return alloc_gdi_handle( mh, OBJ_METAFILE, NULL );
108 /******************************************************************
109 * convert_points
111 * Convert an array of POINTS to an array of POINT.
112 * Result must be freed by caller.
114 static POINT *convert_points( UINT count, const POINTS *pts )
116 UINT i;
117 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
118 if (ret)
120 for (i = 0; i < count; i++)
122 ret[i].x = pts[i].x;
123 ret[i].y = pts[i].y;
126 return ret;
129 /******************************************************************
130 * DeleteMetaFile (GDI32.@)
132 * Delete a memory-based metafile.
135 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
137 METAHEADER *mh = free_gdi_handle( hmf );
139 if (!mh) return FALSE;
140 HeapFree( GetProcessHeap(), 0, mh );
141 return TRUE;
144 /******************************************************************
145 * MF_ReadMetaFile
147 * Returns a pointer to a memory based METAHEADER read in from file HFILE
150 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
152 METAHEADER *mh;
153 DWORD BytesRead, size;
155 size = sizeof(METAHEADER);
156 mh = HeapAlloc( GetProcessHeap(), 0, size );
157 if(!mh) return NULL;
158 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
159 BytesRead != size) {
160 HeapFree( GetProcessHeap(), 0, mh );
161 return NULL;
163 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
164 mh->mtHeaderSize != size / 2)
166 HeapFree( GetProcessHeap(), 0, mh );
167 return NULL;
169 size = mh->mtSize * 2;
170 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
171 if(!mh) return NULL;
172 size -= sizeof(METAHEADER);
173 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
174 NULL) == 0 ||
175 BytesRead != size) {
176 HeapFree( GetProcessHeap(), 0, mh );
177 return NULL;
180 if (mh->mtType != METAFILE_MEMORY) {
181 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
182 mh->mtType = METAFILE_MEMORY;
184 return mh;
187 /******************************************************************
188 * GetMetaFileA (GDI32.@)
190 * Read a metafile from a file. Returns handle to a memory-based metafile.
192 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
194 METAHEADER *mh;
195 HANDLE hFile;
197 TRACE("%s\n", lpFilename);
199 if(!lpFilename)
200 return 0;
202 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
203 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
204 return 0;
206 mh = MF_ReadMetaFile(hFile);
207 CloseHandle(hFile);
208 if(!mh) return 0;
209 return MF_Create_HMETAFILE( mh );
212 /******************************************************************
213 * GetMetaFileW (GDI32.@)
215 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
217 METAHEADER *mh;
218 HANDLE hFile;
220 TRACE("%s\n", debugstr_w(lpFilename));
222 if(!lpFilename)
223 return 0;
225 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
226 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
227 return 0;
229 mh = MF_ReadMetaFile(hFile);
230 CloseHandle(hFile);
231 if(!mh) return 0;
232 return MF_Create_HMETAFILE( mh );
236 /******************************************************************
237 * MF_LoadDiskBasedMetaFile
239 * Creates a new memory-based metafile from a disk-based one.
241 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
243 METAHEADERDISK *mhd;
244 HANDLE hfile;
245 METAHEADER *mh2;
247 if(mh->mtType != METAFILE_DISK) {
248 ERR("Not a disk based metafile\n");
249 return NULL;
251 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
253 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
254 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
255 WARN("Can't open file of disk based metafile\n");
256 return NULL;
258 mh2 = MF_ReadMetaFile(hfile);
259 CloseHandle(hfile);
260 return mh2;
263 /******************************************************************
264 * MF_CreateMetaHeaderDisk
266 * Take a memory based METAHEADER and change it to a disk based METAHEADER
267 * associated with filename. Note: Trashes contents of old one.
269 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
271 METAHEADERDISK *mhd;
273 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
274 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
275 mh->mtType = METAFILE_DISK;
276 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
278 if( uni )
279 WideCharToMultiByte(CP_ACP, 0, filename, -1,
280 mhd->filename, sizeof mhd->filename, NULL, NULL);
281 else
282 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
283 return mh;
286 /* return a copy of the metafile bits, to be freed with HeapFree */
287 static METAHEADER *get_metafile_bits( HMETAFILE hmf )
289 METAHEADER *ret, *mh = GDI_GetObjPtr( hmf, OBJ_METAFILE );
291 if (!mh) return NULL;
293 if (mh->mtType != METAFILE_DISK)
295 ret = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
296 if (ret) memcpy( ret, mh, mh->mtSize * 2 );
298 else ret = MF_LoadDiskBasedMetaFile( mh );
300 GDI_ReleaseObj( hmf );
301 return ret;
304 /******************************************************************
305 * CopyMetaFileW (GDI32.@)
307 * Copies the metafile corresponding to hSrcMetaFile to either
308 * a disk file, if a filename is given, or to a new memory based
309 * metafile, if lpFileName is NULL.
311 * PARAMS
312 * hSrcMetaFile [I] handle of metafile to copy
313 * lpFilename [I] filename if copying to a file
315 * RETURNS
316 * Handle to metafile copy on success, NULL on failure.
318 * BUGS
319 * Copying to disk returns NULL even if successful.
321 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
323 METAHEADER *mh = get_metafile_bits( hSrcMetaFile );
324 HANDLE hFile;
326 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
328 if(!mh) return 0;
330 if(lpFilename) { /* disk based metafile */
331 DWORD w;
332 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
333 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
334 HeapFree( GetProcessHeap(), 0, mh );
335 return 0;
337 WriteFile(hFile, mh, mh->mtSize * 2, &w, NULL);
338 CloseHandle(hFile);
341 return MF_Create_HMETAFILE( mh );
345 /******************************************************************
346 * CopyMetaFileA (GDI32.@)
348 * See CopyMetaFileW.
350 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
352 UNICODE_STRING lpFilenameW;
353 HMETAFILE ret = 0;
355 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
356 else lpFilenameW.Buffer = NULL;
358 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
359 if (lpFilenameW.Buffer)
360 RtlFreeUnicodeString(&lpFilenameW);
361 return ret;
364 /******************************************************************
365 * PlayMetaFile (GDI32.@)
367 * Renders the metafile specified by hmf in the DC specified by
368 * hdc. Returns FALSE on failure, TRUE on success.
370 * PARAMS
371 * hdc [I] handle of DC to render in
372 * hmf [I] handle of metafile to render
374 * RETURNS
375 * Success: TRUE
376 * Failure: FALSE
378 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
380 METAHEADER *mh = get_metafile_bits( hmf );
381 METARECORD *mr;
382 HANDLETABLE *ht;
383 unsigned int offset = 0;
384 WORD i;
385 HPEN hPen;
386 HBRUSH hBrush;
387 HPALETTE hPal;
388 HRGN hRgn;
390 if (!mh) return FALSE;
392 /* save DC */
393 hPen = GetCurrentObject(hdc, OBJ_PEN);
394 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
395 hPal = GetCurrentObject(hdc, OBJ_PAL);
397 hRgn = CreateRectRgn(0, 0, 0, 0);
398 if (!GetClipRgn(hdc, hRgn))
400 DeleteObject(hRgn);
401 hRgn = 0;
404 /* create the handle table */
405 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
406 sizeof(HANDLETABLE) * mh->mtNoObjects);
407 if(!ht)
409 HeapFree( GetProcessHeap(), 0, mh );
410 return FALSE;
413 /* loop through metafile playing records */
414 offset = mh->mtHeaderSize * 2;
415 while (offset < mh->mtSize * 2)
417 mr = (METARECORD *)((char *)mh + offset);
418 TRACE("offset=%04x,size=%08x\n",
419 offset, mr->rdSize);
420 if (mr->rdSize < 3) { /* catch illegal record sizes */
421 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
422 mr->rdSize,offset,mh->mtSize*2);
423 break;
426 offset += mr->rdSize * 2;
427 if (mr->rdFunction == META_EOF) {
428 TRACE("Got META_EOF so stopping\n");
429 break;
431 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
434 /* restore DC */
435 SelectObject(hdc, hPen);
436 SelectObject(hdc, hBrush);
437 SelectPalette(hdc, hPal, FALSE);
438 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
439 DeleteObject(hRgn);
441 /* free objects in handle table */
442 for(i = 0; i < mh->mtNoObjects; i++)
443 if(*(ht->objectHandle + i) != 0)
444 DeleteObject(*(ht->objectHandle + i));
446 HeapFree( GetProcessHeap(), 0, ht );
447 HeapFree( GetProcessHeap(), 0, mh );
448 return TRUE;
451 /******************************************************************
452 * EnumMetaFile (GDI32.@)
454 * Loop through the metafile records in hmf, calling the user-specified
455 * function for each one, stopping when the user's function returns FALSE
456 * (which is considered to be failure)
457 * or when no records are left (which is considered to be success).
459 * RETURNS
460 * TRUE on success, FALSE on failure.
462 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
464 METAHEADER *mh = get_metafile_bits( hmf );
465 METARECORD *mr;
466 HANDLETABLE *ht;
467 BOOL result = TRUE;
468 int i;
469 unsigned int offset = 0;
470 HPEN hPen;
471 HBRUSH hBrush;
472 HFONT hFont;
474 TRACE("(%p,%p,%p,%lx)\n", hdc, hmf, lpEnumFunc, lpData);
476 if (!mh) return FALSE;
478 /* save the current pen, brush and font */
479 hPen = GetCurrentObject(hdc, OBJ_PEN);
480 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
481 hFont = GetCurrentObject(hdc, OBJ_FONT);
483 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
484 sizeof(HANDLETABLE) * mh->mtNoObjects);
486 /* loop through metafile records */
487 offset = mh->mtHeaderSize * 2;
489 while (offset < (mh->mtSize * 2))
491 mr = (METARECORD *)((char *)mh + offset);
492 if(mr->rdFunction == META_EOF) {
493 TRACE("Got META_EOF so stopping\n");
494 break;
496 TRACE("Calling EnumFunc with record type %x\n",
497 mr->rdFunction);
498 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, lpData ))
500 result = FALSE;
501 break;
504 offset += (mr->rdSize * 2);
507 /* restore pen, brush and font */
508 SelectObject(hdc, hBrush);
509 SelectObject(hdc, hPen);
510 SelectObject(hdc, hFont);
512 /* free objects in handle table */
513 for(i = 0; i < mh->mtNoObjects; i++)
514 if(*(ht->objectHandle + i) != 0)
515 DeleteObject(*(ht->objectHandle + i));
517 HeapFree( GetProcessHeap(), 0, ht);
518 HeapFree( GetProcessHeap(), 0, mh);
519 return result;
522 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
523 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
524 /******************************************************************
525 * PlayMetaFileRecord (GDI32.@)
527 * Render a single metafile record specified by *mr in the DC hdc, while
528 * using the handle table *ht, of length handles,
529 * to store metafile objects.
531 * BUGS
532 * The following metafile records are unimplemented:
534 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
535 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
536 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
538 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
540 short s1;
541 POINT *pt;
542 BITMAPINFOHEADER *infohdr;
544 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
546 switch (mr->rdFunction)
548 case META_EOF:
549 break;
551 case META_DELETEOBJECT:
552 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
553 *(ht->objectHandle + mr->rdParm[0]) = 0;
554 break;
556 case META_SETBKCOLOR:
557 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
558 break;
560 case META_SETBKMODE:
561 SetBkMode(hdc, mr->rdParm[0]);
562 break;
564 case META_SETMAPMODE:
565 SetMapMode(hdc, mr->rdParm[0]);
566 break;
568 case META_SETROP2:
569 SetROP2(hdc, mr->rdParm[0]);
570 break;
572 case META_SETRELABS:
573 SetRelAbs(hdc, mr->rdParm[0]);
574 break;
576 case META_SETPOLYFILLMODE:
577 SetPolyFillMode(hdc, mr->rdParm[0]);
578 break;
580 case META_SETSTRETCHBLTMODE:
581 SetStretchBltMode(hdc, mr->rdParm[0]);
582 break;
584 case META_SETTEXTCOLOR:
585 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
586 break;
588 case META_SETWINDOWORG:
589 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
590 break;
592 case META_SETWINDOWEXT:
593 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
594 break;
596 case META_SETVIEWPORTORG:
597 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
598 break;
600 case META_SETVIEWPORTEXT:
601 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
602 break;
604 case META_OFFSETWINDOWORG:
605 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
606 break;
608 case META_SCALEWINDOWEXT:
609 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
610 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
611 break;
613 case META_OFFSETVIEWPORTORG:
614 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
615 break;
617 case META_SCALEVIEWPORTEXT:
618 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
619 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
620 break;
622 case META_LINETO:
623 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
624 break;
626 case META_MOVETO:
627 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
628 break;
630 case META_EXCLUDECLIPRECT:
631 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
632 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
633 break;
635 case META_INTERSECTCLIPRECT:
636 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
637 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
638 break;
640 case META_ARC:
641 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
642 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
643 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
644 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
645 break;
647 case META_ELLIPSE:
648 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
649 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
650 break;
652 case META_FLOODFILL:
653 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
654 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
655 break;
657 case META_PIE:
658 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
659 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
660 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
661 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
662 break;
664 case META_RECTANGLE:
665 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
666 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
667 break;
669 case META_ROUNDRECT:
670 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
671 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
672 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
673 break;
675 case META_PATBLT:
676 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
677 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
678 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
679 break;
681 case META_SAVEDC:
682 SaveDC(hdc);
683 break;
685 case META_SETPIXEL:
686 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
687 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
688 break;
690 case META_OFFSETCLIPRGN:
691 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
692 break;
694 case META_TEXTOUT:
695 s1 = mr->rdParm[0];
696 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
697 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
698 (char *)(mr->rdParm + 1), s1);
699 break;
701 case META_POLYGON:
702 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
704 Polygon(hdc, pt, mr->rdParm[0]);
705 HeapFree( GetProcessHeap(), 0, pt );
707 break;
709 case META_POLYPOLYGON:
711 UINT i, total;
712 SHORT *counts = (SHORT *)(mr->rdParm + 1);
714 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
715 pt = convert_points( total, (POINTS *)(counts + mr->rdParm[0]) );
716 if (pt)
718 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
719 if (cnt32)
721 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
722 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
723 HeapFree( GetProcessHeap(), 0, cnt32 );
726 HeapFree( GetProcessHeap(), 0, pt );
728 break;
730 case META_POLYLINE:
731 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
733 Polyline( hdc, pt, mr->rdParm[0] );
734 HeapFree( GetProcessHeap(), 0, pt );
736 break;
738 case META_RESTOREDC:
739 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
740 break;
742 case META_SELECTOBJECT:
743 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
744 break;
746 case META_CHORD:
747 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
748 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
749 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
750 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
751 break;
753 case META_CREATEPATTERNBRUSH:
754 switch (mr->rdParm[0])
756 case BS_PATTERN:
757 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
758 MF_AddHandle(ht, handles,
759 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
760 infohdr->biHeight,
761 infohdr->biPlanes,
762 infohdr->biBitCount,
763 mr->rdParm +
764 (sizeof(BITMAPINFOHEADER) / 2) + 4)));
765 break;
767 case BS_DIBPATTERN:
768 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
769 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
770 break;
772 default:
773 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
774 mr->rdParm[0]);
775 break;
777 break;
779 case META_CREATEPENINDIRECT:
781 LOGPEN pen;
782 pen.lopnStyle = mr->rdParm[0];
783 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
784 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
785 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
786 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
788 break;
790 case META_CREATEFONTINDIRECT:
792 LOGFONTA font;
793 font.lfHeight = (SHORT)mr->rdParm[0];
794 font.lfWidth = (SHORT)mr->rdParm[1];
795 font.lfEscapement = (SHORT)mr->rdParm[2];
796 font.lfOrientation = (SHORT)mr->rdParm[3];
797 font.lfWeight = (SHORT)mr->rdParm[4];
798 font.lfItalic = LOBYTE(mr->rdParm[5]);
799 font.lfUnderline = HIBYTE(mr->rdParm[5]);
800 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
801 font.lfCharSet = HIBYTE(mr->rdParm[6]);
802 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
803 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
804 font.lfQuality = LOBYTE(mr->rdParm[8]);
805 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
806 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
807 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
809 break;
811 case META_CREATEBRUSHINDIRECT:
813 LOGBRUSH brush;
814 brush.lbStyle = mr->rdParm[0];
815 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
816 brush.lbHatch = mr->rdParm[3];
817 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
819 break;
821 case META_CREATEPALETTE:
822 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
823 break;
825 case META_SETTEXTALIGN:
826 SetTextAlign(hdc, mr->rdParm[0]);
827 break;
829 case META_SELECTPALETTE:
830 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
831 break;
833 case META_SETMAPPERFLAGS:
834 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
835 break;
837 case META_REALIZEPALETTE:
838 GDIRealizePalette(hdc);
839 break;
841 case META_ESCAPE:
842 switch (mr->rdParm[0]) {
843 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
844 case GETPHYSPAGESIZE:
845 case GETPRINTINGOFFSET:
846 return FALSE;
847 case SETABORTPROC:
848 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
849 return FALSE;
851 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
852 break;
854 case META_EXTTEXTOUT:
855 MF_Play_MetaExtTextOut( hdc, mr );
856 break;
858 case META_STRETCHDIB:
860 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
861 LPSTR bits = (LPSTR)info + bitmap_info_size( info, mr->rdParm[2] );
862 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
863 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
864 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
865 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
867 break;
869 case META_DIBSTRETCHBLT:
871 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
872 LPSTR bits = (LPSTR)info + bitmap_info_size( info, DIB_RGB_COLORS );
873 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
874 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
875 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
876 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
878 break;
880 case META_STRETCHBLT:
882 HDC hdcSrc = CreateCompatibleDC(hdc);
883 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
884 mr->rdParm[11], /*Height*/
885 mr->rdParm[13], /*Planes*/
886 mr->rdParm[14], /*BitsPixel*/
887 &mr->rdParm[15]); /*bits*/
888 SelectObject(hdcSrc,hbitmap);
889 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
890 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
891 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
892 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
893 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
894 DeleteDC(hdcSrc);
896 break;
898 case META_BITBLT:
900 HDC hdcSrc = CreateCompatibleDC(hdc);
901 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
902 mr->rdParm[8]/*Height*/,
903 mr->rdParm[10]/*Planes*/,
904 mr->rdParm[11]/*BitsPixel*/,
905 &mr->rdParm[12]/*bits*/);
906 SelectObject(hdcSrc,hbitmap);
907 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
908 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
909 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
910 MAKELONG(0,mr->rdParm[0]));
911 DeleteDC(hdcSrc);
913 break;
915 case META_CREATEREGION:
917 HRGN hrgn = CreateRectRgn(0,0,0,0);
919 MF_Play_MetaCreateRegion(mr, hrgn);
920 MF_AddHandle(ht, handles, hrgn);
922 break;
924 case META_FILLREGION:
925 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
926 *(ht->objectHandle + mr->rdParm[0]));
927 break;
929 case META_FRAMEREGION:
930 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
931 *(ht->objectHandle + mr->rdParm[2]),
932 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
933 break;
935 case META_INVERTREGION:
936 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
937 break;
939 case META_PAINTREGION:
940 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
941 break;
943 case META_SELECTCLIPREGION:
945 HRGN hrgn = 0;
947 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
948 SelectClipRgn(hdc, hrgn);
950 break;
952 case META_DIBCREATEPATTERNBRUSH:
953 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
954 but there's no difference */
955 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
956 break;
958 case META_DIBBITBLT:
959 /* In practice I've found that there are two layouts for
960 META_DIBBITBLT, one (the first here) is the usual one when a src
961 dc is actually passed to it, the second occurs when the src dc is
962 passed in as NULL to the creating BitBlt. As the second case has
963 no dib, a size check will suffice to distinguish.
965 Caolan.McNamara@ul.ie */
967 if (mr->rdSize > 12) {
968 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
969 LPSTR bits = (LPSTR)info + bitmap_info_size(info, mr->rdParm[0]);
971 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
972 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
973 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
974 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
976 else /* equivalent to a PatBlt */
977 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
978 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
979 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
980 break;
982 case META_SETTEXTCHAREXTRA:
983 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
984 break;
986 case META_SETTEXTJUSTIFICATION:
987 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
988 break;
990 case META_EXTFLOODFILL:
991 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
992 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
993 mr->rdParm[0]);
994 break;
996 case META_SETDIBTODEV:
998 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
999 char *bits = (char *)info + bitmap_info_size( info, mr->rdParm[0] );
1000 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1001 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1002 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1003 mr->rdParm[2], mr->rdParm[1], bits, info,
1004 mr->rdParm[0]);
1005 break;
1008 #define META_UNIMP(x) case x: \
1009 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1010 break;
1011 META_UNIMP(META_DRAWTEXT)
1012 META_UNIMP(META_ANIMATEPALETTE)
1013 META_UNIMP(META_SETPALENTRIES)
1014 META_UNIMP(META_RESIZEPALETTE)
1015 META_UNIMP(META_RESETDC)
1016 META_UNIMP(META_STARTDOC)
1017 META_UNIMP(META_STARTPAGE)
1018 META_UNIMP(META_ENDPAGE)
1019 META_UNIMP(META_ABORTDOC)
1020 META_UNIMP(META_ENDDOC)
1021 META_UNIMP(META_CREATEBRUSH)
1022 META_UNIMP(META_CREATEBITMAPINDIRECT)
1023 META_UNIMP(META_CREATEBITMAP)
1024 #undef META_UNIMP
1026 default:
1027 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1028 return FALSE;
1030 return TRUE;
1033 /******************************************************************
1034 * SetMetaFileBitsEx (GDI32.@)
1036 * Create a metafile from raw data. No checking of the data is performed.
1037 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1039 * PARAMS
1040 * size [I] size of metafile, in bytes
1041 * lpData [I] pointer to metafile data
1043 * RETURNS
1044 * Success: Handle to metafile.
1045 * Failure: NULL.
1047 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1049 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1050 METAHEADER *mh_out;
1052 if (size & 1) return 0;
1054 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1055 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1057 SetLastError(ERROR_INVALID_DATA);
1058 return 0;
1061 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1062 if (!mh_out)
1064 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1065 return 0;
1068 memcpy(mh_out, mh_in, size);
1069 mh_out->mtSize = size / 2;
1070 return MF_Create_HMETAFILE(mh_out);
1073 /*****************************************************************
1074 * GetMetaFileBitsEx (GDI32.@)
1076 * Get raw metafile data.
1078 * Copies the data from metafile _hmf_ into the buffer _buf_.
1080 * PARAMS
1081 * hmf [I] metafile
1082 * nSize [I] size of buf
1083 * buf [O] buffer to receive raw metafile data
1085 * RETURNS
1086 * If _buf_ is zero, returns size of buffer required. Otherwise,
1087 * returns number of bytes copied.
1089 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1091 METAHEADER *mh = GDI_GetObjPtr( hmf, OBJ_METAFILE );
1092 UINT mfSize;
1093 BOOL mf_copy = FALSE;
1095 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1096 if (!mh) return 0; /* FIXME: error code */
1097 if(mh->mtType == METAFILE_DISK)
1099 mh = MF_LoadDiskBasedMetaFile( mh );
1100 if (!mh)
1102 GDI_ReleaseObj( hmf );
1103 return 0;
1105 mf_copy = TRUE;
1107 mfSize = mh->mtSize * 2;
1108 if (buf)
1110 if(mfSize > nSize) mfSize = nSize;
1111 memmove(buf, mh, mfSize);
1113 if (mf_copy) HeapFree( GetProcessHeap(), 0, mh );
1114 GDI_ReleaseObj( hmf );
1115 TRACE("returning size %d\n", mfSize);
1116 return mfSize;
1119 /******************************************************************
1120 * add_mf_comment
1122 * Helper for GetWinMetaFileBits
1124 * Add the MFCOMMENT record[s] which is essentially a copy
1125 * of the original emf.
1127 static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
1129 DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i;
1130 BYTE *bits, *chunk_data;
1131 emf_in_wmf_comment *chunk = NULL;
1132 BOOL ret = FALSE;
1133 static const DWORD max_chunk_size = 0x2000;
1135 if(!size) return FALSE;
1136 chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size);
1137 if(!bits) return FALSE;
1138 if(!GetEnhMetaFileBits(emf, size, bits)) goto end;
1140 chunk = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(emf_in_wmf_comment, emf_data[max_chunk_size]));
1141 if(!chunk) goto end;
1143 chunk->magic = WMFC_MAGIC;
1144 chunk->unk04 = 1;
1145 chunk->unk06 = 0;
1146 chunk->unk08 = 0;
1147 chunk->unk0a = 1;
1148 chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1149 chunk->unk0e = 0;
1150 chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
1151 chunk->chunk_size = max_chunk_size;
1152 chunk->remaining_size = size;
1153 chunk->emf_size = size;
1155 for(i = 0; i < chunk->num_chunks; i++)
1157 if(i == chunk->num_chunks - 1) /* last chunk */
1158 chunk->chunk_size = chunk->remaining_size;
1160 chunk->remaining_size -= chunk->chunk_size;
1161 memcpy(chunk->emf_data, chunk_data, chunk->chunk_size);
1162 chunk_data += chunk->chunk_size;
1164 if(!Escape(hdc, MFCOMMENT, FIELD_OFFSET(emf_in_wmf_comment, emf_data[chunk->chunk_size]), (char*)chunk, NULL))
1165 goto end;
1167 ret = TRUE;
1168 end:
1169 HeapFree(GetProcessHeap(), 0, chunk);
1170 HeapFree(GetProcessHeap(), 0, bits);
1171 return ret;
1174 /*******************************************************************
1175 * muldiv
1177 * Behaves somewhat differently to MulDiv when the answer is -ve
1178 * and also rounds n.5 towards zero
1180 static INT muldiv(INT m1, INT m2, INT d)
1182 LONGLONG ret;
1184 ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1186 if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1188 if(ret > 0) ret--;
1189 else ret++;
1191 return ret;
1194 /******************************************************************
1195 * set_window
1197 * Helper for GetWinMetaFileBits
1199 * Add the SetWindowOrg and SetWindowExt records
1201 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1203 ENHMETAHEADER header;
1204 INT horz_res, vert_res, horz_size, vert_size;
1205 POINT pt;
1207 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1209 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1210 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1211 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1212 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1214 switch(map_mode)
1216 case MM_TEXT:
1217 case MM_ISOTROPIC:
1218 case MM_ANISOTROPIC:
1219 pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1220 pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
1221 break;
1222 case MM_LOMETRIC:
1223 pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1224 pt.x = muldiv( header.rclFrame.left, 1, 10);
1225 break;
1226 case MM_HIMETRIC:
1227 pt.y = -header.rclFrame.top + 1;
1228 pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
1229 break;
1230 case MM_LOENGLISH:
1231 pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1232 pt.x = muldiv( header.rclFrame.left, 10, 254);
1233 break;
1234 case MM_HIENGLISH:
1235 pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1236 pt.x = muldiv( header.rclFrame.left, 100, 254);
1237 break;
1238 case MM_TWIPS:
1239 pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1240 pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
1241 break;
1242 default:
1243 WARN("Unknown map mode %d\n", map_mode);
1244 return FALSE;
1246 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1248 pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1249 pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1250 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1251 return TRUE;
1254 /******************************************************************
1255 * GetWinMetaFileBits [GDI32.@]
1257 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1258 UINT cbBuffer, LPBYTE lpbBuffer,
1259 INT map_mode, HDC hdcRef)
1261 HDC hdcmf;
1262 HMETAFILE hmf;
1263 UINT ret, full_size;
1264 RECT rc;
1266 GetClipBox(hdcRef, &rc);
1268 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1269 map_mode, hdcRef, wine_dbgstr_rect(&rc));
1271 hdcmf = CreateMetaFileW(NULL);
1273 add_mf_comment(hdcmf, hemf);
1274 SetMapMode(hdcmf, map_mode);
1275 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1276 goto error;
1278 PlayEnhMetaFile(hdcmf, hemf, &rc);
1279 hmf = CloseMetaFile(hdcmf);
1280 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1281 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1282 DeleteMetaFile(hmf);
1284 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1286 WORD checksum = 0;
1287 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1288 UINT i;
1290 for(i = 0; i < full_size / 2; i++)
1291 checksum += ((WORD*)lpbBuffer)[i];
1292 comment_rec->rdParm[8] = ~checksum + 1;
1294 return ret;
1296 error:
1297 DeleteMetaFile(CloseMetaFile(hdcmf));
1298 return 0;
1301 /******************************************************************
1302 * MF_Play_MetaCreateRegion
1304 * Handles META_CREATEREGION for PlayMetaFileRecord().
1306 * The layout of the record looks something like this:
1308 * rdParm meaning
1309 * 0 Always 0?
1310 * 1 Always 6?
1311 * 2 Looks like a handle? - not constant
1312 * 3 0 or 1 ??
1313 * 4 Total number of bytes
1314 * 5 No. of separate bands = n [see below]
1315 * 6 Largest number of x co-ords in a band
1316 * 7-10 Bounding box x1 y1 x2 y2
1317 * 11-... n bands
1319 * Regions are divided into bands that are uniform in the
1320 * y-direction. Each band consists of pairs of on/off x-coords and is
1321 * written as
1322 * m y0 y1 x1 x2 x3 ... xm m
1323 * into successive rdParm[]s.
1325 * This is probably just a dump of the internal RGNOBJ?
1327 * HDMD - 18/12/97
1331 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1333 WORD band, pair;
1334 WORD *start, *end;
1335 INT16 y0, y1;
1336 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1338 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1339 band++, start = end + 1) {
1340 if(*start / 2 != (*start + 1) / 2) {
1341 WARN("Delimiter not even.\n");
1342 DeleteObject( hrgn2 );
1343 return FALSE;
1346 end = start + *start + 3;
1347 if(end > (WORD *)mr + mr->rdSize) {
1348 WARN("End points outside record.\n");
1349 DeleteObject( hrgn2 );
1350 return FALSE;
1353 if(*start != *end) {
1354 WARN("Mismatched delimiters.\n");
1355 DeleteObject( hrgn2 );
1356 return FALSE;
1359 y0 = *(INT16 *)(start + 1);
1360 y1 = *(INT16 *)(start + 2);
1361 for(pair = 0; pair < *start / 2; pair++) {
1362 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1363 *(INT16 *)(start + 4 + 2*pair), y1 );
1364 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1367 DeleteObject( hrgn2 );
1368 return TRUE;
1372 /******************************************************************
1373 * MF_Play_MetaExtTextOut
1375 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1378 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1380 INT *dx = NULL;
1381 int i;
1382 SHORT *dxx;
1383 LPSTR sot;
1384 DWORD len;
1385 WORD s1;
1386 RECT rect;
1387 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1389 s1 = mr->rdParm[2]; /* String length */
1390 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1391 + sizeof(UINT16) + (isrect ? 4 * sizeof(SHORT) : 0);
1392 /* rec len without dx array */
1394 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1395 if (isrect)
1397 rect.left = (SHORT)mr->rdParm[4];
1398 rect.top = (SHORT)mr->rdParm[5];
1399 rect.right = (SHORT)mr->rdParm[6];
1400 rect.bottom = (SHORT)mr->rdParm[7];
1401 sot += 4 * sizeof(SHORT); /* there is a rectangle, so add offset */
1404 if (mr->rdSize == len / 2)
1405 dxx = NULL; /* determine if array is present */
1406 else
1407 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1409 dxx = (SHORT *)(sot+(((s1+1)>>1)*2));
1410 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1411 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1413 else {
1414 TRACE("%s len: %d\n", sot, mr->rdSize);
1415 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1416 len, s1, mr->rdSize, mr->rdParm[3]);
1417 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1419 ExtTextOutA( hdc,
1420 (SHORT)mr->rdParm[1], /* X position */
1421 (SHORT)mr->rdParm[0], /* Y position */
1422 mr->rdParm[3], /* options */
1423 &rect, /* rectangle */
1424 sot, /* string */
1425 s1, dx); /* length, dx array */
1426 if (dx)
1428 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1429 HeapFree( GetProcessHeap(), 0, dx );
1431 return TRUE;