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 * set_window
1227 *
1228 * Helper for GetWinMetaFileBits
1229 *
1230 * Add the SetWindowOrg and SetWindowExt records
1231 */
1232 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1233 {
1234 ENHMETAHEADER header;
1235 INT horz_res, vert_res, horz_size, vert_size;
1236 POINT pt;
1237
1238 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1239
1240 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1241 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1242 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1243 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1244
1245 switch(map_mode)
1246 {
1247 case MM_TEXT:
1248 case MM_ISOTROPIC:
1249 case MM_ANISOTROPIC:
1250 pt.y = MulDiv(header.rclFrame.top, vert_res, vert_size * 100);
1251 pt.x = MulDiv(header.rclFrame.left, horz_res, horz_size * 100);
1252 break;
1253 case MM_LOMETRIC:
1254 pt.y = MulDiv(-header.rclFrame.top, 1, 10) + 1;
1255 pt.x = MulDiv( header.rclFrame.left, 1, 10);
1256 break;
1257 case MM_HIMETRIC:
1258 pt.y = -header.rclFrame.top + 1;
1259 pt.x = header.rclFrame.left;
1260 break;
1261 case MM_LOENGLISH:
1262 pt.y = MulDiv(-header.rclFrame.top, 10, 254) + 1;
1263 pt.x = MulDiv( header.rclFrame.left, 10, 254);
1264 break;
1265 case MM_HIENGLISH:
1266 pt.y = MulDiv(-header.rclFrame.top, 100, 254) + 1;
1267 pt.x = MulDiv( header.rclFrame.left, 100, 254);
1268 break;
1269 case MM_TWIPS:
1270 pt.y = MulDiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1271 pt.x = MulDiv( header.rclFrame.left, 72 * 20, 2540);
1272 break;
1273 default:
1274 WARN("Unknown map mode %d\n", map_mode);
1275 return FALSE;
1276 }
1277 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1278
1279 pt.x = MulDiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1280 pt.y = MulDiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1281 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1282 return TRUE;
1283 }
1284
1285 /******************************************************************
1286 * GetWinMetaFileBits [GDI32.@]
1287 */
1288 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1289 UINT cbBuffer, LPBYTE lpbBuffer,
1290 INT map_mode, HDC hdcRef)
1291 {
1292 HDC hdcmf;
1293 HMETAFILE hmf;
1294 UINT ret, full_size;
1295 RECT rc;
1296
1297 GetClipBox(hdcRef, &rc);
1298
1299 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1300 map_mode, hdcRef, wine_dbgstr_rect(&rc));
1301
1302 hdcmf = CreateMetaFileW(NULL);
1303
1304 add_mf_comment(hdcmf, hemf);
1305 SetMapMode(hdcmf, map_mode);
1306 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1307 goto error;
1308
1309 PlayEnhMetaFile(hdcmf, hemf, &rc);
1310 hmf = CloseMetaFile(hdcmf);
1311 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1312 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1313 DeleteMetaFile(hmf);
1314
1315 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1316 {
1317 WORD checksum = 0;
1318 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1319 UINT i;
1320
1321 for(i = 0; i < full_size / 2; i++)
1322 checksum += ((WORD*)lpbBuffer)[i];
1323 comment_rec->rdParm[8] = ~checksum + 1;
1324 }
1325 return ret;
1326
1327 error:
1328 DeleteMetaFile(CloseMetaFile(hdcmf));
1329 return 0;
1330 }
1331
1332 /******************************************************************
1333 * MF_Play_MetaCreateRegion
1334 *
1335 * Handles META_CREATEREGION for PlayMetaFileRecord().
1336 *
1337 * The layout of the record looks something like this:
1338 *
1339 * rdParm meaning
1340 * 0 Always 0?
1341 * 1 Always 6?
1342 * 2 Looks like a handle? - not constant
1343 * 3 0 or 1 ??
1344 * 4 Total number of bytes
1345 * 5 No. of separate bands = n [see below]
1346 * 6 Largest number of x co-ords in a band
1347 * 7-10 Bounding box x1 y1 x2 y2
1348 * 11-... n bands
1349 *
1350 * Regions are divided into bands that are uniform in the
1351 * y-direction. Each band consists of pairs of on/off x-coords and is
1352 * written as
1353 * m y0 y1 x1 x2 x3 ... xm m
1354 * into successive rdParm[]s.
1355 *
1356 * This is probably just a dump of the internal RGNOBJ?
1357 *
1358 * HDMD - 18/12/97
1359 *
1360 */
1361
1362 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1363 {
1364 WORD band, pair;
1365 WORD *start, *end;
1366 INT16 y0, y1;
1367 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1368
1369 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1370 band++, start = end + 1) {
1371 if(*start / 2 != (*start + 1) / 2) {
1372 WARN("Delimiter not even.\n");
1373 DeleteObject( hrgn2 );
1374 return FALSE;
1375 }
1376
1377 end = start + *start + 3;
1378 if(end > (WORD *)mr + mr->rdSize) {
1379 WARN("End points outside record.\n");
1380 DeleteObject( hrgn2 );
1381 return FALSE;
1382 }
1383
1384 if(*start != *end) {
1385 WARN("Mismatched delimiters.\n");
1386 DeleteObject( hrgn2 );
1387 return FALSE;
1388 }
1389
1390 y0 = *(INT16 *)(start + 1);
1391 y1 = *(INT16 *)(start + 2);
1392 for(pair = 0; pair < *start / 2; pair++) {
1393 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1394 *(INT16 *)(start + 4 + 2*pair), y1 );
1395 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1396 }
1397 }
1398 DeleteObject( hrgn2 );
1399 return TRUE;
1400 }
1401
1402
1403 /******************************************************************
1404 * MF_Play_MetaExtTextOut
1405 *
1406 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1407 */
1408
1409 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1410 {
1411 INT *dx = NULL;
1412 int i;
1413 LPINT16 dxx;
1414 LPSTR sot;
1415 DWORD len;
1416 WORD s1;
1417 RECT rect;
1418 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1419
1420 s1 = mr->rdParm[2]; /* String length */
1421 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1422 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1423 /* rec len without dx array */
1424
1425 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1426 if (isrect)
1427 {
1428 rect.left = (SHORT)mr->rdParm[4];
1429 rect.top = (SHORT)mr->rdParm[5];
1430 rect.right = (SHORT)mr->rdParm[6];
1431 rect.bottom = (SHORT)mr->rdParm[7];
1432 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1433 }
1434
1435 if (mr->rdSize == len / 2)
1436 dxx = NULL; /* determine if array is present */
1437 else
1438 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1439 {
1440 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1441 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1442 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1443 }
1444 else {
1445 TRACE("%s len: %d\n", sot, mr->rdSize);
1446 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1447 len, s1, mr->rdSize, mr->rdParm[3]);
1448 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1449 }
1450 ExtTextOutA( hdc,
1451 (SHORT)mr->rdParm[1], /* X position */
1452 (SHORT)mr->rdParm[0], /* Y position */
1453 mr->rdParm[3], /* options */
1454 &rect, /* rectangle */
1455 sot, /* string */
1456 s1, dx); /* length, dx array */
1457 if (dx)
1458 {
1459 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1460 HeapFree( GetProcessHeap(), 0, dx );
1461 }
1462 return TRUE;
1463 }
1464
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.