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