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