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