comctl32/datetime: It isn't allowed to change DTS_SHOWNONE after creation.
[wine] / dlls / gdi32 / metafile.c
CommitLineData
5819953c
AJ
1/*
2 * Metafile functions
3 *
4 * Copyright David W. Metcalfe, 1994
396ee740
DP
5 * Copyright Niels de Carpentier, 1996
6 * Copyright Albrecht Kleine, 1996
7 * Copyright Huw Davies, 1996
234bc24d 8 *
0799c1a7
AJ
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
360a3f91 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
396ee740
DP
22 *
23 * NOTES
24 *
b94e4330
HD
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 *
9a624916 29 * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
b94e4330
HD
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
45b944ed 34 * METAFILE_MEMORY (1). Note this is identical to the disk image of a
b94e4330
HD
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
9a624916 46 */
b94e4330 47
33929be4 48#include "config.h"
b94e4330 49
75b8f888 50#include <stdarg.h>
aca05783 51#include <string.h>
ade697e8 52#include <fcntl.h>
33929be4 53
75b8f888
AJ
54#include "windef.h"
55#include "winbase.h"
56#include "wingdi.h"
506ab8bc
VB
57#include "winreg.h"
58#include "winternl.h"
6ec42c0c 59#include "gdi_private.h"
0799c1a7 60#include "wine/debug.h"
5819953c 61
0799c1a7 62WINE_DEFAULT_DEBUG_CHANNEL(metafile);
b4b9fae6 63
f899ef07
AJ
64#include "pshpack1.h"
65typedef struct
66{
67 DWORD dw1, dw2, dw3;
68 WORD w4;
69 CHAR filename[0x100];
70} METAHEADERDISK;
71#include "poppack.h"
72
78b041cf
AJ
73typedef struct
74{
75 GDIOBJHDR header;
76 METAHEADER *mh;
77} METAFILEOBJ;
78
ed29c905 79
bf9130af
AJ
80/******************************************************************
81 * MF_AddHandle
82 *
83 * Add a handle to an external handle table and return the index
84 */
15b9ed9f 85static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
bf9130af
AJ
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/******************************************************************
b94e4330
HD
102 * MF_Create_HMETATFILE
103 *
104 * Creates a (32 bit) HMETAFILE object from a METAHEADER
105 *
106 * HMETAFILEs are GDI objects.
107 */
108HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
109{
311c53db
AJ
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 );
b94e4330
HD
117 return hmf;
118}
119
b94e4330
HD
120/******************************************************************
121 * MF_GetMetaHeader
122 *
123 * Returns ptr to METAHEADER associated with HMETAFILE
b94e4330
HD
124 */
125static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
126{
8af0eda7 127 METAHEADER *ret = NULL;
5811a2cc 128 METAFILEOBJ * metaObj = GDI_GetObjPtr( hmf, OBJ_METAFILE );
8af0eda7
AJ
129 if (metaObj)
130 {
131 ret = metaObj->mh;
132 GDI_ReleaseObj( hmf );
133 }
134 return ret;
b94e4330
HD
135}
136
15b9ed9f
AJ
137/******************************************************************
138 * convert_points
139 *
140 * Convert an array of POINT16 to an array of POINT.
141 * Result must be freed by caller.
142 */
143static 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
b94e4330 158/******************************************************************
d0a41774 159 * DeleteMetaFile (GDI32.@)
b94e4330
HD
160 *
161 * Delete a memory-based metafile.
162 */
163
164BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
165{
de831f33 166 METAFILEOBJ * metaObj = free_gdi_handle( hmf );
2a2321bb
AJ
167 if (!metaObj) return FALSE;
168 HeapFree( GetProcessHeap(), 0, metaObj->mh );
de831f33 169 return HeapFree( GetProcessHeap(), 0, metaObj );
b94e4330
HD
170}
171
172/******************************************************************
173 * MF_ReadMetaFile
174 *
175 * Returns a pointer to a memory based METAHEADER read in from file HFILE
176 *
177 */
f824852b 178METAHEADER *MF_ReadMetaFile(HANDLE hfile)
b94e4330
HD
179{
180 METAHEADER *mh;
181 DWORD BytesRead, size;
182
183 size = sizeof(METAHEADER);
90476d6b 184 mh = HeapAlloc( GetProcessHeap(), 0, size );
b94e4330
HD
185 if(!mh) return NULL;
186 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
187 BytesRead != size) {
90476d6b 188 HeapFree( GetProcessHeap(), 0, mh );
b94e4330
HD
189 return NULL;
190 }
5f2bf16d
DT
191 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
192 mh->mtHeaderSize != size / 2)
193 {
82977c14
HD
194 HeapFree( GetProcessHeap(), 0, mh );
195 return NULL;
196 }
b94e4330 197 size = mh->mtSize * 2;
90476d6b 198 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
b94e4330
HD
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) {
90476d6b 204 HeapFree( GetProcessHeap(), 0, mh );
b94e4330
HD
205 return NULL;
206 }
207
208 if (mh->mtType != METAFILE_MEMORY) {
15657090 209 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
b94e4330
HD
210 mh->mtType = METAFILE_MEMORY;
211 }
212 return mh;
213}
214
f0cbfa0c 215/******************************************************************
d0a41774 216 * GetMetaFileA (GDI32.@)
60ce85c9 217 *
b94e4330 218 * Read a metafile from a file. Returns handle to a memory-based metafile.
f0cbfa0c 219 */
b94e4330 220HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
234bc24d 221{
b94e4330 222 METAHEADER *mh;
da2b6a9f 223 HANDLE hFile;
9a624916 224
15657090 225 TRACE("%s\n", lpFilename);
b94e4330
HD
226
227 if(!lpFilename)
228 return 0;
902da699 229
e987634c 230 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
da2b6a9f 231 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
b94e4330
HD
232 return 0;
233
234 mh = MF_ReadMetaFile(hFile);
235 CloseHandle(hFile);
236 if(!mh) return 0;
237 return MF_Create_HMETAFILE( mh );
234bc24d
AJ
238}
239
cdcdede2 240/******************************************************************
d0a41774 241 * GetMetaFileW (GDI32.@)
f0cbfa0c 242 */
a3960292 243HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
f0cbfa0c 244{
b94e4330 245 METAHEADER *mh;
da2b6a9f 246 HANDLE hFile;
9a624916 247
15657090 248 TRACE("%s\n", debugstr_w(lpFilename));
b94e4330
HD
249
250 if(!lpFilename)
251 return 0;
252
e987634c 253 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
da2b6a9f 254 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
b94e4330
HD
255 return 0;
256
257 mh = MF_ReadMetaFile(hFile);
258 CloseHandle(hFile);
259 if(!mh) return 0;
260 return MF_Create_HMETAFILE( mh );
f0cbfa0c
AJ
261}
262
263
264/******************************************************************
b94e4330
HD
265 * MF_LoadDiskBasedMetaFile
266 *
267 * Creates a new memory-based metafile from a disk-based one.
cdcdede2 268 */
f824852b 269METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
b94e4330
HD
270{
271 METAHEADERDISK *mhd;
da2b6a9f 272 HANDLE hfile;
b94e4330 273 METAHEADER *mh2;
cdcdede2 274
b94e4330 275 if(mh->mtType != METAFILE_DISK) {
15657090 276 ERR("Not a disk based metafile\n");
b94e4330
HD
277 return NULL;
278 }
279 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
280
e987634c 281 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
da2b6a9f 282 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
15657090 283 WARN("Can't open file of disk based metafile\n");
b94e4330
HD
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
44b52b12 295 * associated with filename. Note: Trashes contents of old one.
b94e4330 296 */
4eaf41b5 297METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
f0cbfa0c 298{
b94e4330 299 METAHEADERDISK *mhd;
b94e4330 300
90476d6b 301 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
b94e4330
HD
302 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
303 mh->mtType = METAFILE_DISK;
b94e4330 304 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
4eaf41b5
MM
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 );
b94e4330
HD
311 return mh;
312}
313
f0cbfa0c 314/******************************************************************
506ab8bc 315 * CopyMetaFileW (GDI32.@)
60ce85c9
AJ
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 *
396ee740
DP
321 * PARAMS
322 * hSrcMetaFile [I] handle of metafile to copy
323 * lpFilename [I] filename if copying to a file
60ce85c9 324 *
396ee740 325 * RETURNS
60ce85c9
AJ
326 * Handle to metafile copy on success, NULL on failure.
327 *
328 * BUGS
60ce85c9 329 * Copying to disk returns NULL even if successful.
f0cbfa0c 330 */
396ee740 331HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
783a3954 332{
b94e4330
HD
333 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
334 METAHEADER *mh2 = NULL;
da2b6a9f 335 HANDLE hFile;
b94e4330 336
506ab8bc 337 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
9a624916 338
b94e4330 339 if(!mh) return 0;
9a624916 340
b94e4330
HD
341 if(mh->mtType == METAFILE_DISK)
342 mh2 = MF_LoadDiskBasedMetaFile(mh);
343 else {
90476d6b 344 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
b94e4330
HD
345 memcpy( mh2, mh, mh->mtSize * 2 );
346 }
b94e4330
HD
347
348 if(lpFilename) { /* disk based metafile */
bcfa5b09 349 DWORD w;
506ab8bc 350 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
da2b6a9f 351 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
90476d6b 352 HeapFree( GetProcessHeap(), 0, mh2 );
cdcdede2 353 return 0;
b94e4330 354 }
bcfa5b09 355 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
b94e4330 356 CloseHandle(hFile);
b94e4330 357 }
46ea8b3f 358
b94e4330 359 return MF_Create_HMETAFILE( mh2 );
cdcdede2
AJ
360}
361
f0cbfa0c
AJ
362
363/******************************************************************
506ab8bc 364 * CopyMetaFileA (GDI32.@)
79e3a1be
MA
365 *
366 * See CopyMetaFileW.
f0cbfa0c 367 */
396ee740 368HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
f0cbfa0c 369{
506ab8bc 370 UNICODE_STRING lpFilenameW;
193cf50a 371 HMETAFILE ret = 0;
193cf50a 372
506ab8bc
VB
373 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
374 else lpFilenameW.Buffer = NULL;
375
766315e1
HD
376 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
377 if (lpFilenameW.Buffer)
378 RtlFreeUnicodeString(&lpFilenameW);
f0cbfa0c
AJ
379 return ret;
380}
381
b94e4330
HD
382/*******************************************************************
383 * MF_PlayMetaFile
60ce85c9 384 *
b94e4330 385 * Helper for PlayMetaFile
5819953c 386 */
f824852b 387BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
5819953c 388{
5819953c 389
36ca1368 390 METARECORD *mr;
15b9ed9f 391 HANDLETABLE *ht;
4d75640d 392 unsigned int offset = 0;
2ace16ac 393 WORD i;
a3960292
AJ
394 HPEN hPen;
395 HBRUSH hBrush;
396 HFONT hFont;
02a15500
DT
397 HPALETTE hPal;
398 HRGN hRgn;
b94e4330
HD
399 BOOL loaded = FALSE;
400
491502b9 401 if (!mh) return FALSE;
2a2321bb 402 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
b94e4330
HD
403 mh = MF_LoadDiskBasedMetaFile(mh);
404 if(!mh) return FALSE;
405 loaded = TRUE;
406 }
46ea8b3f 407
02a15500 408 /* save DC */
7c57a72c
HD
409 hPen = GetCurrentObject(hdc, OBJ_PEN);
410 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
411 hFont = GetCurrentObject(hdc, OBJ_FONT);
02a15500
DT
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 }
7c57a72c 420
36ca1368 421 /* create the handle table */
90476d6b 422 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
15b9ed9f 423 sizeof(HANDLETABLE) * mh->mtNoObjects);
b94e4330 424 if(!ht) return FALSE;
9a624916 425
36ca1368 426 /* loop through metafile playing records */
cdcdede2
AJ
427 offset = mh->mtHeaderSize * 2;
428 while (offset < mh->mtSize * 2)
36ca1368 429 {
0623a6f3 430 mr = (METARECORD *)((char *)mh + offset);
a0b260e7 431 TRACE("offset=%04x,size=%08x\n",
46ea8b3f 432 offset, mr->rdSize);
d6d64196 433 if (mr->rdSize < 3) { /* catch illegal record sizes */
a0b260e7 434 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
d6d64196
MM
435 mr->rdSize,offset,mh->mtSize*2);
436 break;
44ed71f5 437 }
47a38c36 438
cdcdede2 439 offset += mr->rdSize * 2;
47a38c36
EP
440 if (mr->rdFunction == META_EOF) {
441 TRACE("Got META_EOF so stopping\n");
442 break;
443 }
15b9ed9f 444 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
36ca1368
AJ
445 }
446
02a15500 447 /* restore DC */
a3960292 448 SelectObject(hdc, hPen);
02a15500
DT
449 SelectObject(hdc, hBrush);
450 SelectPalette(hdc, hPal, FALSE);
451 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
452 DeleteObject(hRgn);
349a9531 453
2ace16ac
AJ
454 /* free objects in handle table */
455 for(i = 0; i < mh->mtNoObjects; i++)
456 if(*(ht->objectHandle + i) != 0)
a3960292 457 DeleteObject(*(ht->objectHandle + i));
9a624916 458
cdcdede2 459 /* free handle table */
90476d6b 460 HeapFree( GetProcessHeap(), 0, ht );
b94e4330 461 if(loaded)
90476d6b 462 HeapFree( GetProcessHeap(), 0, mh );
cdcdede2
AJ
463 return TRUE;
464}
465
b94e4330 466/******************************************************************
d0a41774 467 * PlayMetaFile (GDI32.@)
60ce85c9 468 *
b94e4330
HD
469 * Renders the metafile specified by hmf in the DC specified by
470 * hdc. Returns FALSE on failure, TRUE on success.
396ee740
DP
471 *
472 * PARAMS
473 * hdc [I] handle of DC to render in
474 * hmf [I] handle of metafile to render
79e3a1be
MA
475 *
476 * RETURNS
477 * Success: TRUE
478 * Failure: FALSE
cdcdede2 479 */
396ee740 480BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
cdcdede2 481{
b94e4330 482 METAHEADER *mh = MF_GetMetaHeader( hmf );
8af0eda7 483 return MF_PlayMetaFile( hdc, mh );
b94e4330
HD
484}
485
b94e4330 486/******************************************************************
d0a41774 487 * EnumMetaFile (GDI32.@)
b94e4330
HD
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)
9a624916 492 * or when no records are left (which is considered to be success).
b94e4330
HD
493 *
494 * RETURNS
495 * TRUE on success, FALSE on failure.
b94e4330 496 */
396ee740 497BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
783a3954 498{
ab86a9e5 499 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
46ea8b3f 500 METARECORD *mr;
a3960292 501 HANDLETABLE *ht;
ab86a9e5 502 BOOL result = TRUE;
4d75640d
JM
503 int i;
504 unsigned int offset = 0;
a3960292
AJ
505 HPEN hPen;
506 HBRUSH hBrush;
507 HFONT hFont;
46ea8b3f 508
547cdc2b 509 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
46ea8b3f 510 if (!mh) return 0;
8af0eda7 511 if(mh->mtType == METAFILE_DISK)
ab86a9e5 512 {
8af0eda7
AJ
513 /* Create a memory-based copy */
514 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
ab86a9e5
AJ
515 mh = mhTemp;
516 }
8af0eda7 517
46ea8b3f 518 /* save the current pen, brush and font */
7c57a72c
HD
519 hPen = GetCurrentObject(hdc, OBJ_PEN);
520 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
521 hFont = GetCurrentObject(hdc, OBJ_FONT);
46ea8b3f 522
9a624916 523 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
a3960292 524 sizeof(HANDLETABLE) * mh->mtNoObjects);
b94e4330 525
46ea8b3f
AJ
526 /* loop through metafile records */
527 offset = mh->mtHeaderSize * 2;
9a624916 528
46ea8b3f
AJ
529 while (offset < (mh->mtSize * 2))
530 {
531 mr = (METARECORD *)((char *)mh + offset);
43ff7d2d
HD
532 if(mr->rdFunction == META_EOF) {
533 TRACE("Got META_EOF so stopping\n");
534 break;
535 }
15657090 536 TRACE("Calling EnumFunc with record type %x\n",
56166a6f 537 mr->rdFunction);
46ea8b3f
AJ
538 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
539 {
540 result = FALSE;
541 break;
542 }
9a624916 543
46ea8b3f
AJ
544 offset += (mr->rdSize * 2);
545 }
546
547 /* restore pen, brush and font */
a3960292
AJ
548 SelectObject(hdc, hBrush);
549 SelectObject(hdc, hPen);
550 SelectObject(hdc, hFont);
46ea8b3f
AJ
551
552 /* free objects in handle table */
553 for(i = 0; i < mh->mtNoObjects; i++)
554 if(*(ht->objectHandle + i) != 0)
a3960292 555 DeleteObject(*(ht->objectHandle + i));
46ea8b3f
AJ
556
557 /* free handle table */
90476d6b 558 HeapFree( GetProcessHeap(), 0, ht);
ab86a9e5 559 /* free a copy of metafile */
5ad7d858 560 HeapFree( GetProcessHeap(), 0, mhTemp );
46ea8b3f
AJ
561 return result;
562}
563
b94e4330 564static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
15b9ed9f 565static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
36ca1368 566/******************************************************************
15b9ed9f 567 * PlayMetaFileRecord (GDI32.@)
60ce85c9
AJ
568 *
569 * Render a single metafile record specified by *mr in the DC hdc, while
15b9ed9f 570 * using the handle table *ht, of length handles,
60ce85c9
AJ
571 * to store metafile objects.
572 *
573 * BUGS
574 * The following metafile records are unimplemented:
575 *
7603deae 576 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
60ce85c9
AJ
577 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
578 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
36ca1368 579 */
15b9ed9f
AJ
580BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
581{
36ca1368 582 short s1;
15b9ed9f 583 POINT *pt;
36ca1368
AJ
584 BITMAPINFOHEADER *infohdr;
585
547cdc2b 586 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
9a624916 587
36ca1368
AJ
588 switch (mr->rdFunction)
589 {
234bc24d 590 case META_EOF:
56166a6f 591 break;
234bc24d
AJ
592
593 case META_DELETEOBJECT:
15b9ed9f
AJ
594 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
595 *(ht->objectHandle + mr->rdParm[0]) = 0;
596 break;
234bc24d 597
36ca1368 598 case META_SETBKCOLOR:
15b9ed9f
AJ
599 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
600 break;
36ca1368
AJ
601
602 case META_SETBKMODE:
15b9ed9f
AJ
603 SetBkMode(hdc, mr->rdParm[0]);
604 break;
36ca1368
AJ
605
606 case META_SETMAPMODE:
15b9ed9f
AJ
607 SetMapMode(hdc, mr->rdParm[0]);
608 break;
36ca1368
AJ
609
610 case META_SETROP2:
15b9ed9f
AJ
611 SetROP2(hdc, mr->rdParm[0]);
612 break;
36ca1368
AJ
613
614 case META_SETRELABS:
15b9ed9f
AJ
615 SetRelAbs(hdc, mr->rdParm[0]);
616 break;
36ca1368
AJ
617
618 case META_SETPOLYFILLMODE:
15b9ed9f
AJ
619 SetPolyFillMode(hdc, mr->rdParm[0]);
620 break;
36ca1368
AJ
621
622 case META_SETSTRETCHBLTMODE:
15b9ed9f
AJ
623 SetStretchBltMode(hdc, mr->rdParm[0]);
624 break;
0623a6f3 625
36ca1368 626 case META_SETTEXTCOLOR:
15b9ed9f
AJ
627 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
628 break;
36ca1368
AJ
629
630 case META_SETWINDOWORG:
15b9ed9f
AJ
631 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
632 break;
36ca1368
AJ
633
634 case META_SETWINDOWEXT:
15b9ed9f
AJ
635 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
636 break;
36ca1368
AJ
637
638 case META_SETVIEWPORTORG:
15b9ed9f
AJ
639 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
640 break;
36ca1368
AJ
641
642 case META_SETVIEWPORTEXT:
15b9ed9f
AJ
643 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
644 break;
36ca1368
AJ
645
646 case META_OFFSETWINDOWORG:
15b9ed9f
AJ
647 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
648 break;
36ca1368
AJ
649
650 case META_SCALEWINDOWEXT:
15b9ed9f
AJ
651 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
652 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
653 break;
36ca1368
AJ
654
655 case META_OFFSETVIEWPORTORG:
15b9ed9f
AJ
656 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
657 break;
36ca1368
AJ
658
659 case META_SCALEVIEWPORTEXT:
15b9ed9f
AJ
660 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
661 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
662 break;
36ca1368
AJ
663
664 case META_LINETO:
15b9ed9f
AJ
665 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
666 break;
36ca1368
AJ
667
668 case META_MOVETO:
15b9ed9f
AJ
669 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
670 break;
36ca1368
AJ
671
672 case META_EXCLUDECLIPRECT:
15b9ed9f
AJ
673 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
674 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
675 break;
36ca1368
AJ
676
677 case META_INTERSECTCLIPRECT:
15b9ed9f
AJ
678 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
679 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
680 break;
36ca1368
AJ
681
682 case META_ARC:
15b9ed9f
AJ
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;
36ca1368
AJ
688
689 case META_ELLIPSE:
15b9ed9f
AJ
690 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
691 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
692 break;
36ca1368
AJ
693
694 case META_FLOODFILL:
15b9ed9f
AJ
695 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
696 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
697 break;
36ca1368
AJ
698
699 case META_PIE:
15b9ed9f
AJ
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;
36ca1368
AJ
705
706 case META_RECTANGLE:
15b9ed9f
AJ
707 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
708 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
709 break;
36ca1368
AJ
710
711 case META_ROUNDRECT:
15b9ed9f
AJ
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;
36ca1368
AJ
716
717 case META_PATBLT:
15b9ed9f
AJ
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;
36ca1368
AJ
722
723 case META_SAVEDC:
15b9ed9f
AJ
724 SaveDC(hdc);
725 break;
36ca1368
AJ
726
727 case META_SETPIXEL:
15b9ed9f
AJ
728 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
729 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
730 break;
36ca1368
AJ
731
732 case META_OFFSETCLIPRGN:
15b9ed9f
AJ
733 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
734 break;
36ca1368
AJ
735
736 case META_TEXTOUT:
15b9ed9f
AJ
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;
36ca1368
AJ
742
743 case META_POLYGON:
15b9ed9f
AJ
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;
36ca1368 750
234bc24d 751 case META_POLYPOLYGON:
15b9ed9f
AJ
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;
234bc24d 771
36ca1368 772 case META_POLYLINE:
15b9ed9f
AJ
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;
36ca1368
AJ
779
780 case META_RESTOREDC:
15b9ed9f
AJ
781 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
782 break;
36ca1368
AJ
783
784 case META_SELECTOBJECT:
15b9ed9f
AJ
785 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
786 break;
36ca1368
AJ
787
788 case META_CHORD:
15b9ed9f
AJ
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;
36ca1368
AJ
794
795 case META_CREATEPATTERNBRUSH:
15b9ed9f
AJ
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,
667a1ed5
MS
805 mr->rdParm +
806 (sizeof(BITMAPINFOHEADER) / 2) + 4)));
15b9ed9f
AJ
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;
9a624916 820
36ca1368 821 case META_CREATEPENINDIRECT:
15b9ed9f
AJ
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;
36ca1368 831
988ca977 832 case META_CREATEFONTINDIRECT:
15b9ed9f
AJ
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;
988ca977 852
36ca1368 853 case META_CREATEBRUSHINDIRECT:
15b9ed9f
AJ
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;
36ca1368 862
902da699 863 case META_CREATEPALETTE:
15b9ed9f
AJ
864 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
865 break;
902da699
AJ
866
867 case META_SETTEXTALIGN:
15b9ed9f
AJ
868 SetTextAlign(hdc, mr->rdParm[0]);
869 break;
902da699
AJ
870
871 case META_SELECTPALETTE:
15b9ed9f
AJ
872 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
873 break;
902da699
AJ
874
875 case META_SETMAPPERFLAGS:
15b9ed9f
AJ
876 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
877 break;
902da699
AJ
878
879 case META_REALIZEPALETTE:
15b9ed9f
AJ
880 GDIRealizePalette(hdc);
881 break;
902da699
AJ
882
883 case META_ESCAPE:
b49a1de1
MM
884 switch (mr->rdParm[0]) {
885 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
bde68851
AJ
886 case GETPHYSPAGESIZE:
887 case GETPRINTINGOFFSET:
b49a1de1
MM
888 return FALSE;
889 case SETABORTPROC:
890 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
891 return FALSE;
892 }
187c2b41 893 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
902da699
AJ
894 break;
895
f1aa3030 896 case META_EXTTEXTOUT:
56166a6f 897 MF_Play_MetaExtTextOut( hdc, mr );
15b9ed9f 898 break;
9a624916 899
cdcdede2
AJ
900 case META_STRETCHDIB:
901 {
15b9ed9f 902 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
515b40c2 903 LPSTR bits = (LPSTR)info + bitmap_info_size( info, mr->rdParm[2] );
15b9ed9f
AJ
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,
8da12c43 907 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
cdcdede2
AJ
908 }
909 break;
f1aa3030
AJ
910
911 case META_DIBSTRETCHBLT:
912 {
15b9ed9f 913 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
003392b5 914 LPSTR bits = (LPSTR)info + bitmap_info_size( info, DIB_RGB_COLORS );
15b9ed9f
AJ
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,
8da12c43 918 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
f1aa3030 919 }
9a624916 920 break;
f1aa3030
AJ
921
922 case META_STRETCHBLT:
923 {
15b9ed9f
AJ
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*/
667a1ed5 929 &mr->rdParm[15]); /*bits*/
15b9ed9f
AJ
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);
f1aa3030
AJ
937 }
938 break;
939
b94e4330 940 case META_BITBLT:
f1aa3030 941 {
15b9ed9f
AJ
942 HDC hdcSrc = CreateCompatibleDC(hdc);
943 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
8da12c43
AJ
944 mr->rdParm[8]/*Height*/,
945 mr->rdParm[10]/*Planes*/,
946 mr->rdParm[11]/*BitsPixel*/,
667a1ed5 947 &mr->rdParm[12]/*bits*/);
15b9ed9f
AJ
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],
8da12c43 952 MAKELONG(0,mr->rdParm[0]));
15b9ed9f 953 DeleteDC(hdcSrc);
f1aa3030
AJ
954 }
955 break;
889f7424 956
889f7424 957 case META_CREATEREGION:
0623a6f3 958 {
15b9ed9f 959 HRGN hrgn = CreateRectRgn(0,0,0,0);
9a624916 960
15b9ed9f
AJ
961 MF_Play_MetaCreateRegion(mr, hrgn);
962 MF_AddHandle(ht, handles, hrgn);
0623a6f3
AJ
963 }
964 break;
889f7424 965
b94e4330 966 case META_FILLREGION:
15b9ed9f
AJ
967 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
968 *(ht->objectHandle + mr->rdParm[0]));
7603deae
HD
969 break;
970
971 case META_FRAMEREGION:
15b9ed9f
AJ
972 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
973 *(ht->objectHandle + mr->rdParm[2]),
974 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
889f7424
AJ
975 break;
976
b94e4330 977 case META_INVERTREGION:
15b9ed9f 978 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
9a624916 979 break;
889f7424 980
b94e4330 981 case META_PAINTREGION:
15b9ed9f 982 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
889f7424
AJ
983 break;
984
b94e4330 985 case META_SELECTCLIPREGION:
f4f7689c
UC
986 {
987 HRGN hrgn = 0;
988
989 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
990 SelectClipRgn(hdc, hrgn);
991 }
15b9ed9f 992 break;
889f7424 993
b94e4330 994 case META_DIBCREATEPATTERNBRUSH:
15b9ed9f
AJ
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;
84c70f55 999
56166a6f
HD
1000 case META_DIBBITBLT:
1001 /* In practice I've found that there are two layouts for
15b9ed9f
AJ
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.
56166a6f 1006
15b9ed9f 1007 Caolan.McNamara@ul.ie */
56166a6f
HD
1008
1009 if (mr->rdSize > 12) {
15b9ed9f 1010 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
515b40c2 1011 LPSTR bits = (LPSTR)info + bitmap_info_size(info, mr->rdParm[0]);
15b9ed9f
AJ
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;
9a624916 1023
b94e4330 1024 case META_SETTEXTCHAREXTRA:
15b9ed9f
AJ
1025 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1026 break;
491502b9 1027
b94e4330 1028 case META_SETTEXTJUSTIFICATION:
15b9ed9f
AJ
1029 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1030 break;
7ff1c415 1031
ae8a748a 1032 case META_EXTFLOODFILL:
15b9ed9f
AJ
1033 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1034 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1035 mr->rdParm[0]);
ae8a748a
CM
1036 break;
1037
56166a6f 1038 case META_SETDIBTODEV:
15b9ed9f
AJ
1039 {
1040 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
515b40c2 1041 char *bits = (char *)info + bitmap_info_size( info, mr->rdParm[0] );
15b9ed9f
AJ
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 }
56166a6f
HD
1049
1050#define META_UNIMP(x) case x: \
15657090 1051FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
56166a6f 1052break;
c6c09442 1053 META_UNIMP(META_DRAWTEXT)
c6c09442
AJ
1054 META_UNIMP(META_ANIMATEPALETTE)
1055 META_UNIMP(META_SETPALENTRIES)
1056 META_UNIMP(META_RESIZEPALETTE)
c6c09442
AJ
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
f1aa3030 1067
36ca1368 1068 default:
15b9ed9f
AJ
1069 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1070 return FALSE;
36ca1368 1071 }
b94e4330 1072 return TRUE;
54c2711f
AJ
1073}
1074
54c2711f 1075/******************************************************************
d0a41774 1076 * SetMetaFileBitsEx (GDI32.@)
9a624916 1077 *
c7c217b3 1078 * Create a metafile from raw data. No checking of the data is performed.
396ee740
DP
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
79e3a1be
MA
1084 *
1085 * RETURNS
1086 * Success: Handle to metafile.
1087 * Failure: NULL.
54c2711f 1088 */
396ee740 1089HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
54c2711f 1090{
17ec5aba
AT
1091 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1092 METAHEADER *mh_out;
5f2bf16d
DT
1093
1094 if (size & 1) return 0;
1095
17ec5aba
AT
1096 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1097 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
5f2bf16d
DT
1098 {
1099 SetLastError(ERROR_INVALID_DATA);
1100 return 0;
1101 }
1102
17ec5aba
AT
1103 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1104 if (!mh_out)
5f2bf16d
DT
1105 {
1106 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1107 return 0;
1108 }
1109
17ec5aba
AT
1110 memcpy(mh_out, mh_in, size);
1111 mh_out->mtSize = size / 2;
1112 return MF_Create_HMETAFILE(mh_out);
54c2711f
AJ
1113}
1114
46ea8b3f 1115/*****************************************************************
783a3954
JG
1116 * GetMetaFileBitsEx (GDI32.@)
1117 *
1118 * Get raw metafile data.
9a624916 1119 *
46ea8b3f 1120 * Copies the data from metafile _hmf_ into the buffer _buf_.
396ee740
DP
1121 *
1122 * PARAMS
1123 * hmf [I] metafile
1124 * nSize [I] size of buf
1125 * buf [O] buffer to receive raw metafile data
79e3a1be
MA
1126 *
1127 * RETURNS
1128 * If _buf_ is zero, returns size of buffer required. Otherwise,
1129 * returns number of bytes copied.
46ea8b3f 1130 */
396ee740 1131UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
783a3954 1132{
b94e4330
HD
1133 METAHEADER *mh = MF_GetMetaHeader(hmf);
1134 UINT mfSize;
1135
547cdc2b 1136 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
b94e4330
HD
1137 if (!mh) return 0; /* FIXME: error code */
1138 if(mh->mtType == METAFILE_DISK)
15657090 1139 FIXME("Disk-based metafile?\n");
b94e4330
HD
1140 mfSize = mh->mtSize * 2;
1141 if (!buf) {
15657090 1142 TRACE("returning size %d\n", mfSize);
b94e4330
HD
1143 return mfSize;
1144 }
1145 if(mfSize > nSize) mfSize = nSize;
1146 memmove(buf, mh, mfSize);
7bb6fd1d 1147 return mfSize;
46ea8b3f
AJ
1148}
1149
41bbc007
HD
1150#include <pshpack2.h>
1151typedef 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
1168static 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 */
1178static 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;
1219end:
1220 HeapFree(GetProcessHeap(), 0, chunk);
1221 HeapFree(GetProcessHeap(), 0, bits);
1222 return ret;
1223}
1224
787ead80
HD
1225/*******************************************************************
1226 * muldiv
1227 *
1228 * Behaves somewhat differently to MulDiv when the answer is -ve
1229 * and also rounds n.5 towards zero
1230 */
1231static INT muldiv(INT m1, INT m2, INT d)
1232{
1233 LONGLONG ret;
1234
1235 ret = ((LONGLONG)m1 * m2 + d/2) / d; /* Always add d/2 even if ret will be -ve */
1236
1237 if((LONGLONG)m1 * m2 * 2 == (2 * ret - 1) * d) /* If the answer is exactly n.5 round towards zero */
1238 {
1239 if(ret > 0) ret--;
1240 else ret++;
1241 }
1242 return ret;
1243}
1244
8edbd063
HD
1245/******************************************************************
1246 * set_window
1247 *
1248 * Helper for GetWinMetaFileBits
1249 *
1250 * Add the SetWindowOrg and SetWindowExt records
1251 */
1252static BOOL set_window(HDC hdc, HENHMETAFILE emf, HDC ref_dc, INT map_mode)
1253{
1254 ENHMETAHEADER header;
1255 INT horz_res, vert_res, horz_size, vert_size;
1256 POINT pt;
1257
1258 if(!GetEnhMetaFileHeader(emf, sizeof(header), &header)) return FALSE;
1259
1260 horz_res = GetDeviceCaps(ref_dc, HORZRES);
1261 vert_res = GetDeviceCaps(ref_dc, VERTRES);
1262 horz_size = GetDeviceCaps(ref_dc, HORZSIZE);
1263 vert_size = GetDeviceCaps(ref_dc, VERTSIZE);
1264
1265 switch(map_mode)
1266 {
1267 case MM_TEXT:
1268 case MM_ISOTROPIC:
1269 case MM_ANISOTROPIC:
787ead80
HD
1270 pt.y = muldiv(header.rclFrame.top, vert_res, vert_size * 100);
1271 pt.x = muldiv(header.rclFrame.left, horz_res, horz_size * 100);
8edbd063
HD
1272 break;
1273 case MM_LOMETRIC:
787ead80
HD
1274 pt.y = muldiv(-header.rclFrame.top, 1, 10) + 1;
1275 pt.x = muldiv( header.rclFrame.left, 1, 10);
8edbd063
HD
1276 break;
1277 case MM_HIMETRIC:
1278 pt.y = -header.rclFrame.top + 1;
787ead80 1279 pt.x = (header.rclFrame.left >= 0) ? header.rclFrame.left : header.rclFrame.left + 1; /* See the tests */
8edbd063
HD
1280 break;
1281 case MM_LOENGLISH:
787ead80
HD
1282 pt.y = muldiv(-header.rclFrame.top, 10, 254) + 1;
1283 pt.x = muldiv( header.rclFrame.left, 10, 254);
8edbd063
HD
1284 break;
1285 case MM_HIENGLISH:
787ead80
HD
1286 pt.y = muldiv(-header.rclFrame.top, 100, 254) + 1;
1287 pt.x = muldiv( header.rclFrame.left, 100, 254);
8edbd063
HD
1288 break;
1289 case MM_TWIPS:
787ead80
HD
1290 pt.y = muldiv(-header.rclFrame.top, 72 * 20, 2540) + 1;
1291 pt.x = muldiv( header.rclFrame.left, 72 * 20, 2540);
8edbd063
HD
1292 break;
1293 default:
1294 WARN("Unknown map mode %d\n", map_mode);
1295 return FALSE;
1296 }
1297 SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
1298
787ead80
HD
1299 pt.x = muldiv(header.rclFrame.right - header.rclFrame.left, horz_res, horz_size * 100);
1300 pt.y = muldiv(header.rclFrame.bottom - header.rclFrame.top, vert_res, vert_size * 100);
8edbd063
HD
1301 SetWindowExtEx(hdc, pt.x, pt.y, NULL);
1302 return TRUE;
1303}
1304
0c0e3beb 1305/******************************************************************
d0a41774 1306 * GetWinMetaFileBits [GDI32.@]
0c0e3beb 1307 */
a3960292
AJ
1308UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1309 UINT cbBuffer, LPBYTE lpbBuffer,
8edbd063 1310 INT map_mode, HDC hdcRef)
0c0e3beb 1311{
b482e9ac
HD
1312 HDC hdcmf;
1313 HMETAFILE hmf;
41bbc007 1314 UINT ret, full_size;
6cc56740 1315 RECT rc;
6cc56740
UC
1316
1317 GetClipBox(hdcRef, &rc);
6cc56740
UC
1318
1319 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
8edbd063 1320 map_mode, hdcRef, wine_dbgstr_rect(&rc));
b482e9ac 1321
d7af14f1 1322 hdcmf = CreateMetaFileW(NULL);
41bbc007
HD
1323
1324 add_mf_comment(hdcmf, hemf);
8edbd063
HD
1325 SetMapMode(hdcmf, map_mode);
1326 if(!set_window(hdcmf, hemf, hdcRef, map_mode))
1327 goto error;
41bbc007 1328
6cc56740 1329 PlayEnhMetaFile(hdcmf, hemf, &rc);
b482e9ac 1330 hmf = CloseMetaFile(hdcmf);
41bbc007 1331 full_size = GetMetaFileBitsEx(hmf, 0, NULL);
b482e9ac
HD
1332 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1333 DeleteMetaFile(hmf);
6cc56740 1334
41bbc007
HD
1335 if(ret && ret == full_size && lpbBuffer) /* fixup checksum, but only if retrieving all of the bits */
1336 {
1337 WORD checksum = 0;
1338 METARECORD *comment_rec = (METARECORD*)(lpbBuffer + sizeof(METAHEADER));
1339 UINT i;
1340
1341 for(i = 0; i < full_size / 2; i++)
1342 checksum += ((WORD*)lpbBuffer)[i];
1343 comment_rec->rdParm[8] = ~checksum + 1;
1344 }
b482e9ac 1345 return ret;
8edbd063
HD
1346
1347error:
1348 DeleteMetaFile(CloseMetaFile(hdcmf));
1349 return 0;
0c0e3beb 1350}
46ea8b3f 1351
0623a6f3 1352/******************************************************************
b94e4330 1353 * MF_Play_MetaCreateRegion
0623a6f3
AJ
1354 *
1355 * Handles META_CREATEREGION for PlayMetaFileRecord().
396ee740 1356 *
0623a6f3 1357 * The layout of the record looks something like this:
9a624916 1358 *
8da12c43 1359 * rdParm meaning
0623a6f3
AJ
1360 * 0 Always 0?
1361 * 1 Always 6?
1362 * 2 Looks like a handle? - not constant
1363 * 3 0 or 1 ??
1364 * 4 Total number of bytes
282f7270 1365 * 5 No. of separate bands = n [see below]
0623a6f3
AJ
1366 * 6 Largest number of x co-ords in a band
1367 * 7-10 Bounding box x1 y1 x2 y2
1368 * 11-... n bands
1369 *
1370 * Regions are divided into bands that are uniform in the
1371 * y-direction. Each band consists of pairs of on/off x-coords and is
1372 * written as
1373 * m y0 y1 x1 x2 x3 ... xm m
8da12c43 1374 * into successive rdParm[]s.
0623a6f3
AJ
1375 *
1376 * This is probably just a dump of the internal RGNOBJ?
1377 *
1378 * HDMD - 18/12/97
1379 *
1380 */
1381
b94e4330 1382static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
0623a6f3
AJ
1383{
1384 WORD band, pair;
1385 WORD *start, *end;
1386 INT16 y0, y1;
a3960292 1387 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
0623a6f3 1388
8da12c43 1389 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
0623a6f3
AJ
1390 band++, start = end + 1) {
1391 if(*start / 2 != (*start + 1) / 2) {
15657090 1392 WARN("Delimiter not even.\n");
a3960292 1393 DeleteObject( hrgn2 );
0623a6f3
AJ
1394 return FALSE;
1395 }
1396
1397 end = start + *start + 3;
1398 if(end > (WORD *)mr + mr->rdSize) {
15657090 1399 WARN("End points outside record.\n");
a3960292 1400 DeleteObject( hrgn2 );
0623a6f3
AJ
1401 return FALSE;
1402 }
1403
1404 if(*start != *end) {
15657090 1405 WARN("Mismatched delimiters.\n");
a3960292 1406 DeleteObject( hrgn2 );
0623a6f3
AJ
1407 return FALSE;
1408 }
1409
1410 y0 = *(INT16 *)(start + 1);
1411 y1 = *(INT16 *)(start + 2);
1412 for(pair = 0; pair < *start / 2; pair++) {
a3960292 1413 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
0623a6f3 1414 *(INT16 *)(start + 4 + 2*pair), y1 );
a3960292 1415 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
0623a6f3
AJ
1416 }
1417 }
a3960292 1418 DeleteObject( hrgn2 );
0623a6f3
AJ
1419 return TRUE;
1420 }
9a624916 1421
0623a6f3 1422
56166a6f
HD
1423/******************************************************************
1424 * MF_Play_MetaExtTextOut
1425 *
1426 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
36ca1368 1427 */
56166a6f 1428
15b9ed9f 1429static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
56166a6f 1430{
15b9ed9f
AJ
1431 INT *dx = NULL;
1432 int i;
56166a6f 1433 LPINT16 dxx;
9a624916 1434 LPSTR sot;
56166a6f
HD
1435 DWORD len;
1436 WORD s1;
15b9ed9f 1437 RECT rect;
b482e9ac 1438 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
56166a6f
HD
1439
1440 s1 = mr->rdParm[2]; /* String length */
1441 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
b482e9ac 1442 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
56166a6f
HD
1443 /* rec len without dx array */
1444
1445 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
b482e9ac 1446 if (isrect)
15b9ed9f
AJ
1447 {
1448 rect.left = (SHORT)mr->rdParm[4];
1449 rect.top = (SHORT)mr->rdParm[5];
1450 rect.right = (SHORT)mr->rdParm[6];
1451 rect.bottom = (SHORT)mr->rdParm[7];
56166a6f 1452 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
15b9ed9f 1453 }
9a624916 1454
56166a6f 1455 if (mr->rdSize == len / 2)
45b944ed 1456 dxx = NULL; /* determine if array is present */
9a624916 1457 else
56166a6f 1458 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
15b9ed9f
AJ
1459 {
1460 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1461 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
d0d4c74e 1462 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
15b9ed9f 1463 }
56166a6f 1464 else {
a0b260e7
MS
1465 TRACE("%s len: %d\n", sot, mr->rdSize);
1466 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
56166a6f 1467 len, s1, mr->rdSize, mr->rdParm[3]);
45b944ed 1468 dxx = NULL; /* shouldn't happen -- but if, we continue with NULL */
56166a6f 1469 }
15b9ed9f
AJ
1470 ExtTextOutA( hdc,
1471 (SHORT)mr->rdParm[1], /* X position */
1472 (SHORT)mr->rdParm[0], /* Y position */
1473 mr->rdParm[3], /* options */
1474 &rect, /* rectangle */
1475 sot, /* string */
396ee740 1476 s1, dx); /* length, dx array */
15b9ed9f
AJ
1477 if (dx)
1478 {
a0b260e7 1479 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
15b9ed9f
AJ
1480 HeapFree( GetProcessHeap(), 0, dx );
1481 }
56166a6f
HD
1482 return TRUE;
1483}