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