windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / gdi32 / metafile.c
blob911dfeecf61e7221d27a3f4fe853863da9497cbd
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 <stdarg.h>
49 #include <string.h>
50 #include <fcntl.h>
52 #include "windef.h"
53 #include "winbase.h"
54 #include "wingdi.h"
55 #include "winreg.h"
56 #include "winnls.h"
57 #include "winternl.h"
58 #include "gdi_private.h"
60 #include "wine/debug.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
65 static CRITICAL_SECTION metafile_cs;
66 static CRITICAL_SECTION_DEBUG critsect_debug =
68 0, 0, &metafile_cs,
69 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
70 0, 0, { (DWORD_PTR)(__FILE__ ": metafile_cs") }
72 static CRITICAL_SECTION metafile_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
74 /******************************************************************
75 * MF_AddHandle
77 * Add a handle to an external handle table and return the index
79 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
81 int i;
83 for (i = 0; i < htlen; i++)
85 if (*(ht->objectHandle + i) == 0)
87 *(ht->objectHandle + i) = hobj;
88 return i;
91 return -1;
95 /******************************************************************
96 * MF_Create_HMETATFILE
98 * Creates a (32 bit) HMETAFILE object from a METAHEADER
100 * HMETAFILEs are GDI objects.
102 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
104 HANDLE handle;
106 if (!(handle = NtGdiCreateClientObj( NTGDI_OBJ_METAFILE )))
107 return 0;
109 set_gdi_client_ptr( handle, mh );
110 return handle;
113 static int bitmap_info_size( const BITMAPINFO *info, WORD coloruse )
115 unsigned int colors, size, masks = 0;
117 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
119 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
120 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
121 return sizeof(BITMAPCOREHEADER) + colors *
122 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
124 else /* assume BITMAPINFOHEADER */
126 if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
127 else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
128 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
129 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
130 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
134 /******************************************************************
135 * convert_points
137 * Convert an array of POINTS to an array of POINT.
138 * Result must be freed by caller.
140 static POINT *convert_points( UINT count, const POINTS *pts )
142 UINT i;
143 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
144 if (ret)
146 for (i = 0; i < count; i++)
148 ret[i].x = pts[i].x;
149 ret[i].y = pts[i].y;
152 return ret;
155 /******************************************************************
156 * DeleteMetaFile (GDI32.@)
158 * Delete a memory-based metafile.
161 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
163 METAHEADER *data;
164 BOOL ret = FALSE;
166 EnterCriticalSection( &metafile_cs );
167 if ((data = get_gdi_client_ptr( hmf, NTGDI_OBJ_METAFILE )))
169 ret = NtGdiDeleteClientObj( hmf );
170 if (ret) HeapFree( GetProcessHeap(), 0, data );
172 LeaveCriticalSection( &metafile_cs );
174 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
175 return ret;
178 /******************************************************************
179 * MF_ReadMetaFile
181 * Returns a pointer to a memory based METAHEADER read in from file HFILE
184 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
186 METAHEADER *mh;
187 DWORD BytesRead, size;
189 size = sizeof(METAHEADER);
190 mh = HeapAlloc( GetProcessHeap(), 0, size );
191 if(!mh) return NULL;
192 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
193 BytesRead != size) {
194 HeapFree( GetProcessHeap(), 0, mh );
195 return NULL;
197 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
198 mh->mtHeaderSize != size / 2)
200 HeapFree( GetProcessHeap(), 0, mh );
201 return NULL;
203 size = mh->mtSize * 2;
204 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
205 if(!mh) return NULL;
206 size -= sizeof(METAHEADER);
207 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
208 NULL) == 0 ||
209 BytesRead != size) {
210 HeapFree( GetProcessHeap(), 0, mh );
211 return NULL;
214 if (mh->mtType != METAFILE_MEMORY) {
215 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
216 mh->mtType = METAFILE_MEMORY;
218 return mh;
221 /******************************************************************
222 * GetMetaFileA (GDI32.@)
224 * Read a metafile from a file. Returns handle to a memory-based metafile.
226 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
228 METAHEADER *mh;
229 HANDLE hFile;
231 TRACE("%s\n", lpFilename);
233 if(!lpFilename)
234 return 0;
236 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
237 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
238 return 0;
240 mh = MF_ReadMetaFile(hFile);
241 CloseHandle(hFile);
242 if(!mh) return 0;
243 return MF_Create_HMETAFILE( mh );
246 /******************************************************************
247 * GetMetaFileW (GDI32.@)
249 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
251 METAHEADER *mh;
252 HANDLE hFile;
254 TRACE("%s\n", debugstr_w(lpFilename));
256 if(!lpFilename)
257 return 0;
259 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
260 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
261 return 0;
263 mh = MF_ReadMetaFile(hFile);
264 CloseHandle(hFile);
265 if(!mh) return 0;
266 return MF_Create_HMETAFILE( mh );
270 /* return a copy of the metafile bits, to be freed with HeapFree */
271 static METAHEADER *get_metafile_bits( HMETAFILE hmf )
273 METAHEADER *ret = NULL, *metafile;
275 EnterCriticalSection( &metafile_cs );
276 if ((metafile = get_gdi_client_ptr( hmf, NTGDI_OBJ_METAFILE )))
278 ret = HeapAlloc( GetProcessHeap(), 0, metafile->mtSize * 2 );
279 if (ret) memcpy( ret, metafile, metafile->mtSize * 2 );
281 else SetLastError( ERROR_INVALID_HANDLE );
282 LeaveCriticalSection( &metafile_cs );
284 return ret;
287 /******************************************************************
288 * CopyMetaFileW (GDI32.@)
290 * Copies the metafile corresponding to hSrcMetaFile to either
291 * a disk file, if a filename is given, or to a new memory based
292 * metafile, if lpFileName is NULL.
294 * PARAMS
295 * hSrcMetaFile [I] handle of metafile to copy
296 * lpFilename [I] filename if copying to a file
298 * RETURNS
299 * Handle to metafile copy on success, NULL on failure.
301 * BUGS
302 * Copying to disk returns NULL even if successful.
304 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
306 METAHEADER *mh = get_metafile_bits( hSrcMetaFile );
307 HANDLE hFile;
309 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
311 if(!mh) return 0;
313 if(lpFilename) { /* disk based metafile */
314 DWORD w;
315 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
316 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
317 HeapFree( GetProcessHeap(), 0, mh );
318 return 0;
320 WriteFile(hFile, mh, mh->mtSize * 2, &w, NULL);
321 CloseHandle(hFile);
324 return MF_Create_HMETAFILE( mh );
328 /******************************************************************
329 * CopyMetaFileA (GDI32.@)
331 * See CopyMetaFileW.
333 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
335 UNICODE_STRING lpFilenameW;
336 HMETAFILE ret = 0;
338 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
339 else lpFilenameW.Buffer = NULL;
341 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
342 if (lpFilenameW.Buffer)
343 RtlFreeUnicodeString(&lpFilenameW);
344 return ret;
347 /******************************************************************
348 * PlayMetaFile (GDI32.@)
350 * Renders the metafile specified by hmf in the DC specified by
351 * hdc. Returns FALSE on failure, TRUE on success.
353 * PARAMS
354 * hdc [I] handle of DC to render in
355 * hmf [I] handle of metafile to render
357 * RETURNS
358 * Success: TRUE
359 * Failure: FALSE
361 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
363 BOOL metadc = GetObjectType(hdc) == OBJ_METADC;
364 METAHEADER *mh = get_metafile_bits( hmf );
365 METARECORD *mr;
366 HANDLETABLE *ht;
367 unsigned int offset = 0;
368 WORD i;
369 HPEN hPen;
370 HBRUSH hBrush;
371 HPALETTE hPal;
372 HRGN hRgn;
374 if (!mh) return FALSE;
376 if (!metadc)
378 /* save DC */
379 hPen = GetCurrentObject(hdc, OBJ_PEN);
380 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
381 hPal = GetCurrentObject(hdc, OBJ_PAL);
383 hRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
384 if (!GetClipRgn(hdc, hRgn))
386 DeleteObject(hRgn);
387 hRgn = 0;
391 /* create the handle table */
392 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
393 sizeof(HANDLETABLE) * mh->mtNoObjects);
394 if(!ht)
396 HeapFree( GetProcessHeap(), 0, mh );
397 return FALSE;
400 /* loop through metafile playing records */
401 offset = mh->mtHeaderSize * 2;
402 while (offset < mh->mtSize * 2)
404 mr = (METARECORD *)((char *)mh + offset);
405 TRACE("offset=%04x,size=%08lx\n",
406 offset, mr->rdSize);
407 if (mr->rdSize < 3) { /* catch illegal record sizes */
408 TRACE("Entry got size %ld at offset %d, total mf length is %ld\n",
409 mr->rdSize,offset,mh->mtSize*2);
410 break;
413 offset += mr->rdSize * 2;
414 if (mr->rdFunction == META_EOF) {
415 TRACE("Got META_EOF so stopping\n");
416 break;
418 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
421 if (!metadc)
423 /* restore DC */
424 SelectObject(hdc, hPen);
425 SelectObject(hdc, hBrush);
426 SelectPalette(hdc, hPal, FALSE);
427 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
428 DeleteObject(hRgn);
431 /* free objects in handle table */
432 for(i = 0; i < mh->mtNoObjects; i++)
433 if(*(ht->objectHandle + i) != 0)
434 DeleteObject(*(ht->objectHandle + i));
436 HeapFree( GetProcessHeap(), 0, ht );
437 HeapFree( GetProcessHeap(), 0, mh );
438 return TRUE;
441 /******************************************************************
442 * EnumMetaFile (GDI32.@)
444 * Loop through the metafile records in hmf, calling the user-specified
445 * function for each one, stopping when the user's function returns FALSE
446 * (which is considered to be failure)
447 * or when no records are left (which is considered to be success).
449 * RETURNS
450 * TRUE on success, FALSE on failure.
452 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
454 METAHEADER *mh = get_metafile_bits( hmf );
455 METARECORD *mr;
456 HANDLETABLE *ht;
457 BOOL result = TRUE;
458 int i;
459 unsigned int offset = 0;
460 HPEN hPen;
461 HBRUSH hBrush;
462 HFONT hFont;
464 TRACE("(%p,%p,%p,%Ix)\n", hdc, hmf, lpEnumFunc, lpData);
466 if (!mh) return FALSE;
468 /* save the current pen, brush and font */
469 hPen = GetCurrentObject(hdc, OBJ_PEN);
470 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
471 hFont = GetCurrentObject(hdc, OBJ_FONT);
473 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
474 sizeof(HANDLETABLE) * mh->mtNoObjects);
476 /* loop through metafile records */
477 offset = mh->mtHeaderSize * 2;
479 while (offset < (mh->mtSize * 2))
481 mr = (METARECORD *)((char *)mh + offset);
482 if(mr->rdFunction == META_EOF) {
483 TRACE("Got META_EOF so stopping\n");
484 break;
486 TRACE("Calling EnumFunc with record type %x\n",
487 mr->rdFunction);
488 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, lpData ))
490 result = FALSE;
491 break;
494 offset += (mr->rdSize * 2);
497 /* restore pen, brush and font */
498 SelectObject(hdc, hBrush);
499 SelectObject(hdc, hPen);
500 SelectObject(hdc, hFont);
502 /* free objects in handle table */
503 for(i = 0; i < mh->mtNoObjects; i++)
504 if(*(ht->objectHandle + i) != 0)
505 DeleteObject(*(ht->objectHandle + i));
507 HeapFree( GetProcessHeap(), 0, ht);
508 HeapFree( GetProcessHeap(), 0, mh);
509 return result;
512 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
513 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
514 /******************************************************************
515 * PlayMetaFileRecord (GDI32.@)
517 * Render a single metafile record specified by *mr in the DC hdc, while
518 * using the handle table *ht, of length handles,
519 * to store metafile objects.
521 * BUGS
522 * The following metafile records are unimplemented:
524 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
525 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
526 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
528 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
530 short s1;
531 POINT *pt;
532 BITMAPINFOHEADER *infohdr;
534 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
536 switch (mr->rdFunction)
538 case META_EOF:
539 break;
541 case META_DELETEOBJECT:
542 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
543 *(ht->objectHandle + mr->rdParm[0]) = 0;
544 break;
546 case META_SETBKCOLOR:
547 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
548 break;
550 case META_SETBKMODE:
551 SetBkMode(hdc, mr->rdParm[0]);
552 break;
554 case META_SETMAPMODE:
555 SetMapMode(hdc, mr->rdParm[0]);
556 break;
558 case META_SETROP2:
559 SetROP2(hdc, mr->rdParm[0]);
560 break;
562 case META_SETRELABS:
563 SetRelAbs(hdc, mr->rdParm[0]);
564 break;
566 case META_SETPOLYFILLMODE:
567 SetPolyFillMode(hdc, mr->rdParm[0]);
568 break;
570 case META_SETSTRETCHBLTMODE:
571 SetStretchBltMode(hdc, mr->rdParm[0]);
572 break;
574 case META_SETTEXTCOLOR:
575 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
576 break;
578 case META_SETWINDOWORG:
579 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
580 break;
582 case META_SETWINDOWEXT:
583 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
584 break;
586 case META_SETVIEWPORTORG:
587 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
588 break;
590 case META_SETVIEWPORTEXT:
591 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
592 break;
594 case META_OFFSETWINDOWORG:
595 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
596 break;
598 case META_SCALEWINDOWEXT:
599 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
600 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
601 break;
603 case META_OFFSETVIEWPORTORG:
604 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
605 break;
607 case META_SCALEVIEWPORTEXT:
608 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
609 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
610 break;
612 case META_LINETO:
613 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
614 break;
616 case META_MOVETO:
617 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
618 break;
620 case META_EXCLUDECLIPRECT:
621 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
622 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
623 break;
625 case META_INTERSECTCLIPRECT:
626 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
627 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
628 break;
630 case META_ARC:
631 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
632 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
633 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
634 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
635 break;
637 case META_ELLIPSE:
638 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
639 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
640 break;
642 case META_FLOODFILL:
643 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
644 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
645 break;
647 case META_PIE:
648 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
649 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
650 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
651 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
652 break;
654 case META_RECTANGLE:
655 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
656 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
657 break;
659 case META_ROUNDRECT:
660 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
661 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
662 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
663 break;
665 case META_PATBLT:
666 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
667 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
668 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
669 break;
671 case META_SAVEDC:
672 SaveDC(hdc);
673 break;
675 case META_SETPIXEL:
676 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
677 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
678 break;
680 case META_OFFSETCLIPRGN:
681 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
682 break;
684 case META_TEXTOUT:
685 s1 = mr->rdParm[0];
686 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
687 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
688 (char *)(mr->rdParm + 1), s1);
689 break;
691 case META_POLYGON:
692 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
694 Polygon(hdc, pt, mr->rdParm[0]);
695 HeapFree( GetProcessHeap(), 0, pt );
697 break;
699 case META_POLYPOLYGON:
701 UINT i, total;
702 SHORT *counts = (SHORT *)(mr->rdParm + 1);
704 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
705 pt = convert_points( total, (POINTS *)(counts + mr->rdParm[0]) );
706 if (pt)
708 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
709 if (cnt32)
711 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
712 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
713 HeapFree( GetProcessHeap(), 0, cnt32 );
716 HeapFree( GetProcessHeap(), 0, pt );
718 break;
720 case META_POLYLINE:
721 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
723 Polyline( hdc, pt, mr->rdParm[0] );
724 HeapFree( GetProcessHeap(), 0, pt );
726 break;
728 case META_RESTOREDC:
729 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
730 break;
732 case META_SELECTOBJECT:
733 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
734 break;
736 case META_CHORD:
737 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
738 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
739 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
740 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
741 break;
743 case META_CREATEPATTERNBRUSH:
744 switch (mr->rdParm[0])
746 case BS_PATTERN:
747 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
748 MF_AddHandle(ht, handles,
749 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
750 infohdr->biHeight,
751 infohdr->biPlanes,
752 infohdr->biBitCount,
753 mr->rdParm +
754 (sizeof(BITMAPINFOHEADER) / 2) + 4)));
755 break;
757 case BS_DIBPATTERN:
758 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
759 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
760 break;
762 default:
763 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
764 mr->rdParm[0]);
765 break;
767 break;
769 case META_CREATEPENINDIRECT:
771 LOGPEN pen;
772 pen.lopnStyle = mr->rdParm[0];
773 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
774 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
775 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
776 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
778 break;
780 case META_CREATEFONTINDIRECT:
782 LOGFONTA font;
783 font.lfHeight = (SHORT)mr->rdParm[0];
784 font.lfWidth = (SHORT)mr->rdParm[1];
785 font.lfEscapement = (SHORT)mr->rdParm[2];
786 font.lfOrientation = (SHORT)mr->rdParm[3];
787 font.lfWeight = (SHORT)mr->rdParm[4];
788 font.lfItalic = LOBYTE(mr->rdParm[5]);
789 font.lfUnderline = HIBYTE(mr->rdParm[5]);
790 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
791 font.lfCharSet = HIBYTE(mr->rdParm[6]);
792 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
793 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
794 font.lfQuality = LOBYTE(mr->rdParm[8]);
795 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
796 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
797 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
799 break;
801 case META_CREATEBRUSHINDIRECT:
803 LOGBRUSH brush;
804 brush.lbStyle = mr->rdParm[0];
805 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
806 brush.lbHatch = mr->rdParm[3];
807 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
809 break;
811 case META_CREATEPALETTE:
812 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
813 break;
815 case META_SETTEXTALIGN:
816 SetTextAlign(hdc, mr->rdParm[0]);
817 break;
819 case META_SELECTPALETTE:
820 SelectPalette( hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0] );
821 break;
823 case META_SETMAPPERFLAGS:
824 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
825 break;
827 case META_REALIZEPALETTE:
828 RealizePalette(hdc);
829 break;
831 case META_ESCAPE:
832 switch (mr->rdParm[0]) {
833 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
834 case GETPHYSPAGESIZE:
835 case GETPRINTINGOFFSET:
836 return FALSE;
837 case SETABORTPROC:
838 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
839 return FALSE;
841 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
842 break;
844 case META_EXTTEXTOUT:
845 MF_Play_MetaExtTextOut( hdc, mr );
846 break;
848 case META_STRETCHDIB:
850 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
851 LPSTR bits = (LPSTR)info + bitmap_info_size( info, mr->rdParm[2] );
852 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
853 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
854 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
855 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
857 break;
859 case META_DIBSTRETCHBLT:
861 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
862 LPSTR bits = (LPSTR)info + bitmap_info_size( info, DIB_RGB_COLORS );
863 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
864 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
865 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
866 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
868 break;
870 case META_STRETCHBLT:
872 HDC hdcSrc = NtGdiCreateCompatibleDC( hdc );
873 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
874 mr->rdParm[11], /*Height*/
875 mr->rdParm[13], /*Planes*/
876 mr->rdParm[14], /*BitsPixel*/
877 &mr->rdParm[15]); /*bits*/
878 SelectObject(hdcSrc,hbitmap);
879 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
880 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
881 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
882 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
883 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
884 DeleteDC(hdcSrc);
886 break;
888 case META_BITBLT:
890 HDC hdcSrc = NtGdiCreateCompatibleDC( hdc );
891 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
892 mr->rdParm[8]/*Height*/,
893 mr->rdParm[10]/*Planes*/,
894 mr->rdParm[11]/*BitsPixel*/,
895 &mr->rdParm[12]/*bits*/);
896 SelectObject(hdcSrc,hbitmap);
897 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
898 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
899 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
900 MAKELONG(0,mr->rdParm[0]));
901 DeleteDC(hdcSrc);
903 break;
905 case META_CREATEREGION:
907 HRGN hrgn = NtGdiCreateRectRgn(0,0,0,0);
909 MF_Play_MetaCreateRegion(mr, hrgn);
910 MF_AddHandle(ht, handles, hrgn);
912 break;
914 case META_FILLREGION:
915 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
916 *(ht->objectHandle + mr->rdParm[0]));
917 break;
919 case META_FRAMEREGION:
920 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
921 *(ht->objectHandle + mr->rdParm[2]),
922 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
923 break;
925 case META_INVERTREGION:
926 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
927 break;
929 case META_PAINTREGION:
930 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
931 break;
933 case META_SELECTCLIPREGION:
935 HRGN hrgn = 0;
937 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
938 SelectClipRgn(hdc, hrgn);
940 break;
942 case META_DIBCREATEPATTERNBRUSH:
943 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
944 but there's no difference */
945 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
946 break;
948 case META_DIBBITBLT:
949 /* In practice I've found that there are two layouts for
950 META_DIBBITBLT, one (the first here) is the usual one when a src
951 dc is actually passed to it, the second occurs when the src dc is
952 passed in as NULL to the creating BitBlt. As the second case has
953 no dib, a size check will suffice to distinguish.
955 Caolan.McNamara@ul.ie */
957 if (mr->rdSize > 12) {
958 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
959 LPSTR bits = (LPSTR)info + bitmap_info_size(info, mr->rdParm[0]);
961 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
962 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
963 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
964 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
966 else /* equivalent to a PatBlt */
967 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
968 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
969 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
970 break;
972 case META_SETTEXTCHAREXTRA:
973 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
974 break;
976 case META_SETTEXTJUSTIFICATION:
977 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
978 break;
980 case META_EXTFLOODFILL:
981 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
982 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
983 mr->rdParm[0]);
984 break;
986 case META_SETDIBTODEV:
988 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
989 char *bits = (char *)info + bitmap_info_size( info, mr->rdParm[0] );
990 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
991 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
992 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
993 mr->rdParm[2], mr->rdParm[1], bits, info,
994 mr->rdParm[0]);
995 break;
998 #define META_UNIMP(x) case x: \
999 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1000 break;
1001 META_UNIMP(META_DRAWTEXT)
1002 META_UNIMP(META_ANIMATEPALETTE)
1003 META_UNIMP(META_SETPALENTRIES)
1004 META_UNIMP(META_RESIZEPALETTE)
1005 META_UNIMP(META_RESETDC)
1006 META_UNIMP(META_STARTDOC)
1007 META_UNIMP(META_STARTPAGE)
1008 META_UNIMP(META_ENDPAGE)
1009 META_UNIMP(META_ABORTDOC)
1010 META_UNIMP(META_ENDDOC)
1011 META_UNIMP(META_CREATEBRUSH)
1012 META_UNIMP(META_CREATEBITMAPINDIRECT)
1013 META_UNIMP(META_CREATEBITMAP)
1014 #undef META_UNIMP
1016 default:
1017 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1018 return FALSE;
1020 return TRUE;
1023 /******************************************************************
1024 * SetMetaFileBitsEx (GDI32.@)
1026 * Create a metafile from raw data. No checking of the data is performed.
1027 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1029 * PARAMS
1030 * size [I] size of metafile, in bytes
1031 * lpData [I] pointer to metafile data
1033 * RETURNS
1034 * Success: Handle to metafile.
1035 * Failure: NULL.
1037 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1039 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1040 METAHEADER *mh_out;
1042 if (size & 1) return 0;
1044 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1045 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1047 SetLastError(ERROR_INVALID_DATA);
1048 return 0;
1051 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1052 if (!mh_out)
1054 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1055 return 0;
1058 memcpy(mh_out, mh_in, size);
1059 mh_out->mtSize = size / 2;
1060 return MF_Create_HMETAFILE(mh_out);
1063 /*****************************************************************
1064 * GetMetaFileBitsEx (GDI32.@)
1066 * Get raw metafile data.
1068 * Copies the data from metafile _hmf_ into the buffer _buf_.
1070 * PARAMS
1071 * hmf [I] metafile
1072 * nSize [I] size of buf
1073 * buf [O] buffer to receive raw metafile data
1075 * RETURNS
1076 * If _buf_ is zero, returns size of buffer required. Otherwise,
1077 * returns number of bytes copied.
1079 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT buf_size, void *buf )
1081 METAHEADER *metafile;
1082 UINT size = 0;
1084 TRACE( "(%p,%d,%p)\n", hmf, buf_size, buf );
1086 EnterCriticalSection( &metafile_cs );
1087 if ((metafile = get_gdi_client_ptr( hmf, NTGDI_OBJ_METAFILE )))
1089 size = metafile->mtSize * 2;
1090 if (buf)
1092 if(size > buf_size) size = buf_size;
1093 memmove( buf, metafile, size );
1096 else SetLastError( ERROR_INVALID_HANDLE );
1097 LeaveCriticalSection( &metafile_cs );
1099 TRACE( "returning size %d\n", size );
1100 return size;
1103 /******************************************************************
1104 * add_mf_comment
1106 * Helper for GetWinMetaFileBits
1108 * Add the MFCOMMENT record[s] which is essentially a copy
1109 * of the original emf.
1111 static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
1113 DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i;
1114 BYTE *bits, *chunk_data;
1115 emf_in_wmf_comment *chunk = NULL;
1116 BOOL ret = FALSE;
1117 static const DWORD max_chunk_size = 0x2000;
1119 if(!size) return FALSE;
1120 chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size);
1121 if(!bits) return FALSE;
1122 if(!GetEnhMetaFileBits(emf, size, bits)) goto end;
1124 chunk = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(emf_in_wmf_comment, emf_data[max_chunk_size]));
1125 if(!chunk) goto end;
1127 chunk->comment_id = WMFC_MAGIC;
1128 chunk->comment_type = 0x1;
1129 chunk->version = 0x00010000;
1130 chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1131 chunk->flags = 0;
1132 chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
1133 chunk->chunk_size = max_chunk_size;
1134 chunk->remaining_size = size;
1135 chunk->emf_size = size;
1137 for(i = 0; i < chunk->num_chunks; i++)
1139 if(i == chunk->num_chunks - 1) /* last chunk */
1140 chunk->chunk_size = chunk->remaining_size;
1142 chunk->remaining_size -= chunk->chunk_size;
1143 memcpy(chunk->emf_data, chunk_data, chunk->chunk_size);
1144 chunk_data += chunk->chunk_size;
1146 if(!Escape(hdc, MFCOMMENT, FIELD_OFFSET(emf_in_wmf_comment, emf_data[chunk->chunk_size]), (char*)chunk, NULL))
1147 goto end;
1149 ret = TRUE;
1150 end:
1151 HeapFree(GetProcessHeap(), 0, chunk);
1152 HeapFree(GetProcessHeap(), 0, bits);
1153 return ret;
1156 /*******************************************************************
1157 * muldiv
1159 * Behaves somewhat differently to MulDiv when the answer is -ve
1160 * and also rounds n.5 towards zero
1162 static INT muldiv(INT m1, INT m2, INT d)
1164 LONGLONG ret;
1166 ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1168 if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1170 if(ret > 0) ret--;
1171 else ret++;
1173 return ret;
1176 /******************************************************************
1177 * set_window
1179 * Helper for GetWinMetaFileBits
1181 * Add the SetWindowOrg and SetWindowExt records
1183 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1185 ENHMETAHEADER header;
1186 INT horz_res, vert_res, horz_size, vert_size;
1187 POINT pt;
1189 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1191 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1192 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1193 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1194 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1196 switch(map_mode)
1198 case MM_TEXT:
1199 case MM_ISOTROPIC:
1200 case MM_ANISOTROPIC:
1201 pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1202 pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
1203 break;
1204 case MM_LOMETRIC:
1205 pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1206 pt.x = muldiv( header.rclFrame.left, 1, 10);
1207 break;
1208 case MM_HIMETRIC:
1209 pt.y = -header.rclFrame.top + 1;
1210 pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
1211 break;
1212 case MM_LOENGLISH:
1213 pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1214 pt.x = muldiv( header.rclFrame.left, 10, 254);
1215 break;
1216 case MM_HIENGLISH:
1217 pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1218 pt.x = muldiv( header.rclFrame.left, 100, 254);
1219 break;
1220 case MM_TWIPS:
1221 pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1222 pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
1223 break;
1224 default:
1225 WARN("Unknown map mode %d\n", map_mode);
1226 return FALSE;
1228 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1230 pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1231 pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1232 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1233 return TRUE;
1236 /******************************************************************
1237 * GetWinMetaFileBits [GDI32.@]
1239 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1240 UINT cbBuffer, LPBYTE lpbBuffer,
1241 INT map_mode, HDC hdcRef)
1243 HDC hdcmf;
1244 HMETAFILE hmf;
1245 UINT ret, full_size;
1246 RECT rc;
1248 NtGdiGetAppClipBox(hdcRef, &rc);
1250 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1251 map_mode, hdcRef, wine_dbgstr_rect(&rc));
1253 hdcmf = CreateMetaFileW(NULL);
1255 add_mf_comment(hdcmf, hemf);
1256 SetMapMode(hdcmf, map_mode);
1257 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1258 goto error;
1260 PlayEnhMetaFile(hdcmf, hemf, &rc);
1261 hmf = CloseMetaFile(hdcmf);
1262 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1263 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1264 DeleteMetaFile(hmf);
1266 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1268 WORD checksum = 0;
1269 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1270 UINT i;
1272 for(i = 0; i < full_size / 2; i++)
1273 checksum += ((WORD*)lpbBuffer)[i];
1274 comment_rec->rdParm[8] = ~checksum + 1;
1276 return ret;
1278 error:
1279 DeleteMetaFile(CloseMetaFile(hdcmf));
1280 return 0;
1283 /******************************************************************
1284 * MF_Play_MetaCreateRegion
1286 * Handles META_CREATEREGION for PlayMetaFileRecord().
1288 * The layout of the record looks something like this:
1290 * rdParm meaning
1291 * 0 Always 0?
1292 * 1 Always 6?
1293 * 2 Looks like a handle? - not constant
1294 * 3 0 or 1 ??
1295 * 4 Total number of bytes
1296 * 5 No. of separate bands = n [see below]
1297 * 6 Largest number of x co-ords in a band
1298 * 7-10 Bounding box x1 y1 x2 y2
1299 * 11-... n bands
1301 * Regions are divided into bands that are uniform in the
1302 * y-direction. Each band consists of pairs of on/off x-coords and is
1303 * written as
1304 * m y0 y1 x1 x2 x3 ... xm m
1305 * into successive rdParm[]s.
1307 * This is probably just a dump of the internal RGNOBJ?
1309 * HDMD - 18/12/97
1313 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1315 WORD band, pair;
1316 WORD *start, *end;
1317 INT16 y0, y1;
1318 HRGN hrgn2 = NtGdiCreateRectRgn( 0, 0, 0, 0 );
1320 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1321 band++, start = end + 1) {
1322 if(*start / 2 != (*start + 1) / 2) {
1323 WARN("Delimiter not even.\n");
1324 DeleteObject( hrgn2 );
1325 return FALSE;
1328 end = start + *start + 3;
1329 if(end > (WORD *)mr + mr->rdSize) {
1330 WARN("End points outside record.\n");
1331 DeleteObject( hrgn2 );
1332 return FALSE;
1335 if(*start != *end) {
1336 WARN("Mismatched delimiters.\n");
1337 DeleteObject( hrgn2 );
1338 return FALSE;
1341 y0 = *(INT16 *)(start + 1);
1342 y1 = *(INT16 *)(start + 2);
1343 for(pair = 0; pair < *start / 2; pair++) {
1344 NtGdiSetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1345 *(INT16 *)(start + 4 + 2*pair), y1 );
1346 NtGdiCombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
1349 DeleteObject( hrgn2 );
1350 return TRUE;
1354 /******************************************************************
1355 * MF_Play_MetaExtTextOut
1357 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1360 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1362 INT *dx = NULL;
1363 int i;
1364 SHORT *dxx;
1365 LPSTR sot;
1366 DWORD len;
1367 WORD s1;
1368 RECT rect;
1369 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1371 s1 = mr->rdParm[2]; /* String length */
1372 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1373 + sizeof(UINT16) + (isrect ? 4 * sizeof(SHORT) : 0);
1374 /* rec len without dx array */
1376 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1377 if (isrect)
1379 rect.left = (SHORT)mr->rdParm[4];
1380 rect.top = (SHORT)mr->rdParm[5];
1381 rect.right = (SHORT)mr->rdParm[6];
1382 rect.bottom = (SHORT)mr->rdParm[7];
1383 sot += 4 * sizeof(SHORT); /* there is a rectangle, so add offset */
1386 if (mr->rdSize == len / 2)
1387 dxx = NULL; /* determine if array is present */
1388 else
1389 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1391 dxx = (SHORT *)(sot+(((s1+1)>>1)*2));
1392 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1393 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1395 else {
1396 TRACE("%s len: %ld\n", sot, mr->rdSize);
1397 WARN("Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1398 len, s1, mr->rdSize, mr->rdParm[3]);
1399 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1401 ExtTextOutA( hdc,
1402 (SHORT)mr->rdParm[1], /* X position */
1403 (SHORT)mr->rdParm[0], /* Y position */
1404 mr->rdParm[3], /* options */
1405 &rect, /* rectangle */
1406 sot, /* string */
1407 s1, dx); /* length, dx array */
1408 if (dx)
1410 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1411 HeapFree( GetProcessHeap(), 0, dx );
1413 return TRUE;