Added Win16 implementation for GetRegionData().
[wine] / objects / metafile.c
1 /*
2  * Metafile functions
3  *
4  * Copyright  David W. Metcalfe, 1994
5  *            Niels de Carpentier, Albrecht Kleine, Huw Davies 1996
6  *
7  */
8
9 #include <string.h>
10 #include <fcntl.h>
11 #include "windows.h"
12 #include "gdi.h"
13 #include "bitmap.h"
14 #include "file.h"
15 #include "heap.h"
16 #include "metafile.h"
17 #include "metafiledrv.h"
18 #include "toolhelp.h"
19 #include "debug.h"
20
21 /******************************************************************
22  *         MF_AddHandle
23  *
24  *    Add a handle to an external handle table and return the index
25  */
26
27 static int MF_AddHandle(HANDLETABLE16 *ht, WORD htlen, HGDIOBJ16 hobj)
28 {
29     int i;
30
31     for (i = 0; i < htlen; i++)
32     {
33         if (*(ht->objectHandle + i) == 0)
34         {
35             *(ht->objectHandle + i) = hobj;
36             return i;
37         }
38     }
39     return -1;
40 }
41
42
43 /******************************************************************
44  *         MF_AddHandleDC
45  *
46  * Note: this function assumes that we never delete objects.
47  * If we do someday, we'll need to maintain a table to re-use deleted
48  * handles.
49  */
50 static int MF_AddHandleDC( DC *dc )
51 {
52     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dc->physDev;
53     physDev->mh->mtNoObjects++;
54     return physDev->nextHandle++;
55 }
56
57
58 /******************************************************************
59  *         GetMetaFile16   (GDI.124)
60  */
61 HMETAFILE16 WINAPI GetMetaFile16( LPCSTR lpFilename )
62 {
63     return GetMetaFile32A( lpFilename );
64 }
65
66
67 /******************************************************************
68  *         GetMetaFile32A   (GDI32.197)
69  *
70  *  Read a metafile from a file. Returns handle to a disk-based metafile.
71  */
72 HMETAFILE32 WINAPI GetMetaFile32A( 
73                                   LPCSTR lpFilename 
74                       /* pointer to string containing filename to read */
75 )
76 {
77   HMETAFILE16 hmf;
78   METAHEADER *mh;
79   HFILE32 hFile;
80   DWORD size;
81   
82   TRACE(metafile,"%s\n", lpFilename);
83
84   if (!lpFilename)
85     return 0;
86
87   hmf = GlobalAlloc16(GMEM_MOVEABLE, MFHEADERSIZE);
88   mh = (METAHEADER *)GlobalLock16(hmf);
89   
90   if (!mh)
91   {
92     GlobalFree16(hmf);
93     return 0;
94   }
95   
96   if ((hFile = _lopen32(lpFilename, OF_READ)) == HFILE_ERROR32)
97   {
98     GlobalFree16(hmf);
99     return 0;
100   }
101   
102   if (_lread32(hFile, (char *)mh, MFHEADERSIZE) == HFILE_ERROR32)
103   {
104     _lclose32( hFile );
105     GlobalFree16(hmf);
106     return 0;
107   }
108   
109   size = mh->mtSize * 2;         /* alloc memory for whole metafile */
110   GlobalUnlock16(hmf);
111   hmf = GlobalReAlloc16(hmf,size,GMEM_MOVEABLE);
112   mh = (METAHEADER *)GlobalLock16(hmf);
113   
114   if (!mh)
115   {
116     _lclose32( hFile );
117     GlobalFree16(hmf);
118     return 0;
119   }
120   
121   if (_lread32(hFile, (char*)mh + mh->mtHeaderSize * 2, 
122                 size - mh->mtHeaderSize * 2) == HFILE_ERROR32)
123   {
124     _lclose32( hFile );
125     GlobalFree16(hmf);
126     return 0;
127   }
128   
129   _lclose32(hFile);
130
131   if (mh->mtType != 1)
132   {
133     GlobalFree16(hmf);
134     return 0;
135   }
136   
137   GlobalUnlock16(hmf);
138   return hmf;
139
140 }
141
142
143 /******************************************************************
144  *         GetMetaFile32W   (GDI32.199)
145  */
146 HMETAFILE32 WINAPI GetMetaFile32W( LPCWSTR lpFilename )
147 {
148     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFilename );
149     HMETAFILE32 ret = GetMetaFile32A( p );
150     HeapFree( GetProcessHeap(), 0, p );
151     return ret;
152 }
153
154
155 /******************************************************************
156  *         CopyMetaFile16   (GDI.151)
157  */
158
159 HMETAFILE16 WINAPI CopyMetaFile16( HMETAFILE16 hSrcMetaFile, LPCSTR lpFilename )
160 {
161     return CopyMetaFile32A( hSrcMetaFile, lpFilename );
162 }
163
164
165 /******************************************************************
166  *         CopyMetaFile32A   (GDI32.23)
167  *
168  *  Copies the metafile corresponding to hSrcMetaFile to either
169  *  a disk file, if a filename is given, or to a new memory based
170  *  metafile, if lpFileName is NULL.
171  *
172  * RETURNS
173  *
174  *  Handle to metafile copy on success, NULL on failure.
175  *
176  * BUGS
177  *
178  *  Copying to disk returns NULL even if successful.
179  */
180 HMETAFILE32 WINAPI CopyMetaFile32A(
181                    HMETAFILE32 hSrcMetaFile, /* handle of metafile to copy */
182                    LPCSTR lpFilename /* filename if copying to a file */
183 ) {
184     HMETAFILE16 handle = 0;
185     METAHEADER *mh;
186     METAHEADER *mh2;
187     HFILE32 hFile;
188     
189     TRACE(metafile,"(%08x,%s)\n", hSrcMetaFile, lpFilename);
190     
191     mh = (METAHEADER *)GlobalLock16(hSrcMetaFile);
192     
193     if (!mh)
194       return 0;
195     
196     if (lpFilename)          /* disk based metafile */
197         {
198         int i,j;
199         hFile = _lcreat32(lpFilename, 0);
200         j=mh->mtType;
201         mh->mtType=1;        /* disk file version stores 1 here */
202         i=_lwrite32(hFile, (char *)mh, mh->mtSize * 2) ;
203         mh->mtType=j;        /* restore old value  [0 or 1] */  
204         _lclose32(hFile);
205         if (i == -1)
206             return 0;
207         /* FIXME: return value */
208         }
209     else                     /* memory based metafile */
210         {
211         handle = GlobalAlloc16(GMEM_MOVEABLE,mh->mtSize * 2);
212         mh2 = (METAHEADER *)GlobalLock16(handle);
213         memcpy(mh2,mh, mh->mtSize * 2);
214         GlobalUnlock16(handle);
215         }
216
217     GlobalUnlock16(hSrcMetaFile);
218     return handle;
219 }
220
221
222 /******************************************************************
223  *         CopyMetaFile32W   (GDI32.24)
224  */
225 HMETAFILE32 WINAPI CopyMetaFile32W( HMETAFILE32 hSrcMetaFile,
226                                     LPCWSTR lpFilename )
227 {
228     LPSTR p = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFilename );
229     HMETAFILE32 ret = CopyMetaFile32A( hSrcMetaFile, p );
230     HeapFree( GetProcessHeap(), 0, p );
231     return ret;
232 }
233
234
235 /******************************************************************
236  *         IsValidMetaFile   (GDI.410)
237  *
238  *  Attempts to check if a given metafile is correctly formatted.
239  *  Currently, the only things verified are several properties of the
240  *  header.
241  *
242  * RETURNS
243  *  TRUE if hmf passes some tests for being a valid metafile, FALSE otherwise.
244  *
245  * BUGS
246  *  This is not exactly what windows does, see _Undocumented_Windows_
247  *  for details.
248  */
249
250 BOOL16 WINAPI IsValidMetaFile(HMETAFILE16 hmf)
251 {
252     BOOL16 resu=FALSE;
253     METAHEADER *mh = (METAHEADER *)GlobalLock16(hmf);
254     if (mh) {
255       if (mh->mtType == 1 || mh->mtType == 0) 
256         if (mh->mtHeaderSize == MFHEADERSIZE/sizeof(INT16))
257           if (mh->mtVersion == MFVERSION)
258             resu=TRUE;
259       GlobalUnlock16(hmf);
260     }
261     TRACE(metafile,"IsValidMetaFile %x => %d\n",hmf,resu);
262     return resu;         
263 }
264
265
266 /******************************************************************
267  *         PlayMetaFile16   (GDI.123)
268  *
269  */
270 BOOL16 WINAPI PlayMetaFile16( HDC16 hdc, HMETAFILE16 hmf )
271 {
272     return PlayMetaFile32( hdc, hmf );
273 }
274
275 /******************************************************************
276  *         PlayMetaFile32   (GDI32.265)
277  *
278  *  Renders the metafile specified by hmf in the DC specified by
279  *  hdc. Returns FALSE on failure, TRUE on success.
280  */
281 BOOL32 WINAPI PlayMetaFile32( 
282                              HDC32 hdc, /* handle of DC to render in */
283                              HMETAFILE32 hmf /* handle of metafile to render */
284 )
285 {
286     METAHEADER *mh = (METAHEADER *)GlobalLock16(hmf);
287     METARECORD *mr;
288     HANDLETABLE16 *ht;
289     HGLOBAL16 hHT;
290     int offset = 0;
291     WORD i;
292     HPEN32 hPen;
293     HBRUSH32 hBrush;
294     HFONT32 hFont;
295     DC *dc;
296     
297     TRACE(metafile,"(%04x %04x)\n",hdc,hmf);
298     if (!mh) return FALSE;
299
300     /* save the current pen, brush and font */
301     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
302     hPen = dc->w.hPen;
303     hBrush = dc->w.hBrush;
304     hFont = dc->w.hFont;
305     GDI_HEAP_UNLOCK(hdc);
306     /* create the handle table */
307     hHT = GlobalAlloc16(GMEM_MOVEABLE|GMEM_ZEROINIT,
308                       sizeof(HANDLETABLE16) * mh->mtNoObjects);
309     ht = (HANDLETABLE16 *)GlobalLock16(hHT);
310
311     
312     /* loop through metafile playing records */
313     offset = mh->mtHeaderSize * 2;
314     while (offset < mh->mtSize * 2)
315     {
316         mr = (METARECORD *)((char *)mh + offset);
317         TRACE(metafile,"offset=%04x,size=%08lx\n",
318             offset, mr->rdSize);
319         if (!mr->rdSize) {
320             TRACE(metafile,"Entry got size 0 at offset %d, total mf length is %ld\n",
321                 offset,mh->mtSize*2);
322                 break; /* would loop endlessly otherwise */
323         }
324         offset += mr->rdSize * 2;
325         PlayMetaFileRecord16( hdc, ht, mr, mh->mtNoObjects );
326     }
327
328     SelectObject32(hdc, hBrush);
329     SelectObject32(hdc, hPen);
330     SelectObject32(hdc, hFont);
331
332     /* free objects in handle table */
333     for(i = 0; i < mh->mtNoObjects; i++)
334       if(*(ht->objectHandle + i) != 0)
335         DeleteObject32(*(ht->objectHandle + i));
336     
337     /* free handle table */
338     GlobalFree16(hHT);
339
340     return TRUE;
341 }
342
343
344 /******************************************************************
345  *            EnumMetaFile16   (GDI.175)
346  *
347  *  Loop through the metafile records in hmf, calling the user-specified
348  *  function for each one, stopping when the user's function returns FALSE
349  *  (which is considered to be failure)
350  *  or when no records are left (which is considered to be success). 
351  *
352  * RETURNS
353  *  TRUE on success, FALSE on failure.
354  * 
355  * HISTORY
356  *   Niels de carpentier, april 1996
357  */
358 BOOL16 WINAPI EnumMetaFile16( 
359                              HDC16 hdc, 
360                              HMETAFILE16 hmf,
361                              MFENUMPROC16 lpEnumFunc, 
362                              LPARAM lpData 
363 )
364 {
365     METAHEADER *mh = (METAHEADER *)GlobalLock16(hmf);
366     METARECORD *mr;
367     HANDLETABLE16 *ht;
368     HGLOBAL16 hHT;
369     SEGPTR spht;
370     int offset = 0;
371     WORD i, seg;
372     HPEN32 hPen;
373     HBRUSH32 hBrush;
374     HFONT32 hFont;
375     DC *dc;
376     BOOL16 result = TRUE;
377     
378     TRACE(metafile,"(%04x, %04x, %08lx, %08lx)\n",
379                      hdc, hmf, (DWORD)lpEnumFunc, lpData);
380
381     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
382     hPen = dc->w.hPen;
383     hBrush = dc->w.hBrush;
384     hFont = dc->w.hFont;
385     GDI_HEAP_UNLOCK(hdc);
386
387     /* create the handle table */
388     
389     hHT = GlobalAlloc16(GMEM_MOVEABLE | GMEM_ZEROINIT,
390                      sizeof(HANDLETABLE16) * mh->mtNoObjects);
391     spht = WIN16_GlobalLock16(hHT);
392    
393     seg = GlobalHandleToSel(hmf);
394     offset = mh->mtHeaderSize * 2;
395     
396     /* loop through metafile records */
397     
398     while (offset < (mh->mtSize * 2))
399     {
400         mr = (METARECORD *)((char *)mh + offset);
401         if (!lpEnumFunc( hdc, (HANDLETABLE16 *)spht,
402                          (METARECORD *) PTR_SEG_OFF_TO_HUGEPTR(seg, offset),
403                          mh->mtNoObjects, (LONG)lpData ))
404         {
405             result = FALSE;
406             break;
407         }
408         
409
410         offset += (mr->rdSize * 2);
411     }
412
413     SelectObject32(hdc, hBrush);
414     SelectObject32(hdc, hPen);
415     SelectObject32(hdc, hFont);
416
417     ht = (HANDLETABLE16 *)GlobalLock16(hHT);
418
419     /* free objects in handle table */
420     for(i = 0; i < mh->mtNoObjects; i++)
421       if(*(ht->objectHandle + i) != 0)
422         DeleteObject32(*(ht->objectHandle + i));
423
424     /* free handle table */
425     GlobalFree16(hHT);
426     GlobalUnlock16(hmf);
427     return result;
428 }
429
430 BOOL32 WINAPI EnumMetaFile32( 
431                              HDC32 hdc, 
432                              HMETAFILE32 hmf,
433                              MFENUMPROC32 lpEnumFunc, 
434                              LPARAM lpData 
435 ) {
436     METAHEADER *mh = (METAHEADER *)GlobalLock16(hmf);
437     METARECORD *mr;
438     HANDLETABLE32 *ht;
439     BOOL32 result = TRUE;
440     int i, offset = 0;
441     DC *dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
442     HPEN32 hPen;
443     HBRUSH32 hBrush;
444     HFONT32 hFont;
445
446     TRACE(metafile,"(%08x,%08x,%p,%p)\n",
447                      hdc, hmf, lpEnumFunc, (void*)lpData);
448     if (!mh) return 0;
449
450     /* save the current pen, brush and font */
451     if (!dc) return 0;
452     hPen = dc->w.hPen;
453     hBrush = dc->w.hBrush;
454     hFont = dc->w.hFont;
455     GDI_HEAP_UNLOCK(hdc);
456
457
458     ht = (HANDLETABLE32 *) GlobalAlloc32(GPTR, 
459                             sizeof(HANDLETABLE32) * mh->mtNoObjects);
460     
461     /* loop through metafile records */
462     offset = mh->mtHeaderSize * 2;
463     
464     while (offset < (mh->mtSize * 2))
465     {
466         mr = (METARECORD *)((char *)mh + offset);
467         if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
468         {
469             result = FALSE;
470             break;
471         }
472         
473         offset += (mr->rdSize * 2);
474     }
475
476     /* restore pen, brush and font */
477     SelectObject32(hdc, hBrush);
478     SelectObject32(hdc, hPen);
479     SelectObject32(hdc, hFont);
480
481     /* free objects in handle table */
482     for(i = 0; i < mh->mtNoObjects; i++)
483       if(*(ht->objectHandle + i) != 0)
484         DeleteObject32(*(ht->objectHandle + i));
485
486     /* free handle table */
487     GlobalFree32((HGLOBAL32)ht);
488     GlobalUnlock16(hmf);
489     return result;
490 }
491
492 static BOOL32 MF_Meta_CreateRegion( METARECORD *mr, HRGN32 hrgn );
493
494 /******************************************************************
495  *             PlayMetaFileRecord16   (GDI.176)
496  *
497  *   Render a single metafile record specified by *mr in the DC hdc, while
498  *   using the handle table *ht, of length nHandles, 
499  *   to store metafile objects.
500  *
501  * BUGS
502  *  The following metafile records are unimplemented:
503  *
504  *  FRAMEREGION, DRAWTEXT, SETDIBTODEV, ANIMATEPALETTE, SETPALENTRIES,
505  *  RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
506  *  ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
507  *
508  */
509 void WINAPI PlayMetaFileRecord16( 
510             HDC16 hdc, /* DC to render metafile into */
511             HANDLETABLE16 *ht, /* pointer to handle table for metafile objects */
512             METARECORD *mr, /* pointer to metafile record to render */
513             UINT16 nHandles /* size of handle table */
514 ) {
515     short s1;
516     HANDLE16 hndl;
517     char *ptr;
518     BITMAPINFOHEADER *infohdr;
519
520     TRACE(metafile,"(%04x %08lx %08lx %04x) function %04x\n",
521                  hdc,(LONG)ht, (LONG)mr, nHandles, mr->rdFunction);
522     
523     switch (mr->rdFunction)
524     {
525     case META_EOF:
526       break;
527
528     case META_DELETEOBJECT:
529       DeleteObject32(*(ht->objectHandle + *(mr->rdParam)));
530       *(ht->objectHandle + *(mr->rdParam)) = 0;
531       break;
532
533     case META_SETBKCOLOR:
534         SetBkColor16(hdc, MAKELONG(*(mr->rdParam), *(mr->rdParam + 1)));
535         break;
536
537     case META_SETBKMODE:
538         SetBkMode16(hdc, *(mr->rdParam));
539         break;
540
541     case META_SETMAPMODE:
542         SetMapMode16(hdc, *(mr->rdParam));
543         break;
544
545     case META_SETROP2:
546         SetROP216(hdc, *(mr->rdParam));
547         break;
548
549     case META_SETRELABS:
550         SetRelAbs16(hdc, *(mr->rdParam));
551         break;
552
553     case META_SETPOLYFILLMODE:
554         SetPolyFillMode16(hdc, *(mr->rdParam));
555         break;
556
557     case META_SETSTRETCHBLTMODE:
558         SetStretchBltMode16(hdc, *(mr->rdParam));
559         break;
560
561     case META_SETTEXTCOLOR:
562         SetTextColor16(hdc, MAKELONG(*(mr->rdParam), *(mr->rdParam + 1)));
563         break;
564
565     case META_SETWINDOWORG:
566         SetWindowOrg(hdc, *(mr->rdParam + 1), *(mr->rdParam));
567         break;
568
569     case META_SETWINDOWEXT:
570         SetWindowExt(hdc, *(mr->rdParam + 1), *(mr->rdParam));
571         break;
572
573     case META_SETVIEWPORTORG:
574         SetViewportOrg(hdc, *(mr->rdParam + 1), *(mr->rdParam));
575         break;
576
577     case META_SETVIEWPORTEXT:
578         SetViewportExt(hdc, *(mr->rdParam + 1), *(mr->rdParam));
579         break;
580
581     case META_OFFSETWINDOWORG:
582         OffsetWindowOrg(hdc, *(mr->rdParam + 1), *(mr->rdParam));
583         break;
584
585     case META_SCALEWINDOWEXT:
586         ScaleWindowExt(hdc, *(mr->rdParam + 3), *(mr->rdParam + 2),
587                        *(mr->rdParam + 1), *(mr->rdParam));
588         break;
589
590     case META_OFFSETVIEWPORTORG:
591         OffsetViewportOrg(hdc, *(mr->rdParam + 1), *(mr->rdParam));
592         break;
593
594     case META_SCALEVIEWPORTEXT:
595         ScaleViewportExt(hdc, *(mr->rdParam + 3), *(mr->rdParam + 2),
596                          *(mr->rdParam + 1), *(mr->rdParam));
597         break;
598
599     case META_LINETO:
600         LineTo32(hdc, (INT16)*(mr->rdParam + 1), (INT16)*(mr->rdParam));
601         break;
602
603     case META_MOVETO:
604         MoveTo(hdc, *(mr->rdParam + 1), *(mr->rdParam));
605         break;
606
607     case META_EXCLUDECLIPRECT:
608         ExcludeClipRect16( hdc, *(mr->rdParam + 3), *(mr->rdParam + 2),
609                            *(mr->rdParam + 1), *(mr->rdParam) );
610         break;
611
612     case META_INTERSECTCLIPRECT:
613         IntersectClipRect16( hdc, *(mr->rdParam + 3), *(mr->rdParam + 2),
614                              *(mr->rdParam + 1), *(mr->rdParam) );
615         break;
616
617     case META_ARC:
618         Arc32(hdc, (INT16)*(mr->rdParam + 7), (INT16)*(mr->rdParam + 6),
619               (INT16)*(mr->rdParam + 5), (INT16)*(mr->rdParam + 4),
620               (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
621              (INT16)*(mr->rdParam + 1), (INT16)*(mr->rdParam));
622         break;
623
624     case META_ELLIPSE:
625         Ellipse32(hdc, (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
626                   (INT16)*(mr->rdParam + 1), (INT16)*(mr->rdParam));
627         break;
628
629     case META_FLOODFILL:
630         FloodFill32(hdc, (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
631                     MAKELONG(*(mr->rdParam), *(mr->rdParam + 1)));
632         break;
633
634     case META_PIE:
635         Pie32(hdc, (INT16)*(mr->rdParam + 7), (INT16)*(mr->rdParam + 6),
636               (INT16)*(mr->rdParam + 5), (INT16)*(mr->rdParam + 4),
637               (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
638              (INT16)*(mr->rdParam + 1), (INT16)*(mr->rdParam));
639         break;
640
641     case META_RECTANGLE:
642         Rectangle32(hdc, (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
643                     (INT16)*(mr->rdParam + 1), (INT16)*(mr->rdParam));
644         break;
645
646     case META_ROUNDRECT:
647         RoundRect32(hdc, (INT16)*(mr->rdParam + 5), (INT16)*(mr->rdParam + 4),
648                     (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
649                     (INT16)*(mr->rdParam + 1), (INT16)*(mr->rdParam));
650         break;
651
652     case META_PATBLT:
653         PatBlt16(hdc, *(mr->rdParam + 5), *(mr->rdParam + 4),
654                  *(mr->rdParam + 3), *(mr->rdParam + 2),
655                  MAKELONG(*(mr->rdParam), *(mr->rdParam + 1)));
656         break;
657
658     case META_SAVEDC:
659         SaveDC32(hdc);
660         break;
661
662     case META_SETPIXEL:
663         SetPixel32(hdc, (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
664                    MAKELONG(*(mr->rdParam), *(mr->rdParam + 1)));
665         break;
666
667     case META_OFFSETCLIPRGN:
668         OffsetClipRgn16( hdc, *(mr->rdParam + 1), *(mr->rdParam) );
669         break;
670
671     case META_TEXTOUT:
672         s1 = *(mr->rdParam);
673         TextOut16(hdc, *(mr->rdParam + ((s1 + 1) >> 1) + 2),
674                   *(mr->rdParam + ((s1 + 1) >> 1) + 1), 
675                   (char *)(mr->rdParam + 1), s1);
676         break;
677
678     case META_POLYGON:
679         Polygon16(hdc, (LPPOINT16)(mr->rdParam + 1), *(mr->rdParam));
680         break;
681
682     case META_POLYPOLYGON:
683       PolyPolygon16(hdc, (LPPOINT16)(mr->rdParam + *(mr->rdParam) + 1),
684                     (LPINT16)(mr->rdParam + 1), *(mr->rdParam)); 
685       break;
686
687     case META_POLYLINE:
688         Polyline16(hdc, (LPPOINT16)(mr->rdParam + 1), *(mr->rdParam));
689         break;
690
691     case META_RESTOREDC:
692         RestoreDC32(hdc, (INT16)*(mr->rdParam));
693         break;
694
695     case META_SELECTOBJECT:
696         SelectObject32(hdc, *(ht->objectHandle + *(mr->rdParam)));
697         break;
698
699     case META_CHORD:
700         Chord32(hdc, (INT16)*(mr->rdParam + 7), (INT16)*(mr->rdParam + 6),
701                 (INT16)*(mr->rdParam+5), (INT16)*(mr->rdParam + 4),
702                 (INT16)*(mr->rdParam + 3), (INT16)*(mr->rdParam + 2),
703                (INT16)*(mr->rdParam + 1), (INT16)*(mr->rdParam));
704         break;
705
706     case META_CREATEPATTERNBRUSH:
707         switch (*(mr->rdParam))
708         {
709         case BS_PATTERN:
710             infohdr = (BITMAPINFOHEADER *)(mr->rdParam + 2);
711             MF_AddHandle(ht, nHandles,
712                          CreatePatternBrush32(CreateBitmap32(infohdr->biWidth, 
713                                       infohdr->biHeight, 
714                                       infohdr->biPlanes, 
715                                       infohdr->biBitCount,
716                                       (LPSTR)(mr->rdParam + 
717                                       (sizeof(BITMAPINFOHEADER) / 2) + 4))));
718             break;
719
720         case BS_DIBPATTERN:
721             s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
722             hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
723             ptr = GlobalLock16(hndl);
724             memcpy(ptr, mr->rdParam + 2, s1);
725             GlobalUnlock16(hndl);
726             MF_AddHandle(ht, nHandles,
727                          CreateDIBPatternBrush32(hndl, *(mr->rdParam + 1)));
728             GlobalFree16(hndl);
729         }
730         break;
731         
732     case META_CREATEPENINDIRECT:
733         MF_AddHandle(ht, nHandles, 
734                      CreatePenIndirect16((LOGPEN16 *)(&(mr->rdParam))));
735         break;
736
737     case META_CREATEFONTINDIRECT:
738         MF_AddHandle(ht, nHandles, 
739                      CreateFontIndirect16((LOGFONT16 *)(&(mr->rdParam))));
740         break;
741
742     case META_CREATEBRUSHINDIRECT:
743         MF_AddHandle(ht, nHandles, 
744                      CreateBrushIndirect16((LOGBRUSH16 *)(&(mr->rdParam))));
745         break;
746
747     /* W. Magro: Some new metafile operations.  Not all debugged. */
748     case META_CREATEPALETTE:
749         MF_AddHandle(ht, nHandles, 
750                      CreatePalette16((LPLOGPALETTE)mr->rdParam));
751         break;
752
753     case META_SETTEXTALIGN:
754         SetTextAlign16(hdc, *(mr->rdParam));
755         break;
756
757     case META_SELECTPALETTE:
758         SelectPalette16(hdc, *(ht->objectHandle + *(mr->rdParam+1)),*(mr->rdParam));
759         break;
760
761     case META_SETMAPPERFLAGS:
762         SetMapperFlags16(hdc, *(mr->rdParam));
763         break;
764
765     case META_REALIZEPALETTE:
766         RealizePalette16(hdc);
767         break;
768
769     case META_ESCAPE:
770         FIXME(metafile, "META_ESCAPE unimplemented.\n");
771         break;
772
773         /* --- Begin of fixed or new metafile operations. July 1996 ----*/
774     case META_EXTTEXTOUT:
775       {
776         LPINT16 dxx;
777         LPSTR sot; 
778         DWORD len;
779
780         s1 = mr->rdParam[2];                              /* String length */
781         len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
782          + sizeof(UINT16) +  (mr->rdParam[3] ? sizeof(RECT16) : 0);  /* rec len without dx array */
783
784         sot= (LPSTR)&mr->rdParam[4];                    /* start_of_text */
785         if (mr->rdParam[3])
786            sot+=sizeof(RECT16);                         /* there is a rectangle, so add offset */
787          
788         if (mr->rdSize == len / 2)
789           dxx = NULL;                                   /* determine if array present */
790         else 
791           if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
792             dxx = (LPINT16)(sot+(((s1+1)>>1)*2));          
793           else 
794           {
795            TRACE(metafile,"%s  len: %ld\n",
796              sot,mr->rdSize);
797            WARN(metafile,
798              "Please report: PlayMetaFile/ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
799                    len,s1,mr->rdSize,mr->rdParam[3]);
800            dxx = NULL; /* should't happen -- but if, we continue with NULL [for workaround] */
801           }
802         ExtTextOut16( hdc, mr->rdParam[1],              /* X position */
803                            mr->rdParam[0],              /* Y position */
804                            mr->rdParam[3],              /* options */
805                            mr->rdParam[3] ? (LPRECT16) &mr->rdParam[4]:NULL,  /* rectangle */
806                            sot,                         /* string */
807                            s1, dxx);                    /* length, dx array */
808         if (dxx)                      
809           TRACE(metafile,"%s  len: %ld  dx0: %d\n",
810             sot,mr->rdSize,dxx[0]);
811        }
812        break;
813     
814     case META_STRETCHDIB:
815       {
816        LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParam[11]);
817        LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParam[2] );
818        StretchDIBits16(hdc,mr->rdParam[10],mr->rdParam[9],mr->rdParam[8],
819                        mr->rdParam[7],mr->rdParam[6],mr->rdParam[5],
820                        mr->rdParam[4],mr->rdParam[3],bits,info,
821                        mr->rdParam[2],MAKELONG(mr->rdParam[0],mr->rdParam[1]));
822       }
823       break;
824
825     case META_DIBSTRETCHBLT:
826       {
827        LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParam[10]); 
828        LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParam[2] );
829        StretchDIBits16(hdc,mr->rdParam[9],mr->rdParam[8],mr->rdParam[7],
830                        mr->rdParam[6],mr->rdParam[5],mr->rdParam[4],
831                        mr->rdParam[3],mr->rdParam[2],bits,info,
832                        DIB_RGB_COLORS,MAKELONG(mr->rdParam[0],mr->rdParam[1]));
833       }
834       break;              
835
836     case META_STRETCHBLT:
837       {
838        HDC16 hdcSrc=CreateCompatibleDC16(hdc);
839        HBITMAP32 hbitmap=CreateBitmap32(mr->rdParam[10], /*Width */
840                                         mr->rdParam[11], /*Height*/
841                                         mr->rdParam[13], /*Planes*/
842                                         mr->rdParam[14], /*BitsPixel*/
843                                         (LPSTR)&mr->rdParam[15]);  /*bits*/
844        SelectObject32(hdcSrc,hbitmap);
845        StretchBlt16(hdc,mr->rdParam[9],mr->rdParam[8],
846                     mr->rdParam[7],mr->rdParam[6],
847                     hdcSrc,mr->rdParam[5],mr->rdParam[4],
848                     mr->rdParam[3],mr->rdParam[2],
849                     MAKELONG(mr->rdParam[0],mr->rdParam[1]));
850        DeleteDC32(hdcSrc);                  
851       }
852       break;
853
854     case META_BITBLT:            /* <-- not yet debugged */
855       {
856        HDC16 hdcSrc=CreateCompatibleDC16(hdc);
857        HBITMAP32 hbitmap=CreateBitmap32(mr->rdParam[7]/*Width */,
858                                         mr->rdParam[8]/*Height*/,
859                                         mr->rdParam[10]/*Planes*/,
860                                         mr->rdParam[11]/*BitsPixel*/,
861                                         (LPSTR)&mr->rdParam[12]/*bits*/);
862        SelectObject32(hdcSrc,hbitmap);
863        BitBlt32(hdc,(INT16)mr->rdParam[6],(INT16)mr->rdParam[5],
864                 (INT16)mr->rdParam[4],(INT16)mr->rdParam[3],
865                 hdcSrc, (INT16)mr->rdParam[2],(INT16)mr->rdParam[1],
866                 MAKELONG(0,mr->rdParam[0]));
867        DeleteDC32(hdcSrc);                  
868       }
869       break;
870
871        /* --- Begin of new metafile operations. April, 1997 (ak) ----*/
872     case META_CREATEREGION:
873       {
874         HRGN32 hrgn = CreateRectRgn32(0,0,0,0);
875  
876         MF_Meta_CreateRegion(mr, hrgn);
877         MF_AddHandle(ht, nHandles, hrgn);
878       }
879       break;
880
881      case META_FILLREGION:
882         FillRgn16(hdc, *(ht->objectHandle + *(mr->rdParam)),
883                        *(ht->objectHandle + *(mr->rdParam+1)));
884         break;
885
886      case META_INVERTREGION:
887         InvertRgn16(hdc, *(ht->objectHandle + *(mr->rdParam)));
888         break; 
889
890      case META_PAINTREGION:
891         PaintRgn16(hdc, *(ht->objectHandle + *(mr->rdParam)));
892         break;
893
894      case META_SELECTCLIPREGION:
895         SelectClipRgn32(hdc, *(ht->objectHandle + *(mr->rdParam)));
896         break;
897
898      case META_DIBCREATEPATTERNBRUSH:
899         /*  *(mr->rdParam) may be BS_PATTERN or BS_DIBPATTERN: but there's no difference */
900         TRACE(metafile,"%d\n",*(mr->rdParam));
901         s1 = mr->rdSize * 2 - sizeof(METARECORD) - 2;
902         hndl = GlobalAlloc16(GMEM_MOVEABLE, s1);
903         ptr = GlobalLock16(hndl);
904         memcpy(ptr, mr->rdParam + 2, s1);
905         GlobalUnlock16(hndl);
906         MF_AddHandle(ht, nHandles,CreateDIBPatternBrush16(hndl, *(mr->rdParam + 1)));
907         GlobalFree16(hndl);
908         break;
909
910      case META_DIBBITBLT:
911         {
912          LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParam[8]);
913          LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParam[0] );
914          StretchDIBits16(hdc,mr->rdParam[7],mr->rdParam[6],mr->rdParam[5],
915                        mr->rdParam[4],mr->rdParam[3],mr->rdParam[2],
916                        mr->rdParam[5],mr->rdParam[4],bits,info,
917                        DIB_RGB_COLORS,MAKELONG(mr->rdParam[0],mr->rdParam[1]));
918         }
919         break;  
920        
921      case META_SETTEXTCHAREXTRA:
922             SetTextCharacterExtra16(hdc, (INT16)*(mr->rdParam));
923             break;
924
925      case META_SETTEXTJUSTIFICATION:
926         SetTextJustification32(hdc, *(mr->rdParam + 1), *(mr->rdParam));
927         break;
928
929 #define META_UNIMP(x) case x: FIXME(metafile, "PlayMetaFileRecord:record type "#x" not implemented.\n");break;
930     META_UNIMP(META_FRAMEREGION)
931     META_UNIMP(META_DRAWTEXT)
932     META_UNIMP(META_SETDIBTODEV)
933     META_UNIMP(META_ANIMATEPALETTE)
934     META_UNIMP(META_SETPALENTRIES)
935     META_UNIMP(META_RESIZEPALETTE)
936     META_UNIMP(META_EXTFLOODFILL)
937     META_UNIMP(META_RESETDC)
938     META_UNIMP(META_STARTDOC)
939     META_UNIMP(META_STARTPAGE)
940     META_UNIMP(META_ENDPAGE)
941     META_UNIMP(META_ABORTDOC)
942     META_UNIMP(META_ENDDOC)
943     META_UNIMP(META_CREATEBRUSH)
944     META_UNIMP(META_CREATEBITMAPINDIRECT)
945     META_UNIMP(META_CREATEBITMAP)
946 #undef META_UNIMP
947
948     default:
949         WARN(metafile, "PlayMetaFileRecord: Unknown record type %x\n",
950                                               mr->rdFunction);
951     }
952 }
953
954
955 BOOL32 WINAPI PlayMetaFileRecord32( 
956      HDC32 hdc, 
957      HANDLETABLE32 *handletable, 
958      METARECORD *metarecord, 
959      UINT32 handles  
960     )
961 {
962   HANDLETABLE16 * ht = (void *)GlobalAlloc32(GPTR, 
963                                handles*sizeof(HANDLETABLE16));
964   int i = 0;
965   TRACE(metafile, "(%08x,%p,%p,%d)\n", hdc, handletable, metarecord, handles); 
966   for (i=0; i<handles; i++)  
967     ht->objectHandle[i] =  handletable->objectHandle[i];
968   PlayMetaFileRecord16(hdc, ht, metarecord, handles);
969   for (i=0; i<handles; i++) 
970     handletable->objectHandle[i] = ht->objectHandle[i];
971   GlobalFree32((HGLOBAL32)ht);
972   return TRUE;
973 }
974
975 /******************************************************************
976  *         GetMetaFileBits   (GDI.159)
977  *
978  * Trade in a metafile object handle for a handle to the metafile memory.
979  *
980  */
981
982 HGLOBAL16 WINAPI GetMetaFileBits(
983                                  HMETAFILE16 hmf /* metafile handle */
984                                  )
985 {
986     TRACE(metafile,"hMem out: %04x\n", hmf);
987     return hmf;
988 }
989
990 /******************************************************************
991  *         SetMetaFileBits   (GDI.160)
992  *
993  * Trade in a metafile memory handle for a handle to a metafile object.
994  * The memory region should hold a proper metafile, otherwise
995  * problems will occur when it is used. Validity of the memory is not
996  * checked. The function is essentially just the identity function.
997  */
998 HMETAFILE16 WINAPI SetMetaFileBits( 
999                                    HGLOBAL16 hMem 
1000                         /* handle to a memory region holding a metafile */
1001 )
1002 {
1003     TRACE(metafile,"hmf out: %04x\n", hMem);
1004
1005     return hMem;
1006 }
1007
1008 /******************************************************************
1009  *         SetMetaFileBitsBetter   (GDI.196)
1010  *
1011  * Trade in a metafile memory handle for a handle to a metafile object,
1012  * making a cursory check (using IsValidMetaFile()) that the memory
1013  * handle points to a valid metafile.
1014  *
1015  * RETURNS
1016  *  Handle to a metafile on success, NULL on failure..
1017  */
1018 HMETAFILE16 WINAPI SetMetaFileBitsBetter( HMETAFILE16 hMeta )
1019 {
1020    if( IsValidMetaFile( hMeta ) )
1021        return (HMETAFILE16)GlobalReAlloc16( hMeta, 0, 
1022                            GMEM_SHARE | GMEM_NODISCARD | GMEM_MODIFY);
1023    return (HMETAFILE16)0;
1024 }
1025
1026 /******************************************************************
1027  *         SetMetaFileBitsEx    (GDI32.323)
1028  * 
1029  *  Create a metafile from raw data. No checking of the data is performed.
1030  *  Use _GetMetaFileBitsEx_ to get raw data from a metafile.
1031  */
1032 HMETAFILE32 WINAPI SetMetaFileBitsEx( 
1033      UINT32 size, /* size of metafile, in bytes */
1034      const BYTE *lpData /* pointer to metafile data */  
1035     )
1036 {
1037   HMETAFILE32 hmf = GlobalAlloc16(GHND, size);
1038   BYTE *p = GlobalLock16(hmf) ;
1039   TRACE(metafile, "(%d,%p) returning %08x\n", size, lpData, hmf);
1040   if (!hmf || !p) return 0;
1041   memcpy(p, lpData, size);
1042   GlobalUnlock16(hmf);
1043   return hmf;
1044 }
1045
1046 /*****************************************************************
1047  *  GetMetaFileBitsEx     (GDI32.198)  Get raw metafile data
1048  * 
1049  *  Copies the data from metafile _hmf_ into the buffer _buf_.
1050  *  If _buf_ is zero, returns size of buffer required. Otherwise,
1051  *  returns number of bytes copied.
1052  */
1053 UINT32 WINAPI GetMetaFileBitsEx( 
1054      HMETAFILE32 hmf, /* metafile */
1055      UINT32 nSize, /* size of buf */ 
1056      LPVOID buf   /* buffer to receive raw metafile data */  
1057 ) {
1058   METAHEADER *h = GlobalLock16(hmf);
1059   TRACE(metafile, "(%08x,%d,%p)\n", hmf, nSize, buf);
1060   if (!h) return 0;  /* FIXME: error code */
1061   if (!buf) {
1062     GlobalUnlock16(hmf);
1063     TRACE(metafile,"returning size %ld\n", h->mtSize);
1064     return h->mtSize;
1065   }
1066   memmove(buf, h, MIN(nSize, h->mtSize));
1067   GlobalUnlock16(hmf);
1068   return MIN(nSize, h->mtSize);
1069 }
1070
1071
1072 /******************************************************************
1073  *         MF_Meta_CreateRegion
1074  *
1075  *  Handles META_CREATEREGION for PlayMetaFileRecord().
1076  */
1077
1078 /*
1079  *      The layout of the record looks something like this:
1080  *       
1081  *       rdParam        meaning
1082  *       0              Always 0?
1083  *       1              Always 6?
1084  *       2              Looks like a handle? - not constant
1085  *       3              0 or 1 ??
1086  *       4              Total number of bytes
1087  *       5              No. of seperate bands = n [see below]
1088  *       6              Largest number of x co-ords in a band
1089  *       7-10           Bounding box x1 y1 x2 y2
1090  *       11-...         n bands
1091  *
1092  *       Regions are divided into bands that are uniform in the
1093  *       y-direction. Each band consists of pairs of on/off x-coords and is
1094  *       written as
1095  *              m y0 y1 x1 x2 x3 ... xm m
1096  *       into successive rdParam[]s.
1097  *
1098  *       This is probably just a dump of the internal RGNOBJ?
1099  *
1100  *       HDMD - 18/12/97
1101  *
1102  */
1103
1104 static BOOL32 MF_Meta_CreateRegion( METARECORD *mr, HRGN32 hrgn )
1105 {
1106     WORD band, pair;
1107     WORD *start, *end;
1108     INT16 y0, y1;
1109     HRGN32 hrgn2 = CreateRectRgn32( 0, 0, 0, 0 );
1110
1111     for(band  = 0, start = &(mr->rdParam[11]); band < mr->rdParam[5];
1112                                                 band++, start = end + 1) {
1113         if(*start / 2 != (*start + 1) / 2) {
1114             WARN(metafile, "Delimiter not even.\n");
1115             DeleteObject32( hrgn2 );
1116             return FALSE;
1117         }
1118
1119         end = start + *start + 3;
1120         if(end > (WORD *)mr + mr->rdSize) {
1121             WARN(metafile, "End points outside record.\n");
1122             DeleteObject32( hrgn2 );
1123             return FALSE;
1124         }
1125
1126         if(*start != *end) {
1127             WARN(metafile, "Mismatched delimiters.\n");
1128             DeleteObject32( hrgn2 );
1129             return FALSE;
1130         }
1131
1132         y0 = *(INT16 *)(start + 1);
1133         y1 = *(INT16 *)(start + 2);
1134         for(pair = 0; pair < *start / 2; pair++) {
1135             SetRectRgn32( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1136                                  *(INT16 *)(start + 4 + 2*pair), y1 );
1137             CombineRgn32(hrgn, hrgn, hrgn2, RGN_OR);
1138         }
1139     }
1140     DeleteObject32( hrgn2 );
1141     return TRUE;
1142  }
1143  
1144
1145 /******************************************************************
1146  *         MF_WriteRecord
1147  *
1148  * Warning: this function can change the metafile handle.
1149  */
1150
1151 static BOOL32 MF_WriteRecord( DC *dc, METARECORD *mr, DWORD rlen)
1152 {
1153     DWORD len;
1154     METAHEADER *mh;
1155     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dc->physDev;
1156
1157     switch(physDev->mh->mtType)
1158     {
1159     case METAFILE_MEMORY:
1160         len = physDev->mh->mtSize * 2 + rlen;
1161         mh = HeapReAlloc( SystemHeap, 0, physDev->mh, len );
1162         if (!mh) return FALSE;
1163         physDev->mh = mh;
1164         memcpy((WORD *)physDev->mh + physDev->mh->mtSize, mr, rlen);
1165         break;
1166     case METAFILE_DISK:
1167         TRACE(metafile,"Writing record to disk\n");
1168         if (_lwrite32(physDev->mh->mtNoParameters, (char *)mr, rlen) == -1)
1169             return FALSE;
1170         break;
1171     default:
1172         ERR(metafile, "Unknown metafile type %d\n", physDev->mh->mtType );
1173         return FALSE;
1174     }
1175
1176     physDev->mh->mtSize += rlen / 2;
1177     physDev->mh->mtMaxRecord = MAX(physDev->mh->mtMaxRecord, rlen / 2);
1178     return TRUE;
1179 }
1180
1181
1182 /******************************************************************
1183  *         MF_MetaParam0
1184  */
1185
1186 BOOL32 MF_MetaParam0(DC *dc, short func)
1187 {
1188     char buffer[8];
1189     METARECORD *mr = (METARECORD *)&buffer;
1190     
1191     mr->rdSize = 3;
1192     mr->rdFunction = func;
1193     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1194 }
1195
1196
1197 /******************************************************************
1198  *         MF_MetaParam1
1199  */
1200 BOOL32 MF_MetaParam1(DC *dc, short func, short param1)
1201 {
1202     char buffer[8];
1203     METARECORD *mr = (METARECORD *)&buffer;
1204     
1205     mr->rdSize = 4;
1206     mr->rdFunction = func;
1207     *(mr->rdParam) = param1;
1208     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1209 }
1210
1211
1212 /******************************************************************
1213  *         MF_MetaParam2
1214  */
1215 BOOL32 MF_MetaParam2(DC *dc, short func, short param1, short param2)
1216 {
1217     char buffer[10];
1218     METARECORD *mr = (METARECORD *)&buffer;
1219     
1220     mr->rdSize = 5;
1221     mr->rdFunction = func;
1222     *(mr->rdParam) = param2;
1223     *(mr->rdParam + 1) = param1;
1224     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1225 }
1226
1227
1228 /******************************************************************
1229  *         MF_MetaParam4
1230  */
1231
1232 BOOL32 MF_MetaParam4(DC *dc, short func, short param1, short param2, 
1233                    short param3, short param4)
1234 {
1235     char buffer[14];
1236     METARECORD *mr = (METARECORD *)&buffer;
1237     
1238     mr->rdSize = 7;
1239     mr->rdFunction = func;
1240     *(mr->rdParam) = param4;
1241     *(mr->rdParam + 1) = param3;
1242     *(mr->rdParam + 2) = param2;
1243     *(mr->rdParam + 3) = param1;
1244     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1245 }
1246
1247
1248 /******************************************************************
1249  *         MF_MetaParam6
1250  */
1251
1252 BOOL32 MF_MetaParam6(DC *dc, short func, short param1, short param2, 
1253                    short param3, short param4, short param5, short param6)
1254 {
1255     char buffer[18];
1256     METARECORD *mr = (METARECORD *)&buffer;
1257     
1258     mr->rdSize = 9;
1259     mr->rdFunction = func;
1260     *(mr->rdParam) = param6;
1261     *(mr->rdParam + 1) = param5;
1262     *(mr->rdParam + 2) = param4;
1263     *(mr->rdParam + 3) = param3;
1264     *(mr->rdParam + 4) = param2;
1265     *(mr->rdParam + 5) = param1;
1266     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1267 }
1268
1269
1270 /******************************************************************
1271  *         MF_MetaParam8
1272  */
1273 BOOL32 MF_MetaParam8(DC *dc, short func, short param1, short param2, 
1274                    short param3, short param4, short param5,
1275                    short param6, short param7, short param8)
1276 {
1277     char buffer[22];
1278     METARECORD *mr = (METARECORD *)&buffer;
1279     
1280     mr->rdSize = 11;
1281     mr->rdFunction = func;
1282     *(mr->rdParam) = param8;
1283     *(mr->rdParam + 1) = param7;
1284     *(mr->rdParam + 2) = param6;
1285     *(mr->rdParam + 3) = param5;
1286     *(mr->rdParam + 4) = param4;
1287     *(mr->rdParam + 5) = param3;
1288     *(mr->rdParam + 6) = param2;
1289     *(mr->rdParam + 7) = param1;
1290     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1291 }
1292
1293
1294 /******************************************************************
1295  *         MF_CreateBrushIndirect
1296  */
1297
1298 BOOL32 MF_CreateBrushIndirect(DC *dc, HBRUSH16 hBrush, LOGBRUSH16 *logbrush)
1299 {
1300     int index;
1301     char buffer[sizeof(METARECORD) - 2 + sizeof(*logbrush)];
1302     METARECORD *mr = (METARECORD *)&buffer;
1303
1304     mr->rdSize = (sizeof(METARECORD) + sizeof(*logbrush) - 2) / 2;
1305     mr->rdFunction = META_CREATEBRUSHINDIRECT;
1306     memcpy(&(mr->rdParam), logbrush, sizeof(*logbrush));
1307     if (!(MF_WriteRecord( dc, mr, mr->rdSize * 2))) return FALSE;
1308
1309     mr->rdSize = sizeof(METARECORD) / 2;
1310     mr->rdFunction = META_SELECTOBJECT;
1311
1312     if ((index = MF_AddHandleDC( dc )) == -1) return FALSE;
1313     *(mr->rdParam) = index;
1314     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1315 }
1316
1317
1318 /******************************************************************
1319  *         MF_CreatePatternBrush
1320  */
1321
1322 BOOL32 MF_CreatePatternBrush(DC *dc, HBRUSH16 hBrush, LOGBRUSH16 *logbrush)
1323 {
1324     DWORD len, bmSize, biSize;
1325     HGLOBAL16 hmr;
1326     METARECORD *mr;
1327     BITMAPOBJ *bmp;
1328     BITMAPINFO *info;
1329     BITMAPINFOHEADER *infohdr;
1330     int index;
1331     char buffer[sizeof(METARECORD)];
1332
1333     switch (logbrush->lbStyle)
1334     {
1335     case BS_PATTERN:
1336         bmp = (BITMAPOBJ *)GDI_GetObjPtr((HGDIOBJ16)logbrush->lbHatch, BITMAP_MAGIC);
1337         if (!bmp) return FALSE;
1338         len = sizeof(METARECORD) + sizeof(BITMAPINFOHEADER) + 
1339               (bmp->bitmap.bmHeight * bmp->bitmap.bmWidthBytes) + 6;
1340         if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1341           {
1342             GDI_HEAP_UNLOCK((HGDIOBJ16)logbrush->lbHatch);
1343             return FALSE;
1344           }
1345         mr = (METARECORD *)GlobalLock16(hmr);
1346         memset(mr, 0, len);
1347         mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
1348         mr->rdSize = len / 2;
1349         *(mr->rdParam) = logbrush->lbStyle;
1350         *(mr->rdParam + 1) = DIB_RGB_COLORS;
1351         infohdr = (BITMAPINFOHEADER *)(mr->rdParam + 2);
1352         infohdr->biSize = sizeof(BITMAPINFOHEADER);
1353         infohdr->biWidth = bmp->bitmap.bmWidth;
1354         infohdr->biHeight = bmp->bitmap.bmHeight;
1355         infohdr->biPlanes = bmp->bitmap.bmPlanes;
1356         infohdr->biBitCount = bmp->bitmap.bmBitsPixel;
1357         memcpy(mr->rdParam + (sizeof(BITMAPINFOHEADER) / 2) + 4,
1358                PTR_SEG_TO_LIN(bmp->bitmap.bmBits),
1359                bmp->bitmap.bmHeight * bmp->bitmap.bmWidthBytes);
1360         GDI_HEAP_UNLOCK(logbrush->lbHatch);
1361         break;
1362
1363     case BS_DIBPATTERN:
1364         info = (BITMAPINFO *)GlobalLock16((HGLOBAL16)logbrush->lbHatch);
1365         if (info->bmiHeader.biCompression)
1366             bmSize = info->bmiHeader.biSizeImage;
1367         else
1368             bmSize = (info->bmiHeader.biWidth * info->bmiHeader.biBitCount 
1369                     + 31) / 32 * 8 * info->bmiHeader.biHeight;
1370         biSize = DIB_BitmapInfoSize(info, LOWORD(logbrush->lbColor)); 
1371         len = sizeof(METARECORD) + biSize + bmSize + 2;
1372         if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1373             return FALSE;
1374         mr = (METARECORD *)GlobalLock16(hmr);
1375         memset(mr, 0, len);
1376         mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
1377         mr->rdSize = len / 2;
1378         *(mr->rdParam) = logbrush->lbStyle;
1379         *(mr->rdParam + 1) = LOWORD(logbrush->lbColor);
1380         memcpy(mr->rdParam + 2, info, biSize + bmSize);
1381         break;
1382     default:
1383         return FALSE;
1384     }
1385     if (!(MF_WriteRecord(dc, mr, len)))
1386     {
1387         GlobalFree16(hmr);
1388         return FALSE;
1389     }
1390
1391     GlobalFree16(hmr);
1392     
1393     mr = (METARECORD *)&buffer;
1394     mr->rdSize = sizeof(METARECORD) / 2;
1395     mr->rdFunction = META_SELECTOBJECT;
1396
1397     if ((index = MF_AddHandleDC( dc )) == -1) return FALSE;
1398     *(mr->rdParam) = index;
1399     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1400 }
1401
1402
1403 /******************************************************************
1404  *         MF_CreatePenIndirect
1405  */
1406
1407 BOOL32 MF_CreatePenIndirect(DC *dc, HPEN16 hPen, LOGPEN16 *logpen)
1408 {
1409     int index;
1410     char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
1411     METARECORD *mr = (METARECORD *)&buffer;
1412
1413     mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
1414     mr->rdFunction = META_CREATEPENINDIRECT;
1415     memcpy(&(mr->rdParam), logpen, sizeof(*logpen));
1416     if (!(MF_WriteRecord( dc, mr, mr->rdSize * 2))) return FALSE;
1417
1418     mr->rdSize = sizeof(METARECORD) / 2;
1419     mr->rdFunction = META_SELECTOBJECT;
1420
1421     if ((index = MF_AddHandleDC( dc )) == -1) return FALSE;
1422     *(mr->rdParam) = index;
1423     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1424 }
1425
1426
1427 /******************************************************************
1428  *         MF_CreateFontIndirect
1429  */
1430
1431 BOOL32 MF_CreateFontIndirect(DC *dc, HFONT16 hFont, LOGFONT16 *logfont)
1432 {
1433     int index;
1434     char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
1435     METARECORD *mr = (METARECORD *)&buffer;
1436
1437     mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
1438     mr->rdFunction = META_CREATEFONTINDIRECT;
1439     memcpy(&(mr->rdParam), logfont, sizeof(LOGFONT16));
1440     if (!(MF_WriteRecord( dc, mr, mr->rdSize * 2))) return FALSE;
1441
1442     mr->rdSize = sizeof(METARECORD) / 2;
1443     mr->rdFunction = META_SELECTOBJECT;
1444
1445     if ((index = MF_AddHandleDC( dc )) == -1) return FALSE;
1446     *(mr->rdParam) = index;
1447     return MF_WriteRecord( dc, mr, mr->rdSize * 2);
1448 }
1449
1450
1451 /******************************************************************
1452  *         MF_TextOut
1453  */
1454 BOOL32 MF_TextOut(DC *dc, short x, short y, LPCSTR str, short count)
1455 {
1456     BOOL32 ret;
1457     DWORD len;
1458     HGLOBAL16 hmr;
1459     METARECORD *mr;
1460
1461     len = sizeof(METARECORD) + (((count + 1) >> 1) * 2) + 4;
1462     if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1463         return FALSE;
1464     mr = (METARECORD *)GlobalLock16(hmr);
1465     memset(mr, 0, len);
1466
1467     mr->rdSize = len / 2;
1468     mr->rdFunction = META_TEXTOUT;
1469     *(mr->rdParam) = count;
1470     memcpy(mr->rdParam + 1, str, count);
1471     *(mr->rdParam + ((count + 1) >> 1) + 1) = y;
1472     *(mr->rdParam + ((count + 1) >> 1) + 2) = x;
1473     ret = MF_WriteRecord( dc, mr, mr->rdSize * 2);
1474     GlobalFree16(hmr);
1475     return ret;
1476 }
1477
1478 /******************************************************************
1479  *         MF_ExtTextOut
1480  */
1481 BOOL32 MF_ExtTextOut(DC*dc, short x, short y, UINT16 flags, const RECT16 *rect,
1482                      LPCSTR str, short count, const INT16 *lpDx)
1483 {
1484     BOOL32 ret;
1485     DWORD len;
1486     HGLOBAL16 hmr;
1487     METARECORD *mr;
1488     
1489     if((!flags && rect) || (flags && !rect))
1490         WARN(metafile, "Inconsistent flags and rect\n");
1491     len = sizeof(METARECORD) + (((count + 1) >> 1) * 2) + 2 * sizeof(short)
1492             + sizeof(UINT16);
1493     if(rect)
1494         len += sizeof(RECT16);
1495     if (lpDx)
1496      len+=count*sizeof(INT16);
1497     if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1498         return FALSE;
1499     mr = (METARECORD *)GlobalLock16(hmr);
1500     memset(mr, 0, len);
1501
1502     mr->rdSize = len / 2;
1503     mr->rdFunction = META_EXTTEXTOUT;
1504     *(mr->rdParam) = y;
1505     *(mr->rdParam + 1) = x;
1506     *(mr->rdParam + 2) = count;
1507     *(mr->rdParam + 3) = flags;
1508     if (rect) memcpy(mr->rdParam + 4, rect, sizeof(RECT16));
1509     memcpy(mr->rdParam + (rect ? 8 : 4), str, count);
1510     if (lpDx)
1511      memcpy(mr->rdParam + (rect ? 8 : 4) + ((count + 1) >> 1),lpDx,
1512       count*sizeof(INT16));
1513     ret = MF_WriteRecord( dc, mr, mr->rdSize * 2);
1514     GlobalFree16(hmr);
1515     return ret;
1516 }
1517
1518 /******************************************************************
1519  *         MF_MetaPoly - implements Polygon and Polyline
1520  */
1521 BOOL32 MF_MetaPoly(DC *dc, short func, LPPOINT16 pt, short count)
1522 {
1523     BOOL32 ret;
1524     DWORD len;
1525     HGLOBAL16 hmr;
1526     METARECORD *mr;
1527
1528     len = sizeof(METARECORD) + (count * 4); 
1529     if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1530         return FALSE;
1531     mr = (METARECORD *)GlobalLock16(hmr);
1532     memset(mr, 0, len);
1533
1534     mr->rdSize = len / 2;
1535     mr->rdFunction = func;
1536     *(mr->rdParam) = count;
1537     memcpy(mr->rdParam + 1, pt, count * 4);
1538     ret = MF_WriteRecord( dc, mr, mr->rdSize * 2);
1539     GlobalFree16(hmr);
1540     return ret;
1541 }
1542
1543
1544 /******************************************************************
1545  *         MF_BitBlt
1546  */
1547 BOOL32 MF_BitBlt(DC *dcDest, short xDest, short yDest, short width,
1548                  short height, DC *dcSrc, short xSrc, short ySrc, DWORD rop)
1549 {
1550     BOOL32 ret;
1551     DWORD len;
1552     HGLOBAL16 hmr;
1553     METARECORD *mr;
1554     BITMAP16  BM;
1555
1556     GetObject16(dcSrc->w.hBitmap, sizeof(BITMAP16), &BM);
1557     len = sizeof(METARECORD) + 12 * sizeof(INT16) + BM.bmWidthBytes * BM.bmHeight;
1558     if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1559         return FALSE;
1560     mr = (METARECORD *)GlobalLock16(hmr);
1561     mr->rdFunction = META_BITBLT;
1562     *(mr->rdParam + 7) = BM.bmWidth;
1563     *(mr->rdParam + 8) = BM.bmHeight;
1564     *(mr->rdParam + 9) = BM.bmWidthBytes;
1565     *(mr->rdParam +10) = BM.bmPlanes;
1566     *(mr->rdParam +11) = BM.bmBitsPixel;
1567     TRACE(metafile,"MF_StretchBlt->len = %ld  rop=%lx  \n",len,rop);
1568     if (GetBitmapBits32(dcSrc->w.hBitmap,BM.bmWidthBytes * BM.bmHeight,
1569                         mr->rdParam +12))
1570     {
1571       mr->rdSize = len / sizeof(INT16);
1572       *(mr->rdParam) = HIWORD(rop);
1573       *(mr->rdParam + 1) = ySrc;
1574       *(mr->rdParam + 2) = xSrc;
1575       *(mr->rdParam + 3) = height;
1576       *(mr->rdParam + 4) = width;
1577       *(mr->rdParam + 5) = yDest;
1578       *(mr->rdParam + 6) = xDest;
1579       ret = MF_WriteRecord( dcDest, mr, mr->rdSize * 2);
1580     }  
1581     else
1582         ret = FALSE;
1583     GlobalFree16(hmr);
1584     return ret;
1585 }
1586
1587
1588 /**********************************************************************
1589  *         MF_StretchBlt         
1590  * this function contains TWO ways for procesing StretchBlt in metafiles,
1591  * decide between rdFunction values  META_STRETCHBLT or META_DIBSTRETCHBLT
1592  * via #define STRETCH_VIA_DIB
1593  */
1594 #define STRETCH_VIA_DIB
1595 #undef  STRETCH_VIA_DIB
1596 BOOL32 MF_StretchBlt(DC *dcDest, short xDest, short yDest, short widthDest,
1597                      short heightDest, DC *dcSrc, short xSrc, short ySrc, 
1598                      short widthSrc, short heightSrc, DWORD rop)
1599 {
1600     BOOL32 ret;
1601     DWORD len;
1602     HGLOBAL16 hmr;
1603     METARECORD *mr;
1604     BITMAP16  BM;
1605 #ifdef STRETCH_VIA_DIB    
1606     LPBITMAPINFOHEADER lpBMI;
1607     WORD nBPP;
1608 #endif  
1609     GetObject16(dcSrc->w.hBitmap, sizeof(BITMAP16), &BM);
1610 #ifdef STRETCH_VIA_DIB
1611     nBPP = BM.bmPlanes * BM.bmBitsPixel;
1612     len = sizeof(METARECORD) + 10 * sizeof(INT16) 
1613             + sizeof(BITMAPINFOHEADER) + (nBPP != 24 ? 1 << nBPP: 0) * sizeof(RGBQUAD) 
1614               + ((BM.bmWidth * nBPP + 31) / 32) * 4 * BM.bmHeight;
1615     if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1616         return FALSE;
1617     mr = (METARECORD *)GlobalLock16(hmr);
1618     mr->rdFunction = META_DIBSTRETCHBLT;
1619     lpBMI=(LPBITMAPINFOHEADER)(mr->rdParam+10);
1620     lpBMI->biSize      = sizeof(BITMAPINFOHEADER);
1621     lpBMI->biWidth     = BM.bmWidth;
1622     lpBMI->biHeight    = BM.bmHeight;
1623     lpBMI->biPlanes    = 1;
1624     lpBMI->biBitCount  = nBPP;                              /* 1,4,8 or 24 */
1625     lpBMI->biClrUsed   = nBPP != 24 ? 1 << nBPP : 0;
1626     lpBMI->biSizeImage = ((lpBMI->biWidth * nBPP + 31) / 32) * 4 * lpBMI->biHeight;
1627     lpBMI->biCompression = BI_RGB;
1628     lpBMI->biXPelsPerMeter = MulDiv32(GetDeviceCaps(dcSrc->hSelf,LOGPIXELSX),3937,100);
1629     lpBMI->biYPelsPerMeter = MulDiv32(GetDeviceCaps(dcSrc->hSelf,LOGPIXELSY),3937,100);
1630     lpBMI->biClrImportant  = 0;                          /* 1 meter  = 39.37 inch */
1631
1632     TRACE(metafile,"MF_StretchBltViaDIB->len = %ld  rop=%lx  PixYPM=%ld Caps=%d\n",
1633                len,rop,lpBMI->biYPelsPerMeter,GetDeviceCaps(hdcSrc,LOGPIXELSY));
1634     if (GetDIBits(hdcSrc,dcSrc->w.hBitmap,0,(UINT32)lpBMI->biHeight,
1635                   (LPSTR)lpBMI + DIB_BitmapInfoSize( (BITMAPINFO *)lpBMI,
1636                                                      DIB_RGB_COLORS ),
1637                   (LPBITMAPINFO)lpBMI, DIB_RGB_COLORS))
1638 #else
1639     len = sizeof(METARECORD) + 15 * sizeof(INT16) + BM.bmWidthBytes * BM.bmHeight;
1640     if (!(hmr = GlobalAlloc16(GMEM_MOVEABLE, len)))
1641         return FALSE;
1642     mr = (METARECORD *)GlobalLock16(hmr);
1643     mr->rdFunction = META_STRETCHBLT;
1644     *(mr->rdParam +10) = BM.bmWidth;
1645     *(mr->rdParam +11) = BM.bmHeight;
1646     *(mr->rdParam +12) = BM.bmWidthBytes;
1647     *(mr->rdParam +13) = BM.bmPlanes;
1648     *(mr->rdParam +14) = BM.bmBitsPixel;
1649     TRACE(metafile,"MF_StretchBlt->len = %ld  rop=%lx  \n",len,rop);
1650     if (GetBitmapBits32( dcSrc->w.hBitmap, BM.bmWidthBytes * BM.bmHeight,
1651                          mr->rdParam +15))
1652 #endif    
1653     {
1654       mr->rdSize = len / sizeof(INT16);
1655       *(mr->rdParam) = LOWORD(rop);
1656       *(mr->rdParam + 1) = HIWORD(rop);
1657       *(mr->rdParam + 2) = heightSrc;
1658       *(mr->rdParam + 3) = widthSrc;
1659       *(mr->rdParam + 4) = ySrc;
1660       *(mr->rdParam + 5) = xSrc;
1661       *(mr->rdParam + 6) = heightDest;
1662       *(mr->rdParam + 7) = widthDest;
1663       *(mr->rdParam + 8) = yDest;
1664       *(mr->rdParam + 9) = xDest;
1665       ret = MF_WriteRecord( dcDest, mr, mr->rdSize * 2);
1666     }  
1667     else
1668         ret = FALSE;
1669     GlobalFree16(hmr);
1670     return ret;
1671 }
1672
1673
1674 /******************************************************************
1675  *         MF_CreateRegion
1676  */
1677 INT16 MF_CreateRegion(DC *dc, HRGN32 hrgn)
1678 {
1679     DWORD len;
1680     METARECORD *mr;
1681     RGNDATA *rgndata;
1682     RECT32 *pCurRect, *pEndRect;
1683     WORD Bands = 0, MaxBands = 0;
1684     WORD *Param, *StartBand;
1685     BOOL32 ret;
1686
1687     len = GetRegionData32( hrgn, 0, NULL );
1688     if( !(rgndata = HeapAlloc( SystemHeap, 0, len )) ) {
1689         WARN(metafile, "MF_CreateRegion: can't alloc rgndata buffer\n");
1690         return -1;
1691     }
1692     GetRegionData32( hrgn, len, rgndata );
1693
1694     /* Overestimate of length:
1695      * Assume every rect is a separate band -> 6 WORDs per rect
1696      */
1697     len = sizeof(METARECORD) + 20 + (rgndata->rdh.nCount * 12);
1698     if( !(mr = HeapAlloc( SystemHeap, 0, len )) ) {
1699         WARN(metafile, "MF_CreateRegion: can't alloc METARECORD buffer\n");
1700         HeapFree( SystemHeap, 0, rgndata );
1701         return -1;
1702     }
1703
1704     memset(mr, 0, len);
1705         
1706     Param = mr->rdParam + 11;
1707     StartBand = NULL;
1708
1709     pEndRect = (RECT32 *)rgndata->Buffer + rgndata->rdh.nCount;
1710     for(pCurRect = (RECT32 *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
1711     {
1712         if( StartBand && pCurRect->top == *(StartBand + 1) )
1713         {
1714             *Param++ = pCurRect->left;
1715             *Param++ = pCurRect->right;
1716         }
1717         else
1718         {
1719             if(StartBand)
1720             {
1721                 *StartBand = Param - StartBand - 3;
1722                 *Param++ = *StartBand;
1723                 if(*StartBand > MaxBands)
1724                     MaxBands = *StartBand;
1725                 Bands++;
1726             }
1727             StartBand = Param++;
1728             *Param++ = pCurRect->top;
1729             *Param++ = pCurRect->bottom;
1730             *Param++ = pCurRect->left;
1731             *Param++ = pCurRect->right;
1732         }
1733     }
1734     len = Param - (WORD *)mr;
1735     
1736     mr->rdParam[0] = 0;
1737     mr->rdParam[1] = 6;
1738     mr->rdParam[2] = 0x1234;
1739     mr->rdParam[3] = 0;
1740     mr->rdParam[4] = len * 2;
1741     mr->rdParam[5] = Bands;
1742     mr->rdParam[6] = MaxBands;
1743     mr->rdParam[7] = rgndata->rdh.rcBound.left;
1744     mr->rdParam[8] = rgndata->rdh.rcBound.top;
1745     mr->rdParam[9] = rgndata->rdh.rcBound.right;
1746     mr->rdParam[10] = rgndata->rdh.rcBound.bottom;
1747     mr->rdFunction = META_CREATEREGION;
1748     mr->rdSize = len / 2;
1749     ret = MF_WriteRecord( dc, mr, mr->rdSize * 2 );     
1750     HeapFree( SystemHeap, 0, mr );
1751     HeapFree( SystemHeap, 0, rgndata );
1752     if(!ret) 
1753     {
1754         WARN(metafile, "MF_CreateRegion: MF_WriteRecord failed\n");
1755         return -1;
1756     }
1757     return MF_AddHandleDC( dc );
1758 }