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

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

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

~ [ 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.