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