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