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