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