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