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 HFONT hFont;
398 HPALETTE hPal;
399 HRGN hRgn;
400 BOOL loaded = FALSE;
401
402 if (!mh) return FALSE;
403 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
404 mh = MF_LoadDiskBasedMetaFile(mh);
405 if(!mh) return FALSE;
406 loaded = TRUE;
407 }
408
409 /* save DC */
410 hPen = GetCurrentObject(hdc, OBJ_PEN);
411 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
412 hFont = GetCurrentObject(hdc, OBJ_FONT);
413 hPal = GetCurrentObject(hdc, OBJ_PAL);
414
415 hRgn = CreateRectRgn(0, 0, 0, 0);
416 if (!GetClipRgn(hdc, hRgn))
417 {
418 DeleteObject(hRgn);
419 hRgn = 0;
420 }
421
422 /* create the handle table */
423 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
424 sizeof(HANDLETABLE) * mh->mtNoObjects);
425 if(!ht) return FALSE;
426
427 /* loop through metafile playing records */
428 offset = mh->mtHeaderSize * 2;
429 while (offset < mh->mtSize * 2)
430 {
431 mr = (METARECORD *)((char *)mh + offset);
432 TRACE("offset=%04x,size=%08x\n",
433 offset, mr->rdSize);
434 if (mr->rdSize < 3) { /* catch illegal record sizes */
435 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
436 mr->rdSize,offset,mh->mtSize*2);
437 break;
438 }
439
440 offset += mr->rdSize * 2;
441 if (mr->rdFunction == META_EOF) {
442 TRACE("Got META_EOF so stopping\n");
443 break;
444 }
445 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
446 }
447
448 /* restore DC */
449 SelectObject(hdc, hPen);
450 SelectObject(hdc, hBrush);
451 SelectPalette(hdc, hPal, FALSE);
452 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
453 DeleteObject(hRgn);
454
455 /* free objects in handle table */
456 for(i = 0; i < mh->mtNoObjects; i++)
457 if(*(ht->objectHandle + i) != 0)
458 DeleteObject(*(ht->objectHandle + i));
459
460 /* free handle table */
461 HeapFree( GetProcessHeap(), 0, ht );
462 if(loaded)
463 HeapFree( GetProcessHeap(), 0, mh );
464 return TRUE;
465 }
466
467 /******************************************************************
468 * PlayMetaFile (GDI32.@)
469 *
470 * Renders the metafile specified by hmf in the DC specified by
471 * hdc. Returns FALSE on failure, TRUE on success.
472 *
473 * PARAMS
474 * hdc [I] handle of DC to render in
475 * hmf [I] handle of metafile to render
476 *
477 * RETURNS
478 * Success: TRUE
479 * Failure: FALSE
480 */
481 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
482 {
483 METAHEADER *mh = MF_GetMetaHeader( hmf );
484 return MF_PlayMetaFile( hdc, mh );
485 }
486
487 /******************************************************************
488 * EnumMetaFile (GDI32.@)
489 *
490 * Loop through the metafile records in hmf, calling the user-specified
491 * function for each one, stopping when the user's function returns FALSE
492 * (which is considered to be failure)
493 * or when no records are left (which is considered to be success).
494 *
495 * RETURNS
496 * TRUE on success, FALSE on failure.
497 */
498 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
499 {
500 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
501 METARECORD *mr;
502 HANDLETABLE *ht;
503 BOOL result = TRUE;
504 int i;
505 unsigned int offset = 0;
506 HPEN hPen;
507 HBRUSH hBrush;
508 HFONT hFont;
509
510 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
511 if (!mh) return 0;
512 if(mh->mtType == METAFILE_DISK)
513 {
514 /* Create a memory-based copy */
515 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
516 mh = mhTemp;
517 }
518
519 /* save the current pen, brush and font */
520 hPen = GetCurrentObject(hdc, OBJ_PEN);
521 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
522 hFont = GetCurrentObject(hdc, OBJ_FONT);
523
524 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
525 sizeof(HANDLETABLE) * mh->mtNoObjects);
526
527 /* loop through metafile records */
528 offset = mh->mtHeaderSize * 2;
529
530 while (offset < (mh->mtSize * 2))
531 {
532 mr = (METARECORD *)((char *)mh + offset);
533 if(mr->rdFunction == META_EOF) {
534 TRACE("Got META_EOF so stopping\n");
535 break;
536 }
537 TRACE("Calling EnumFunc with record type %x\n",
538 mr->rdFunction);
539 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
540 {
541 result = FALSE;
542 break;
543 }
544
545 offset += (mr->rdSize * 2);
546 }
547
548 /* restore pen, brush and font */
549 SelectObject(hdc, hBrush);
550 SelectObject(hdc, hPen);
551 SelectObject(hdc, hFont);
552
553 /* free objects in handle table */
554 for(i = 0; i < mh->mtNoObjects; i++)
555 if(*(ht->objectHandle + i) != 0)
556 DeleteObject(*(ht->objectHandle + i));
557
558 /* free handle table */
559 HeapFree( GetProcessHeap(), 0, ht);
560 /* free a copy of metafile */
561 HeapFree( GetProcessHeap(), 0, mhTemp );
562 return result;
563 }
564
565 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
566 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
567 /******************************************************************
568 * PlayMetaFileRecord (GDI32.@)
569 *
570 * Render a single metafile record specified by *mr in the DC hdc, while
571 * using the handle table *ht, of length handles,
572 * to store metafile objects.
573 *
574 * BUGS
575 * The following metafile records are unimplemented:
576 *
577 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
578 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
579 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
580 */
581 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
582 {
583 short s1;
584 POINT *pt;
585 BITMAPINFOHEADER *infohdr;
586
587 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
588
589 switch (mr->rdFunction)
590 {
591 case META_EOF:
592 break;
593
594 case META_DELETEOBJECT:
595 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
596 *(ht->objectHandle + mr->rdParm[0]) = 0;
597 break;
598
599 case META_SETBKCOLOR:
600 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
601 break;
602
603 case META_SETBKMODE:
604 SetBkMode(hdc, mr->rdParm[0]);
605 break;
606
607 case META_SETMAPMODE:
608 SetMapMode(hdc, mr->rdParm[0]);
609 break;
610
611 case META_SETROP2:
612 SetROP2(hdc, mr->rdParm[0]);
613 break;
614
615 case META_SETRELABS:
616 SetRelAbs(hdc, mr->rdParm[0]);
617 break;
618
619 case META_SETPOLYFILLMODE:
620 SetPolyFillMode(hdc, mr->rdParm[0]);
621 break;
622
623 case META_SETSTRETCHBLTMODE:
624 SetStretchBltMode(hdc, mr->rdParm[0]);
625 break;
626
627 case META_SETTEXTCOLOR:
628 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
629 break;
630
631 case META_SETWINDOWORG:
632 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
633 break;
634
635 case META_SETWINDOWEXT:
636 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
637 break;
638
639 case META_SETVIEWPORTORG:
640 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
641 break;
642
643 case META_SETVIEWPORTEXT:
644 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
645 break;
646
647 case META_OFFSETWINDOWORG:
648 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
649 break;
650
651 case META_SCALEWINDOWEXT:
652 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
653 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
654 break;
655
656 case META_OFFSETVIEWPORTORG:
657 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
658 break;
659
660 case META_SCALEVIEWPORTEXT:
661 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
662 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
663 break;
664
665 case META_LINETO:
666 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
667 break;
668
669 case META_MOVETO:
670 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
671 break;
672
673 case META_EXCLUDECLIPRECT:
674 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
675 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
676 break;
677
678 case META_INTERSECTCLIPRECT:
679 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
680 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
681 break;
682
683 case META_ARC:
684 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
685 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
686 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
687 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
688 break;
689
690 case META_ELLIPSE:
691 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
692 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
693 break;
694
695 case META_FLOODFILL:
696 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
697 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
698 break;
699
700 case META_PIE:
701 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
702 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
703 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
704 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
705 break;
706
707 case META_RECTANGLE:
708 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
709 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
710 break;
711
712 case META_ROUNDRECT:
713 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
714 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
715 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
716 break;
717
718 case META_PATBLT:
719 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
720 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
721 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
722 break;
723
724 case META_SAVEDC:
725 SaveDC(hdc);
726 break;
727
728 case META_SETPIXEL:
729 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
730 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
731 break;
732
733 case META_OFFSETCLIPRGN:
734 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
735 break;
736
737 case META_TEXTOUT:
738 s1 = mr->rdParm[0];
739 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
740 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
741 (char *)(mr->rdParm + 1), s1);
742 break;
743
744 case META_POLYGON:
745 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
746 {
747 Polygon(hdc, pt, mr->rdParm[0]);
748 HeapFree( GetProcessHeap(), 0, pt );
749 }
750 break;
751
752 case META_POLYPOLYGON:
753 {
754 UINT i, total;
755 SHORT *counts = (SHORT *)(mr->rdParm + 1);
756
757 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
758 pt = convert_points( total, (POINTS *)(counts + mr->rdParm[0]) );
759 if (pt)
760 {
761 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
762 if (cnt32)
763 {
764 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
765 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
766 HeapFree( GetProcessHeap(), 0, cnt32 );
767 }
768 }
769 HeapFree( GetProcessHeap(), 0, pt );
770 }
771 break;
772
773 case META_POLYLINE:
774 if ((pt = convert_points( mr->rdParm[0], (POINTS *)(mr->rdParm + 1))))
775 {
776 Polyline( hdc, pt, mr->rdParm[0] );
777 HeapFree( GetProcessHeap(), 0, pt );
778 }
779 break;
780
781 case META_RESTOREDC:
782 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
783 break;
784
785 case META_SELECTOBJECT:
786 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
787 break;
788
789 case META_CHORD:
790 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
791 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
792 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
793 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
794 break;
795
796 case META_CREATEPATTERNBRUSH:
797 switch (mr->rdParm[0])
798 {
799 case BS_PATTERN:
800 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
801 MF_AddHandle(ht, handles,
802 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
803 infohdr->biHeight,
804 infohdr->biPlanes,
805 infohdr->biBitCount,
806 mr->rdParm +
807 (sizeof(BITMAPINFOHEADER) / 2) + 4)));
808 break;
809
810 case BS_DIBPATTERN:
811 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
812 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
813 break;
814
815 default:
816 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
817 mr->rdParm[0]);
818 break;
819 }
820 break;
821
822 case META_CREATEPENINDIRECT:
823 {
824 LOGPEN pen;
825 pen.lopnStyle = mr->rdParm[0];
826 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
827 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
828 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
829 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
830 }
831 break;
832
833 case META_CREATEFONTINDIRECT:
834 {
835 LOGFONTA font;
836 font.lfHeight = (SHORT)mr->rdParm[0];
837 font.lfWidth = (SHORT)mr->rdParm[1];
838 font.lfEscapement = (SHORT)mr->rdParm[2];
839 font.lfOrientation = (SHORT)mr->rdParm[3];
840 font.lfWeight = (SHORT)mr->rdParm[4];
841 font.lfItalic = LOBYTE(mr->rdParm[5]);
842 font.lfUnderline = HIBYTE(mr->rdParm[5]);
843 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
844 font.lfCharSet = HIBYTE(mr->rdParm[6]);
845 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
846 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
847 font.lfQuality = LOBYTE(mr->rdParm[8]);
848 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
849 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
850 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
851 }
852 break;
853
854 case META_CREATEBRUSHINDIRECT:
855 {
856 LOGBRUSH brush;
857 brush.lbStyle = mr->rdParm[0];
858 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
859 brush.lbHatch = mr->rdParm[3];
860 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
861 }
862 break;
863
864 case META_CREATEPALETTE:
865 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
866 break;
867
868 case META_SETTEXTALIGN:
869 SetTextAlign(hdc, mr->rdParm[0]);
870 break;
871
872 case META_SELECTPALETTE:
873 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
874 break;
875
876 case META_SETMAPPERFLAGS:
877 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
878 break;
879
880 case META_REALIZEPALETTE:
881 GDIRealizePalette(hdc);
882 break;
883
884 case META_ESCAPE:
885 switch (mr->rdParm[0]) {
886 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
887 case GETPHYSPAGESIZE:
888 case GETPRINTINGOFFSET:
889 return FALSE;
890 case SETABORTPROC:
891 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
892 return FALSE;
893 }
894 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
895 break;
896
897 case META_EXTTEXTOUT:
898 MF_Play_MetaExtTextOut( hdc, mr );
899 break;
900
901 case META_STRETCHDIB:
902 {
903 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
904 LPSTR bits = (LPSTR)info + bitmap_info_size( info, mr->rdParm[2] );
905 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
906 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
907 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
908 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
909 }
910 break;
911
912 case META_DIBSTRETCHBLT:
913 {
914 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
915 LPSTR bits = (LPSTR)info + bitmap_info_size( info, DIB_RGB_COLORS );
916 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
917 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
918 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
919 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
920 }
921 break;
922
923 case META_STRETCHBLT:
924 {
925 HDC hdcSrc = CreateCompatibleDC(hdc);
926 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
927 mr->rdParm[11], /*Height*/
928 mr->rdParm[13], /*Planes*/
929 mr->rdParm[14], /*BitsPixel*/
930 &mr->rdParm[15]); /*bits*/
931 SelectObject(hdcSrc,hbitmap);
932 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
933 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
934 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
935 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
936 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
937 DeleteDC(hdcSrc);
938 }
939 break;
940
941 case META_BITBLT:
942 {
943 HDC hdcSrc = CreateCompatibleDC(hdc);
944 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
945 mr->rdParm[8]/*Height*/,
946 mr->rdParm[10]/*Planes*/,
947 mr->rdParm[11]/*BitsPixel*/,
948 &mr->rdParm[12]/*bits*/);
949 SelectObject(hdcSrc,hbitmap);
950 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
951 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
952 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
953 MAKELONG(0,mr->rdParm[0]));
954 DeleteDC(hdcSrc);
955 }
956 break;
957
958 case META_CREATEREGION:
959 {
960 HRGN hrgn = CreateRectRgn(0,0,0,0);
961
962 MF_Play_MetaCreateRegion(mr, hrgn);
963 MF_AddHandle(ht, handles, hrgn);
964 }
965 break;
966
967 case META_FILLREGION:
968 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
969 *(ht->objectHandle + mr->rdParm[0]));
970 break;
971
972 case META_FRAMEREGION:
973 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
974 *(ht->objectHandle + mr->rdParm[2]),
975 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
976 break;
977
978 case META_INVERTREGION:
979 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
980 break;
981
982 case META_PAINTREGION:
983 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
984 break;
985
986 case META_SELECTCLIPREGION:
987 {
988 HRGN hrgn = 0;
989
990 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
991 SelectClipRgn(hdc, hrgn);
992 }
993 break;
994
995 case META_DIBCREATEPATTERNBRUSH:
996 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
997 but there's no difference */
998 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
999 break;
1000
1001 case META_DIBBITBLT:
1002 /* In practice I've found that there are two layouts for
1003 META_DIBBITBLT, one (the first here) is the usual one when a src
1004 dc is actually passed to it, the second occurs when the src dc is
1005 passed in as NULL to the creating BitBlt. As the second case has
1006 no dib, a size check will suffice to distinguish.
1007
1008 Caolan.McNamara@ul.ie */
1009
1010 if (mr->rdSize > 12) {
1011 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1012 LPSTR bits = (LPSTR)info + bitmap_info_size(info, mr->rdParm[0]);
1013
1014 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1015 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1016 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1017 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1018 }
1019 else /* equivalent to a PatBlt */
1020 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1021 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1022 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1023 break;
1024
1025 case META_SETTEXTCHAREXTRA:
1026 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1027 break;
1028
1029 case META_SETTEXTJUSTIFICATION:
1030 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1031 break;
1032
1033 case META_EXTFLOODFILL:
1034 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1035 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1036 mr->rdParm[0]);
1037 break;
1038
1039 case META_SETDIBTODEV:
1040 {
1041 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1042 char *bits = (char *)info + bitmap_info_size( info, mr->rdParm[0] );
1043 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1044 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1045 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1046 mr->rdParm[2], mr->rdParm[1], bits, info,
1047 mr->rdParm[0]);
1048 break;
1049 }
1050
1051 #define META_UNIMP(x) case x: \
1052 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1053 break;
1054 META_UNIMP(META_DRAWTEXT)
1055 META_UNIMP(META_ANIMATEPALETTE)
1056 META_UNIMP(META_SETPALENTRIES)
1057 META_UNIMP(META_RESIZEPALETTE)
1058 META_UNIMP(META_RESETDC)
1059 META_UNIMP(META_STARTDOC)
1060 META_UNIMP(META_STARTPAGE)
1061 META_UNIMP(META_ENDPAGE)
1062 META_UNIMP(META_ABORTDOC)
1063 META_UNIMP(META_ENDDOC)
1064 META_UNIMP(META_CREATEBRUSH)
1065 META_UNIMP(META_CREATEBITMAPINDIRECT)
1066 META_UNIMP(META_CREATEBITMAP)
1067 #undef META_UNIMP
1068
1069 default:
1070 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1071 return FALSE;
1072 }
1073 return TRUE;
1074 }
1075
1076 /******************************************************************
1077 * SetMetaFileBitsEx (GDI32.@)
1078 *
1079 * Create a metafile from raw data. No checking of the data is performed.
1080 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1081 *
1082 * PARAMS
1083 * size [I] size of metafile, in bytes
1084 * lpData [I] pointer to metafile data
1085 *
1086 * RETURNS
1087 * Success: Handle to metafile.
1088 * Failure: NULL.
1089 */
1090 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1091 {
1092 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1093 METAHEADER *mh_out;
1094
1095 if (size & 1) return 0;
1096
1097 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1098 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1099 {
1100 SetLastError(ERROR_INVALID_DATA);
1101 return 0;
1102 }
1103
1104 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1105 if (!mh_out)
1106 {
1107 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1108 return 0;
1109 }
1110
1111 memcpy(mh_out, mh_in, size);
1112 mh_out->mtSize = size / 2;
1113 return MF_Create_HMETAFILE(mh_out);
1114 }
1115
1116 /*****************************************************************
1117 * GetMetaFileBitsEx (GDI32.@)
1118 *
1119 * Get raw metafile data.
1120 *
1121 * Copies the data from metafile _hmf_ into the buffer _buf_.
1122 *
1123 * PARAMS
1124 * hmf [I] metafile
1125 * nSize [I] size of buf
1126 * buf [O] buffer to receive raw metafile data
1127 *
1128 * RETURNS
1129 * If _buf_ is zero, returns size of buffer required. Otherwise,
1130 * returns number of bytes copied.
1131 */
1132 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1133 {
1134 METAHEADER *mh = MF_GetMetaHeader(hmf);
1135 UINT mfSize;
1136
1137 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1138 if (!mh) return 0; /* FIXME: error code */
1139 if(mh->mtType == METAFILE_DISK)
1140 FIXME("Disk-based metafile?\n");
1141 mfSize = mh->mtSize * 2;
1142 if (!buf) {
1143 TRACE("returning size %d\n", mfSize);
1144 return mfSize;
1145 }
1146 if(mfSize > nSize) mfSize = nSize;
1147 memmove(buf, mh, mfSize);
1148 return mfSize;
1149 }
1150
1151 #include <pshpack2.h>
1152 typedef struct
1153 {
1154 DWORD magic; /* WMFC */
1155 WORD unk04; /* 1 */
1156 WORD unk06; /* 0 */
1157 WORD unk08; /* 0 */
1158 WORD unk0a; /* 1 */
1159 WORD checksum;
1160 DWORD unk0e; /* 0 */
1161 DWORD num_chunks;
1162 DWORD chunk_size;
1163 DWORD remaining_size;
1164 DWORD emf_size;
1165 BYTE *emf_data;
1166 } mf_comment_chunk;
1167 #include <poppack.h>
1168
1169 static const DWORD wmfc_magic = 0x43464d57;
1170
1171 /******************************************************************
1172 * add_mf_comment
1173 *
1174 * Helper for GetWinMetaFileBits
1175 *
1176 * Add the MFCOMMENT record[s] which is essentially a copy
1177 * of the original emf.
1178 */
1179 static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf)
1180 {
1181 DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i;
1182 BYTE *bits, *chunk_data;
1183 mf_comment_chunk *chunk = NULL;
1184 BOOL ret = FALSE;
1185 static const DWORD max_chunk_size = 0x2000;
1186
1187 if(!size) return FALSE;
1188 chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size);
1189 if(!bits) return FALSE;
1190 if(!GetEnhMetaFileBits(emf, size, bits)) goto end;
1191
1192 chunk = HeapAlloc(GetProcessHeap(), 0, max_chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data));
1193 if(!chunk) goto end;
1194
1195 chunk->magic = wmfc_magic;
1196 chunk->unk04 = 1;
1197 chunk->unk06 = 0;
1198 chunk->unk08 = 0;
1199 chunk->unk0a = 1;
1200 chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1201 chunk->unk0e = 0;
1202 chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size;
1203 chunk->chunk_size = max_chunk_size;
1204 chunk->remaining_size = size;
1205 chunk->emf_size = size;
1206
1207 for(i = 0; i < chunk->num_chunks; i++)
1208 {
1209 if(i == chunk->num_chunks - 1) /* last chunk */
1210 chunk->chunk_size = chunk->remaining_size;
1211
1212 chunk->remaining_size -= chunk->chunk_size;
1213 memcpy(&chunk->emf_data, chunk_data, chunk->chunk_size);
1214 chunk_data += chunk->chunk_size;
1215
1216 if(!Escape(hdc, MFCOMMENT, chunk->chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data), (char*)chunk, NULL))
1217 goto end;
1218 }
1219 ret = TRUE;
1220 end:
1221 HeapFree(GetProcessHeap(), 0, chunk);
1222 HeapFree(GetProcessHeap(), 0, bits);
1223 return ret;
1224 }
1225
1226 /*******************************************************************
1227 * muldiv
1228 *
1229 * Behaves somewhat differently to MulDiv when the answer is -ve
1230 * and also rounds n.5 towards zero
1231 */
1232 static INT muldiv(INT m1, INT m2, INT d)
1233 {
1234 LONGLONG ret;
1235
1236 ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1237
1238 if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1239 {
1240 if(ret > 0) ret--;
1241 else ret++;
1242 }
1243 return ret;
1244 }
1245
1246 /******************************************************************
1247 * set_window
1248 *
1249 * Helper for GetWinMetaFileBits
1250 *
1251 * Add the SetWindowOrg and SetWindowExt records
1252 */
1253 static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1254 {
1255 ENHMETAHEADER header;
1256 INT horz_res, vert_res, horz_size, vert_size;
1257 POINT pt;
1258
1259 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1260
1261 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1262 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1263 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1264 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1265
1266 switch(map_mode)
1267 {
1268 case MM_TEXT:
1269 case MM_ISOTROPIC:
1270 case MM_ANISOTROPIC:
1271 pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1272 pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
1273 break;
1274 case MM_LOMETRIC:
1275 pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1276 pt.x = muldiv( header.rclFrame.left, 1, 10);
1277 break;
1278 case MM_HIMETRIC:
1279 pt.y = -header.rclFrame.top + 1;
1280 pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
1281 break;
1282 case MM_LOENGLISH:
1283 pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1284 pt.x = muldiv( header.rclFrame.left, 10, 254);
1285 break;
1286 case MM_HIENGLISH:
1287 pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1288 pt.x = muldiv( header.rclFrame.left, 100, 254);
1289 break;
1290 case MM_TWIPS:
1291 pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1292 pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
1293 break;
1294 default:
1295 WARN("Unknown map mode %d\n", map_mode);
1296 return FALSE;
1297 }
1298 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1299
1300 pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1301 pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
1302 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1303 return TRUE;
1304 }
1305
1306 /******************************************************************
1307 * GetWinMetaFileBits [GDI32.@]
1308 */
1309 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1310 UINT cbBuffer, LPBYTE lpbBuffer,
1311 INT map_mode, HDC hdcRef)
1312 {
1313 HDC hdcmf;
1314 HMETAFILE hmf;
1315 UINT ret, full_size;
1316 RECT rc;
1317
1318 GetClipBox(hdcRef, &rc);
1319
1320 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1321 map_mode, hdcRef, wine_dbgstr_rect(&rc));
1322
1323 hdcmf = CreateMetaFileW(NULL);
1324
1325 add_mf_comment(hdcmf, hemf);
1326 SetMapMode(hdcmf, map_mode);
1327 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1328 goto error;
1329
1330 PlayEnhMetaFile(hdcmf, hemf, &rc);
1331 hmf = CloseMetaFile(hdcmf);
1332 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
1333 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1334 DeleteMetaFile(hmf);
1335
1336 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1337 {
1338 WORD checksum = 0;
1339 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1340 UINT i;
1341
1342 for(i = 0; i < full_size / 2; i++)
1343 checksum += ((WORD*)lpbBuffer)[i];
1344 comment_rec->rdParm[8] = ~checksum + 1;
1345 }
1346 return ret;
1347
1348 error:
1349 DeleteMetaFile(CloseMetaFile(hdcmf));
1350 return 0;
1351 }
1352
1353 /******************************************************************
1354 * MF_Play_MetaCreateRegion
1355 *
1356 * Handles META_CREATEREGION for PlayMetaFileRecord().
1357 *
1358 * The layout of the record looks something like this:
1359 *
1360 * rdParm meaning
1361 * 0 Always 0?
1362 * 1 Always 6?
1363 * 2 Looks like a handle? - not constant
1364 * 3 0 or 1 ??
1365 * 4 Total number of bytes
1366 * 5 No. of separate bands = n [see below]
1367 * 6 Largest number of x co-ords in a band
1368 * 7-10 Bounding box x1 y1 x2 y2
1369 * 11-... n bands
1370 *
1371 * Regions are divided into bands that are uniform in the
1372 * y-direction. Each band consists of pairs of on/off x-coords and is
1373 * written as
1374 * m y0 y1 x1 x2 x3 ... xm m
1375 * into successive rdParm[]s.
1376 *
1377 * This is probably just a dump of the internal RGNOBJ?
1378 *
1379 * HDMD - 18/12/97
1380 *
1381 */
1382
1383 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1384 {
1385 WORD band, pair;
1386 WORD *start, *end;
1387 INT16 y0, y1;
1388 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1389
1390 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1391 band++, start = end + 1) {
1392 if(*start / 2 != (*start + 1) / 2) {
1393 WARN("Delimiter not even.\n");
1394 DeleteObject( hrgn2 );
1395 return FALSE;
1396 }
1397
1398 end = start + *start + 3;
1399 if(end > (WORD *)mr + mr->rdSize) {
1400 WARN("End points outside record.\n");
1401 DeleteObject( hrgn2 );
1402 return FALSE;
1403 }
1404
1405 if(*start != *end) {
1406 WARN("Mismatched delimiters.\n");
1407 DeleteObject( hrgn2 );
1408 return FALSE;
1409 }
1410
1411 y0 = *(INT16 *)(start + 1);
1412 y1 = *(INT16 *)(start + 2);
1413 for(pair = 0; pair < *start / 2; pair++) {
1414 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1415 *(INT16 *)(start + 4 + 2*pair), y1 );
1416 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1417 }
1418 }
1419 DeleteObject( hrgn2 );
1420 return TRUE;
1421 }
1422
1423
1424 /******************************************************************
1425 * MF_Play_MetaExtTextOut
1426 *
1427 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1428 */
1429
1430 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1431 {
1432 INT *dx = NULL;
1433 int i;
1434 SHORT *dxx;
1435 LPSTR sot;
1436 DWORD len;
1437 WORD s1;
1438 RECT rect;
1439 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1440
1441 s1 = mr->rdParm[2]; /* String length */
1442 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1443 + sizeof(UINT16) + (isrect ? 4 * sizeof(SHORT) : 0);
1444 /* rec len without dx array */
1445
1446 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1447 if (isrect)
1448 {
1449 rect.left = (SHORT)mr->rdParm[4];
1450 rect.top = (SHORT)mr->rdParm[5];
1451 rect.right = (SHORT)mr->rdParm[6];
1452 rect.bottom = (SHORT)mr->rdParm[7];
1453 sot += 4 * sizeof(SHORT); /* there is a rectangle, so add offset */
1454 }
1455
1456 if (mr->rdSize == len / 2)
1457 dxx = NULL; /* determine if array is present */
1458 else
1459 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1460 {
1461 dxx = (SHORT *)(sot+(((s1+1)>>1)*2));
1462 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1463 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1464 }
1465 else {
1466 TRACE("%s len: %d\n", sot, mr->rdSize);
1467 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1468 len, s1, mr->rdSize, mr->rdParm[3]);
1469 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
1470 }
1471 ExtTextOutA( hdc,
1472 (SHORT)mr->rdParm[1], /* X position */
1473 (SHORT)mr->rdParm[0], /* Y position */
1474 mr->rdParm[3], /* options */
1475 &rect, /* rectangle */
1476 sot, /* string */
1477 s1, dx); /* length, dx array */
1478 if (dx)
1479 {
1480 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1481 HeapFree( GetProcessHeap(), 0, dx );
1482 }
1483 return TRUE;
1484 }
1485
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.