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