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