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