Commit | Line | Data |
---|---|---|
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 | 62 | WINE_DEFAULT_DEBUG_CHANNEL(metafile); |
b4b9fae6 | 63 | |
f899ef07 AJ |
64 | #include "pshpack1.h" |
65 | typedef struct | |
66 | { | |
67 | DWORD dw1, dw2, dw3; | |
68 | WORD w4; | |
69 | CHAR filename[0x100]; | |
70 | } METAHEADERDISK; | |
71 | #include "poppack.h" | |
72 | ||
78b041cf AJ |
73 | typedef 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 | 85 | static 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 | */ | |
108 | HMETAFILE 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 | */ |
125 | static 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 | */ | |
143 | static POINT *convert_points( UINT count, POINT16 *pt16 ) | |
144 | { | |
145 | UINT i; | |
146 | POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) ); | |
147 | if (ret) | |
148 | { | |
149 | for (i = 0; i < count; i++) | |
150 | { | |
151 | ret[i].x = pt16[i].x; | |
152 | ret[i].y = pt16[i].y; | |
153 | } | |
154 | } | |
155 | return ret; | |
156 | } | |
157 | ||
b94e4330 | 158 | /****************************************************************** |
d0a41774 | 159 | * DeleteMetaFile (GDI32.@) |
b94e4330 HD |
160 | * |
161 | * Delete a memory-based metafile. | |
162 | */ | |
163 | ||
164 | BOOL 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 | 178 | METAHEADER *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 | 220 | HMETAFILE 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 | 243 | HMETAFILE 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 | 269 | METAHEADER *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 | 297 | METAHEADER *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 | 331 | HMETAFILE 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 | 368 | HMETAFILE 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 | 387 | BOOL 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 | 480 | BOOL 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 | 497 | BOOL 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 | 564 | static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn ); |
15b9ed9f | 565 | static 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 |
580 | BOOL 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 | 1051 | FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \ |
56166a6f | 1052 | break; |
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 | 1089 | HMETAFILE 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 | 1131 | UINT 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> |
1151 | typedef struct | |
1152 | { | |
1153 | DWORD magic; /* WMFC */ | |
1154 | WORD unk04; /* 1 */ | |
1155 | WORD unk06; /* 0 */ | |
1156 | WORD unk08; /* 0 */ | |
1157 | WORD unk0a; /* 1 */ | |
1158 | WORD checksum; | |
1159 | DWORD unk0e; /* 0 */ | |
1160 | DWORD num_chunks; | |
1161 | DWORD chunk_size; | |
1162 | DWORD remaining_size; | |
1163 | DWORD emf_size; | |
1164 | BYTE *emf_data; | |
1165 | } mf_comment_chunk; | |
1166 | #include <poppack.h> | |
1167 | ||
1168 | static const DWORD wmfc_magic = 0x43464d57; | |
1169 | ||
1170 | /****************************************************************** | |
1171 | * add_mf_comment | |
1172 | * | |
1173 | * Helper for GetWinMetaFileBits | |
1174 | * | |
1175 | * Add the MFCOMMENT record[s] which is essentially a copy | |
1176 | * of the original emf. | |
1177 | */ | |
1178 | static BOOL add_mf_comment(HDC hdc, HENHMETAFILE emf) | |
1179 | { | |
1180 | DWORD size = GetEnhMetaFileBits(emf, 0, NULL), i; | |
1181 | BYTE *bits, *chunk_data; | |
1182 | mf_comment_chunk *chunk = NULL; | |
1183 | BOOL ret = FALSE; | |
1184 | static const DWORD max_chunk_size = 0x2000; | |
1185 | ||
1186 | if(!size) return FALSE; | |
1187 | chunk_data = bits = HeapAlloc(GetProcessHeap(), 0, size); | |
1188 | if(!bits) return FALSE; | |
1189 | if(!GetEnhMetaFileBits(emf, size, bits)) goto end; | |
1190 | ||
1191 | chunk = HeapAlloc(GetProcessHeap(), 0, max_chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data)); | |
1192 | if(!chunk) goto end; | |
1193 | ||
1194 | chunk->magic = wmfc_magic; | |
1195 | chunk->unk04 = 1; | |
1196 | chunk->unk06 = 0; | |
1197 | chunk->unk08 = 0; | |
1198 | chunk->unk0a = 1; | |
1199 | chunk->checksum = 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */ | |
1200 | chunk->unk0e = 0; | |
1201 | chunk->num_chunks = (size + max_chunk_size - 1) / max_chunk_size; | |
1202 | chunk->chunk_size = max_chunk_size; | |
1203 | chunk->remaining_size = size; | |
1204 | chunk->emf_size = size; | |
1205 | ||
1206 | for(i = 0; i < chunk->num_chunks; i++) | |
1207 | { | |
1208 | if(i == chunk->num_chunks - 1) /* last chunk */ | |
1209 | chunk->chunk_size = chunk->remaining_size; | |
1210 | ||
1211 | chunk->remaining_size -= chunk->chunk_size; | |
1212 | memcpy(&chunk->emf_data, chunk_data, chunk->chunk_size); | |
1213 | chunk_data += chunk->chunk_size; | |
1214 | ||
1215 | if(!Escape(hdc, MFCOMMENT, chunk->chunk_size + FIELD_OFFSET(mf_comment_chunk, emf_data), (char*)chunk, NULL)) | |
1216 | goto end; | |
1217 | } | |
1218 | ret = TRUE; | |
1219 | end: | |
1220 | HeapFree(GetProcessHeap(), 0, chunk); | |
1221 | HeapFree(GetProcessHeap(), 0, bits); | |
1222 | return ret; | |
1223 | } | |
1224 | ||
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 | */ | |
1231 | static 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 | */ | |
1252 | static 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 |
1308 | UINT 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 | |
1347 | error: | |
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 | 1382 | static 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 | 1429 | static 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 | } |