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