winhttp/tests: Make sure proxy settings are restored.
[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
1092     TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1093     if (!mh) return 0;  /* FIXME: error code */
1094     if(mh->mtType == METAFILE_DISK)
1095         FIXME("Disk-based metafile?\n");
1096     mfSize = mh->mtSize * 2;
1097     if (buf)
1098     {
1099         if(mfSize > nSize) mfSize = nSize;
1100         memmove(buf, mh, mfSize);
1101     }
1102     GDI_ReleaseObj( hmf );
1103     TRACE("returning size %d\n", mfSize);
1104     return mfSize;
1105 }
1106
1107 #include <pshpack2.h>
1108 typedef struct
1109 {
1110     DWORD magic;   /* WMFC */
1111     WORD unk04;    /* 1 */
1112     WORD unk06;    /* 0 */
1113     WORD unk08;    /* 0 */
1114     WORD unk0a;    /* 1 */
1115     WORD checksum;
1116     DWORD unk0e;   /* 0 */
1117     DWORD num_chunks;
1118     DWORD chunk_size;
1119     DWORD remaining_size;
1120     DWORD emf_size;
1121     BYTE *emf_data;
1122 } mf_comment_chunk;
1123 #include <poppack.h>
1124
1125 static const DWORD wmfc_magic = 0x43464d57;
1126
1127 /******************************************************************
1128  *         add_mf_comment
1129  *
1130  * Helper for GetWinMetaFileBits
1131  *
1132  * Add the MFCOMMENT record[s] which is essentially a copy
1133  * of the original emf.
1134  */
1135 static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
1136 {
1137     DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i;
1138     BYTE *bits, *chunk_data;
1139     mf_comment_chunk *chunk = NULL;
1140     BOOL ret = FALSE;
1141     static const DWORD max_chunk_size = 0x2000;
1142
1143     if(!size) return FALSE;
1144     chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size);
1145     if(!bits) return FALSE;
1146     if(!GetEnhMetaFileBits(emf, size, bits)) goto end;
1147
1148     chunk = HeapAlloc(GetProcessHeap(), 0, max_chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data));
1149     if(!chunk) goto end;
1150
1151     chunk->magic = wmfc_magic;
1152     chunk->unk04 = 1;
1153     chunk->unk06 = 0;
1154     chunk->unk08 = 0;
1155     chunk->unk0a = 1;
1156     chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1157     chunk->unk0e = 0;
1158     chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
1159     chunk->chunk_size = max_chunk_size;
1160     chunk->remaining_size = size;
1161     chunk->emf_size = size;
1162
1163     for(i = 0; i < chunk->num_chunks; i++)
1164     {
1165         if(i == chunk->num_chunks - 1) /* last chunk */
1166             chunk->chunk_size = chunk->remaining_size;
1167
1168         chunk->remaining_size -= chunk->chunk_size;
1169         memcpy(&chunk->emf_data, chunk_data, chunk->chunk_size);
1170         chunk_data += chunk->chunk_size;
1171
1172         if(!Escape(hdc, MFCOMMENT, chunk->chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data), (char*)chunk, NULL))
1173             goto end;
1174     }
1175     ret = TRUE;
1176 end:
1177     HeapFree(GetProcessHeap(), 0, chunk);
1178     HeapFree(GetProcessHeap(), 0, bits);
1179     return ret;
1180 }
1181
1182 /*******************************************************************
1183  *        muldiv
1184  *
1185  * Behaves somewhat differently to MulDiv when the answer is -ve
1186  * and also rounds n.5 towards zero
1187  */
1188 static INT muldiv(INT m1, INT m2, INT d)
1189 {
1190     LONGLONG ret;
1191
1192     ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1193
1194     if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1195     {
1196         if(ret > 0) ret--;
1197         else ret++;
1198     }
1199     return ret;
1200 }
1201
1202 /******************************************************************
1203  *         set_window
1204  *
1205  * Helper for GetWinMetaFileBits
1206  *
1207  * Add the SetWindowOrg and SetWindowExt records
1208  */
1209 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1210 {
1211     ENHMETAHEADER header;
1212     INT horz_res, vert_res, horz_size, vert_size;
1213     POINT pt;
1214
1215     if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1216
1217     horz_res = GetDeviceCaps(ref_dc, HORZRES);
1218     vert_res = GetDeviceCaps(ref_dc, VERTRES);
1219     horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1220     vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1221
1222     switch(map_mode)
1223     {
1224     case MM_TEXT:
1225     case MM_ISOTROPIC:
1226     case MM_ANISOTROPIC:
1227         pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1228         pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
1229         break;
1230     case MM_LOMETRIC:
1231         pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1232         pt.x = muldiv( header.rclFrame.left, 1, 10);
1233         break;
1234     case MM_HIMETRIC:
1235         pt.y = -header.rclFrame.top + 1;
1236         pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
1237         break;
1238     case MM_LOENGLISH:
1239         pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1240         pt.x = muldiv( header.rclFrame.left, 10, 254);
1241         break;
1242     case MM_HIENGLISH:
1243         pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1244         pt.x = muldiv( header.rclFrame.left, 100, 254);
1245         break;
1246     case MM_TWIPS:
1247         pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1248         pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
1249         break;
1250     default:
1251         WARN("Unknown map mode %d\n", map_mode);
1252         return FALSE;
1253     }
1254     SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1255
1256     pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1257     pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1258     SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1259     return TRUE;
1260 }
1261
1262 /******************************************************************
1263  *         GetWinMetaFileBits [GDI32.@]
1264  */
1265 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1266                                 UINT cbBuffer, LPBYTE lpbBuffer,
1267                                 INT map_mode, HDC hdcRef)
1268 {
1269     HDC hdcmf;
1270     HMETAFILE hmf;
1271     UINT ret, full_size;
1272     RECT rc;
1273
1274     GetClipBox(hdcRef, &rc);
1275
1276     TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1277           map_mode, hdcRef, wine_dbgstr_rect(&rc));
1278
1279     hdcmf = CreateMetaFileW(NULL);
1280
1281     add_mf_comment(hdcmf, hemf);
1282     SetMapMode(hdcmf, map_mode);
1283     if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1284         goto error;
1285
1286     PlayEnhMetaFile(hdcmf, hemf, &rc);
1287     hmf = CloseMetaFile(hdcmf);
1288     full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1289     ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1290     DeleteMetaFile(hmf);
1291
1292     if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1293     {
1294         WORD checksum = 0;
1295         METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1296         UINT i;
1297
1298         for(i = 0; i < full_size / 2; i++)
1299             checksum += ((WORD*)lpbBuffer)[i];
1300         comment_rec->rdParm[8] = ~checksum + 1;
1301     }
1302     return ret;
1303
1304 error:
1305     DeleteMetaFile(CloseMetaFile(hdcmf));
1306     return 0;
1307 }
1308
1309 /******************************************************************
1310  *         MF_Play_MetaCreateRegion
1311  *
1312  *  Handles META_CREATEREGION for PlayMetaFileRecord().
1313  *
1314  *      The layout of the record looks something like this:
1315  *
1316  *       rdParm meaning
1317  *       0              Always 0?
1318  *       1              Always 6?
1319  *       2              Looks like a handle? - not constant
1320  *       3              0 or 1 ??
1321  *       4              Total number of bytes
1322  *       5              No. of separate bands = n [see below]
1323  *       6              Largest number of x co-ords in a band
1324  *       7-10           Bounding box x1 y1 x2 y2
1325  *       11-...         n bands
1326  *
1327  *       Regions are divided into bands that are uniform in the
1328  *       y-direction. Each band consists of pairs of on/off x-coords and is
1329  *       written as
1330  *              m y0 y1 x1 x2 x3 ... xm m
1331  *       into successive rdParm[]s.
1332  *
1333  *       This is probably just a dump of the internal RGNOBJ?
1334  *
1335  *       HDMD - 18/12/97
1336  *
1337  */
1338
1339 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1340 {
1341     WORD band, pair;
1342     WORD *start, *end;
1343     INT16 y0, y1;
1344     HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1345
1346     for(band  = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1347                                                 band++, start = end + 1) {
1348         if(*start / 2 != (*start + 1) / 2) {
1349             WARN("Delimiter not even.\n");
1350             DeleteObject( hrgn2 );
1351             return FALSE;
1352         }
1353
1354         end = start + *start + 3;
1355         if(end > (WORD *)mr + mr->rdSize) {
1356             WARN("End points outside record.\n");
1357             DeleteObject( hrgn2 );
1358             return FALSE;
1359         }
1360
1361         if(*start != *end) {
1362             WARN("Mismatched delimiters.\n");
1363             DeleteObject( hrgn2 );
1364             return FALSE;
1365         }
1366
1367         y0 = *(INT16 *)(start + 1);
1368         y1 = *(INT16 *)(start + 2);
1369         for(pair = 0; pair < *start / 2; pair++) {
1370             SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1371                                  *(INT16 *)(start + 4 + 2*pair), y1 );
1372             CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1373         }
1374     }
1375     DeleteObject( hrgn2 );
1376     return TRUE;
1377  }
1378
1379
1380 /******************************************************************
1381  *         MF_Play_MetaExtTextOut
1382  *
1383  *  Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1384  */
1385
1386 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1387 {
1388     INT *dx = NULL;
1389     int i;
1390     SHORT *dxx;
1391     LPSTR sot;
1392     DWORD len;
1393     WORD s1;
1394     RECT rect;
1395     BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1396
1397     s1 = mr->rdParm[2];                              /* String length */
1398     len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1399         + sizeof(UINT16) + (isrect ? 4 * sizeof(SHORT) : 0);
1400                                            /* rec len without dx array */
1401
1402     sot = (LPSTR)&mr->rdParm[4];                      /* start_of_text */
1403     if (isrect)
1404     {
1405         rect.left   = (SHORT)mr->rdParm[4];
1406         rect.top    = (SHORT)mr->rdParm[5];
1407         rect.right  = (SHORT)mr->rdParm[6];
1408         rect.bottom = (SHORT)mr->rdParm[7];
1409         sot += 4 * sizeof(SHORT);  /* there is a rectangle, so add offset */
1410     }
1411
1412     if (mr->rdSize == len / 2)
1413         dxx = NULL;                      /* determine if array is present */
1414     else
1415         if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1416         {
1417             dxx = (SHORT *)(sot+(((s1+1)>>1)*2));
1418             dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1419             if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1420         }
1421         else {
1422             TRACE("%s  len: %d\n",  sot, mr->rdSize);
1423             WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1424                  len, s1, mr->rdSize, mr->rdParm[3]);
1425             dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1426         }
1427     ExtTextOutA( hdc,
1428                  (SHORT)mr->rdParm[1],       /* X position */
1429                  (SHORT)mr->rdParm[0],       /* Y position */
1430                  mr->rdParm[3],              /* options */
1431                  &rect,                      /* rectangle */
1432                  sot,                        /* string */
1433                  s1, dx);                    /* length, dx array */
1434     if (dx)
1435     {
1436         TRACE("%s  len: %d  dx0: %d\n", sot, mr->rdSize, dx[0]);
1437         HeapFree( GetProcessHeap(), 0, dx );
1438     }
1439     return TRUE;
1440 }