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