gdi32: Avoid redundant computation of the gradient bounding rectangle.
[wine/multimedia.git] / dlls / gdi32 / metafile.c
blobfbc88d1b07860e0e814b5644c7171b2340c5263b
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"
74 typedef struct
76 GDIOBJHDR header;
77 METAHEADER *mh;
78 } METAFILEOBJ;
81 /******************************************************************
82 * MF_AddHandle
84 * Add a handle to an external handle table and return the index
86 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
88 int i;
90 for (i = 0; i < htlen; i++)
92 if (*(ht->objectHandle + i) == 0)
94 *(ht->objectHandle + i) = hobj;
95 return i;
98 return -1;
102 /******************************************************************
103 * MF_Create_HMETATFILE
105 * Creates a (32 bit) HMETAFILE object from a METAHEADER
107 * HMETAFILEs are GDI objects.
109 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
111 HMETAFILE hmf;
112 METAFILEOBJ *metaObj;
114 if (!(metaObj = HeapAlloc( GetProcessHeap(), 0, sizeof(*metaObj) ))) return 0;
115 metaObj->mh = mh;
116 if (!(hmf = alloc_gdi_handle( &metaObj->header, OBJ_METAFILE, NULL )))
117 HeapFree( GetProcessHeap(), 0, metaObj );
118 return hmf;
121 /******************************************************************
122 * MF_GetMetaHeader
124 * Returns ptr to METAHEADER associated with HMETAFILE
126 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
128 METAHEADER *ret = NULL;
129 METAFILEOBJ * metaObj = GDI_GetObjPtr( hmf, OBJ_METAFILE );
130 if (metaObj)
132 ret = metaObj->mh;
133 GDI_ReleaseObj( hmf );
135 return ret;
138 /******************************************************************
139 * convert_points
141 * Convert an array of POINTS to an array of POINT.
142 * Result must be freed by caller.
144 static POINT *convert_points( UINT count, const POINTS *pts )
146 UINT i;
147 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
148 if (ret)
150 for (i = 0; i < count; i++)
152 ret[i].x = pts[i].x;
153 ret[i].y = pts[i].y;
156 return ret;
159 /******************************************************************
160 * DeleteMetaFile (GDI32.@)
162 * Delete a memory-based metafile.
165 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
167 METAFILEOBJ * metaObj = free_gdi_handle( hmf );
168 if (!metaObj) return FALSE;
169 HeapFree( GetProcessHeap(), 0, metaObj->mh );
170 return HeapFree( GetProcessHeap(), 0, metaObj );
173 /******************************************************************
174 * MF_ReadMetaFile
176 * Returns a pointer to a memory based METAHEADER read in from file HFILE
179 static METAHEADER *MF_ReadMetaFile(HANDLE hfile)
181 METAHEADER *mh;
182 DWORD BytesRead, size;
184 size = sizeof(METAHEADER);
185 mh = HeapAlloc( GetProcessHeap(), 0, size );
186 if(!mh) return NULL;
187 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
188 BytesRead != size) {
189 HeapFree( GetProcessHeap(), 0, mh );
190 return NULL;
192 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
193 mh->mtHeaderSize != size / 2)
195 HeapFree( GetProcessHeap(), 0, mh );
196 return NULL;
198 size = mh->mtSize * 2;
199 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
200 if(!mh) return NULL;
201 size -= sizeof(METAHEADER);
202 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
203 NULL) == 0 ||
204 BytesRead != size) {
205 HeapFree( GetProcessHeap(), 0, mh );
206 return NULL;
209 if (mh->mtType != METAFILE_MEMORY) {
210 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
211 mh->mtType = METAFILE_MEMORY;
213 return mh;
216 /******************************************************************
217 * GetMetaFileA (GDI32.@)
219 * Read a metafile from a file. Returns handle to a memory-based metafile.
221 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
223 METAHEADER *mh;
224 HANDLE hFile;
226 TRACE("%s\n", lpFilename);
228 if(!lpFilename)
229 return 0;
231 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
232 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
233 return 0;
235 mh = MF_ReadMetaFile(hFile);
236 CloseHandle(hFile);
237 if(!mh) return 0;
238 return MF_Create_HMETAFILE( mh );
241 /******************************************************************
242 * GetMetaFileW (GDI32.@)
244 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
246 METAHEADER *mh;
247 HANDLE hFile;
249 TRACE("%s\n", debugstr_w(lpFilename));
251 if(!lpFilename)
252 return 0;
254 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
255 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
256 return 0;
258 mh = MF_ReadMetaFile(hFile);
259 CloseHandle(hFile);
260 if(!mh) return 0;
261 return MF_Create_HMETAFILE( mh );
265 /******************************************************************
266 * MF_LoadDiskBasedMetaFile
268 * Creates a new memory-based metafile from a disk-based one.
270 static METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
272 METAHEADERDISK *mhd;
273 HANDLE hfile;
274 METAHEADER *mh2;
276 if(mh->mtType != METAFILE_DISK) {
277 ERR("Not a disk based metafile\n");
278 return NULL;
280 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
282 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
283 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
284 WARN("Can't open file of disk based metafile\n");
285 return NULL;
287 mh2 = MF_ReadMetaFile(hfile);
288 CloseHandle(hfile);
289 return mh2;
292 /******************************************************************
293 * MF_CreateMetaHeaderDisk
295 * Take a memory based METAHEADER and change it to a disk based METAHEADER
296 * associated with filename. Note: Trashes contents of old one.
298 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
300 METAHEADERDISK *mhd;
302 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
303 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
304 mh->mtType = METAFILE_DISK;
305 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
307 if( uni )
308 WideCharToMultiByte(CP_ACP, 0, filename, -1,
309 mhd->filename, sizeof mhd->filename, NULL, NULL);
310 else
311 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
312 return mh;
315 /******************************************************************
316 * CopyMetaFileW (GDI32.@)
318 * Copies the metafile corresponding to hSrcMetaFile to either
319 * a disk file, if a filename is given, or to a new memory based
320 * metafile, if lpFileName is NULL.
322 * PARAMS
323 * hSrcMetaFile [I] handle of metafile to copy
324 * lpFilename [I] filename if copying to a file
326 * RETURNS
327 * Handle to metafile copy on success, NULL on failure.
329 * BUGS
330 * Copying to disk returns NULL even if successful.
332 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
334 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
335 METAHEADER *mh2 = NULL;
336 HANDLE hFile;
338 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
340 if(!mh) return 0;
342 if(mh->mtType == METAFILE_DISK)
343 mh2 = MF_LoadDiskBasedMetaFile(mh);
344 else {
345 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
346 memcpy( mh2, mh, mh->mtSize * 2 );
349 if(lpFilename) { /* disk based metafile */
350 DWORD w;
351 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
352 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
353 HeapFree( GetProcessHeap(), 0, mh2 );
354 return 0;
356 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
357 CloseHandle(hFile);
360 return MF_Create_HMETAFILE( mh2 );
364 /******************************************************************
365 * CopyMetaFileA (GDI32.@)
367 * See CopyMetaFileW.
369 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
371 UNICODE_STRING lpFilenameW;
372 HMETAFILE ret = 0;
374 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
375 else lpFilenameW.Buffer = NULL;
377 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
378 if (lpFilenameW.Buffer)
379 RtlFreeUnicodeString(&lpFilenameW);
380 return ret;
383 /*******************************************************************
384 * MF_PlayMetaFile
386 * Helper for PlayMetaFile
388 static BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
391 METARECORD *mr;
392 HANDLETABLE *ht;
393 unsigned int offset = 0;
394 WORD i;
395 HPEN hPen;
396 HBRUSH hBrush;
397 HPALETTE hPal;
398 HRGN hRgn;
399 BOOL loaded = FALSE;
401 if (!mh) return FALSE;
402 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
403 mh = MF_LoadDiskBasedMetaFile(mh);
404 if(!mh) return FALSE;
405 loaded = TRUE;
408 /* save DC */
409 hPen = GetCurrentObject(hdc, OBJ_PEN);
410 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
411 hPal = GetCurrentObject(hdc, OBJ_PAL);
413 hRgn = CreateRectRgn(0, 0, 0, 0);
414 if (!GetClipRgn(hdc, hRgn))
416 DeleteObject(hRgn);
417 hRgn = 0;
420 /* create the handle table */
421 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
422 sizeof(HANDLETABLE) * mh->mtNoObjects);
423 if(!ht) return FALSE;
425 /* loop through metafile playing records */
426 offset = mh->mtHeaderSize * 2;
427 while (offset < mh->mtSize * 2)
429 mr = (METARECORD *)((char *)mh + offset);
430 TRACE("offset=%04x,size=%08x\n",
431 offset, mr->rdSize);
432 if (mr->rdSize < 3) { /* catch illegal record sizes */
433 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
434 mr->rdSize,offset,mh->mtSize*2);
435 break;
438 offset += mr->rdSize * 2;
439 if (mr->rdFunction == META_EOF) {
440 TRACE("Got META_EOF so stopping\n");
441 break;
443 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
446 /* restore DC */
447 SelectObject(hdc, hPen);
448 SelectObject(hdc, hBrush);
449 SelectPalette(hdc, hPal, FALSE);
450 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
451 DeleteObject(hRgn);
453 /* free objects in handle table */
454 for(i = 0; i < mh->mtNoObjects; i++)
455 if(*(ht->objectHandle + i) != 0)
456 DeleteObject(*(ht->objectHandle + i));
458 /* free handle table */
459 HeapFree( GetProcessHeap(), 0, ht );
460 if(loaded)
461 HeapFree( GetProcessHeap(), 0, mh );
462 return TRUE;
465 /******************************************************************
466 * PlayMetaFile (GDI32.@)
468 * Renders the metafile specified by hmf in the DC specified by
469 * hdc. Returns FALSE on failure, TRUE on success.
471 * PARAMS
472 * hdc [I] handle of DC to render in
473 * hmf [I] handle of metafile to render
475 * RETURNS
476 * Success: TRUE
477 * Failure: FALSE
479 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
481 METAHEADER *mh = MF_GetMetaHeader( hmf );
482 return MF_PlayMetaFile( hdc, mh );
485 /******************************************************************
486 * EnumMetaFile (GDI32.@)
488 * Loop through the metafile records in hmf, calling the user-specified
489 * function for each one, stopping when the user's function returns FALSE
490 * (which is considered to be failure)
491 * or when no records are left (which is considered to be success).
493 * RETURNS
494 * TRUE on success, FALSE on failure.
496 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
498 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
499 METARECORD *mr;
500 HANDLETABLE *ht;
501 BOOL result = TRUE;
502 int i;
503 unsigned int offset = 0;
504 HPEN hPen;
505 HBRUSH hBrush;
506 HFONT hFont;
508 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
509 if (!mh) return 0;
510 if(mh->mtType == METAFILE_DISK)
512 /* Create a memory-based copy */
513 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
514 mh = mhTemp;
517 /* save the current pen, brush and font */
518 hPen = GetCurrentObject(hdc, OBJ_PEN);
519 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
520 hFont = GetCurrentObject(hdc, OBJ_FONT);
522 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
523 sizeof(HANDLETABLE) * mh->mtNoObjects);
525 /* loop through metafile records */
526 offset = mh->mtHeaderSize * 2;
528 while (offset < (mh->mtSize * 2))
530 mr = (METARECORD *)((char *)mh + offset);
531 if(mr->rdFunction == META_EOF) {
532 TRACE("Got META_EOF so stopping\n");
533 break;
535 TRACE("Calling EnumFunc with record type %x\n",
536 mr->rdFunction);
537 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
539 result = FALSE;
540 break;
543 offset += (mr->rdSize * 2);
546 /* restore pen, brush and font */
547 SelectObject(hdc, hBrush);
548 SelectObject(hdc, hPen);
549 SelectObject(hdc, hFont);
551 /* free objects in handle table */
552 for(i = 0; i < mh->mtNoObjects; i++)
553 if(*(ht->objectHandle + i) != 0)
554 DeleteObject(*(ht->objectHandle + i));
556 /* free handle table */
557 HeapFree( GetProcessHeap(), 0, ht);
558 /* free a copy of metafile */
559 HeapFree( GetProcessHeap(), 0, mhTemp );
560 return result;
563 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
564 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
565 /******************************************************************
566 * PlayMetaFileRecord (GDI32.@)
568 * Render a single metafile record specified by *mr in the DC hdc, while
569 * using the handle table *ht, of length handles,
570 * to store metafile objects.
572 * BUGS
573 * The following metafile records are unimplemented:
575 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
576 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
577 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
579 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
581 short s1;
582 POINT *pt;
583 BITMAPINFOHEADER *infohdr;
585 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
587 switch (mr->rdFunction)
589 case META_EOF:
590 break;
592 case META_DELETEOBJECT:
593 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
594 *(ht->objectHandle + mr->rdParm[0]) = 0;
595 break;
597 case META_SETBKCOLOR:
598 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
599 break;
601 case META_SETBKMODE:
602 SetBkMode(hdc, mr->rdParm[0]);
603 break;
605 case META_SETMAPMODE:
606 SetMapMode(hdc, mr->rdParm[0]);
607 break;
609 case META_SETROP2:
610 SetROP2(hdc, mr->rdParm[0]);
611 break;
613 case META_SETRELABS:
614 SetRelAbs(hdc, mr->rdParm[0]);
615 break;
617 case META_SETPOLYFILLMODE:
618 SetPolyFillMode(hdc, mr->rdParm[0]);
619 break;
621 case META_SETSTRETCHBLTMODE:
622 SetStretchBltMode(hdc, mr->rdParm[0]);
623 break;
625 case META_SETTEXTCOLOR:
626 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
627 break;
629 case META_SETWINDOWORG:
630 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
631 break;
633 case META_SETWINDOWEXT:
634 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
635 break;
637 case META_SETVIEWPORTORG:
638 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
639 break;
641 case META_SETVIEWPORTEXT:
642 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
643 break;
645 case META_OFFSETWINDOWORG:
646 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
647 break;
649 case META_SCALEWINDOWEXT:
650 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
651 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
652 break;
654 case META_OFFSETVIEWPORTORG:
655 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
656 break;
658 case META_SCALEVIEWPORTEXT:
659 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
660 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
661 break;
663 case META_LINETO:
664 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
665 break;
667 case META_MOVETO:
668 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
669 break;
671 case META_EXCLUDECLIPRECT:
672 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
673 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
674 break;
676 case META_INTERSECTCLIPRECT:
677 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
678 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
679 break;
681 case META_ARC:
682 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
683 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
684 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
685 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
686 break;
688 case META_ELLIPSE:
689 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
690 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
691 break;
693 case META_FLOODFILL:
694 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
695 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
696 break;
698 case META_PIE:
699 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
700 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
701 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
702 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
703 break;
705 case META_RECTANGLE:
706 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
707 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
708 break;
710 case META_ROUNDRECT:
711 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
712 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
713 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
714 break;
716 case META_PATBLT:
717 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
718 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
719 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
720 break;
722 case META_SAVEDC:
723 SaveDC(hdc);
724 break;
726 case META_SETPIXEL:
727 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
728 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
729 break;
731 case META_OFFSETCLIPRGN:
732 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
733 break;
735 case META_TEXTOUT:
736 s1 = mr->rdParm[0];
737 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
738 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
739 (char *)(mr->rdParm + 1), s1);
740 break;
742 case META_POLYGON:
743 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
745 Polygon(hdc, pt, mr->rdParm[0]);
746 HeapFree( GetProcessHeap(), 0, pt );
748 break;
750 case META_POLYPOLYGON:
752 UINT i, total;
753 SHORT *counts = (SHORT *)(mr->rdParm + 1);
755 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
756 pt = convert_points( total, (POINTS *)(counts + mr->rdParm[0]) );
757 if (pt)
759 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
760 if (cnt32)
762 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
763 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
764 HeapFree( GetProcessHeap(), 0, cnt32 );
767 HeapFree( GetProcessHeap(), 0, pt );
769 break;
771 case META_POLYLINE:
772 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
774 Polyline( hdc, pt, mr->rdParm[0] );
775 HeapFree( GetProcessHeap(), 0, pt );
777 break;
779 case META_RESTOREDC:
780 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
781 break;
783 case META_SELECTOBJECT:
784 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
785 break;
787 case META_CHORD:
788 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
789 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
790 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
791 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
792 break;
794 case META_CREATEPATTERNBRUSH:
795 switch (mr->rdParm[0])
797 case BS_PATTERN:
798 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
799 MF_AddHandle(ht, handles,
800 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
801 infohdr->biHeight,
802 infohdr->biPlanes,
803 infohdr->biBitCount,
804 mr->rdParm +
805 (sizeof(BITMAPINFOHEADER) / 2) + 4)));
806 break;
808 case BS_DIBPATTERN:
809 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
810 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
811 break;
813 default:
814 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
815 mr->rdParm[0]);
816 break;
818 break;
820 case META_CREATEPENINDIRECT:
822 LOGPEN pen;
823 pen.lopnStyle = mr->rdParm[0];
824 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
825 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
826 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
827 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
829 break;
831 case META_CREATEFONTINDIRECT:
833 LOGFONTA font;
834 font.lfHeight = (SHORT)mr->rdParm[0];
835 font.lfWidth = (SHORT)mr->rdParm[1];
836 font.lfEscapement = (SHORT)mr->rdParm[2];
837 font.lfOrientation = (SHORT)mr->rdParm[3];
838 font.lfWeight = (SHORT)mr->rdParm[4];
839 font.lfItalic = LOBYTE(mr->rdParm[5]);
840 font.lfUnderline = HIBYTE(mr->rdParm[5]);
841 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
842 font.lfCharSet = HIBYTE(mr->rdParm[6]);
843 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
844 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
845 font.lfQuality = LOBYTE(mr->rdParm[8]);
846 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
847 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
848 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
850 break;
852 case META_CREATEBRUSHINDIRECT:
854 LOGBRUSH brush;
855 brush.lbStyle = mr->rdParm[0];
856 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
857 brush.lbHatch = mr->rdParm[3];
858 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
860 break;
862 case META_CREATEPALETTE:
863 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
864 break;
866 case META_SETTEXTALIGN:
867 SetTextAlign(hdc, mr->rdParm[0]);
868 break;
870 case META_SELECTPALETTE:
871 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
872 break;
874 case META_SETMAPPERFLAGS:
875 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
876 break;
878 case META_REALIZEPALETTE:
879 GDIRealizePalette(hdc);
880 break;
882 case META_ESCAPE:
883 switch (mr->rdParm[0]) {
884 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
885 case GETPHYSPAGESIZE:
886 case GETPRINTINGOFFSET:
887 return FALSE;
888 case SETABORTPROC:
889 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
890 return FALSE;
892 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
893 break;
895 case META_EXTTEXTOUT:
896 MF_Play_MetaExtTextOut( hdc, mr );
897 break;
899 case META_STRETCHDIB:
901 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
902 LPSTR bits = (LPSTR)info + bitmap_info_size( info, mr->rdParm[2] );
903 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
904 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
905 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
906 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
908 break;
910 case META_DIBSTRETCHBLT:
912 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
913 LPSTR bits = (LPSTR)info + bitmap_info_size( info, DIB_RGB_COLORS );
914 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
915 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
916 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
917 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
919 break;
921 case META_STRETCHBLT:
923 HDC hdcSrc = CreateCompatibleDC(hdc);
924 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
925 mr->rdParm[11], /*Height*/
926 mr->rdParm[13], /*Planes*/
927 mr->rdParm[14], /*BitsPixel*/
928 &mr->rdParm[15]); /*bits*/
929 SelectObject(hdcSrc,hbitmap);
930 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
931 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
932 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
933 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
934 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
935 DeleteDC(hdcSrc);
937 break;
939 case META_BITBLT:
941 HDC hdcSrc = CreateCompatibleDC(hdc);
942 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
943 mr->rdParm[8]/*Height*/,
944 mr->rdParm[10]/*Planes*/,
945 mr->rdParm[11]/*BitsPixel*/,
946 &mr->rdParm[12]/*bits*/);
947 SelectObject(hdcSrc,hbitmap);
948 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
949 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
950 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
951 MAKELONG(0,mr->rdParm[0]));
952 DeleteDC(hdcSrc);
954 break;
956 case META_CREATEREGION:
958 HRGN hrgn = CreateRectRgn(0,0,0,0);
960 MF_Play_MetaCreateRegion(mr, hrgn);
961 MF_AddHandle(ht, handles, hrgn);
963 break;
965 case META_FILLREGION:
966 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
967 *(ht->objectHandle + mr->rdParm[0]));
968 break;
970 case META_FRAMEREGION:
971 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
972 *(ht->objectHandle + mr->rdParm[2]),
973 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
974 break;
976 case META_INVERTREGION:
977 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
978 break;
980 case META_PAINTREGION:
981 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
982 break;
984 case META_SELECTCLIPREGION:
986 HRGN hrgn = 0;
988 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
989 SelectClipRgn(hdc, hrgn);
991 break;
993 case META_DIBCREATEPATTERNBRUSH:
994 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
995 but there's no difference */
996 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
997 break;
999 case META_DIBBITBLT:
1000 /* In practice I've found that there are two layouts for
1001 META_DIBBITBLT, one (the first here) is the usual one when a src
1002 dc is actually passed to it, the second occurs when the src dc is
1003 passed in as NULL to the creating BitBlt. As the second case has
1004 no dib, a size check will suffice to distinguish.
1006 Caolan.McNamara@ul.ie */
1008 if (mr->rdSize > 12) {
1009 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1010 LPSTR bits = (LPSTR)info + bitmap_info_size(info, mr->rdParm[0]);
1012 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1013 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1014 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1015 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1017 else /* equivalent to a PatBlt */
1018 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1019 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1020 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1021 break;
1023 case META_SETTEXTCHAREXTRA:
1024 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1025 break;
1027 case META_SETTEXTJUSTIFICATION:
1028 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1029 break;
1031 case META_EXTFLOODFILL:
1032 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1033 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1034 mr->rdParm[0]);
1035 break;
1037 case META_SETDIBTODEV:
1039 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1040 char *bits = (char *)info + bitmap_info_size( info, mr->rdParm[0] );
1041 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1042 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1043 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1044 mr->rdParm[2], mr->rdParm[1], bits, info,
1045 mr->rdParm[0]);
1046 break;
1049 #define META_UNIMP(x) case x: \
1050 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1051 break;
1052 META_UNIMP(META_DRAWTEXT)
1053 META_UNIMP(META_ANIMATEPALETTE)
1054 META_UNIMP(META_SETPALENTRIES)
1055 META_UNIMP(META_RESIZEPALETTE)
1056 META_UNIMP(META_RESETDC)
1057 META_UNIMP(META_STARTDOC)
1058 META_UNIMP(META_STARTPAGE)
1059 META_UNIMP(META_ENDPAGE)
1060 META_UNIMP(META_ABORTDOC)
1061 META_UNIMP(META_ENDDOC)
1062 META_UNIMP(META_CREATEBRUSH)
1063 META_UNIMP(META_CREATEBITMAPINDIRECT)
1064 META_UNIMP(META_CREATEBITMAP)
1065 #undef META_UNIMP
1067 default:
1068 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1069 return FALSE;
1071 return TRUE;
1074 /******************************************************************
1075 * SetMetaFileBitsEx (GDI32.@)
1077 * Create a metafile from raw data. No checking of the data is performed.
1078 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1080 * PARAMS
1081 * size [I] size of metafile, in bytes
1082 * lpData [I] pointer to metafile data
1084 * RETURNS
1085 * Success: Handle to metafile.
1086 * Failure: NULL.
1088 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1090 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1091 METAHEADER *mh_out;
1093 if (size & 1) return 0;
1095 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1096 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1098 SetLastError(ERROR_INVALID_DATA);
1099 return 0;
1102 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1103 if (!mh_out)
1105 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1106 return 0;
1109 memcpy(mh_out, mh_in, size);
1110 mh_out->mtSize = size / 2;
1111 return MF_Create_HMETAFILE(mh_out);
1114 /*****************************************************************
1115 * GetMetaFileBitsEx (GDI32.@)
1117 * Get raw metafile data.
1119 * Copies the data from metafile _hmf_ into the buffer _buf_.
1121 * PARAMS
1122 * hmf [I] metafile
1123 * nSize [I] size of buf
1124 * buf [O] buffer to receive raw metafile data
1126 * RETURNS
1127 * If _buf_ is zero, returns size of buffer required. Otherwise,
1128 * returns number of bytes copied.
1130 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1132 METAHEADER *mh = MF_GetMetaHeader(hmf);
1133 UINT mfSize;
1135 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1136 if (!mh) return 0; /* FIXME: error code */
1137 if(mh->mtType == METAFILE_DISK)
1138 FIXME("Disk-based metafile?\n");
1139 mfSize = mh->mtSize * 2;
1140 if (!buf) {
1141 TRACE("returning size %d\n", mfSize);
1142 return mfSize;
1144 if(mfSize > nSize) mfSize = nSize;
1145 memmove(buf, mh, mfSize);
1146 return mfSize;
1149 #include <pshpack2.h>
1150 typedef struct
1152 DWORD magic; /* WMFC */
1153 WORD unk04; /* 1 */
1154 WORD unk06; /* 0 */
1155 WORD unk08; /* 0 */
1156 WORD unk0a; /* 1 */
1157 WORD checksum;
1158 DWORD unk0e; /* 0 */
1159 DWORD num_chunks;
1160 DWORD chunk_size;
1161 DWORD remaining_size;
1162 DWORD emf_size;
1163 BYTE *emf_data;
1164 } mf_comment_chunk;
1165 #include <poppack.h>
1167 static const DWORD wmfc_magic = 0x43464d57;
1169 /******************************************************************
1170 * add_mf_comment
1172 * Helper for GetWinMetaFileBits
1174 * Add the MFCOMMENT record[s] which is essentially a copy
1175 * of the original emf.
1177 static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
1179 DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i;
1180 BYTE *bits, *chunk_data;
1181 mf_comment_chunk *chunk = NULL;
1182 BOOL ret = FALSE;
1183 static const DWORD max_chunk_size = 0x2000;
1185 if(!size) return FALSE;
1186 chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size);
1187 if(!bits) return FALSE;
1188 if(!GetEnhMetaFileBits(emf, size, bits)) goto end;
1190 chunk = HeapAlloc(GetProcessHeap(), 0, max_chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data));
1191 if(!chunk) goto end;
1193 chunk->magic = wmfc_magic;
1194 chunk->unk04 = 1;
1195 chunk->unk06 = 0;
1196 chunk->unk08 = 0;
1197 chunk->unk0a = 1;
1198 chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1199 chunk->unk0e = 0;
1200 chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
1201 chunk->chunk_size = max_chunk_size;
1202 chunk->remaining_size = size;
1203 chunk->emf_size = size;
1205 for(i = 0; i < chunk->num_chunks; i++)
1207 if(i == chunk->num_chunks - 1) /* last chunk */
1208 chunk->chunk_size = chunk->remaining_size;
1210 chunk->remaining_size -= chunk->chunk_size;
1211 memcpy(&chunk->emf_data, chunk_data, chunk->chunk_size);
1212 chunk_data += chunk->chunk_size;
1214 if(!Escape(hdc, MFCOMMENT, chunk->chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data), (char*)chunk, NULL))
1215 goto end;
1217 ret = TRUE;
1218 end:
1219 HeapFree(GetProcessHeap(), 0, chunk);
1220 HeapFree(GetProcessHeap(), 0, bits);
1221 return ret;
1224 /*******************************************************************
1225 * muldiv
1227 * Behaves somewhat differently to MulDiv when the answer is -ve
1228 * and also rounds n.5 towards zero
1230 static INT muldiv(INT m1, INT m2, INT d)
1232 LONGLONG ret;
1234 ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1236 if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1238 if(ret > 0) ret--;
1239 else ret++;
1241 return ret;
1244 /******************************************************************
1245 * set_window
1247 * Helper for GetWinMetaFileBits
1249 * Add the SetWindowOrg and SetWindowExt records
1251 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1253 ENHMETAHEADER header;
1254 INT horz_res, vert_res, horz_size, vert_size;
1255 POINT pt;
1257 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1259 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1260 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1261 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1262 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1264 switch(map_mode)
1266 case MM_TEXT:
1267 case MM_ISOTROPIC:
1268 case MM_ANISOTROPIC:
1269 pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1270 pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
1271 break;
1272 case MM_LOMETRIC:
1273 pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1274 pt.x = muldiv( header.rclFrame.left, 1, 10);
1275 break;
1276 case MM_HIMETRIC:
1277 pt.y = -header.rclFrame.top + 1;
1278 pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
1279 break;
1280 case MM_LOENGLISH:
1281 pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1282 pt.x = muldiv( header.rclFrame.left, 10, 254);
1283 break;
1284 case MM_HIENGLISH:
1285 pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1286 pt.x = muldiv( header.rclFrame.left, 100, 254);
1287 break;
1288 case MM_TWIPS:
1289 pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1290 pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
1291 break;
1292 default:
1293 WARN("Unknown map mode %d\n", map_mode);
1294 return FALSE;
1296 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1298 pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1299 pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1300 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1301 return TRUE;
1304 /******************************************************************
1305 * GetWinMetaFileBits [GDI32.@]
1307 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1308 UINT cbBuffer, LPBYTE lpbBuffer,
1309 INT map_mode, HDC hdcRef)
1311 HDC hdcmf;
1312 HMETAFILE hmf;
1313 UINT ret, full_size;
1314 RECT rc;
1316 GetClipBox(hdcRef, &rc);
1318 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1319 map_mode, hdcRef, wine_dbgstr_rect(&rc));
1321 hdcmf = CreateMetaFileW(NULL);
1323 add_mf_comment(hdcmf, hemf);
1324 SetMapMode(hdcmf, map_mode);
1325 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1326 goto error;
1328 PlayEnhMetaFile(hdcmf, hemf, &rc);
1329 hmf = CloseMetaFile(hdcmf);
1330 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1331 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1332 DeleteMetaFile(hmf);
1334 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1336 WORD checksum = 0;
1337 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1338 UINT i;
1340 for(i = 0; i < full_size / 2; i++)
1341 checksum += ((WORD*)lpbBuffer)[i];
1342 comment_rec->rdParm[8] = ~checksum + 1;
1344 return ret;
1346 error:
1347 DeleteMetaFile(CloseMetaFile(hdcmf));
1348 return 0;
1351 /******************************************************************
1352 * MF_Play_MetaCreateRegion
1354 * Handles META_CREATEREGION for PlayMetaFileRecord().
1356 * The layout of the record looks something like this:
1358 * rdParm meaning
1359 * 0 Always 0?
1360 * 1 Always 6?
1361 * 2 Looks like a handle? - not constant
1362 * 3 0 or 1 ??
1363 * 4 Total number of bytes
1364 * 5 No. of separate bands = n [see below]
1365 * 6 Largest number of x co-ords in a band
1366 * 7-10 Bounding box x1 y1 x2 y2
1367 * 11-... n bands
1369 * Regions are divided into bands that are uniform in the
1370 * y-direction. Each band consists of pairs of on/off x-coords and is
1371 * written as
1372 * m y0 y1 x1 x2 x3 ... xm m
1373 * into successive rdParm[]s.
1375 * This is probably just a dump of the internal RGNOBJ?
1377 * HDMD - 18/12/97
1381 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1383 WORD band, pair;
1384 WORD *start, *end;
1385 INT16 y0, y1;
1386 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1388 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1389 band++, start = end + 1) {
1390 if(*start / 2 != (*start + 1) / 2) {
1391 WARN("Delimiter not even.\n");
1392 DeleteObject( hrgn2 );
1393 return FALSE;
1396 end = start + *start + 3;
1397 if(end > (WORD *)mr + mr->rdSize) {
1398 WARN("End points outside record.\n");
1399 DeleteObject( hrgn2 );
1400 return FALSE;
1403 if(*start != *end) {
1404 WARN("Mismatched delimiters.\n");
1405 DeleteObject( hrgn2 );
1406 return FALSE;
1409 y0 = *(INT16 *)(start + 1);
1410 y1 = *(INT16 *)(start + 2);
1411 for(pair = 0; pair < *start / 2; pair++) {
1412 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1413 *(INT16 *)(start + 4 + 2*pair), y1 );
1414 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1417 DeleteObject( hrgn2 );
1418 return TRUE;
1422 /******************************************************************
1423 * MF_Play_MetaExtTextOut
1425 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1428 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1430 INT *dx = NULL;
1431 int i;
1432 SHORT *dxx;
1433 LPSTR sot;
1434 DWORD len;
1435 WORD s1;
1436 RECT rect;
1437 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1439 s1 = mr->rdParm[2]; /* String length */
1440 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1441 + sizeof(UINT16) + (isrect ? 4 * sizeof(SHORT) : 0);
1442 /* rec len without dx array */
1444 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1445 if (isrect)
1447 rect.left = (SHORT)mr->rdParm[4];
1448 rect.top = (SHORT)mr->rdParm[5];
1449 rect.right = (SHORT)mr->rdParm[6];
1450 rect.bottom = (SHORT)mr->rdParm[7];
1451 sot += 4 * sizeof(SHORT); /* there is a rectangle, so add offset */
1454 if (mr->rdSize == len / 2)
1455 dxx = NULL; /* determine if array is present */
1456 else
1457 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1459 dxx = (SHORT *)(sot+(((s1+1)>>1)*2));
1460 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1461 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1463 else {
1464 TRACE("%s len: %d\n", sot, mr->rdSize);
1465 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1466 len, s1, mr->rdSize, mr->rdParm[3]);
1467 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1469 ExtTextOutA( hdc,
1470 (SHORT)mr->rdParm[1], /* X position */
1471 (SHORT)mr->rdParm[0], /* Y position */
1472 mr->rdParm[3], /* options */
1473 &rect, /* rectangle */
1474 sot, /* string */
1475 s1, dx); /* length, dx array */
1476 if (dx)
1478 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1479 HeapFree( GetProcessHeap(), 0, dx );
1481 return TRUE;