~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/gdi32/metafile.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.