msvcp: Add a macro to access the locale field of I/O streams.
[wine.git] / dlls / gdi32 / metafile.c
blob0cb36afa2de0e21d8c6d5770a70a4831ef5137df
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 );
138 if (!mh) return FALSE;
139 return HeapFree( GetProcessHeap(), 0, mh );
142 /******************************************************************
143 * MF_ReadMetaFile
145 * Returns a pointer to a memory based METAHEADER read in from file HFILE
148 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
150 METAHEADER *mh;
151 DWORD BytesRead, size;
153 size = sizeof(METAHEADER);
154 mh = HeapAlloc( GetProcessHeap(), 0, size );
155 if(!mh) return NULL;
156 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
157 BytesRead != size) {
158 HeapFree( GetProcessHeap(), 0, mh );
159 return NULL;
161 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
162 mh->mtHeaderSize != size / 2)
164 HeapFree( GetProcessHeap(), 0, mh );
165 return NULL;
167 size = mh->mtSize * 2;
168 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
169 if(!mh) return NULL;
170 size -= sizeof(METAHEADER);
171 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
172 NULL) == 0 ||
173 BytesRead != size) {
174 HeapFree( GetProcessHeap(), 0, mh );
175 return NULL;
178 if (mh->mtType != METAFILE_MEMORY) {
179 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
180 mh->mtType = METAFILE_MEMORY;
182 return mh;
185 /******************************************************************
186 * GetMetaFileA (GDI32.@)
188 * Read a metafile from a file. Returns handle to a memory-based metafile.
190 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
192 METAHEADER *mh;
193 HANDLE hFile;
195 TRACE("%s\n", lpFilename);
197 if(!lpFilename)
198 return 0;
200 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
201 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
202 return 0;
204 mh = MF_ReadMetaFile(hFile);
205 CloseHandle(hFile);
206 if(!mh) return 0;
207 return MF_Create_HMETAFILE( mh );
210 /******************************************************************
211 * GetMetaFileW (GDI32.@)
213 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
215 METAHEADER *mh;
216 HANDLE hFile;
218 TRACE("%s\n", debugstr_w(lpFilename));
220 if(!lpFilename)
221 return 0;
223 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
224 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
225 return 0;
227 mh = MF_ReadMetaFile(hFile);
228 CloseHandle(hFile);
229 if(!mh) return 0;
230 return MF_Create_HMETAFILE( mh );
234 /******************************************************************
235 * MF_LoadDiskBasedMetaFile
237 * Creates a new memory-based metafile from a disk-based one.
239 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
241 METAHEADERDISK *mhd;
242 HANDLE hfile;
243 METAHEADER *mh2;
245 if(mh->mtType != METAFILE_DISK) {
246 ERR("Not a disk based metafile\n");
247 return NULL;
249 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
251 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
252 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
253 WARN("Can't open file of disk based metafile\n");
254 return NULL;
256 mh2 = MF_ReadMetaFile(hfile);
257 CloseHandle(hfile);
258 return mh2;
261 /******************************************************************
262 * MF_CreateMetaHeaderDisk
264 * Take a memory based METAHEADER and change it to a disk based METAHEADER
265 * associated with filename. Note: Trashes contents of old one.
267 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
269 METAHEADERDISK *mhd;
271 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
272 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
273 mh->mtType = METAFILE_DISK;
274 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
276 if( uni )
277 WideCharToMultiByte(CP_ACP, 0, filename, -1,
278 mhd->filename, sizeof mhd->filename, NULL, NULL);
279 else
280 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
281 return mh;
284 /* return a copy of the metafile bits, to be freed with HeapFree */
285 static METAHEADER *get_metafile_bits( HMETAFILE hmf )
287 METAHEADER *ret, *mh = GDI_GetObjPtr( hmf, OBJ_METAFILE );
289 if (!mh) return NULL;
291 if (mh->mtType != METAFILE_DISK)
293 ret = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
294 if (ret) memcpy( ret, mh, mh->mtSize * 2 );
296 else ret = MF_LoadDiskBasedMetaFile( mh );
298 GDI_ReleaseObj( hmf );
299 return ret;
302 /******************************************************************
303 * CopyMetaFileW (GDI32.@)
305 * Copies the metafile corresponding to hSrcMetaFile to either
306 * a disk file, if a filename is given, or to a new memory based
307 * metafile, if lpFileName is NULL.
309 * PARAMS
310 * hSrcMetaFile [I] handle of metafile to copy
311 * lpFilename [I] filename if copying to a file
313 * RETURNS
314 * Handle to metafile copy on success, NULL on failure.
316 * BUGS
317 * Copying to disk returns NULL even if successful.
319 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
321 METAHEADER *mh = get_metafile_bits( hSrcMetaFile );
322 HANDLE hFile;
324 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
326 if(!mh) return 0;
328 if(lpFilename) { /* disk based metafile */
329 DWORD w;
330 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
331 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
332 HeapFree( GetProcessHeap(), 0, mh );
333 return 0;
335 WriteFile(hFile, mh, mh->mtSize * 2, &w, NULL);
336 CloseHandle(hFile);
339 return MF_Create_HMETAFILE( mh );
343 /******************************************************************
344 * CopyMetaFileA (GDI32.@)
346 * See CopyMetaFileW.
348 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
350 UNICODE_STRING lpFilenameW;
351 HMETAFILE ret = 0;
353 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
354 else lpFilenameW.Buffer = NULL;
356 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
357 if (lpFilenameW.Buffer)
358 RtlFreeUnicodeString(&lpFilenameW);
359 return ret;
362 /******************************************************************
363 * PlayMetaFile (GDI32.@)
365 * Renders the metafile specified by hmf in the DC specified by
366 * hdc. Returns FALSE on failure, TRUE on success.
368 * PARAMS
369 * hdc [I] handle of DC to render in
370 * hmf [I] handle of metafile to render
372 * RETURNS
373 * Success: TRUE
374 * Failure: FALSE
376 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
378 METAHEADER *mh = get_metafile_bits( hmf );
379 METARECORD *mr;
380 HANDLETABLE *ht;
381 unsigned int offset = 0;
382 WORD i;
383 HPEN hPen;
384 HBRUSH hBrush;
385 HPALETTE hPal;
386 HRGN hRgn;
388 if (!mh) return FALSE;
390 /* save DC */
391 hPen = GetCurrentObject(hdc, OBJ_PEN);
392 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
393 hPal = GetCurrentObject(hdc, OBJ_PAL);
395 hRgn = CreateRectRgn(0, 0, 0, 0);
396 if (!GetClipRgn(hdc, hRgn))
398 DeleteObject(hRgn);
399 hRgn = 0;
402 /* create the handle table */
403 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
404 sizeof(HANDLETABLE) * mh->mtNoObjects);
405 if(!ht)
407 HeapFree( GetProcessHeap(), 0, mh );
408 return FALSE;
411 /* loop through metafile playing records */
412 offset = mh->mtHeaderSize * 2;
413 while (offset < mh->mtSize * 2)
415 mr = (METARECORD *)((char *)mh + offset);
416 TRACE("offset=%04x,size=%08x\n",
417 offset, mr->rdSize);
418 if (mr->rdSize < 3) { /* catch illegal record sizes */
419 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
420 mr->rdSize,offset,mh->mtSize*2);
421 break;
424 offset += mr->rdSize * 2;
425 if (mr->rdFunction == META_EOF) {
426 TRACE("Got META_EOF so stopping\n");
427 break;
429 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
432 /* restore DC */
433 SelectObject(hdc, hPen);
434 SelectObject(hdc, hBrush);
435 SelectPalette(hdc, hPal, FALSE);
436 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
437 DeleteObject(hRgn);
439 /* free objects in handle table */
440 for(i = 0; i < mh->mtNoObjects; i++)
441 if(*(ht->objectHandle + i) != 0)
442 DeleteObject(*(ht->objectHandle + i));
444 HeapFree( GetProcessHeap(), 0, ht );
445 HeapFree( GetProcessHeap(), 0, mh );
446 return TRUE;
449 /******************************************************************
450 * EnumMetaFile (GDI32.@)
452 * Loop through the metafile records in hmf, calling the user-specified
453 * function for each one, stopping when the user's function returns FALSE
454 * (which is considered to be failure)
455 * or when no records are left (which is considered to be success).
457 * RETURNS
458 * TRUE on success, FALSE on failure.
460 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
462 METAHEADER *mh = get_metafile_bits( hmf );
463 METARECORD *mr;
464 HANDLETABLE *ht;
465 BOOL result = TRUE;
466 int i;
467 unsigned int offset = 0;
468 HPEN hPen;
469 HBRUSH hBrush;
470 HFONT hFont;
472 TRACE("(%p,%p,%p,%lx)\n", hdc, hmf, lpEnumFunc, lpData);
474 if (!mh) return FALSE;
476 /* save the current pen, brush and font */
477 hPen = GetCurrentObject(hdc, OBJ_PEN);
478 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
479 hFont = GetCurrentObject(hdc, OBJ_FONT);
481 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
482 sizeof(HANDLETABLE) * mh->mtNoObjects);
484 /* loop through metafile records */
485 offset = mh->mtHeaderSize * 2;
487 while (offset < (mh->mtSize * 2))
489 mr = (METARECORD *)((char *)mh + offset);
490 if(mr->rdFunction == META_EOF) {
491 TRACE("Got META_EOF so stopping\n");
492 break;
494 TRACE("Calling EnumFunc with record type %x\n",
495 mr->rdFunction);
496 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, lpData ))
498 result = FALSE;
499 break;
502 offset += (mr->rdSize * 2);
505 /* restore pen, brush and font */
506 SelectObject(hdc, hBrush);
507 SelectObject(hdc, hPen);
508 SelectObject(hdc, hFont);
510 /* free objects in handle table */
511 for(i = 0; i < mh->mtNoObjects; i++)
512 if(*(ht->objectHandle + i) != 0)
513 DeleteObject(*(ht->objectHandle + i));
515 HeapFree( GetProcessHeap(), 0, ht);
516 HeapFree( GetProcessHeap(), 0, mh);
517 return result;
520 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
521 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
522 /******************************************************************
523 * PlayMetaFileRecord (GDI32.@)
525 * Render a single metafile record specified by *mr in the DC hdc, while
526 * using the handle table *ht, of length handles,
527 * to store metafile objects.
529 * BUGS
530 * The following metafile records are unimplemented:
532 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
533 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
534 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
536 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
538 short s1;
539 POINT *pt;
540 BITMAPINFOHEADER *infohdr;
542 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
544 switch (mr->rdFunction)
546 case META_EOF:
547 break;
549 case META_DELETEOBJECT:
550 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
551 *(ht->objectHandle + mr->rdParm[0]) = 0;
552 break;
554 case META_SETBKCOLOR:
555 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
556 break;
558 case META_SETBKMODE:
559 SetBkMode(hdc, mr->rdParm[0]);
560 break;
562 case META_SETMAPMODE:
563 SetMapMode(hdc, mr->rdParm[0]);
564 break;
566 case META_SETROP2:
567 SetROP2(hdc, mr->rdParm[0]);
568 break;
570 case META_SETRELABS:
571 SetRelAbs(hdc, mr->rdParm[0]);
572 break;
574 case META_SETPOLYFILLMODE:
575 SetPolyFillMode(hdc, mr->rdParm[0]);
576 break;
578 case META_SETSTRETCHBLTMODE:
579 SetStretchBltMode(hdc, mr->rdParm[0]);
580 break;
582 case META_SETTEXTCOLOR:
583 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
584 break;
586 case META_SETWINDOWORG:
587 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
588 break;
590 case META_SETWINDOWEXT:
591 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
592 break;
594 case META_SETVIEWPORTORG:
595 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
596 break;
598 case META_SETVIEWPORTEXT:
599 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
600 break;
602 case META_OFFSETWINDOWORG:
603 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
604 break;
606 case META_SCALEWINDOWEXT:
607 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
608 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
609 break;
611 case META_OFFSETVIEWPORTORG:
612 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
613 break;
615 case META_SCALEVIEWPORTEXT:
616 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
617 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
618 break;
620 case META_LINETO:
621 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
622 break;
624 case META_MOVETO:
625 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
626 break;
628 case META_EXCLUDECLIPRECT:
629 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
630 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
631 break;
633 case META_INTERSECTCLIPRECT:
634 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
635 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
636 break;
638 case META_ARC:
639 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
640 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
641 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
642 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
643 break;
645 case META_ELLIPSE:
646 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
647 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
648 break;
650 case META_FLOODFILL:
651 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
652 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
653 break;
655 case META_PIE:
656 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
657 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
658 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
659 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
660 break;
662 case META_RECTANGLE:
663 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
664 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
665 break;
667 case META_ROUNDRECT:
668 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
669 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
670 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
671 break;
673 case META_PATBLT:
674 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
675 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
676 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
677 break;
679 case META_SAVEDC:
680 SaveDC(hdc);
681 break;
683 case META_SETPIXEL:
684 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
685 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
686 break;
688 case META_OFFSETCLIPRGN:
689 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
690 break;
692 case META_TEXTOUT:
693 s1 = mr->rdParm[0];
694 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
695 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
696 (char *)(mr->rdParm + 1), s1);
697 break;
699 case META_POLYGON:
700 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
702 Polygon(hdc, pt, mr->rdParm[0]);
703 HeapFree( GetProcessHeap(), 0, pt );
705 break;
707 case META_POLYPOLYGON:
709 UINT i, total;
710 SHORT *counts = (SHORT *)(mr->rdParm + 1);
712 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
713 pt = convert_points( total, (POINTS *)(counts + mr->rdParm[0]) );
714 if (pt)
716 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
717 if (cnt32)
719 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
720 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
721 HeapFree( GetProcessHeap(), 0, cnt32 );
724 HeapFree( GetProcessHeap(), 0, pt );
726 break;
728 case META_POLYLINE:
729 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
731 Polyline( hdc, pt, mr->rdParm[0] );
732 HeapFree( GetProcessHeap(), 0, pt );
734 break;
736 case META_RESTOREDC:
737 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
738 break;
740 case META_SELECTOBJECT:
741 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
742 break;
744 case META_CHORD:
745 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
746 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
747 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
748 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
749 break;
751 case META_CREATEPATTERNBRUSH:
752 switch (mr->rdParm[0])
754 case BS_PATTERN:
755 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
756 MF_AddHandle(ht, handles,
757 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
758 infohdr->biHeight,
759 infohdr->biPlanes,
760 infohdr->biBitCount,
761 mr->rdParm +
762 (sizeof(BITMAPINFOHEADER) / 2) + 4)));
763 break;
765 case BS_DIBPATTERN:
766 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
767 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
768 break;
770 default:
771 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
772 mr->rdParm[0]);
773 break;
775 break;
777 case META_CREATEPENINDIRECT:
779 LOGPEN pen;
780 pen.lopnStyle = mr->rdParm[0];
781 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
782 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
783 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
784 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
786 break;
788 case META_CREATEFONTINDIRECT:
790 LOGFONTA font;
791 font.lfHeight = (SHORT)mr->rdParm[0];
792 font.lfWidth = (SHORT)mr->rdParm[1];
793 font.lfEscapement = (SHORT)mr->rdParm[2];
794 font.lfOrientation = (SHORT)mr->rdParm[3];
795 font.lfWeight = (SHORT)mr->rdParm[4];
796 font.lfItalic = LOBYTE(mr->rdParm[5]);
797 font.lfUnderline = HIBYTE(mr->rdParm[5]);
798 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
799 font.lfCharSet = HIBYTE(mr->rdParm[6]);
800 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
801 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
802 font.lfQuality = LOBYTE(mr->rdParm[8]);
803 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
804 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
805 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
807 break;
809 case META_CREATEBRUSHINDIRECT:
811 LOGBRUSH brush;
812 brush.lbStyle = mr->rdParm[0];
813 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
814 brush.lbHatch = mr->rdParm[3];
815 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
817 break;
819 case META_CREATEPALETTE:
820 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
821 break;
823 case META_SETTEXTALIGN:
824 SetTextAlign(hdc, mr->rdParm[0]);
825 break;
827 case META_SELECTPALETTE:
828 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
829 break;
831 case META_SETMAPPERFLAGS:
832 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
833 break;
835 case META_REALIZEPALETTE:
836 GDIRealizePalette(hdc);
837 break;
839 case META_ESCAPE:
840 switch (mr->rdParm[0]) {
841 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
842 case GETPHYSPAGESIZE:
843 case GETPRINTINGOFFSET:
844 return FALSE;
845 case SETABORTPROC:
846 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
847 return FALSE;
849 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
850 break;
852 case META_EXTTEXTOUT:
853 MF_Play_MetaExtTextOut( hdc, mr );
854 break;
856 case META_STRETCHDIB:
858 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
859 LPSTR bits = (LPSTR)info + bitmap_info_size( info, mr->rdParm[2] );
860 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
861 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
862 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
863 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
865 break;
867 case META_DIBSTRETCHBLT:
869 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
870 LPSTR bits = (LPSTR)info + bitmap_info_size( info, DIB_RGB_COLORS );
871 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
872 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
873 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
874 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
876 break;
878 case META_STRETCHBLT:
880 HDC hdcSrc = CreateCompatibleDC(hdc);
881 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
882 mr->rdParm[11], /*Height*/
883 mr->rdParm[13], /*Planes*/
884 mr->rdParm[14], /*BitsPixel*/
885 &mr->rdParm[15]); /*bits*/
886 SelectObject(hdcSrc,hbitmap);
887 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
888 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
889 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
890 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
891 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
892 DeleteDC(hdcSrc);
894 break;
896 case META_BITBLT:
898 HDC hdcSrc = CreateCompatibleDC(hdc);
899 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
900 mr->rdParm[8]/*Height*/,
901 mr->rdParm[10]/*Planes*/,
902 mr->rdParm[11]/*BitsPixel*/,
903 &mr->rdParm[12]/*bits*/);
904 SelectObject(hdcSrc,hbitmap);
905 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
906 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
907 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
908 MAKELONG(0,mr->rdParm[0]));
909 DeleteDC(hdcSrc);
911 break;
913 case META_CREATEREGION:
915 HRGN hrgn = CreateRectRgn(0,0,0,0);
917 MF_Play_MetaCreateRegion(mr, hrgn);
918 MF_AddHandle(ht, handles, hrgn);
920 break;
922 case META_FILLREGION:
923 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
924 *(ht->objectHandle + mr->rdParm[0]));
925 break;
927 case META_FRAMEREGION:
928 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
929 *(ht->objectHandle + mr->rdParm[2]),
930 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
931 break;
933 case META_INVERTREGION:
934 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
935 break;
937 case META_PAINTREGION:
938 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
939 break;
941 case META_SELECTCLIPREGION:
943 HRGN hrgn = 0;
945 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
946 SelectClipRgn(hdc, hrgn);
948 break;
950 case META_DIBCREATEPATTERNBRUSH:
951 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
952 but there's no difference */
953 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
954 break;
956 case META_DIBBITBLT:
957 /* In practice I've found that there are two layouts for
958 META_DIBBITBLT, one (the first here) is the usual one when a src
959 dc is actually passed to it, the second occurs when the src dc is
960 passed in as NULL to the creating BitBlt. As the second case has
961 no dib, a size check will suffice to distinguish.
963 Caolan.McNamara@ul.ie */
965 if (mr->rdSize > 12) {
966 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
967 LPSTR bits = (LPSTR)info + bitmap_info_size(info, mr->rdParm[0]);
969 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
970 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
971 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
972 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
974 else /* equivalent to a PatBlt */
975 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
976 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
977 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
978 break;
980 case META_SETTEXTCHAREXTRA:
981 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
982 break;
984 case META_SETTEXTJUSTIFICATION:
985 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
986 break;
988 case META_EXTFLOODFILL:
989 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
990 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
991 mr->rdParm[0]);
992 break;
994 case META_SETDIBTODEV:
996 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
997 char *bits = (char *)info + bitmap_info_size( info, mr->rdParm[0] );
998 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
999 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1000 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1001 mr->rdParm[2], mr->rdParm[1], bits, info,
1002 mr->rdParm[0]);
1003 break;
1006 #define META_UNIMP(x) case x: \
1007 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1008 break;
1009 META_UNIMP(META_DRAWTEXT)
1010 META_UNIMP(META_ANIMATEPALETTE)
1011 META_UNIMP(META_SETPALENTRIES)
1012 META_UNIMP(META_RESIZEPALETTE)
1013 META_UNIMP(META_RESETDC)
1014 META_UNIMP(META_STARTDOC)
1015 META_UNIMP(META_STARTPAGE)
1016 META_UNIMP(META_ENDPAGE)
1017 META_UNIMP(META_ABORTDOC)
1018 META_UNIMP(META_ENDDOC)
1019 META_UNIMP(META_CREATEBRUSH)
1020 META_UNIMP(META_CREATEBITMAPINDIRECT)
1021 META_UNIMP(META_CREATEBITMAP)
1022 #undef META_UNIMP
1024 default:
1025 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1026 return FALSE;
1028 return TRUE;
1031 /******************************************************************
1032 * SetMetaFileBitsEx (GDI32.@)
1034 * Create a metafile from raw data. No checking of the data is performed.
1035 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1037 * PARAMS
1038 * size [I] size of metafile, in bytes
1039 * lpData [I] pointer to metafile data
1041 * RETURNS
1042 * Success: Handle to metafile.
1043 * Failure: NULL.
1045 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1047 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1048 METAHEADER *mh_out;
1050 if (size & 1) return 0;
1052 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1053 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1055 SetLastError(ERROR_INVALID_DATA);
1056 return 0;
1059 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1060 if (!mh_out)
1062 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1063 return 0;
1066 memcpy(mh_out, mh_in, size);
1067 mh_out->mtSize = size / 2;
1068 return MF_Create_HMETAFILE(mh_out);
1071 /*****************************************************************
1072 * GetMetaFileBitsEx (GDI32.@)
1074 * Get raw metafile data.
1076 * Copies the data from metafile _hmf_ into the buffer _buf_.
1078 * PARAMS
1079 * hmf [I] metafile
1080 * nSize [I] size of buf
1081 * buf [O] buffer to receive raw metafile data
1083 * RETURNS
1084 * If _buf_ is zero, returns size of buffer required. Otherwise,
1085 * returns number of bytes copied.
1087 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1089 METAHEADER *mh = GDI_GetObjPtr( hmf, OBJ_METAFILE );
1090 UINT mfSize;
1091 BOOL mf_copy = FALSE;
1093 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1094 if (!mh) return 0; /* FIXME: error code */
1095 if(mh->mtType == METAFILE_DISK)
1097 mh = MF_LoadDiskBasedMetaFile( mh );
1098 if (!mh)
1100 GDI_ReleaseObj( hmf );
1101 return 0;
1103 mf_copy = TRUE;
1105 mfSize = mh->mtSize * 2;
1106 if (buf)
1108 if(mfSize > nSize) mfSize = nSize;
1109 memmove(buf, mh, mfSize);
1111 if (mf_copy) HeapFree( GetProcessHeap(), 0, mh );
1112 GDI_ReleaseObj( hmf );
1113 TRACE("returning size %d\n", mfSize);
1114 return mfSize;
1117 #include <pshpack2.h>
1118 typedef struct
1120 DWORD magic; /* WMFC */
1121 WORD unk04; /* 1 */
1122 WORD unk06; /* 0 */
1123 WORD unk08; /* 0 */
1124 WORD unk0a; /* 1 */
1125 WORD checksum;
1126 DWORD unk0e; /* 0 */
1127 DWORD num_chunks;
1128 DWORD chunk_size;
1129 DWORD remaining_size;
1130 DWORD emf_size;
1131 BYTE *emf_data;
1132 } mf_comment_chunk;
1133 #include <poppack.h>
1135 static const DWORD wmfc_magic = 0x43464d57;
1137 /******************************************************************
1138 * add_mf_comment
1140 * Helper for GetWinMetaFileBits
1142 * Add the MFCOMMENT record[s] which is essentially a copy
1143 * of the original emf.
1145 static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
1147 DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i;
1148 BYTE *bits, *chunk_data;
1149 mf_comment_chunk *chunk = NULL;
1150 BOOL ret = FALSE;
1151 static const DWORD max_chunk_size = 0x2000;
1153 if(!size) return FALSE;
1154 chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size);
1155 if(!bits) return FALSE;
1156 if(!GetEnhMetaFileBits(emf, size, bits)) goto end;
1158 chunk = HeapAlloc(GetProcessHeap(), 0, max_chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data));
1159 if(!chunk) goto end;
1161 chunk->magic = wmfc_magic;
1162 chunk->unk04 = 1;
1163 chunk->unk06 = 0;
1164 chunk->unk08 = 0;
1165 chunk->unk0a = 1;
1166 chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1167 chunk->unk0e = 0;
1168 chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
1169 chunk->chunk_size = max_chunk_size;
1170 chunk->remaining_size = size;
1171 chunk->emf_size = size;
1173 for(i = 0; i < chunk->num_chunks; i++)
1175 if(i == chunk->num_chunks - 1) /* last chunk */
1176 chunk->chunk_size = chunk->remaining_size;
1178 chunk->remaining_size -= chunk->chunk_size;
1179 memcpy(&chunk->emf_data, chunk_data, chunk->chunk_size);
1180 chunk_data += chunk->chunk_size;
1182 if(!Escape(hdc, MFCOMMENT, chunk->chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data), (char*)chunk, NULL))
1183 goto end;
1185 ret = TRUE;
1186 end:
1187 HeapFree(GetProcessHeap(), 0, chunk);
1188 HeapFree(GetProcessHeap(), 0, bits);
1189 return ret;
1192 /*******************************************************************
1193 * muldiv
1195 * Behaves somewhat differently to MulDiv when the answer is -ve
1196 * and also rounds n.5 towards zero
1198 static INT muldiv(INT m1, INT m2, INT d)
1200 LONGLONG ret;
1202 ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1204 if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1206 if(ret > 0) ret--;
1207 else ret++;
1209 return ret;
1212 /******************************************************************
1213 * set_window
1215 * Helper for GetWinMetaFileBits
1217 * Add the SetWindowOrg and SetWindowExt records
1219 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1221 ENHMETAHEADER header;
1222 INT horz_res, vert_res, horz_size, vert_size;
1223 POINT pt;
1225 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1227 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1228 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1229 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1230 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1232 switch(map_mode)
1234 case MM_TEXT:
1235 case MM_ISOTROPIC:
1236 case MM_ANISOTROPIC:
1237 pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1238 pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
1239 break;
1240 case MM_LOMETRIC:
1241 pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1242 pt.x = muldiv( header.rclFrame.left, 1, 10);
1243 break;
1244 case MM_HIMETRIC:
1245 pt.y = -header.rclFrame.top + 1;
1246 pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
1247 break;
1248 case MM_LOENGLISH:
1249 pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1250 pt.x = muldiv( header.rclFrame.left, 10, 254);
1251 break;
1252 case MM_HIENGLISH:
1253 pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1254 pt.x = muldiv( header.rclFrame.left, 100, 254);
1255 break;
1256 case MM_TWIPS:
1257 pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1258 pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
1259 break;
1260 default:
1261 WARN("Unknown map mode %d\n", map_mode);
1262 return FALSE;
1264 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1266 pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1267 pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1268 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1269 return TRUE;
1272 /******************************************************************
1273 * GetWinMetaFileBits [GDI32.@]
1275 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1276 UINT cbBuffer, LPBYTE lpbBuffer,
1277 INT map_mode, HDC hdcRef)
1279 HDC hdcmf;
1280 HMETAFILE hmf;
1281 UINT ret, full_size;
1282 RECT rc;
1284 GetClipBox(hdcRef, &rc);
1286 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1287 map_mode, hdcRef, wine_dbgstr_rect(&rc));
1289 hdcmf = CreateMetaFileW(NULL);
1291 add_mf_comment(hdcmf, hemf);
1292 SetMapMode(hdcmf, map_mode);
1293 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1294 goto error;
1296 PlayEnhMetaFile(hdcmf, hemf, &rc);
1297 hmf = CloseMetaFile(hdcmf);
1298 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1299 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1300 DeleteMetaFile(hmf);
1302 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1304 WORD checksum = 0;
1305 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1306 UINT i;
1308 for(i = 0; i < full_size / 2; i++)
1309 checksum += ((WORD*)lpbBuffer)[i];
1310 comment_rec->rdParm[8] = ~checksum + 1;
1312 return ret;
1314 error:
1315 DeleteMetaFile(CloseMetaFile(hdcmf));
1316 return 0;
1319 /******************************************************************
1320 * MF_Play_MetaCreateRegion
1322 * Handles META_CREATEREGION for PlayMetaFileRecord().
1324 * The layout of the record looks something like this:
1326 * rdParm meaning
1327 * 0 Always 0?
1328 * 1 Always 6?
1329 * 2 Looks like a handle? - not constant
1330 * 3 0 or 1 ??
1331 * 4 Total number of bytes
1332 * 5 No. of separate bands = n [see below]
1333 * 6 Largest number of x co-ords in a band
1334 * 7-10 Bounding box x1 y1 x2 y2
1335 * 11-... n bands
1337 * Regions are divided into bands that are uniform in the
1338 * y-direction. Each band consists of pairs of on/off x-coords and is
1339 * written as
1340 * m y0 y1 x1 x2 x3 ... xm m
1341 * into successive rdParm[]s.
1343 * This is probably just a dump of the internal RGNOBJ?
1345 * HDMD - 18/12/97
1349 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1351 WORD band, pair;
1352 WORD *start, *end;
1353 INT16 y0, y1;
1354 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1356 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1357 band++, start = end + 1) {
1358 if(*start / 2 != (*start + 1) / 2) {
1359 WARN("Delimiter not even.\n");
1360 DeleteObject( hrgn2 );
1361 return FALSE;
1364 end = start + *start + 3;
1365 if(end > (WORD *)mr + mr->rdSize) {
1366 WARN("End points outside record.\n");
1367 DeleteObject( hrgn2 );
1368 return FALSE;
1371 if(*start != *end) {
1372 WARN("Mismatched delimiters.\n");
1373 DeleteObject( hrgn2 );
1374 return FALSE;
1377 y0 = *(INT16 *)(start + 1);
1378 y1 = *(INT16 *)(start + 2);
1379 for(pair = 0; pair < *start / 2; pair++) {
1380 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1381 *(INT16 *)(start + 4 + 2*pair), y1 );
1382 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1385 DeleteObject( hrgn2 );
1386 return TRUE;
1390 /******************************************************************
1391 * MF_Play_MetaExtTextOut
1393 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1396 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1398 INT *dx = NULL;
1399 int i;
1400 SHORT *dxx;
1401 LPSTR sot;
1402 DWORD len;
1403 WORD s1;
1404 RECT rect;
1405 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1407 s1 = mr->rdParm[2]; /* String length */
1408 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1409 + sizeof(UINT16) + (isrect ? 4 * sizeof(SHORT) : 0);
1410 /* rec len without dx array */
1412 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1413 if (isrect)
1415 rect.left = (SHORT)mr->rdParm[4];
1416 rect.top = (SHORT)mr->rdParm[5];
1417 rect.right = (SHORT)mr->rdParm[6];
1418 rect.bottom = (SHORT)mr->rdParm[7];
1419 sot += 4 * sizeof(SHORT); /* there is a rectangle, so add offset */
1422 if (mr->rdSize == len / 2)
1423 dxx = NULL; /* determine if array is present */
1424 else
1425 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1427 dxx = (SHORT *)(sot+(((s1+1)>>1)*2));
1428 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1429 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1431 else {
1432 TRACE("%s len: %d\n", sot, mr->rdSize);
1433 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1434 len, s1, mr->rdSize, mr->rdParm[3]);
1435 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1437 ExtTextOutA( hdc,
1438 (SHORT)mr->rdParm[1], /* X position */
1439 (SHORT)mr->rdParm[0], /* Y position */
1440 mr->rdParm[3], /* options */
1441 &rect, /* rectangle */
1442 sot, /* string */
1443 s1, dx); /* length, dx array */
1444 if (dx)
1446 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1447 HeapFree( GetProcessHeap(), 0, dx );
1449 return TRUE;