1 /* 2 * Enhanced metafile functions 3 * Copyright 1998 Douglas Ridgway 4 * 1999 Huw D M Davies 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 * 20 * NOTES: 21 * 22 * The enhanced format consists of the following elements: 23 * 24 * A header 25 * A table of handles to GDI objects 26 * An array of metafile records 27 * A private palette 28 * 29 * 30 * The standard format consists of a header and an array of metafile records. 31 * 32 */ 33 34 #include "config.h" 35 #include "wine/port.h" 36 37 #include <stdarg.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <assert.h> 41 #include "windef.h" 42 #include "winbase.h" 43 #include "wingdi.h" 44 #include "winnls.h" 45 #include "winerror.h" 46 #include "gdi_private.h" 47 #include "wine/debug.h" 48 49 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile); 50 51 52 static CRITICAL_SECTION enhmetafile_cs; 53 static CRITICAL_SECTION_DEBUG critsect_debug = 54 { 55 0, 0, &enhmetafile_cs, 56 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 57 0, 0, { (DWORD_PTR)(__FILE__ ": enhmetafile_cs") } 58 }; 59 static CRITICAL_SECTION enhmetafile_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; 60 61 typedef struct 62 { 63 ENHMETAHEADER *emh; 64 BOOL on_disk; /* true if metafile is on disk */ 65 } ENHMETAFILEOBJ; 66 67 static const struct emr_name { 68 DWORD type; 69 const char *name; 70 } emr_names[] = { 71 #define X(p) {p, #p} 72 X(EMR_HEADER), 73 X(EMR_POLYBEZIER), 74 X(EMR_POLYGON), 75 X(EMR_POLYLINE), 76 X(EMR_POLYBEZIERTO), 77 X(EMR_POLYLINETO), 78 X(EMR_POLYPOLYLINE), 79 X(EMR_POLYPOLYGON), 80 X(EMR_SETWINDOWEXTEX), 81 X(EMR_SETWINDOWORGEX), 82 X(EMR_SETVIEWPORTEXTEX), 83 X(EMR_SETVIEWPORTORGEX), 84 X(EMR_SETBRUSHORGEX), 85 X(EMR_EOF), 86 X(EMR_SETPIXELV), 87 X(EMR_SETMAPPERFLAGS), 88 X(EMR_SETMAPMODE), 89 X(EMR_SETBKMODE), 90 X(EMR_SETPOLYFILLMODE), 91 X(EMR_SETROP2), 92 X(EMR_SETSTRETCHBLTMODE), 93 X(EMR_SETTEXTALIGN), 94 X(EMR_SETCOLORADJUSTMENT), 95 X(EMR_SETTEXTCOLOR), 96 X(EMR_SETBKCOLOR), 97 X(EMR_OFFSETCLIPRGN), 98 X(EMR_MOVETOEX), 99 X(EMR_SETMETARGN), 100 X(EMR_EXCLUDECLIPRECT), 101 X(EMR_INTERSECTCLIPRECT), 102 X(EMR_SCALEVIEWPORTEXTEX), 103 X(EMR_SCALEWINDOWEXTEX), 104 X(EMR_SAVEDC), 105 X(EMR_RESTOREDC), 106 X(EMR_SETWORLDTRANSFORM), 107 X(EMR_MODIFYWORLDTRANSFORM), 108 X(EMR_SELECTOBJECT), 109 X(EMR_CREATEPEN), 110 X(EMR_CREATEBRUSHINDIRECT), 111 X(EMR_DELETEOBJECT), 112 X(EMR_ANGLEARC), 113 X(EMR_ELLIPSE), 114 X(EMR_RECTANGLE), 115 X(EMR_ROUNDRECT), 116 X(EMR_ARC), 117 X(EMR_CHORD), 118 X(EMR_PIE), 119 X(EMR_SELECTPALETTE), 120 X(EMR_CREATEPALETTE), 121 X(EMR_SETPALETTEENTRIES), 122 X(EMR_RESIZEPALETTE), 123 X(EMR_REALIZEPALETTE), 124 X(EMR_EXTFLOODFILL), 125 X(EMR_LINETO), 126 X(EMR_ARCTO), 127 X(EMR_POLYDRAW), 128 X(EMR_SETARCDIRECTION), 129 X(EMR_SETMITERLIMIT), 130 X(EMR_BEGINPATH), 131 X(EMR_ENDPATH), 132 X(EMR_CLOSEFIGURE), 133 X(EMR_FILLPATH), 134 X(EMR_STROKEANDFILLPATH), 135 X(EMR_STROKEPATH), 136 X(EMR_FLATTENPATH), 137 X(EMR_WIDENPATH), 138 X(EMR_SELECTCLIPPATH), 139 X(EMR_ABORTPATH), 140 X(EMR_GDICOMMENT), 141 X(EMR_FILLRGN), 142 X(EMR_FRAMERGN), 143 X(EMR_INVERTRGN), 144 X(EMR_PAINTRGN), 145 X(EMR_EXTSELECTCLIPRGN), 146 X(EMR_BITBLT), 147 X(EMR_STRETCHBLT), 148 X(EMR_MASKBLT), 149 X(EMR_PLGBLT), 150 X(EMR_SETDIBITSTODEVICE), 151 X(EMR_STRETCHDIBITS), 152 X(EMR_EXTCREATEFONTINDIRECTW), 153 X(EMR_EXTTEXTOUTA), 154 X(EMR_EXTTEXTOUTW), 155 X(EMR_POLYBEZIER16), 156 X(EMR_POLYGON16), 157 X(EMR_POLYLINE16), 158 X(EMR_POLYBEZIERTO16), 159 X(EMR_POLYLINETO16), 160 X(EMR_POLYPOLYLINE16), 161 X(EMR_POLYPOLYGON16), 162 X(EMR_POLYDRAW16), 163 X(EMR_CREATEMONOBRUSH), 164 X(EMR_CREATEDIBPATTERNBRUSHPT), 165 X(EMR_EXTCREATEPEN), 166 X(EMR_POLYTEXTOUTA), 167 X(EMR_POLYTEXTOUTW), 168 X(EMR_SETICMMODE), 169 X(EMR_CREATECOLORSPACE), 170 X(EMR_SETCOLORSPACE), 171 X(EMR_DELETECOLORSPACE), 172 X(EMR_GLSRECORD), 173 X(EMR_GLSBOUNDEDRECORD), 174 X(EMR_PIXELFORMAT), 175 X(EMR_DRAWESCAPE), 176 X(EMR_EXTESCAPE), 177 X(EMR_STARTDOC), 178 X(EMR_SMALLTEXTOUT), 179 X(EMR_FORCEUFIMAPPING), 180 X(EMR_NAMEDESCAPE), 181 X(EMR_COLORCORRECTPALETTE), 182 X(EMR_SETICMPROFILEA), 183 X(EMR_SETICMPROFILEW), 184 X(EMR_ALPHABLEND), 185 X(EMR_SETLAYOUT), 186 X(EMR_TRANSPARENTBLT), 187 X(EMR_RESERVED_117), 188 X(EMR_GRADIENTFILL), 189 X(EMR_SETLINKEDUFI), 190 X(EMR_SETTEXTJUSTIFICATION), 191 X(EMR_COLORMATCHTOTARGETW), 192 X(EMR_CREATECOLORSPACEW) 193 #undef X 194 }; 195 196 /**************************************************************************** 197 * get_emr_name 198 */ 199 static const char *get_emr_name(DWORD type) 200 { 201 unsigned int i; 202 for(i = 0; i < sizeof(emr_names) / sizeof(emr_names[0]); i++) 203 if(type == emr_names[i].type) return emr_names[i].name; 204 TRACE("Unknown record type %d\n", type); 205 return NULL; 206 } 207 208 /*********************************************************************** 209 * is_dib_monochrome 210 * 211 * Returns whether a DIB can be converted to a monochrome DDB. 212 * 213 * A DIB can be converted if its color table contains only black and 214 * white. Black must be the first color in the color table. 215 * 216 * Note : If the first color in the color table is white followed by 217 * black, we can't convert it to a monochrome DDB with 218 * SetDIBits, because black and white would be inverted. 219 */ 220 static inline BOOL is_dib_monochrome( const BITMAPINFO* info ) 221 { 222 if (info->bmiHeader.biBitCount != 1) return FALSE; 223 224 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 225 { 226 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO *) info)->bmciColors; 227 228 /* Check if the first color is black */ 229 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0)) 230 { 231 rgb++; 232 /* Check if the second color is white */ 233 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff) 234 && (rgb->rgbtBlue == 0xff)); 235 } 236 else return FALSE; 237 } 238 else /* assume BITMAPINFOHEADER */ 239 { 240 const RGBQUAD *rgb = info->bmiColors; 241 242 /* Check if the first color is black */ 243 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && 244 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0)) 245 { 246 rgb++; 247 248 /* Check if the second color is white */ 249 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff) 250 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0)); 251 } 252 else return FALSE; 253 } 254 } 255 256 /**************************************************************************** 257 * EMF_Create_HENHMETAFILE 258 */ 259 HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk ) 260 { 261 HENHMETAFILE hmf; 262 ENHMETAFILEOBJ *metaObj; 263 264 if (emh->iType != EMR_HEADER) 265 { 266 SetLastError(ERROR_INVALID_DATA); 267 return 0; 268 } 269 if (emh->dSignature != ENHMETA_SIGNATURE || 270 (emh->nBytes & 3)) /* refuse to load unaligned EMF as Windows does */ 271 { 272 WARN("Invalid emf header type 0x%08x sig 0x%08x.\n", 273 emh->iType, emh->dSignature); 274 return 0; 275 } 276 if (filesize < emh->nBytes) 277 { 278 WARN("File truncated (got %u bytes, header says %u)\n", emh->nBytes, filesize); 279 return 0; 280 } 281 282 if (!(metaObj = HeapAlloc( GetProcessHeap(), 0, sizeof(*metaObj) ))) return 0; 283 284 metaObj->emh = emh; 285 metaObj->on_disk = on_disk; 286 287 if (!(hmf = alloc_gdi_handle( metaObj, OBJ_ENHMETAFILE, NULL ))) 288 HeapFree( GetProcessHeap(), 0, metaObj ); 289 return hmf; 290 } 291 292 /**************************************************************************** 293 * EMF_Delete_HENHMETAFILE 294 */ 295 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf ) 296 { 297 ENHMETAFILEOBJ *metaObj; 298 BOOL Ret = FALSE; 299 300 EnterCriticalSection( &enhmetafile_cs ); 301 metaObj = free_gdi_handle( hmf ); 302 if(metaObj) 303 { 304 if(metaObj->on_disk) 305 UnmapViewOfFile( metaObj->emh ); 306 else 307 HeapFree( GetProcessHeap(), 0, metaObj->emh ); 308 HeapFree( GetProcessHeap(), 0, metaObj ); 309 Ret = TRUE; 310 } 311 LeaveCriticalSection( &enhmetafile_cs ); 312 return Ret; 313 } 314 315 /****************************************************************** 316 * EMF_GetEnhMetaHeader 317 * 318 * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE 319 */ 320 static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf ) 321 { 322 ENHMETAHEADER *ret = NULL; 323 ENHMETAFILEOBJ *metaObj; 324 325 EnterCriticalSection( &enhmetafile_cs ); 326 metaObj = GDI_GetObjPtr( hmf, OBJ_ENHMETAFILE ); 327 TRACE("hmf %p -> enhmetaObj %p\n", hmf, metaObj); 328 if (metaObj) 329 { 330 ret = metaObj->emh; 331 GDI_ReleaseObj( hmf ); 332 } 333 LeaveCriticalSection( &enhmetafile_cs ); 334 return ret; 335 } 336 337 /***************************************************************************** 338 * EMF_GetEnhMetaFile 339 * 340 */ 341 static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile ) 342 { 343 ENHMETAHEADER *emh; 344 HANDLE hMapping; 345 HENHMETAFILE hemf; 346 DWORD filesize; 347 348 filesize = GetFileSize( hFile, NULL ); 349 350 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); 351 emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 ); 352 CloseHandle( hMapping ); 353 354 if (!emh) return 0; 355 356 hemf = EMF_Create_HENHMETAFILE( emh, filesize, TRUE ); 357 if (!hemf) 358 UnmapViewOfFile( emh ); 359 return hemf; 360 } 361 362 363 /***************************************************************************** 364 * GetEnhMetaFileA (GDI32.@) 365 * 366 * 367 */ 368 HENHMETAFILE WINAPI GetEnhMetaFileA( 369 LPCSTR lpszMetaFile /* [in] filename of enhanced metafile */ 370 ) 371 { 372 HENHMETAFILE hmf; 373 HANDLE hFile; 374 375 hFile = CreateFileA(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0, 376 OPEN_EXISTING, 0, 0); 377 if (hFile == INVALID_HANDLE_VALUE) { 378 WARN("could not open %s\n", lpszMetaFile); 379 return 0; 380 } 381 hmf = EMF_GetEnhMetaFile( hFile ); 382 CloseHandle( hFile ); 383 return hmf; 384 } 385 386 /***************************************************************************** 387 * GetEnhMetaFileW (GDI32.@) 388 */ 389 HENHMETAFILE WINAPI GetEnhMetaFileW( 390 LPCWSTR lpszMetaFile) /* [in] filename of enhanced metafile */ 391 { 392 HENHMETAFILE hmf; 393 HANDLE hFile; 394 395 hFile = CreateFileW(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0, 396 OPEN_EXISTING, 0, 0); 397 if (hFile == INVALID_HANDLE_VALUE) { 398 WARN("could not open %s\n", debugstr_w(lpszMetaFile)); 399 return 0; 400 } 401 hmf = EMF_GetEnhMetaFile( hFile ); 402 CloseHandle( hFile ); 403 return hmf; 404 } 405 406 /***************************************************************************** 407 * GetEnhMetaFileHeader (GDI32.@) 408 * 409 * Retrieves the record containing the header for the specified 410 * enhanced-format metafile. 411 * 412 * RETURNS 413 * If buf is NULL, returns the size of buffer required. 414 * Otherwise, copy up to bufsize bytes of enhanced metafile header into 415 * buf. 416 */ 417 UINT WINAPI GetEnhMetaFileHeader( 418 HENHMETAFILE hmf, /* [in] enhanced metafile */ 419 UINT bufsize, /* [in] size of buffer */ 420 LPENHMETAHEADER buf /* [out] buffer */ 421 ) 422 { 423 LPENHMETAHEADER emh; 424 UINT size; 425 426 emh = EMF_GetEnhMetaHeader(hmf); 427 if(!emh) return FALSE; 428 size = emh->nSize; 429 if (!buf) return size; 430 size = min(size, bufsize); 431 memmove(buf, emh, size); 432 return size; 433 } 434 435 436 /***************************************************************************** 437 * GetEnhMetaFileDescriptionA (GDI32.@) 438 * 439 * See GetEnhMetaFileDescriptionW. 440 */ 441 UINT WINAPI GetEnhMetaFileDescriptionA( 442 HENHMETAFILE hmf, /* [in] enhanced metafile */ 443 UINT size, /* [in] size of buf */ 444 LPSTR buf /* [out] buffer to receive description */ 445 ) 446 { 447 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf); 448 DWORD len; 449 WCHAR *descrW; 450 451 if(!emh) return FALSE; 452 if(emh->nDescription == 0 || emh->offDescription == 0) return 0; 453 descrW = (WCHAR *) ((char *) emh + emh->offDescription); 454 len = WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, NULL, 0, NULL, NULL ); 455 456 if (!buf || !size ) return len; 457 458 len = min( size, len ); 459 WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, buf, len, NULL, NULL ); 460 return len; 461 } 462 463 /***************************************************************************** 464 * GetEnhMetaFileDescriptionW (GDI32.@) 465 * 466 * Copies the description string of an enhanced metafile into a buffer 467 * _buf_. 468 * 469 * RETURNS 470 * If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns 471 * number of characters copied. 472 */ 473 UINT WINAPI GetEnhMetaFileDescriptionW( 474 HENHMETAFILE hmf, /* [in] enhanced metafile */ 475 UINT size, /* [in] size of buf */ 476 LPWSTR buf /* [out] buffer to receive description */ 477 ) 478 { 479 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf); 480 481 if(!emh) return FALSE; 482 if(emh->nDescription == 0 || emh->offDescription == 0) return 0; 483 if (!buf || !size ) return emh->nDescription; 484 485 memmove(buf, (char *) emh + emh->offDescription, min(size,emh->nDescription)*sizeof(WCHAR)); 486 return min(size, emh->nDescription); 487 } 488 489 /**************************************************************************** 490 * SetEnhMetaFileBits (GDI32.@) 491 * 492 * Creates an enhanced metafile by copying _bufsize_ bytes from _buf_. 493 */ 494 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf) 495 { 496 ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize ); 497 HENHMETAFILE hmf; 498 memmove(emh, buf, bufsize); 499 hmf = EMF_Create_HENHMETAFILE( emh, bufsize, FALSE ); 500 if (!hmf) 501 HeapFree( GetProcessHeap(), 0, emh ); 502 return hmf; 503 } 504 505 /***************************************************************************** 506 * GetEnhMetaFileBits (GDI32.@) 507 * 508 */ 509 UINT WINAPI GetEnhMetaFileBits( 510 HENHMETAFILE hmf, 511 UINT bufsize, 512 LPBYTE buf 513 ) 514 { 515 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader( hmf ); 516 UINT size; 517 518 if(!emh) return 0; 519 520 size = emh->nBytes; 521 if( buf == NULL ) return size; 522 523 size = min( size, bufsize ); 524 memmove(buf, emh, size); 525 return size; 526 } 527 528 typedef struct EMF_dc_state 529 { 530 INT mode; 531 XFORM world_transform; 532 INT wndOrgX; 533 INT wndOrgY; 534 INT wndExtX; 535 INT wndExtY; 536 INT vportOrgX; 537 INT vportOrgY; 538 INT vportExtX; 539 INT vportExtY; 540 struct EMF_dc_state *next; 541 } EMF_dc_state; 542 543 typedef struct enum_emh_data 544 { 545 XFORM init_transform; 546 EMF_dc_state state; 547 INT save_level; 548 EMF_dc_state *saved_state; 549 } enum_emh_data; 550 551 #define ENUM_GET_PRIVATE_DATA(ht) \ 552 ((enum_emh_data*)(((unsigned char*)(ht))-sizeof (enum_emh_data))) 553 554 #define WIDTH(rect) ( (rect).right - (rect).left ) 555 #define HEIGHT(rect) ( (rect).bottom - (rect).top ) 556 557 #define IS_WIN9X() (GetVersion()&0x80000000) 558 559 static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info) 560 { 561 XFORM mapping_mode_trans, final_trans; 562 double scaleX, scaleY; 563 564 scaleX = (double)info->state.vportExtX / (double)info->state.wndExtX; 565 scaleY = (double)info->state.vportExtY / (double)info->state.wndExtY; 566 mapping_mode_trans.eM11 = scaleX; 567 mapping_mode_trans.eM12 = 0.0; 568 mapping_mode_trans.eM21 = 0.0; 569 mapping_mode_trans.eM22 = scaleY; 570 mapping_mode_trans.eDx = (double)info->state.vportOrgX - scaleX * (double)info->state.wndOrgX; 571 mapping_mode_trans.eDy = (double)info->state.vportOrgY - scaleY * (double)info->state.wndOrgY; 572 573 CombineTransform(&final_trans, &info->state.world_transform, &mapping_mode_trans); 574 CombineTransform(&final_trans, &final_trans, &info->init_transform); 575 576 if (!SetWorldTransform(hdc, &final_trans)) 577 { 578 ERR("World transform failed!\n"); 579 } 580 } 581 582 static void EMF_RestoreDC( enum_emh_data *info, INT level ) 583 { 584 if (abs(level) > info->save_level || level == 0) return; 585 586 if (level < 0) level = info->save_level + level + 1; 587 588 while (info->save_level >= level) 589 { 590 EMF_dc_state *state = info->saved_state; 591 info->saved_state = state->next; 592 state->next = NULL; 593 if (--info->save_level < level) 594 info->state = *state; 595 HeapFree( GetProcessHeap(), 0, state ); 596 } 597 } 598 599 static void EMF_SaveDC( enum_emh_data *info ) 600 { 601 EMF_dc_state *state = HeapAlloc( GetProcessHeap(), 0, sizeof(*state)); 602 if (state) 603 { 604 *state = info->state; 605 state->next = info->saved_state; 606 info->saved_state = state; 607 info->save_level++; 608 TRACE("save_level %d\n", info->save_level); 609 } 610 } 611 612 static void EMF_SetMapMode(HDC hdc, enum_emh_data *info) 613 { 614 INT horzSize = GetDeviceCaps( hdc, HORZSIZE ); 615 INT vertSize = GetDeviceCaps( hdc, VERTSIZE ); 616 INT horzRes = GetDeviceCaps( hdc, HORZRES ); 617 INT vertRes = GetDeviceCaps( hdc, VERTRES ); 618 619 TRACE("%d\n", info->state.mode); 620 621 switch(info->state.mode) 622 { 623 case MM_TEXT: 624 info->state.wndExtX = 1; 625 info->state.wndExtY = 1; 626 info->state.vportExtX = 1; 627 info->state.vportExtY = 1; 628 break; 629 case MM_LOMETRIC: 630 case MM_ISOTROPIC: 631 info->state.wndExtX = horzSize * 10; 632 info->state.wndExtY = vertSize * 10; 633 info->state.vportExtX = horzRes; 634 info->state.vportExtY = -vertRes; 635 break; 636 case MM_HIMETRIC: 637 info->state.wndExtX = horzSize * 100; 638 info->state.wndExtY = vertSize * 100; 639 info->state.vportExtX = horzRes; 640 info->state.vportExtY = -vertRes; 641 break; 642 case MM_LOENGLISH: 643 info->state.wndExtX = MulDiv(1000, horzSize, 254); 644 info->state.wndExtY = MulDiv(1000, vertSize, 254); 645 info->state.vportExtX = horzRes; 646 info->state.vportExtY = -vertRes; 647 break; 648 case MM_HIENGLISH: 649 info->state.wndExtX = MulDiv(10000, horzSize, 254); 650 info->state.wndExtY = MulDiv(10000, vertSize, 254); 651 info->state.vportExtX = horzRes; 652 info->state.vportExtY = -vertRes; 653 break; 654 case MM_TWIPS: 655 info->state.wndExtX = MulDiv(14400, horzSize, 254); 656 info->state.wndExtY = MulDiv(14400, vertSize, 254); 657 info->state.vportExtX = horzRes; 658 info->state.vportExtY = -vertRes; 659 break; 660 case MM_ANISOTROPIC: 661 break; 662 default: 663 return; 664 } 665 } 666 667 /*********************************************************************** 668 * EMF_FixIsotropic 669 * 670 * Fix viewport extensions for isotropic mode. 671 */ 672 673 static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info) 674 { 675 double xdim = fabs((double)info->state.vportExtX * GetDeviceCaps( hdc, HORZSIZE ) / 676 (GetDeviceCaps( hdc, HORZRES ) * info->state.wndExtX)); 677 double ydim = fabs((double)info->state.vportExtY * GetDeviceCaps( hdc, VERTSIZE ) / 678 (GetDeviceCaps( hdc, VERTRES ) * info->state.wndExtY)); 679 680 if (xdim > ydim) 681 { 682 INT mincx = (info->state.vportExtX >= 0) ? 1 : -1; 683 info->state.vportExtX = floor(info->state.vportExtX * ydim / xdim + 0.5); 684 if (!info->state.vportExtX) info->state.vportExtX = mincx; 685 } 686 else 687 { 688 INT mincy = (info->state.vportExtY >= 0) ? 1 : -1; 689 info->state.vportExtY = floor(info->state.vportExtY * xdim / ydim + 0.5); 690 if (!info->state.vportExtY) info->state.vportExtY = mincy; 691 } 692 } 693 694 /***************************************************************************** 695 * emr_produces_output 696 * 697 * Returns TRUE if the record type writes something to the dc. Used by 698 * PlayEnhMetaFileRecord to determine whether it needs to update the 699 * dc's xform when in win9x mode. 700 * 701 * FIXME: need to test which records should be here. 702 */ 703 static BOOL emr_produces_output(int type) 704 { 705 switch(type) { 706 case EMR_POLYBEZIER: 707 case EMR_POLYGON: 708 case EMR_POLYLINE: 709 case EMR_POLYBEZIERTO: 710 case EMR_POLYLINETO: 711 case EMR_POLYPOLYLINE: 712 case EMR_POLYPOLYGON: 713 case EMR_SETPIXELV: 714 case EMR_MOVETOEX: 715 case EMR_EXCLUDECLIPRECT: 716 case EMR_INTERSECTCLIPRECT: 717 case EMR_SELECTOBJECT: 718 case EMR_ANGLEARC: 719 case EMR_ELLIPSE: 720 case EMR_RECTANGLE: 721 case EMR_ROUNDRECT: 722 case EMR_ARC: 723 case EMR_CHORD: 724 case EMR_PIE: 725 case EMR_EXTFLOODFILL: 726 case EMR_LINETO: 727 case EMR_ARCTO: 728 case EMR_POLYDRAW: 729 case EMR_GDICOMMENT: 730 case EMR_FILLRGN: 731 case EMR_FRAMERGN: 732 case EMR_INVERTRGN: 733 case EMR_PAINTRGN: 734 case EMR_BITBLT: 735 case EMR_STRETCHBLT: 736 case EMR_MASKBLT: 737 case EMR_PLGBLT: 738 case EMR_SETDIBITSTODEVICE: 739 case EMR_STRETCHDIBITS: 740 case EMR_EXTTEXTOUTA: 741 case EMR_EXTTEXTOUTW: 742 case EMR_POLYBEZIER16: 743 case EMR_POLYGON16: 744 case EMR_POLYLINE16: 745 case EMR_POLYBEZIERTO16: 746 case EMR_POLYLINETO16: 747 case EMR_POLYPOLYLINE16: 748 case EMR_POLYPOLYGON16: 749 case EMR_POLYDRAW16: 750 case EMR_POLYTEXTOUTA: 751 case EMR_POLYTEXTOUTW: 752 case EMR_SMALLTEXTOUT: 753 case EMR_ALPHABLEND: 754 case EMR_TRANSPARENTBLT: 755 return TRUE; 756 default: 757 return FALSE; 758 } 759 } 760 761 762 /***************************************************************************** 763 * PlayEnhMetaFileRecord (GDI32.@) 764 * 765 * Render a single enhanced metafile record in the device context hdc. 766 * 767 * RETURNS 768 * TRUE (non zero) on success, FALSE on error. 769 * BUGS 770 * Many unimplemented records. 771 * No error handling on record play failures (ie checking return codes) 772 * 773 * NOTES 774 * WinNT actually updates the current world transform in this function 775 * whereas Win9x does not. 776 */ 777 BOOL WINAPI PlayEnhMetaFileRecord( 778 HDC hdc, /* [in] device context in which to render EMF record */ 779 LPHANDLETABLE handletable, /* [in] array of handles to be used in rendering record */ 780 const ENHMETARECORD *mr, /* [in] EMF record to render */ 781 UINT handles /* [in] size of handle array */ 782 ) 783 { 784 int type; 785 RECT tmprc; 786 enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable); 787 788 TRACE("hdc = %p, handletable = %p, record = %p, numHandles = %d\n", 789 hdc, handletable, mr, handles); 790 if (!mr) return FALSE; 791 792 type = mr->iType; 793 794 TRACE("record %s\n", get_emr_name(type)); 795 switch(type) 796 { 797 case EMR_HEADER: 798 break; 799 case EMR_EOF: 800 break; 801 case EMR_GDICOMMENT: 802 { 803 const EMRGDICOMMENT *lpGdiComment = (const EMRGDICOMMENT *)mr; 804 /* In an enhanced metafile, there can be both public and private GDI comments */ 805 GdiComment( hdc, lpGdiComment->cbData, lpGdiComment->Data ); 806 break; 807 } 808 case EMR_SETMAPMODE: 809 { 810 const EMRSETMAPMODE *pSetMapMode = (const EMRSETMAPMODE *)mr; 811 812 if (info->state.mode == pSetMapMode->iMode && 813 (info->state.mode == MM_ISOTROPIC || info->state.mode == MM_ANISOTROPIC)) 814 break; 815 info->state.mode = pSetMapMode->iMode; 816 EMF_SetMapMode(hdc, info); 817 818 if (!IS_WIN9X()) 819 EMF_Update_MF_Xform(hdc, info); 820 821 break; 822 } 823 case EMR_SETBKMODE: 824 { 825 const EMRSETBKMODE *pSetBkMode = (const EMRSETBKMODE *)mr; 826 SetBkMode(hdc, pSetBkMode->iMode); 827 break; 828 } 829 case EMR_SETBKCOLOR: 830 { 831 const EMRSETBKCOLOR *pSetBkColor = (const EMRSETBKCOLOR *)mr; 832 SetBkColor(hdc, pSetBkColor->crColor); 833 break; 834 } 835 case EMR_SETPOLYFILLMODE: 836 { 837 const EMRSETPOLYFILLMODE *pSetPolyFillMode = (const EMRSETPOLYFILLMODE *)mr; 838 SetPolyFillMode(hdc, pSetPolyFillMode->iMode); 839 break; 840 } 841 case EMR_SETROP2: 842 { 843 const EMRSETROP2 *pSetROP2 = (const EMRSETROP2 *)mr; 844 SetROP2(hdc, pSetROP2->iMode); 845 break; 846 } 847 case EMR_SETSTRETCHBLTMODE: 848 { 849 const EMRSETSTRETCHBLTMODE *pSetStretchBltMode = (const EMRSETSTRETCHBLTMODE *)mr; 850 SetStretchBltMode(hdc, pSetStretchBltMode->iMode); 851 break; 852 } 853 case EMR_SETTEXTALIGN: 854 { 855 const EMRSETTEXTALIGN *pSetTextAlign = (const EMRSETTEXTALIGN *)mr; 856 SetTextAlign(hdc, pSetTextAlign->iMode); 857 break; 858 } 859 case EMR_SETTEXTCOLOR: 860 { 861 const EMRSETTEXTCOLOR *pSetTextColor = (const EMRSETTEXTCOLOR *)mr; 862 SetTextColor(hdc, pSetTextColor->crColor); 863 break; 864 } 865 case EMR_SAVEDC: 866 { 867 if (SaveDC( hdc )) 868 EMF_SaveDC( info ); 869 break; 870 } 871 case EMR_RESTOREDC: 872 { 873 const EMRRESTOREDC *pRestoreDC = (const EMRRESTOREDC *)mr; 874 TRACE("EMR_RESTORE: %d\n", pRestoreDC->iRelative); 875 if (RestoreDC( hdc, pRestoreDC->iRelative )) 876 EMF_RestoreDC( info, pRestoreDC->iRelative ); 877 break; 878 } 879 case EMR_INTERSECTCLIPRECT: 880 { 881 const EMRINTERSECTCLIPRECT *pClipRect = (const EMRINTERSECTCLIPRECT *)mr; 882 TRACE("EMR_INTERSECTCLIPRECT: rect %d,%d - %d, %d\n", 883 pClipRect->rclClip.left, pClipRect->rclClip.top, 884 pClipRect->rclClip.right, pClipRect->rclClip.bottom); 885 IntersectClipRect(hdc, pClipRect->rclClip.left, pClipRect->rclClip.top, 886 pClipRect->rclClip.right, pClipRect->rclClip.bottom); 887 break; 888 } 889 case EMR_SELECTOBJECT: 890 { 891 const EMRSELECTOBJECT *pSelectObject = (const EMRSELECTOBJECT *)mr; 892 if( pSelectObject->ihObject & 0x80000000 ) { 893 /* High order bit is set - it's a stock object 894 * Strip the high bit to get the index. 895 * See MSDN article Q142319 896 */ 897 SelectObject( hdc, GetStockObject( pSelectObject->ihObject & 898 0x7fffffff ) ); 899 } else { 900 /* High order bit wasn't set - not a stock object 901 */ 902 SelectObject( hdc, 903 (handletable->objectHandle)[pSelectObject->ihObject] ); 904 } 905 break; 906 } 907 case EMR_DELETEOBJECT: 908 { 909 const EMRDELETEOBJECT *pDeleteObject = (const EMRDELETEOBJECT *)mr; 910 DeleteObject( (handletable->objectHandle)[pDeleteObject->ihObject]); 911 (handletable->objectHandle)[pDeleteObject->ihObject] = 0; 912 break; 913 } 914 case EMR_SETWINDOWORGEX: 915 { 916 const EMRSETWINDOWORGEX *pSetWindowOrgEx = (const EMRSETWINDOWORGEX *)mr; 917 918 info->state.wndOrgX = pSetWindowOrgEx->ptlOrigin.x; 919 info->state.wndOrgY = pSetWindowOrgEx->ptlOrigin.y; 920 921 TRACE("SetWindowOrgEx: %d,%d\n", info->state.wndOrgX, info->state.wndOrgY); 922 923 if (!IS_WIN9X()) 924 EMF_Update_MF_Xform(hdc, info); 925 926 break; 927 } 928 case EMR_SETWINDOWEXTEX: 929 { 930 const EMRSETWINDOWEXTEX *pSetWindowExtEx = (const EMRSETWINDOWEXTEX *)mr; 931 932 if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC) 933 break; 934 info->state.wndExtX = pSetWindowExtEx->szlExtent.cx; 935 info->state.wndExtY = pSetWindowExtEx->szlExtent.cy; 936 if (info->state.mode == MM_ISOTROPIC) 937 EMF_FixIsotropic(hdc, info); 938 939 TRACE("SetWindowExtEx: %d,%d\n",info->state.wndExtX, info->state.wndExtY); 940 941 if (!IS_WIN9X()) 942 EMF_Update_MF_Xform(hdc, info); 943 944 break; 945 } 946 case EMR_SETVIEWPORTORGEX: 947 { 948 const EMRSETVIEWPORTORGEX *pSetViewportOrgEx = (const EMRSETVIEWPORTORGEX *)mr; 949 950 info->state.vportOrgX = pSetViewportOrgEx->ptlOrigin.x; 951 info->state.vportOrgY = pSetViewportOrgEx->ptlOrigin.y; 952 TRACE("SetViewportOrgEx: %d,%d\n", info->state.vportOrgX, info->state.vportOrgY); 953 954 if (!IS_WIN9X()) 955 EMF_Update_MF_Xform(hdc, info); 956 957 break; 958 } 959 case EMR_SETVIEWPORTEXTEX: 960 { 961 const EMRSETVIEWPORTEXTEX *pSetViewportExtEx = (const EMRSETVIEWPORTEXTEX *)mr; 962 963 if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC) 964 break; 965 info->state.vportExtX = pSetViewportExtEx->szlExtent.cx; 966 info->state.vportExtY = pSetViewportExtEx->szlExtent.cy; 967 if (info->state.mode == MM_ISOTROPIC) 968 EMF_FixIsotropic(hdc, info); 969 TRACE("SetViewportExtEx: %d,%d\n", info->state.vportExtX, info->state.vportExtY); 970 971 if (!IS_WIN9X()) 972 EMF_Update_MF_Xform(hdc, info); 973 974 break; 975 } 976 case EMR_CREATEPEN: 977 { 978 const EMRCREATEPEN *pCreatePen = (const EMRCREATEPEN *)mr; 979 (handletable->objectHandle)[pCreatePen->ihPen] = 980 CreatePenIndirect(&pCreatePen->lopn); 981 break; 982 } 983 case EMR_EXTCREATEPEN: 984 { 985 const EMREXTCREATEPEN *pPen = (const EMREXTCREATEPEN *)mr; 986 LOGBRUSH lb; 987 lb.lbStyle = pPen->elp.elpBrushStyle; 988 lb.lbColor = pPen->elp.elpColor; 989 lb.lbHatch = pPen->elp.elpHatch; 990 991 if(pPen->offBmi || pPen->offBits) 992 FIXME("EMR_EXTCREATEPEN: Need to copy brush bitmap\n"); 993 994 (handletable->objectHandle)[pPen->ihPen] = 995 ExtCreatePen(pPen->elp.elpPenStyle, pPen->elp.elpWidth, &lb, 996 pPen->elp.elpNumEntries, pPen->elp.elpNumEntries ? pPen->elp.elpStyleEntry : NULL); 997 break; 998 } 999 case EMR_CREATEBRUSHINDIRECT: 1000 { 1001 const EMRCREATEBRUSHINDIRECT *pBrush = (const EMRCREATEBRUSHINDIRECT *)mr; 1002 LOGBRUSH brush; 1003 brush.lbStyle = pBrush->lb.lbStyle; 1004 brush.lbColor = pBrush->lb.lbColor; 1005 brush.lbHatch = pBrush->lb.lbHatch; 1006 (handletable->objectHandle)[pBrush->ihBrush] = CreateBrushIndirect(&brush); 1007 break; 1008 } 1009 case EMR_EXTCREATEFONTINDIRECTW: 1010 { 1011 const EMREXTCREATEFONTINDIRECTW *pFont = (const EMREXTCREATEFONTINDIRECTW *)mr; 1012 (handletable->objectHandle)[pFont->ihFont] = 1013 CreateFontIndirectW(&pFont->elfw.elfLogFont); 1014 break; 1015 } 1016 case EMR_MOVETOEX: 1017 { 1018 const EMRMOVETOEX *pMoveToEx = (const EMRMOVETOEX *)mr; 1019 MoveToEx(hdc, pMoveToEx->ptl.x, pMoveToEx->ptl.y, NULL); 1020 break; 1021 } 1022 case EMR_LINETO: 1023 { 1024 const EMRLINETO *pLineTo = (const EMRLINETO *)mr; 1025 LineTo(hdc, pLineTo->ptl.x, pLineTo->ptl.y); 1026 break; 1027 } 1028 case EMR_RECTANGLE: 1029 { 1030 const EMRRECTANGLE *pRect = (const EMRRECTANGLE *)mr; 1031 Rectangle(hdc, pRect->rclBox.left, pRect->rclBox.top, 1032 pRect->rclBox.right, pRect->rclBox.bottom); 1033 break; 1034 } 1035 case EMR_ELLIPSE: 1036 { 1037 const EMRELLIPSE *pEllipse = (const EMRELLIPSE *)mr; 1038 Ellipse(hdc, pEllipse->rclBox.left, pEllipse->rclBox.top, 1039 pEllipse->rclBox.right, pEllipse->rclBox.bottom); 1040 break; 1041 } 1042 case EMR_POLYGON16: 1043 { 1044 const EMRPOLYGON16 *pPoly = (const EMRPOLYGON16 *)mr; 1045 /* Shouldn't use Polygon16 since pPoly->cpts is DWORD */ 1046 POINT *pts = HeapAlloc( GetProcessHeap(), 0, 1047 pPoly->cpts * sizeof(POINT) ); 1048 DWORD i; 1049 for(i = 0; i < pPoly->cpts; i++) 1050 { 1051 pts[i].x = pPoly->apts[i].x; 1052 pts[i].y = pPoly->apts[i].y; 1053 } 1054 Polygon(hdc, pts, pPoly->cpts); 1055 HeapFree( GetProcessHeap(), 0, pts ); 1056 break; 1057 } 1058 case EMR_POLYLINE16: 1059 { 1060 const EMRPOLYLINE16 *pPoly = (const EMRPOLYLINE16 *)mr; 1061 /* Shouldn't use Polyline16 since pPoly->cpts is DWORD */ 1062 POINT *pts = HeapAlloc( GetProcessHeap(), 0, 1063 pPoly->cpts * sizeof(POINT) ); 1064 DWORD i; 1065 for(i = 0; i < pPoly->cpts; i++) 1066 { 1067 pts[i].x = pPoly->apts[i].x; 1068 pts[i].y = pPoly->apts[i].y; 1069 } 1070 Polyline(hdc, pts, pPoly->cpts); 1071 HeapFree( GetProcessHeap(), 0, pts ); 1072 break; 1073 } 1074 case EMR_POLYLINETO16: 1075 { 1076 const EMRPOLYLINETO16 *pPoly = (const EMRPOLYLINETO16 *)mr; 1077 /* Shouldn't use PolylineTo16 since pPoly->cpts is DWORD */ 1078 POINT *pts = HeapAlloc( GetProcessHeap(), 0, 1079 pPoly->cpts * sizeof(POINT) ); 1080 DWORD i; 1081 for(i = 0; i < pPoly->cpts; i++) 1082 { 1083 pts[i].x = pPoly->apts[i].x; 1084 pts[i].y = pPoly->apts[i].y; 1085 } 1086 PolylineTo(hdc, pts, pPoly->cpts); 1087 HeapFree( GetProcessHeap(), 0, pts ); 1088 break; 1089 } 1090 case EMR_POLYBEZIER16: 1091 { 1092 const EMRPOLYBEZIER16 *pPoly = (const EMRPOLYBEZIER16 *)mr; 1093 /* Shouldn't use PolyBezier16 since pPoly->cpts is DWORD */ 1094 POINT *pts = HeapAlloc( GetProcessHeap(), 0, 1095 pPoly->cpts * sizeof(POINT) ); 1096 DWORD i; 1097 for(i = 0; i < pPoly->cpts; i++) 1098 { 1099 pts[i].x = pPoly->apts[i].x; 1100 pts[i].y = pPoly->apts[i].y; 1101 } 1102 PolyBezier(hdc, pts, pPoly->cpts); 1103 HeapFree( GetProcessHeap(), 0, pts ); 1104 break; 1105 } 1106 case EMR_POLYBEZIERTO16: 1107 { 1108 const EMRPOLYBEZIERTO16 *pPoly = (const EMRPOLYBEZIERTO16 *)mr; 1109 /* Shouldn't use PolyBezierTo16 since pPoly->cpts is DWORD */ 1110 POINT *pts = HeapAlloc( GetProcessHeap(), 0, 1111 pPoly->cpts * sizeof(POINT) ); 1112 DWORD i; 1113 for(i = 0; i < pPoly->cpts; i++) 1114 { 1115 pts[i].x = pPoly->apts[i].x; 1116 pts[i].y = pPoly->apts[i].y; 1117 } 1118 PolyBezierTo(hdc, pts, pPoly->cpts); 1119 HeapFree( GetProcessHeap(), 0, pts ); 1120 break; 1121 } 1122 case EMR_POLYPOLYGON16: 1123 { 1124 const EMRPOLYPOLYGON16 *pPolyPoly = (const EMRPOLYPOLYGON16 *)mr; 1125 /* NB POINTS array doesn't start at pPolyPoly->apts it's actually 1126 pPolyPoly->aPolyCounts + pPolyPoly->nPolys */ 1127 1128 const POINTS *pts = (const POINTS *)(pPolyPoly->aPolyCounts + pPolyPoly->nPolys); 1129 POINT *pt = HeapAlloc( GetProcessHeap(), 0, pPolyPoly->cpts * sizeof(POINT) ); 1130 DWORD i; 1131 for(i = 0; i < pPolyPoly->cpts; i++) 1132 { 1133 pt[i].x = pts[i].x; 1134 pt[i].y = pts[i].y; 1135 } 1136 PolyPolygon(hdc, pt, (const INT*)pPolyPoly->aPolyCounts, pPolyPoly->nPolys); 1137 HeapFree( GetProcessHeap(), 0, pt ); 1138 break; 1139 } 1140 case EMR_POLYPOLYLINE16: 1141 { 1142 const EMRPOLYPOLYLINE16 *pPolyPoly = (const EMRPOLYPOLYLINE16 *)mr; 1143 /* NB POINTS array doesn't start at pPolyPoly->apts it's actually 1144 pPolyPoly->aPolyCounts + pPolyPoly->nPolys */ 1145 1146 const POINTS *pts = (const POINTS *)(pPolyPoly->aPolyCounts + pPolyPoly->nPolys); 1147 POINT *pt = HeapAlloc( GetProcessHeap(), 0, pPolyPoly->cpts * sizeof(POINT) ); 1148 DWORD i; 1149 for(i = 0; i < pPolyPoly->cpts; i++) 1150 { 1151 pt[i].x = pts[i].x; 1152 pt[i].y = pts[i].y; 1153 } 1154 PolyPolyline(hdc, pt, pPolyPoly->aPolyCounts, pPolyPoly->nPolys); 1155 HeapFree( GetProcessHeap(), 0, pt ); 1156 break; 1157 } 1158 1159 case EMR_POLYDRAW16: 1160 { 1161 const EMRPOLYDRAW16 *pPolyDraw16 = (const EMRPOLYDRAW16 *)mr; 1162 const POINTS *ptl = pPolyDraw16->apts; 1163 POINT *pts = HeapAlloc(GetProcessHeap(), 0, pPolyDraw16->cpts * sizeof(POINT)); 1164 DWORD i; 1165 1166 /* NB abTypes array doesn't start at pPolyDraw16->abTypes. It's actually 1167 pPolyDraw16->apts + pPolyDraw16->cpts. */ 1168 const BYTE *types = (BYTE*)(pPolyDraw16->apts + pPolyDraw16->cpts); 1169 1170 if (!pts) 1171 break; 1172 1173 for (i = 0; i < pPolyDraw16->cpts; ++i) 1174 { 1175 pts[i].x = ptl[i].x; 1176 pts[i].y = ptl[i].y; 1177 } 1178 1179 PolyDraw(hdc, pts, types, pPolyDraw16->cpts); 1180 HeapFree(GetProcessHeap(), 0, pts); 1181 break; 1182 } 1183 1184 case EMR_STRETCHDIBITS: 1185 { 1186 const EMRSTRETCHDIBITS *pStretchDIBits = (const EMRSTRETCHDIBITS *)mr; 1187 1188 StretchDIBits(hdc, 1189 pStretchDIBits->xDest, 1190 pStretchDIBits->yDest, 1191 pStretchDIBits->cxDest, 1192 pStretchDIBits->cyDest, 1193 pStretchDIBits->xSrc, 1194 pStretchDIBits->ySrc, 1195 pStretchDIBits->cxSrc, 1196 pStretchDIBits->cySrc, 1197 (const BYTE *)mr + pStretchDIBits->offBitsSrc, 1198 (const BITMAPINFO *)((const BYTE *)mr + pStretchDIBits->offBmiSrc), 1199 pStretchDIBits->iUsageSrc, 1200 pStretchDIBits->dwRop); 1201 break; 1202 } 1203 1204 case EMR_EXTTEXTOUTA: 1205 { 1206 const EMREXTTEXTOUTA *pExtTextOutA = (const EMREXTTEXTOUTA *)mr; 1207 RECT rc; 1208 const INT *dx = NULL; 1209 int old_mode; 1210 1211 rc.left = pExtTextOutA->emrtext.rcl.left; 1212 rc.top = pExtTextOutA->emrtext.rcl.top; 1213 rc.right = pExtTextOutA->emrtext.rcl.right; 1214 rc.bottom = pExtTextOutA->emrtext.rcl.bottom; 1215 TRACE("EMR_EXTTEXTOUTA: x,y = %d, %d. rect = %s. flags %08x\n", 1216 pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y, 1217 wine_dbgstr_rect(&rc), pExtTextOutA->emrtext.fOptions); 1218 1219 old_mode = SetGraphicsMode(hdc, pExtTextOutA->iGraphicsMode); 1220 /* Reselect the font back into the dc so that the transformation 1221 gets updated. */ 1222 SelectObject(hdc, GetCurrentObject(hdc, OBJ_FONT)); 1223 1224 /* Linux version of pstoedit produces EMFs with offDx set to 0. 1225 * These files can be enumerated and played under Win98 just 1226 * fine, but at least Win2k chokes on them. 1227 */ 1228 if (pExtTextOutA->emrtext.offDx) 1229 dx = (const INT *)((const BYTE *)mr + pExtTextOutA->emrtext.offDx); 1230 1231 ExtTextOutA(hdc, pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y, 1232 pExtTextOutA->emrtext.fOptions, &rc, 1233 (LPCSTR)((const BYTE *)mr + pExtTextOutA->emrtext.offString), pExtTextOutA->emrtext.nChars, 1234 dx); 1235 1236 SetGraphicsMode(hdc, old_mode); 1237 break; 1238 } 1239 1240 case EMR_EXTTEXTOUTW: 1241 { 1242 const EMREXTTEXTOUTW *pExtTextOutW = (const EMREXTTEXTOUTW *)mr; 1243 RECT rc; 1244 const INT *dx = NULL; 1245 int old_mode; 1246 1247 rc.left = pExtTextOutW->emrtext.rcl.left; 1248 rc.top = pExtTextOutW->emrtext.rcl.top; 1249 rc.right = pExtTextOutW->emrtext.rcl.right; 1250 rc.bottom = pExtTextOutW->emrtext.rcl.bottom; 1251 TRACE("EMR_EXTTEXTOUTW: x,y = %d, %d. rect = %s. flags %08x\n", 1252 pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y, 1253 wine_dbgstr_rect(&rc), pExtTextOutW->emrtext.fOptions); 1254 1255 old_mode = SetGraphicsMode(hdc, pExtTextOutW->iGraphicsMode); 1256 /* Reselect the font back into the dc so that the transformation 1257 gets updated. */ 1258 SelectObject(hdc, GetCurrentObject(hdc, OBJ_FONT)); 1259 1260 /* Linux version of pstoedit produces EMFs with offDx set to 0. 1261 * These files can be enumerated and played under Win98 just 1262 * fine, but at least Win2k chokes on them. 1263 */ 1264 if (pExtTextOutW->emrtext.offDx) 1265 dx = (const INT *)((const BYTE *)mr + pExtTextOutW->emrtext.offDx); 1266 1267 ExtTextOutW(hdc, pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y, 1268 pExtTextOutW->emrtext.fOptions, &rc, 1269 (LPCWSTR)((const BYTE *)mr + pExtTextOutW->emrtext.offString), pExtTextOutW->emrtext.nChars, 1270 dx); 1271 1272 SetGraphicsMode(hdc, old_mode); 1273 break; 1274 } 1275 1276 case EMR_CREATEPALETTE: 1277 { 1278 const EMRCREATEPALETTE *lpCreatePal = (const EMRCREATEPALETTE *)mr; 1279 1280 (handletable->objectHandle)[ lpCreatePal->ihPal ] = 1281 CreatePalette( &lpCreatePal->lgpl ); 1282 1283 break; 1284 } 1285 1286 case EMR_SELECTPALETTE: 1287 { 1288 const EMRSELECTPALETTE *lpSelectPal = (const EMRSELECTPALETTE *)mr; 1289 1290 if( lpSelectPal->ihPal & 0x80000000 ) { 1291 SelectPalette( hdc, GetStockObject(lpSelectPal->ihPal & 0x7fffffff), TRUE); 1292 } else { 1293 SelectPalette( hdc, (handletable->objectHandle)[lpSelectPal->ihPal], TRUE); 1294 } 1295 break; 1296 } 1297 1298 case EMR_REALIZEPALETTE: 1299 { 1300 RealizePalette( hdc ); 1301 break; 1302 } 1303 1304 case EMR_EXTSELECTCLIPRGN: 1305 { 1306 const EMREXTSELECTCLIPRGN *lpRgn = (const EMREXTSELECTCLIPRGN *)mr; 1307 #ifdef __REACTOS__ 1308 const RGNDATA *pRgnData = (const RGNDATA *)lpRgn->RgnData; 1309 DWORD dwSize = sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT); 1310 #endif 1311 HRGN hRgn = 0; 1312 1313 if (mr->nSize >= sizeof(*lpRgn) + sizeof(RGNDATAHEADER)) 1314 #ifdef __REACTOS__ 1315 hRgn = ExtCreateRegion( &info->init_transform, dwSize, pRgnData ); 1316 #else 1317 hRgn = ExtCreateRegion( &info->init_transform, 0, (const RGNDATA *)lpRgn->RgnData ); 1318 #endif 1319 ExtSelectClipRgn(hdc, hRgn, (INT)(lpRgn->iMode)); 1320 /* ExtSelectClipRgn created a copy of the region */ 1321 DeleteObject(hRgn); 1322 break; 1323 } 1324 1325 case EMR_SETMETARGN: 1326 { 1327 SetMetaRgn( hdc ); 1328 break; 1329 } 1330 1331 case EMR_SETWORLDTRANSFORM: 1332 { 1333 const EMRSETWORLDTRANSFORM *lpXfrm = (const EMRSETWORLDTRANSFORM *)mr; 1334 info->state.world_transform = lpXfrm->xform; 1335 1336 if (!IS_WIN9X()) 1337 EMF_Update_MF_Xform(hdc, info); 1338 1339 break; 1340 } 1341 1342 case EMR_POLYBEZIER: 1343 { 1344 const EMRPOLYBEZIER *lpPolyBez = (const EMRPOLYBEZIER *)mr; 1345 PolyBezier(hdc, (const POINT*)lpPolyBez->aptl, (UINT)lpPolyBez->cptl); 1346 break; 1347 } 1348 1349 case EMR_POLYGON: 1350 { 1351 const EMRPOLYGON *lpPoly = (const EMRPOLYGON *)mr; 1352 Polygon( hdc, (const POINT*)lpPoly->aptl, (UINT)lpPoly->cptl ); 1353 break; 1354 } 1355 1356 case EMR_POLYLINE: 1357 { 1358 const EMRPOLYLINE *lpPolyLine = (const EMRPOLYLINE *)mr; 1359 Polyline(hdc, (const POINT*)lpPolyLine->aptl, (UINT)lpPolyLine->cptl); 1360 break; 1361 } 1362 1363 case EMR_POLYBEZIERTO: 1364 { 1365 const EMRPOLYBEZIERTO *lpPolyBezierTo = (const EMRPOLYBEZIERTO *)mr; 1366 PolyBezierTo( hdc, (const POINT*)lpPolyBezierTo->aptl, 1367 (UINT)lpPolyBezierTo->cptl ); 1368 break; 1369 } 1370 1371 case EMR_POLYLINETO: 1372 { 1373 const EMRPOLYLINETO *lpPolyLineTo = (const EMRPOLYLINETO *)mr; 1374 PolylineTo( hdc, (const POINT*)lpPolyLineTo->aptl, 1375 (UINT)lpPolyLineTo->cptl ); 1376 break; 1377 } 1378 1379 case EMR_POLYPOLYLINE: 1380 { 1381 const EMRPOLYPOLYLINE *pPolyPolyline = (const EMRPOLYPOLYLINE *)mr; 1382 /* NB Points at pPolyPolyline->aPolyCounts + pPolyPolyline->nPolys */ 1383 1384 PolyPolyline(hdc, (const POINT*)(pPolyPolyline->aPolyCounts + 1385 pPolyPolyline->nPolys), 1386 pPolyPolyline->aPolyCounts, 1387 pPolyPolyline->nPolys ); 1388 1389 break; 1390 } 1391 1392 case EMR_POLYPOLYGON: 1393 { 1394 const EMRPOLYPOLYGON *pPolyPolygon = (const EMRPOLYPOLYGON *)mr; 1395 1396 /* NB Points at pPolyPolygon->aPolyCounts + pPolyPolygon->nPolys */ 1397 1398 PolyPolygon(hdc, (const POINT*)(pPolyPolygon->aPolyCounts + 1399 pPolyPolygon->nPolys), 1400 (const INT*)pPolyPolygon->aPolyCounts, pPolyPolygon->nPolys ); 1401 break; 1402 } 1403 1404 case EMR_SETBRUSHORGEX: 1405 { 1406 const EMRSETBRUSHORGEX *lpSetBrushOrgEx = (const EMRSETBRUSHORGEX *)mr; 1407 1408 SetBrushOrgEx( hdc, 1409 (INT)lpSetBrushOrgEx->ptlOrigin.x, 1410 (INT)lpSetBrushOrgEx->ptlOrigin.y, 1411 NULL ); 1412 1413 break; 1414 } 1415 1416 case EMR_SETPIXELV: 1417 { 1418 const EMRSETPIXELV *lpSetPixelV = (const EMRSETPIXELV *)mr; 1419 1420 SetPixelV( hdc, 1421 (INT)lpSetPixelV->ptlPixel.x, 1422 (INT)lpSetPixelV->ptlPixel.y, 1423 lpSetPixelV->crColor ); 1424 1425 break; 1426 } 1427 1428 case EMR_SETMAPPERFLAGS: 1429 { 1430 const EMRSETMAPPERFLAGS *lpSetMapperFlags = (const EMRSETMAPPERFLAGS *)mr; 1431 1432 SetMapperFlags( hdc, lpSetMapperFlags->dwFlags ); 1433 1434 break; 1435 } 1436 1437 case EMR_SETCOLORADJUSTMENT: 1438 { 1439 const EMRSETCOLORADJUSTMENT *lpSetColorAdjust = (const EMRSETCOLORADJUSTMENT *)mr; 1440 1441 SetColorAdjustment( hdc, &lpSetColorAdjust->ColorAdjustment ); 1442 1443 break; 1444 } 1445 1446 case EMR_OFFSETCLIPRGN: 1447 { 1448 const EMROFFSETCLIPRGN *lpOffsetClipRgn = (const EMROFFSETCLIPRGN *)mr; 1449 1450 OffsetClipRgn( hdc, 1451 (INT)lpOffsetClipRgn->ptlOffset.x, 1452 (INT)lpOffsetClipRgn->ptlOffset.y ); 1453 FIXME("OffsetClipRgn\n"); 1454 1455 break; 1456 } 1457 1458 case EMR_EXCLUDECLIPRECT: 1459 { 1460 const EMREXCLUDECLIPRECT *lpExcludeClipRect = (const EMREXCLUDECLIPRECT *)mr; 1461 1462 ExcludeClipRect( hdc, 1463 lpExcludeClipRect->rclClip.left, 1464 lpExcludeClipRect->rclClip.top, 1465 lpExcludeClipRect->rclClip.right, 1466 lpExcludeClipRect->rclClip.bottom ); 1467 FIXME("ExcludeClipRect\n"); 1468 1469 break; 1470 } 1471 1472 case EMR_SCALEVIEWPORTEXTEX: 1473 { 1474 const EMRSCALEVIEWPORTEXTEX *lpScaleViewportExtEx = (const EMRSCALEVIEWPORTEXTEX *)mr; 1475 1476 if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC)) 1477 break; 1478 if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom || 1479 !lpScaleViewportExtEx->yNum || !lpScaleViewportExtEx->yDenom) 1480 break; 1481 info->state.vportExtX = MulDiv(info->state.vportExtX, lpScaleViewportExtEx->xNum, 1482 lpScaleViewportExtEx->xDenom); 1483 info->state.vportExtY = MulDiv(info->state.vportExtY, lpScaleViewportExtEx->yNum, 1484 lpScaleViewportExtEx->yDenom); 1485 if (info->state.vportExtX == 0) info->state.vportExtX = 1; 1486 if (info->state.vportExtY == 0) info->state.vportExtY = 1; 1487 if (info->state.mode == MM_ISOTROPIC) 1488 EMF_FixIsotropic(hdc, info); 1489 1490 TRACE("EMRSCALEVIEWPORTEXTEX %d/%d %d/%d\n", 1491 lpScaleViewportExtEx->xNum,lpScaleViewportExtEx->xDenom, 1492 lpScaleViewportExtEx->yNum,lpScaleViewportExtEx->yDenom); 1493 1494 if (!IS_WIN9X()) 1495 EMF_Update_MF_Xform(hdc, info); 1496 1497 break; 1498 } 1499 1500 case EMR_SCALEWINDOWEXTEX: 1501 { 1502 const EMRSCALEWINDOWEXTEX *lpScaleWindowExtEx = (const EMRSCALEWINDOWEXTEX *)mr; 1503 1504 if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC)) 1505 break; 1506 if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom || 1507 !lpScaleWindowExtEx->yNum || !lpScaleWindowExtEx->yDenom) 1508 break; 1509 info->state.wndExtX = MulDiv(info->state.wndExtX, lpScaleWindowExtEx->xNum, 1510 lpScaleWindowExtEx->xDenom); 1511 info->state.wndExtY = MulDiv(info->state.wndExtY, lpScaleWindowExtEx->yNum, 1512 lpScaleWindowExtEx->yDenom); 1513 if (info->state.wndExtX == 0) info->state.wndExtX = 1; 1514 if (info->state.wndExtY == 0) info->state.wndExtY = 1; 1515 if (info->state.mode == MM_ISOTROPIC) 1516 EMF_FixIsotropic(hdc, info); 1517 1518 TRACE("EMRSCALEWINDOWEXTEX %d/%d %d/%d\n", 1519 lpScaleWindowExtEx->xNum,lpScaleWindowExtEx->xDenom, 1520 lpScaleWindowExtEx->yNum,lpScaleWindowExtEx->yDenom); 1521 1522 if (!IS_WIN9X()) 1523 EMF_Update_MF_Xform(hdc, info); 1524 1525 break; 1526 } 1527 1528 case EMR_MODIFYWORLDTRANSFORM: 1529 { 1530 const EMRMODIFYWORLDTRANSFORM *lpModifyWorldTrans = (const EMRMODIFYWORLDTRANSFORM *)mr; 1531 1532 switch(lpModifyWorldTrans->iMode) { 1533 case MWT_IDENTITY: 1534 info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1; 1535 info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0; 1536 info->state.world_transform.eDx = info->state.world_transform.eDy = 0; 1537 if (!IS_WIN9X()) 1538 EMF_Update_MF_Xform(hdc, info); 1539 break; 1540 case MWT_LEFTMULTIPLY: 1541 CombineTransform(&info->state.world_transform, &lpModifyWorldTrans->xform, 1542 &info->state.world_transform); 1543 if (!IS_WIN9X()) 1544 ModifyWorldTransform(hdc, &lpModifyWorldTrans->xform, MWT_LEFTMULTIPLY); 1545 break; 1546 case MWT_RIGHTMULTIPLY: 1547 CombineTransform(&info->state.world_transform, &info->state.world_transform, 1548 &lpModifyWorldTrans->xform); 1549 if (!IS_WIN9X()) 1550 EMF_Update_MF_Xform(hdc, info); 1551 break; 1552 default: 1553 FIXME("Unknown imode %d\n", lpModifyWorldTrans->iMode); 1554 break; 1555 } 1556 break; 1557 } 1558 1559 case EMR_ANGLEARC: 1560 { 1561 const EMRANGLEARC *lpAngleArc = (const EMRANGLEARC *)mr; 1562 1563 AngleArc( hdc, 1564 (INT)lpAngleArc->ptlCenter.x, (INT)lpAngleArc->ptlCenter.y, 1565 lpAngleArc->nRadius, lpAngleArc->eStartAngle, 1566 lpAngleArc->eSweepAngle ); 1567 1568 break; 1569 } 1570 1571 case EMR_ROUNDRECT: 1572 { 1573 const EMRROUNDRECT *lpRoundRect = (const EMRROUNDRECT *)mr; 1574 1575 RoundRect( hdc, 1576 lpRoundRect->rclBox.left, 1577 lpRoundRect->rclBox.top, 1578 lpRoundRect->rclBox.right, 1579 lpRoundRect->rclBox.bottom, 1580 lpRoundRect->szlCorner.cx, 1581 lpRoundRect->szlCorner.cy ); 1582 1583 break; 1584 } 1585 1586 case EMR_ARC: 1587 { 1588 const EMRARC *lpArc = (const EMRARC *)mr; 1589 1590 Arc( hdc, 1591 (INT)lpArc->rclBox.left, 1592 (INT)lpArc->rclBox.top, 1593 (INT)lpArc->rclBox.right, 1594 (INT)lpArc->rclBox.bottom, 1595 (INT)lpArc->ptlStart.x, 1596 (INT)lpArc->ptlStart.y, 1597 (INT)lpArc->ptlEnd.x, 1598 (INT)lpArc->ptlEnd.y ); 1599 1600 break; 1601 } 1602 1603 case EMR_CHORD: 1604 { 1605 const EMRCHORD *lpChord = (const EMRCHORD *)mr; 1606 1607 Chord( hdc, 1608 (INT)lpChord->rclBox.left, 1609 (INT)lpChord->rclBox.top, 1610 (INT)lpChord->rclBox.right, 1611 (INT)lpChord->rclBox.bottom, 1612 (INT)lpChord->ptlStart.x, 1613 (INT)lpChord->ptlStart.y, 1614 (INT)lpChord->ptlEnd.x, 1615 (INT)lpChord->ptlEnd.y ); 1616 1617 break; 1618 } 1619 1620 case EMR_PIE: 1621 { 1622 const EMRPIE *lpPie = (const EMRPIE *)mr; 1623 1624 Pie( hdc, 1625 (INT)lpPie->rclBox.left, 1626 (INT)lpPie->rclBox.top, 1627 (INT)lpPie->rclBox.right, 1628 (INT)lpPie->rclBox.bottom, 1629 (INT)lpPie->ptlStart.x, 1630 (INT)lpPie->ptlStart.y, 1631 (INT)lpPie->ptlEnd.x, 1632 (INT)lpPie->ptlEnd.y ); 1633 1634 break; 1635 } 1636 1637 case EMR_ARCTO: 1638 { 1639 const EMRARC *lpArcTo = (const EMRARC *)mr; 1640 1641 ArcTo( hdc, 1642 (INT)lpArcTo->rclBox.left, 1643 (INT)lpArcTo->rclBox.top, 1644 (INT)lpArcTo->rclBox.right, 1645 (INT)lpArcTo->rclBox.bottom, 1646 (INT)lpArcTo->ptlStart.x, 1647 (INT)lpArcTo->ptlStart.y, 1648 (INT)lpArcTo->ptlEnd.x, 1649 (INT)lpArcTo->ptlEnd.y ); 1650 1651 break; 1652 } 1653 1654 case EMR_EXTFLOODFILL: 1655 { 1656 const EMREXTFLOODFILL *lpExtFloodFill = (const EMREXTFLOODFILL *)mr; 1657 1658 ExtFloodFill( hdc, 1659 (INT)lpExtFloodFill->ptlStart.x, 1660 (INT)lpExtFloodFill->ptlStart.y, 1661 lpExtFloodFill->crColor, 1662 (UINT)lpExtFloodFill->iMode ); 1663 1664 break; 1665 } 1666 1667 case EMR_POLYDRAW: 1668 { 1669 const EMRPOLYDRAW *lpPolyDraw = (const EMRPOLYDRAW *)mr; 1670 PolyDraw( hdc, 1671 (const POINT*)lpPolyDraw->aptl, 1672 lpPolyDraw->abTypes, 1673 (INT)lpPolyDraw->cptl ); 1674 1675 break; 1676 } 1677 1678 case EMR_SETARCDIRECTION: 1679 { 1680 const EMRSETARCDIRECTION *lpSetArcDirection = (const EMRSETARCDIRECTION *)mr; 1681 SetArcDirection( hdc, (INT)lpSetArcDirection->iArcDirection ); 1682 break; 1683 } 1684 1685 case EMR_SETMITERLIMIT: 1686 { 1687 const EMRSETMITERLIMIT *lpSetMiterLimit = (const EMRSETMITERLIMIT *)mr; 1688 SetMiterLimit( hdc, lpSetMiterLimit->eMiterLimit, NULL ); 1689 break; 1690 } 1691 1692 case EMR_BEGINPATH: 1693 { 1694 BeginPath( hdc ); 1695 break; 1696 } 1697 1698 case EMR_ENDPATH: 1699 { 1700 EndPath( hdc ); 1701 break; 1702 } 1703 1704 case EMR_CLOSEFIGURE: 1705 { 1706 CloseFigure( hdc ); 1707 break; 1708 } 1709 1710 case EMR_FILLPATH: 1711 { 1712 /*const EMRFILLPATH lpFillPath = (const EMRFILLPATH *)mr;*/ 1713 FillPath( hdc ); 1714 break; 1715 } 1716 1717 case EMR_STROKEANDFILLPATH: 1718 { 1719 /*const EMRSTROKEANDFILLPATH lpStrokeAndFillPath = (const EMRSTROKEANDFILLPATH *)mr;*/ 1720 StrokeAndFillPath( hdc ); 1721 break; 1722 } 1723 1724 case EMR_STROKEPATH: 1725 { 1726 /*const EMRSTROKEPATH lpStrokePath = (const EMRSTROKEPATH *)mr;*/ 1727 StrokePath( hdc ); 1728 break; 1729 } 1730 1731 case EMR_FLATTENPATH: 1732 { 1733 FlattenPath( hdc ); 1734 break; 1735 } 1736 1737 case EMR_WIDENPATH: 1738 { 1739 WidenPath( hdc ); 1740 break; 1741 } 1742 1743 case EMR_SELECTCLIPPATH: 1744 { 1745 const EMRSELECTCLIPPATH *lpSelectClipPath = (const EMRSELECTCLIPPATH *)mr; 1746 SelectClipPath( hdc, (INT)lpSelectClipPath->iMode ); 1747 break; 1748 } 1749 1750 case EMR_ABORTPATH: 1751 { 1752 AbortPath( hdc ); 1753 break; 1754 } 1755 1756 case EMR_CREATECOLORSPACE: 1757 { 1758 PEMRCREATECOLORSPACE lpCreateColorSpace = (PEMRCREATECOLORSPACE)mr; 1759 (handletable->objectHandle)[lpCreateColorSpace->ihCS] = 1760 CreateColorSpaceA( &lpCreateColorSpace->lcs ); 1761 break; 1762 } 1763 1764 case EMR_SETCOLORSPACE: 1765 { 1766 const EMRSETCOLORSPACE *lpSetColorSpace = (const EMRSETCOLORSPACE *)mr; 1767 SetColorSpace( hdc, 1768 (handletable->objectHandle)[lpSetColorSpace->ihCS] ); 1769 break; 1770 } 1771 1772 case EMR_DELETECOLORSPACE: 1773 { 1774 const EMRDELETECOLORSPACE *lpDeleteColorSpace = (const EMRDELETECOLORSPACE *)mr; 1775 DeleteColorSpace( (handletable->objectHandle)[lpDeleteColorSpace->ihCS] ); 1776 break; 1777 } 1778 1779 case EMR_SETICMMODE: 1780 { 1781 const EMRSETICMMODE *lpSetICMMode = (const EMRSETICMMODE *)mr; 1782 SetICMMode( hdc, (INT)lpSetICMMode->iMode ); 1783 break; 1784 } 1785 1786 case EMR_PIXELFORMAT: 1787 { 1788 INT iPixelFormat; 1789 const EMRPIXELFORMAT *lpPixelFormat = (const EMRPIXELFORMAT *)mr; 1790 1791 iPixelFormat = ChoosePixelFormat( hdc, &lpPixelFormat->pfd ); 1792 SetPixelFormat( hdc, iPixelFormat, &lpPixelFormat->pfd ); 1793 1794 break; 1795 } 1796 1797 case EMR_SETPALETTEENTRIES: 1798 { 1799 const EMRSETPALETTEENTRIES *lpSetPaletteEntries = (const EMRSETPALETTEENTRIES *)mr; 1800 1801 SetPaletteEntries( (handletable->objectHandle)[lpSetPaletteEntries->ihPal], 1802 (UINT)lpSetPaletteEntries->iStart, 1803 (UINT)lpSetPaletteEntries->cEntries, 1804 lpSetPaletteEntries->aPalEntries ); 1805 1806 break; 1807 } 1808 1809 case EMR_RESIZEPALETTE: 1810 { 1811 const EMRRESIZEPALETTE *lpResizePalette = (const EMRRESIZEPALETTE *)mr; 1812 1813 ResizePalette( (handletable->objectHandle)[lpResizePalette->ihPal], 1814 (UINT)lpResizePalette->cEntries ); 1815 1816 break; 1817 } 1818 1819 case EMR_CREATEDIBPATTERNBRUSHPT: 1820 { 1821 const EMRCREATEDIBPATTERNBRUSHPT *lpCreate = (const EMRCREATEDIBPATTERNBRUSHPT *)mr; 1822 LPVOID lpPackedStruct; 1823 1824 /* Check that offsets and data are contained within the record 1825 * (including checking for wrap-arounds). 1826 */ 1827 if ( lpCreate->offBmi + lpCreate->cbBmi > mr->nSize 1828 || lpCreate->offBits + lpCreate->cbBits > mr->nSize 1829 || lpCreate->offBmi + lpCreate->cbBmi < lpCreate->offBmi 1830 || lpCreate->offBits + lpCreate->cbBits < lpCreate->offBits ) 1831 { 1832 ERR("Invalid EMR_CREATEDIBPATTERNBRUSHPT record\n"); 1833 break; 1834 } 1835 1836 /* This is a BITMAPINFO struct followed directly by bitmap bits */ 1837 lpPackedStruct = HeapAlloc( GetProcessHeap(), 0, 1838 lpCreate->cbBmi + lpCreate->cbBits ); 1839 if(!lpPackedStruct) 1840 { 1841 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1842 break; 1843 } 1844 1845 /* Now pack this structure */ 1846 memcpy( lpPackedStruct, 1847 ((const BYTE *)lpCreate) + lpCreate->offBmi, 1848 lpCreate->cbBmi ); 1849 memcpy( ((BYTE*)lpPackedStruct) + lpCreate->cbBmi, 1850 ((const BYTE *)lpCreate) + lpCreate->offBits, 1851 lpCreate->cbBits ); 1852 1853 (handletable->objectHandle)[lpCreate->ihBrush] = 1854 CreateDIBPatternBrushPt( lpPackedStruct, 1855 (UINT)lpCreate->iUsage ); 1856 1857 HeapFree(GetProcessHeap(), 0, lpPackedStruct); 1858 break; 1859 } 1860 1861 case EMR_CREATEMONOBRUSH: 1862 { 1863 const EMRCREATEMONOBRUSH *pCreateMonoBrush = (const EMRCREATEMONOBRUSH *)mr; 1864 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pCreateMonoBrush->offBmi); 1865 HBITMAP hBmp; 1866 1867 /* Need to check if the bitmap is monochrome, and if the 1868 two colors are really black and white */ 1869 if (pCreateMonoBrush->iUsage == DIB_PAL_MONO) 1870 { 1871 BITMAP bm; 1872 1873 /* Undocumented iUsage indicates a mono bitmap with no palette table, 1874 * aligned to 32 rather than 16 bits. 1875 */ 1876 bm.bmType = 0; 1877 bm.bmWidth = pbi->bmiHeader.biWidth; 1878 bm.bmHeight = abs(pbi->bmiHeader.biHeight); 1879 bm.bmWidthBytes = 4 * ((pbi->bmiHeader.biWidth + 31) / 32); 1880 bm.bmPlanes = pbi->bmiHeader.biPlanes; 1881 bm.bmBitsPixel = pbi->bmiHeader.biBitCount; 1882 bm.bmBits = (BYTE *)mr + pCreateMonoBrush->offBits; 1883 hBmp = CreateBitmapIndirect(&bm); 1884 } 1885 else if (is_dib_monochrome(pbi)) 1886 { 1887 /* Top-down DIBs have a negative height */ 1888 LONG height = pbi->bmiHeader.biHeight; 1889 1890 hBmp = CreateBitmap(pbi->bmiHeader.biWidth, abs(height), 1, 1, NULL); 1891 SetDIBits(hdc, hBmp, 0, pbi->bmiHeader.biHeight, 1892 (const BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage); 1893 } 1894 else 1895 { 1896 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT, 1897 (const BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage); 1898 } 1899 1900 (handletable->objectHandle)[pCreateMonoBrush->ihBrush] = CreatePatternBrush(hBmp); 1901 1902 /* CreatePatternBrush created a copy of the bitmap */ 1903 DeleteObject(hBmp); 1904 break; 1905 } 1906 1907 case EMR_BITBLT: 1908 { 1909 const EMRBITBLT *pBitBlt = (const EMRBITBLT *)mr; 1910 1911 if(pBitBlt->offBmiSrc == 0) { /* Record is a PatBlt */ 1912 PatBlt(hdc, pBitBlt->xDest, pBitBlt->yDest, pBitBlt->cxDest, pBitBlt->cyDest, 1913 pBitBlt->dwRop); 1914 } else { /* BitBlt */ 1915 HDC hdcSrc = CreateCompatibleDC(hdc); 1916 HBRUSH hBrush, hBrushOld; 1917 HBITMAP hBmp = 0, hBmpOld = 0; 1918 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pBitBlt->offBmiSrc); 1919 1920 SetGraphicsMode(hdcSrc, GM_ADVANCED); 1921 SetWorldTransform(hdcSrc, &pBitBlt->xformSrc); 1922 1923 hBrush = CreateSolidBrush(pBitBlt->crBkColorSrc); 1924 hBrushOld = SelectObject(hdcSrc, hBrush); 1925 PatBlt(hdcSrc, pBitBlt->rclBounds.left, pBitBlt->rclBounds.top, 1926 pBitBlt->rclBounds.right - pBitBlt->rclBounds.left, 1927 pBitBlt->rclBounds.bottom - pBitBlt->rclBounds.top, PATCOPY); 1928 SelectObject(hdcSrc, hBrushOld); 1929 DeleteObject(hBrush); 1930 1931 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT, 1932 (const BYTE *)mr + pBitBlt->offBitsSrc, pbi, pBitBlt->iUsageSrc); 1933 hBmpOld = SelectObject(hdcSrc, hBmp); 1934 1935 BitBlt(hdc, pBitBlt->xDest, pBitBlt->yDest, pBitBlt->cxDest, pBitBlt->cyDest, 1936 hdcSrc, pBitBlt->xSrc, pBitBlt->ySrc, pBitBlt->dwRop); 1937 1938 SelectObject(hdcSrc, hBmpOld); 1939 DeleteObject(hBmp); 1940 DeleteDC(hdcSrc); 1941 } 1942 break; 1943 } 1944 1945 case EMR_STRETCHBLT: 1946 { 1947 const EMRSTRETCHBLT *pStretchBlt = (const EMRSTRETCHBLT *)mr; 1948 1949 TRACE("EMR_STRETCHBLT: %d, %d %dx%d -> %d, %d %dx%d. rop %08x offBitsSrc %d\n", 1950 pStretchBlt->xSrc, pStretchBlt->ySrc, pStretchBlt->cxSrc, pStretchBlt->cySrc, 1951 pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest, 1952 pStretchBlt->dwRop, pStretchBlt->offBitsSrc); 1953 1954 if(pStretchBlt->offBmiSrc == 0) { /* Record is a PatBlt */ 1955 PatBlt(hdc, pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest, 1956 pStretchBlt->dwRop); 1957 } else { /* StretchBlt */ 1958 HDC hdcSrc = CreateCompatibleDC(hdc); 1959 HBRUSH hBrush, hBrushOld; 1960 HBITMAP hBmp = 0, hBmpOld = 0; 1961 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pStretchBlt->offBmiSrc); 1962 1963 SetGraphicsMode(hdcSrc, GM_ADVANCED); 1964 SetWorldTransform(hdcSrc, &pStretchBlt->xformSrc); 1965 1966 hBrush = CreateSolidBrush(pStretchBlt->crBkColorSrc); 1967 hBrushOld = SelectObject(hdcSrc, hBrush); 1968 PatBlt(hdcSrc, pStretchBlt->rclBounds.left, pStretchBlt->rclBounds.top, 1969 pStretchBlt->rclBounds.right - pStretchBlt->rclBounds.left, 1970 pStretchBlt->rclBounds.bottom - pStretchBlt->rclBounds.top, PATCOPY); 1971 SelectObject(hdcSrc, hBrushOld); 1972 DeleteObject(hBrush); 1973 1974 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT, 1975 (const BYTE *)mr + pStretchBlt->offBitsSrc, pbi, pStretchBlt->iUsageSrc); 1976 hBmpOld = SelectObject(hdcSrc, hBmp); 1977 1978 StretchBlt(hdc, pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest, 1979 hdcSrc, pStretchBlt->xSrc, pStretchBlt->ySrc, pStretchBlt->cxSrc, pStretchBlt->cySrc, 1980 pStretchBlt->dwRop); 1981 1982 SelectObject(hdcSrc, hBmpOld); 1983 DeleteObject(hBmp); 1984 DeleteDC(hdcSrc); 1985 } 1986 break; 1987 } 1988 1989 case EMR_ALPHABLEND: 1990 { 1991 const EMRALPHABLEND *pAlphaBlend = (const EMRALPHABLEND *)mr; 1992 1993 TRACE("EMR_ALPHABLEND: %d, %d %dx%d -> %d, %d %dx%d. blendfn %08x offBitsSrc %d\n", 1994 pAlphaBlend->xSrc, pAlphaBlend->ySrc, pAlphaBlend->cxSrc, pAlphaBlend->cySrc, 1995 pAlphaBlend->xDest, pAlphaBlend->yDest, pAlphaBlend->cxDest, pAlphaBlend->cyDest, 1996 pAlphaBlend->dwRop, pAlphaBlend->offBitsSrc); 1997 1998 if(pAlphaBlend->offBmiSrc == 0) { 1999 FIXME("EMR_ALPHABLEND: offBmiSrc == 0\n"); 2000 } else { 2001 HDC hdcSrc = CreateCompatibleDC(hdc); 2002 HBITMAP hBmp = 0, hBmpOld = 0; 2003 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pAlphaBlend->offBmiSrc); 2004 void *bits; 2005 2006 SetGraphicsMode(hdcSrc, GM_ADVANCED); 2007 SetWorldTransform(hdcSrc, &pAlphaBlend->xformSrc); 2008 2009 hBmp = CreateDIBSection(hdc, pbi, pAlphaBlend->iUsageSrc, &bits, NULL, 0); 2010 memcpy(bits, (const BYTE *)mr + pAlphaBlend->offBitsSrc, pAlphaBlend->cbBitsSrc); 2011 hBmpOld = SelectObject(hdcSrc, hBmp); 2012 2013 GdiAlphaBlend(hdc, pAlphaBlend->xDest, pAlphaBlend->yDest, pAlphaBlend->cxDest, pAlphaBlend->cyDest, 2014 hdcSrc, pAlphaBlend->xSrc, pAlphaBlend->ySrc, pAlphaBlend->cxSrc, pAlphaBlend->cySrc, 2015 *(BLENDFUNCTION *)&pAlphaBlend->dwRop); 2016 2017 SelectObject(hdcSrc, hBmpOld); 2018 DeleteObject(hBmp); 2019 DeleteDC(hdcSrc); 2020 } 2021 break; 2022 } 2023 2024 case EMR_MASKBLT: 2025 { 2026 const EMRMASKBLT *pMaskBlt = (const EMRMASKBLT *)mr; 2027 HDC hdcSrc = CreateCompatibleDC(hdc); 2028 HBRUSH hBrush, hBrushOld; 2029 HBITMAP hBmp, hBmpOld, hBmpMask; 2030 const BITMAPINFO *pbi; 2031 2032 SetGraphicsMode(hdcSrc, GM_ADVANCED); 2033 SetWorldTransform(hdcSrc, &pMaskBlt->xformSrc); 2034 2035 hBrush = CreateSolidBrush(pMaskBlt->crBkColorSrc); 2036 hBrushOld = SelectObject(hdcSrc, hBrush); 2037 PatBlt(hdcSrc, pMaskBlt->rclBounds.left, pMaskBlt->rclBounds.top, 2038 pMaskBlt->rclBounds.right - pMaskBlt->rclBounds.left, 2039 pMaskBlt->rclBounds.bottom - pMaskBlt->rclBounds.top, PATCOPY); 2040 SelectObject(hdcSrc, hBrushOld); 2041 DeleteObject(hBrush); 2042 2043 pbi = (const BITMAPINFO *)((const BYTE *)mr + pMaskBlt->offBmiMask); 2044 hBmpMask = CreateBitmap(pbi->bmiHeader.biWidth, pbi->bmiHeader.biHeight, 2045 1, 1, NULL); 2046 SetDIBits(hdc, hBmpMask, 0, pbi->bmiHeader.biHeight, 2047 (const BYTE *)mr + pMaskBlt->offBitsMask, pbi, pMaskBlt->iUsageMask); 2048 2049 pbi = (const BITMAPINFO *)((const BYTE *)mr + pMaskBlt->offBmiSrc); 2050 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT, 2051 (const BYTE *)mr + pMaskBlt->offBitsSrc, pbi, pMaskBlt->iUsageSrc); 2052 hBmpOld = SelectObject(hdcSrc, hBmp); 2053 MaskBlt(hdc, 2054 pMaskBlt->xDest, 2055 pMaskBlt->yDest, 2056 pMaskBlt->cxDest, 2057 pMaskBlt->cyDest, 2058 hdcSrc, 2059 pMaskBlt->xSrc, 2060 pMaskBlt->ySrc, 2061 hBmpMask, 2062 pMaskBlt->xMask, 2063 pMaskBlt->yMask, 2064 pMaskBlt->dwRop); 2065 SelectObject(hdcSrc, hBmpOld); 2066 DeleteObject(hBmp); 2067 DeleteObject(hBmpMask); 2068 DeleteDC(hdcSrc); 2069 break; 2070 } 2071 2072 case EMR_PLGBLT: 2073 { 2074 const EMRPLGBLT *pPlgBlt = (const EMRPLGBLT *)mr; 2075 HDC hdcSrc = CreateCompatibleDC(hdc); 2076 HBRUSH hBrush, hBrushOld; 2077 HBITMAP hBmp, hBmpOld, hBmpMask; 2078 const BITMAPINFO *pbi; 2079 POINT pts[3]; 2080 2081 SetGraphicsMode(hdcSrc, GM_ADVANCED); 2082 SetWorldTransform(hdcSrc, &pPlgBlt->xformSrc); 2083 2084 pts[0].x = pPlgBlt->aptlDest[0].x; pts[0].y = pPlgBlt->aptlDest[0].y; 2085 pts[1].x = pPlgBlt->aptlDest[1].x; pts[1].y = pPlgBlt->aptlDest[1].y; 2086 pts[2].x = pPlgBlt->aptlDest[2].x; pts[2].y = pPlgBlt->aptlDest[2].y; 2087 2088 hBrush = CreateSolidBrush(pPlgBlt->crBkColorSrc); 2089 hBrushOld = SelectObject(hdcSrc, hBrush); 2090 PatBlt(hdcSrc, pPlgBlt->rclBounds.left, pPlgBlt->rclBounds.top, 2091 pPlgBlt->rclBounds.right - pPlgBlt->rclBounds.left, 2092 pPlgBlt->rclBounds.bottom - pPlgBlt->rclBounds.top, PATCOPY); 2093 SelectObject(hdcSrc, hBrushOld); 2094 DeleteObject(hBrush); 2095 2096 pbi = (const BITMAPINFO *)((const BYTE *)mr + pPlgBlt->offBmiMask); 2097 hBmpMask = CreateBitmap(pbi->bmiHeader.biWidth, pbi->bmiHeader.biHeight, 2098 1, 1, NULL); 2099 SetDIBits(hdc, hBmpMask, 0, pbi->bmiHeader.biHeight, 2100 (const BYTE *)mr + pPlgBlt->offBitsMask, pbi, pPlgBlt->iUsageMask); 2101 2102 pbi = (const BITMAPINFO *)((const BYTE *)mr + pPlgBlt->offBmiSrc); 2103 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT, 2104 (const BYTE *)mr + pPlgBlt->offBitsSrc, pbi, pPlgBlt->iUsageSrc); 2105 hBmpOld = SelectObject(hdcSrc, hBmp); 2106 PlgBlt(hdc, 2107 pts, 2108 hdcSrc, 2109 pPlgBlt->xSrc, 2110 pPlgBlt->ySrc, 2111 pPlgBlt->cxSrc, 2112 pPlgBlt->cySrc, 2113 hBmpMask, 2114 pPlgBlt->xMask, 2115 pPlgBlt->yMask); 2116 SelectObject(hdcSrc, hBmpOld); 2117 DeleteObject(hBmp); 2118 DeleteObject(hBmpMask); 2119 DeleteDC(hdcSrc); 2120 break; 2121 } 2122 2123 case EMR_SETDIBITSTODEVICE: 2124 { 2125 const EMRSETDIBITSTODEVICE *pSetDIBitsToDevice = (const EMRSETDIBITSTODEVICE *)mr; 2126 2127 SetDIBitsToDevice(hdc, 2128 pSetDIBitsToDevice->xDest, 2129 pSetDIBitsToDevice->yDest, 2130 pSetDIBitsToDevice->cxSrc, 2131 pSetDIBitsToDevice->cySrc, 2132 pSetDIBitsToDevice->xSrc, 2133 pSetDIBitsToDevice->ySrc, 2134 pSetDIBitsToDevice->iStartScan, 2135 pSetDIBitsToDevice->cScans, 2136 (const BYTE *)mr + pSetDIBitsToDevice->offBitsSrc, 2137 (const BITMAPINFO *)((const BYTE *)mr + pSetDIBitsToDevice->offBmiSrc), 2138 pSetDIBitsToDevice->iUsageSrc); 2139 break; 2140 } 2141 2142 case EMR_POLYTEXTOUTA: 2143 { 2144 const EMRPOLYTEXTOUTA *pPolyTextOutA = (const EMRPOLYTEXTOUTA *)mr; 2145 POLYTEXTA *polytextA = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutA->cStrings * sizeof(POLYTEXTA)); 2146 LONG i; 2147 XFORM xform, xformOld; 2148 int gModeOld; 2149 2150 gModeOld = SetGraphicsMode(hdc, pPolyTextOutA->iGraphicsMode); 2151 GetWorldTransform(hdc, &xformOld); 2152 2153 xform.eM11 = pPolyTextOutA->exScale; 2154 xform.eM12 = 0.0; 2155 xform.eM21 = 0.0; 2156 xform.eM22 = pPolyTextOutA->eyScale; 2157 xform.eDx = 0.0; 2158 xform.eDy = 0.0; 2159 SetWorldTransform(hdc, &xform); 2160 2161 /* Set up POLYTEXTA structures */ 2162 for(i = 0; i < pPolyTextOutA->cStrings; i++) 2163 { 2164 polytextA[i].x = pPolyTextOutA->aemrtext[i].ptlReference.x; 2165 polytextA[i].y = pPolyTextOutA->aemrtext[i].ptlReference.y; 2166 polytextA[i].n = pPolyTextOutA->aemrtext[i].nChars; 2167 polytextA[i].lpstr = (LPCSTR)((const BYTE *)mr + pPolyTextOutA->aemrtext[i].offString); 2168 polytextA[i].uiFlags = pPolyTextOutA->aemrtext[i].fOptions; 2169 polytextA[i].rcl.left = pPolyTextOutA->aemrtext[i].rcl.left; 2170 polytextA[i].rcl.right = pPolyTextOutA->aemrtext[i].rcl.right; 2171 polytextA[i].rcl.top = pPolyTextOutA->aemrtext[i].rcl.top; 2172 polytextA[i].rcl.bottom = pPolyTextOutA->aemrtext[i].rcl.bottom; 2173 polytextA[i].pdx = (int *)((BYTE *)mr + pPolyTextOutA->aemrtext[i].offDx); 2174 } 2175 PolyTextOutA(hdc, polytextA, pPolyTextOutA->cStrings); 2176 HeapFree(GetProcessHeap(), 0, polytextA); 2177 2178 SetWorldTransform(hdc, &xformOld); 2179 SetGraphicsMode(hdc, gModeOld); 2180 break; 2181 } 2182 2183 case EMR_POLYTEXTOUTW: 2184 { 2185 const EMRPOLYTEXTOUTW *pPolyTextOutW = (const EMRPOLYTEXTOUTW *)mr; 2186 POLYTEXTW *polytextW = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutW->cStrings * sizeof(POLYTEXTW)); 2187 LONG i; 2188 XFORM xform, xformOld; 2189 int gModeOld; 2190 2191 gModeOld = SetGraphicsMode(hdc, pPolyTextOutW->iGraphicsMode); 2192 GetWorldTransform(hdc, &xformOld); 2193 2194 xform.eM11 = pPolyTextOutW->exScale; 2195 xform.eM12 = 0.0; 2196 xform.eM21 = 0.0; 2197 xform.eM22 = pPolyTextOutW->eyScale; 2198 xform.eDx = 0.0; 2199 xform.eDy = 0.0; 2200 SetWorldTransform(hdc, &xform); 2201 2202 /* Set up POLYTEXTW structures */ 2203 for(i = 0; i < pPolyTextOutW->cStrings; i++) 2204 { 2205 polytextW[i].x = pPolyTextOutW->aemrtext[i].ptlReference.x; 2206 polytextW[i].y = pPolyTextOutW->aemrtext[i].ptlReference.y; 2207 polytextW[i].n = pPolyTextOutW->aemrtext[i].nChars; 2208 polytextW[i].lpstr = (LPCWSTR)((const BYTE *)mr + pPolyTextOutW->aemrtext[i].offString); 2209 polytextW[i].uiFlags = pPolyTextOutW->aemrtext[i].fOptions; 2210 polytextW[i].rcl.left = pPolyTextOutW->aemrtext[i].rcl.left; 2211 polytextW[i].rcl.right = pPolyTextOutW->aemrtext[i].rcl.right; 2212 polytextW[i].rcl.top = pPolyTextOutW->aemrtext[i].rcl.top; 2213 polytextW[i].rcl.bottom = pPolyTextOutW->aemrtext[i].rcl.bottom; 2214 polytextW[i].pdx = (int *)((BYTE *)mr + pPolyTextOutW->aemrtext[i].offDx); 2215 } 2216 PolyTextOutW(hdc, polytextW, pPolyTextOutW->cStrings); 2217 HeapFree(GetProcessHeap(), 0, polytextW); 2218 2219 SetWorldTransform(hdc, &xformOld); 2220 SetGraphicsMode(hdc, gModeOld); 2221 break; 2222 } 2223 2224 case EMR_FILLRGN: 2225 { 2226 const EMRFILLRGN *pFillRgn = (const EMRFILLRGN *)mr; 2227 HRGN hRgn = ExtCreateRegion(NULL, pFillRgn->cbRgnData, (const RGNDATA *)pFillRgn->RgnData); 2228 FillRgn(hdc, 2229 hRgn, 2230 (handletable->objectHandle)[pFillRgn->ihBrush]); 2231 DeleteObject(hRgn); 2232 break; 2233 } 2234 2235 case EMR_FRAMERGN: 2236 { 2237 const EMRFRAMERGN *pFrameRgn = (const EMRFRAMERGN *)mr; 2238 HRGN hRgn = ExtCreateRegion(NULL, pFrameRgn->cbRgnData, (const RGNDATA *)pFrameRgn->RgnData); 2239 FrameRgn(hdc, 2240 hRgn, 2241 (handletable->objectHandle)[pFrameRgn->ihBrush], 2242 pFrameRgn->szlStroke.cx, 2243 pFrameRgn->szlStroke.cy); 2244 DeleteObject(hRgn); 2245 break; 2246 } 2247 2248 case EMR_INVERTRGN: 2249 { 2250 const EMRINVERTRGN *pInvertRgn = (const EMRINVERTRGN *)mr; 2251 HRGN hRgn = ExtCreateRegion(NULL, pInvertRgn->cbRgnData, (const RGNDATA *)pInvertRgn->RgnData); 2252 InvertRgn(hdc, hRgn); 2253 DeleteObject(hRgn); 2254 break; 2255 } 2256 2257 case EMR_PAINTRGN: 2258 { 2259 const EMRPAINTRGN *pPaintRgn = (const EMRPAINTRGN *)mr; 2260 HRGN hRgn = ExtCreateRegion(NULL, pPaintRgn->cbRgnData, (const RGNDATA *)pPaintRgn->RgnData); 2261 PaintRgn(hdc, hRgn); 2262 DeleteObject(hRgn); 2263 break; 2264 } 2265 2266 case EMR_SETTEXTJUSTIFICATION: 2267 { 2268 const EMRSETTEXTJUSTIFICATION *pSetTextJust = (const EMRSETTEXTJUSTIFICATION *)mr; 2269 SetTextJustification(hdc, pSetTextJust->nBreakExtra, pSetTextJust->nBreakCount); 2270 break; 2271 } 2272 2273 case EMR_SETLAYOUT: 2274 { 2275 const EMRSETLAYOUT *pSetLayout = (const EMRSETLAYOUT *)mr; 2276 SetLayout(hdc, pSetLayout->iMode); 2277 break; 2278 } 2279 2280 case EMR_GRADIENTFILL: 2281 { 2282 EMRGRADIENTFILL *grad = (EMRGRADIENTFILL *)mr; 2283 GdiGradientFill( hdc, grad->Ver, grad->nVer, grad->Ver + grad->nVer, 2284 grad->nTri, grad->ulMode ); 2285 break; 2286 } 2287 2288 case EMR_DRAWESCAPE: 2289 { 2290 PEMRESCAPE pemr = (PEMRESCAPE)mr; 2291 DrawEscape( hdc, pemr->iEsc, pemr->cjIn, (LPCSTR)pemr->Data ); 2292 break; 2293 } 2294 2295 case EMR_EXTESCAPE: 2296 { 2297 PEMRESCAPE pemr = (PEMRESCAPE)mr; 2298 ExtEscape( hdc, pemr->iEsc, pemr->cjIn, (LPCSTR)pemr->Data, 0, NULL ); 2299 break; 2300 } 2301 2302 case EMR_NAMEDESCAPE: 2303 { 2304 PEMRNAMEDESCAPE pemr = (PEMRNAMEDESCAPE)mr; 2305 INT rounded_size = (pemr->cjIn+3) & ~3; 2306 NamedEscape( hdc, (PWCHAR)&pemr->Data[rounded_size], pemr->iEsc, pemr->cjIn, (LPSTR)pemr->Data, 0, NULL ); 2307 break; 2308 } 2309 2310 case EMR_GLSRECORD: 2311 case EMR_GLSBOUNDEDRECORD: 2312 case EMR_STARTDOC: 2313 case EMR_SMALLTEXTOUT: 2314 case EMR_FORCEUFIMAPPING: 2315 case EMR_COLORCORRECTPALETTE: 2316 case EMR_SETICMPROFILEA: 2317 case EMR_SETICMPROFILEW: 2318 case EMR_TRANSPARENTBLT: 2319 case EMR_SETLINKEDUFI: 2320 case EMR_COLORMATCHTOTARGETW: 2321 case EMR_CREATECOLORSPACEW: 2322 2323 default: 2324 /* From docs: If PlayEnhMetaFileRecord doesn't recognize a 2325 record then ignore and return TRUE. */ 2326 FIXME("type %d is unimplemented\n", type); 2327 break; 2328 } 2329 tmprc.left = tmprc.top = 0; 2330 tmprc.right = tmprc.bottom = 1000; 2331 LPtoDP(hdc, (POINT*)&tmprc, 2); 2332 TRACE("L:0,0 - 1000,1000 -> D:%s\n", wine_dbgstr_rect(&tmprc)); 2333 2334 return TRUE; 2335 } 2336 2337 /***************************************************************************** 2338 * 2339 * EnumEnhMetaFile (GDI32.@) 2340 * 2341 * Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_ 2342 * for each 2343 * record. Returns when either every record has been used or 2344 * when _EnhMetaFunc_ returns FALSE. 2345 * 2346 * 2347 * RETURNS 2348 * TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_ 2349 * returns FALSE. 2350 * 2351 * BUGS 2352 * Ignores rect. 2353 * 2354 * NOTES 2355 * This function behaves differently in Win9x and WinNT. 2356 * 2357 * In WinNT, the DC's world transform is updated as the EMF changes 2358 * the Window/Viewport Extent and Origin or its world transform. 2359 * The actual Window/Viewport Extent and Origin are left untouched. 2360 * 2361 * In Win9x, the DC is left untouched, and PlayEnhMetaFileRecord 2362 * updates the scaling itself but only just before a record that 2363 * writes anything to the DC. 2364 * 2365 * I'm not sure where the data (enum_emh_data) is stored in either 2366 * version. For this implementation, it is stored before the handle 2367 * table, but it could be stored in the DC, in the EMF handle or in 2368 * TLS. 2369 * MJM 5 Oct 2002 2370 */ 2371 BOOL WINAPI EnumEnhMetaFile( 2372 HDC hdc, /* [in] device context to pass to _EnhMetaFunc_ */ 2373 HENHMETAFILE hmf, /* [in] EMF to walk */ 2374 ENHMFENUMPROC callback, /* [in] callback function */ 2375 LPVOID data, /* [in] optional data for callback function */ 2376 const RECT *lpRect /* [in] bounding rectangle for rendered metafile */ 2377 ) 2378 { 2379 BOOL ret; 2380 ENHMETAHEADER *emh; 2381 ENHMETARECORD *emr; 2382 DWORD offset; 2383 UINT i; 2384 HANDLETABLE *ht; 2385 INT savedMode = 0; 2386 XFORM savedXform; 2387 HPEN hPen = NULL; 2388 HBRUSH hBrush = NULL; 2389 HFONT hFont = NULL; 2390 HRGN hRgn = NULL; 2391 enum_emh_data *info; 2392 SIZE vp_size, win_size; 2393 POINT vp_org, win_org; 2394 INT mapMode = MM_TEXT, old_align = 0, old_rop2 = 0, old_arcdir = 0, old_polyfill = 0, old_stretchblt = 0; 2395 COLORREF old_text_color = 0, old_bk_color = 0; 2396 2397 if(!lpRect && hdc) 2398 { 2399 SetLastError(ERROR_INVALID_PARAMETER); 2400 return FALSE; 2401 } 2402 2403 emh = EMF_GetEnhMetaHeader(hmf); 2404 if(!emh) { 2405 SetLastError(ERROR_INVALID_HANDLE); 2406 return FALSE; 2407 } 2408 2409 info = HeapAlloc( GetProcessHeap(), 0, 2410 sizeof (enum_emh_data) + sizeof(HANDLETABLE) * emh->nHandles ); 2411 if(!info) 2412 { 2413 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2414 return FALSE; 2415 } 2416 info->state.mode = MM_TEXT; 2417 info->state.wndOrgX = 0; 2418 info->state.wndOrgY = 0; 2419 info->state.wndExtX = 1; 2420 info->state.wndExtY = 1; 2421 info->state.vportOrgX = 0; 2422 info->state.vportOrgY = 0; 2423 info->state.vportExtX = 1; 2424 info->state.vportExtY = 1; 2425 info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1; 2426 info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0; 2427 info->state.world_transform.eDx = info->state.world_transform.eDy = 0; 2428 2429 info->state.next = NULL; 2430 info->save_level = 0; 2431 info->saved_state = NULL; 2432 info->init_transform = info->state.world_transform; 2433 2434 ht = (HANDLETABLE*) &info[1]; 2435 ht->objectHandle[0] = hmf; 2436 for(i = 1; i < emh->nHandles; i++) 2437 ht->objectHandle[i] = NULL; 2438 2439 if(hdc && !is_meta_dc( hdc )) 2440 { 2441 savedMode = SetGraphicsMode(hdc, GM_ADVANCED); 2442 GetWorldTransform(hdc, &savedXform); 2443 GetViewportExtEx(hdc, &vp_size); 2444 GetWindowExtEx(hdc, &win_size); 2445 GetViewportOrgEx(hdc, &vp_org); 2446 GetWindowOrgEx(hdc, &win_org); 2447 mapMode = GetMapMode(hdc); 2448 2449 /* save DC */ 2450 hPen = GetCurrentObject(hdc, OBJ_PEN); 2451 hBrush = GetCurrentObject(hdc, OBJ_BRUSH); 2452 hFont = GetCurrentObject(hdc, OBJ_FONT); 2453 2454 hRgn = CreateRectRgn(0, 0, 0, 0); 2455 if (!GetClipRgn(hdc, hRgn)) 2456 { 2457 DeleteObject(hRgn); 2458 hRgn = 0; 2459 } 2460 2461 old_text_color = SetTextColor(hdc, RGB(0,0,0)); 2462 old_bk_color = SetBkColor(hdc, RGB(0xff, 0xff, 0xff)); 2463 old_align = SetTextAlign(hdc, 0); 2464 old_rop2 = SetROP2(hdc, R2_COPYPEN); 2465 old_arcdir = SetArcDirection(hdc, AD_COUNTERCLOCKWISE); 2466 old_polyfill = SetPolyFillMode(hdc, ALTERNATE); 2467 old_stretchblt = SetStretchBltMode(hdc, BLACKONWHITE); 2468 2469 if (!IS_WIN9X() ) 2470 { 2471 /* WinNT combines the vp/win ext/org info into a transform */ 2472 double xscale, yscale; 2473 xscale = (double)vp_size.cx / (double)win_size.cx; 2474 yscale = (double)vp_size.cy / (double)win_size.cy; 2475 info->init_transform.eM11 = xscale; 2476 info->init_transform.eM12 = 0.0; 2477 info->init_transform.eM21 = 0.0; 2478 info->init_transform.eM22 = yscale; 2479 info->init_transform.eDx = (double)vp_org.x - xscale * (double)win_org.x; 2480 info->init_transform.eDy = (double)vp_org.y - yscale * (double)win_org.y; 2481 2482 CombineTransform(&info->init_transform, &savedXform, &info->init_transform); 2483 } 2484 2485 if ( lpRect && WIDTH(emh->rclFrame) && HEIGHT(emh->rclFrame) ) 2486 { 2487 double xSrcPixSize, ySrcPixSize, xscale, yscale; 2488 XFORM xform; 2489 2490 TRACE("rect: %s. rclFrame: (%d,%d)-(%d,%d)\n", wine_dbgstr_rect(lpRect), 2491 emh->rclFrame.left, emh->rclFrame.top, emh->rclFrame.right, 2492 emh->rclFrame.bottom); 2493 2494 xSrcPixSize = (double) emh->szlMillimeters.cx / emh->szlDevice.cx; 2495 ySrcPixSize = (double) emh->szlMillimeters.cy / emh->szlDevice.cy; 2496 xscale = (double) WIDTH(*lpRect) * 100.0 / 2497 WIDTH(emh->rclFrame) * xSrcPixSize; 2498 yscale = (double) HEIGHT(*lpRect) * 100.0 / 2499 HEIGHT(emh->rclFrame) * ySrcPixSize; 2500 TRACE("xscale = %f, yscale = %f\n", xscale, yscale); 2501 2502 xform.eM11 = xscale; 2503 xform.eM12 = 0; 2504 xform.eM21 = 0; 2505 xform.eM22 = yscale; 2506 xform.eDx = (double) lpRect->left - (double) WIDTH(*lpRect) / WIDTH(emh->rclFrame) * emh->rclFrame.left; 2507 xform.eDy = (double) lpRect->top - (double) HEIGHT(*lpRect) / HEIGHT(emh->rclFrame) * emh->rclFrame.top; 2508 2509 CombineTransform(&info->init_transform, &xform, &info->init_transform); 2510 } 2511 2512 /* WinNT resets the current vp/win org/ext */ 2513 if ( !IS_WIN9X() ) 2514 { 2515 SetMapMode(hdc, MM_TEXT); 2516 SetWindowOrgEx(hdc, 0, 0, NULL); 2517 SetViewportOrgEx(hdc, 0, 0, NULL); 2518 EMF_Update_MF_Xform(hdc, info); 2519 } 2520 } 2521 2522 ret = TRUE; 2523 offset = 0; 2524 while(ret && offset < emh->nBytes) 2525 { 2526 emr = (ENHMETARECORD *)((char *)emh + offset); 2527 2528 if (offset + 8 > emh->nBytes || 2529 offset > offset + emr->nSize || 2530 offset + emr->nSize > emh->nBytes) 2531 { 2532 WARN("record truncated\n"); 2533 break; 2534 } 2535 2536 /* In Win9x mode we update the xform if the record will produce output */ 2537 if (hdc && IS_WIN9X() && emr_produces_output(emr->iType)) 2538 EMF_Update_MF_Xform(hdc, info); 2539 2540 TRACE("Calling EnumFunc with record %s, size %d\n", get_emr_name(emr->iType), emr->nSize); 2541 ret = (*callback)(hdc, ht, emr, emh->nHandles, (LPARAM)data); 2542 offset += emr->nSize; 2543 } 2544 2545 if (hdc && !is_meta_dc( hdc )) 2546 { 2547 SetStretchBltMode(hdc, old_stretchblt); 2548 SetPolyFillMode(hdc, old_polyfill); 2549 SetArcDirection(hdc, old_arcdir); 2550 SetROP2(hdc, old_rop2); 2551 SetTextAlign(hdc, old_align); 2552 SetBkColor(hdc, old_bk_color); 2553 SetTextColor(hdc, old_text_color); 2554 2555 /* restore DC */ 2556 SelectObject(hdc, hBrush); 2557 SelectObject(hdc, hPen); 2558 SelectObject(hdc, hFont); 2559 ExtSelectClipRgn(hdc, hRgn, RGN_COPY); 2560 DeleteObject(hRgn); 2561 2562 SetWorldTransform(hdc, &savedXform); 2563 if (savedMode) 2564 SetGraphicsMode(hdc, savedMode); 2565 SetMapMode(hdc, mapMode); 2566 SetWindowOrgEx(hdc, win_org.x, win_org.y, NULL); 2567 SetWindowExtEx(hdc, win_size.cx, win_size.cy, NULL); 2568 SetViewportOrgEx(hdc, vp_org.x, vp_org.y, NULL); 2569 SetViewportExtEx(hdc, vp_size.cx, vp_size.cy, NULL); 2570 } 2571 2572 for(i = 1; i < emh->nHandles; i++) /* Don't delete element 0 (hmf) */ 2573 if( (ht->objectHandle)[i] ) 2574 DeleteObject( (ht->objectHandle)[i] ); 2575 2576 while (info->saved_state) 2577 { 2578 EMF_dc_state *state = info->saved_state; 2579 info->saved_state = info->saved_state->next; 2580 HeapFree( GetProcessHeap(), 0, state ); 2581 } 2582 HeapFree( GetProcessHeap(), 0, info ); 2583 return ret; 2584 } 2585 2586 static INT CALLBACK EMF_PlayEnhMetaFileCallback(HDC hdc, HANDLETABLE *ht, 2587 const ENHMETARECORD *emr, 2588 INT handles, LPARAM data) 2589 { 2590 return PlayEnhMetaFileRecord(hdc, ht, emr, handles); 2591 } 2592 2593 /************************************************************************** 2594 * PlayEnhMetaFile (GDI32.@) 2595 * 2596 * Renders an enhanced metafile into a specified rectangle *lpRect 2597 * in device context hdc. 2598 * 2599 * RETURNS 2600 * Success: TRUE 2601 * Failure: FALSE 2602 */ 2603 BOOL WINAPI PlayEnhMetaFile( 2604 HDC hdc, /* [in] DC to render into */ 2605 HENHMETAFILE hmf, /* [in] metafile to render */ 2606 const RECT *lpRect /* [in] rectangle to place metafile inside */ 2607 ) 2608 { 2609 return EnumEnhMetaFile(hdc, hmf, EMF_PlayEnhMetaFileCallback, NULL, lpRect); 2610 } 2611 2612 /***************************************************************************** 2613 * DeleteEnhMetaFile (GDI32.@) 2614 * 2615 * Deletes an enhanced metafile and frees the associated storage. 2616 */ 2617 BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf) 2618 { 2619 return EMF_Delete_HENHMETAFILE( hmf ); 2620 } 2621 2622 /***************************************************************************** 2623 * CopyEnhMetaFileA (GDI32.@) 2624 * 2625 * Duplicate an enhanced metafile. 2626 * 2627 * 2628 */ 2629 HENHMETAFILE WINAPI CopyEnhMetaFileA( 2630 HENHMETAFILE hmfSrc, 2631 LPCSTR file) 2632 { 2633 ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst; 2634 HENHMETAFILE hmfDst; 2635 2636 if(!emrSrc) return FALSE; 2637 if (!file) { 2638 emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes ); 2639 memcpy( emrDst, emrSrc, emrSrc->nBytes ); 2640 hmfDst = EMF_Create_HENHMETAFILE( emrDst, emrSrc->nBytes, FALSE ); 2641 if (!hmfDst) 2642 HeapFree( GetProcessHeap(), 0, emrDst ); 2643 } else { 2644 HANDLE hFile; 2645 DWORD w; 2646 hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0, 2647 NULL, CREATE_ALWAYS, 0, 0); 2648 WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL); 2649 CloseHandle( hFile ); 2650 /* Reopen file for reading only, so that apps can share 2651 read access to the file while hmf is still valid */ 2652 hFile = CreateFileA( file, GENERIC_READ, FILE_SHARE_READ, 2653 NULL, OPEN_EXISTING, 0, 0); 2654 if(hFile == INVALID_HANDLE_VALUE) { 2655 ERR("Can't reopen emf for reading\n"); 2656 return 0; 2657 } 2658 hmfDst = EMF_GetEnhMetaFile( hFile ); 2659 CloseHandle( hFile ); 2660 } 2661 return hmfDst; 2662 } 2663 2664 /***************************************************************************** 2665 * CopyEnhMetaFileW (GDI32.@) 2666 * 2667 * See CopyEnhMetaFileA. 2668 * 2669 * 2670 */ 2671 HENHMETAFILE WINAPI CopyEnhMetaFileW( 2672 HENHMETAFILE hmfSrc, 2673 LPCWSTR file) 2674 { 2675 ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst; 2676 HENHMETAFILE hmfDst; 2677 2678 if(!emrSrc) return FALSE; 2679 if (!file) { 2680 emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes ); 2681 memcpy( emrDst, emrSrc, emrSrc->nBytes ); 2682 hmfDst = EMF_Create_HENHMETAFILE( emrDst, emrSrc->nBytes, FALSE ); 2683 if (!hmfDst) 2684 HeapFree( GetProcessHeap(), 0, emrDst ); 2685 } else { 2686 HANDLE hFile; 2687 DWORD w; 2688 hFile = CreateFileW( file, GENERIC_WRITE | GENERIC_READ, 0, 2689 NULL, CREATE_ALWAYS, 0, 0); 2690 WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL); 2691 CloseHandle( hFile ); 2692 /* Reopen file for reading only, so that apps can share 2693 read access to the file while hmf is still valid */ 2694 hFile = CreateFileW( file, GENERIC_READ, FILE_SHARE_READ, 2695 NULL, OPEN_EXISTING, 0, 0); 2696 if(hFile == INVALID_HANDLE_VALUE) { 2697 ERR("Can't reopen emf for reading\n"); 2698 return 0; 2699 } 2700 hmfDst = EMF_GetEnhMetaFile( hFile ); 2701 CloseHandle( hFile ); 2702 } 2703 return hmfDst; 2704 } 2705 2706 2707 /* Struct to be used to be passed in the LPVOID parameter for cbEnhPaletteCopy */ 2708 typedef struct tagEMF_PaletteCopy 2709 { 2710 UINT cEntries; 2711 LPPALETTEENTRY lpPe; 2712 } EMF_PaletteCopy; 2713 2714 /*************************************************************** 2715 * Find the EMR_EOF record and then use it to find the 2716 * palette entries for this enhanced metafile. 2717 * The lpData is actually a pointer to an EMF_PaletteCopy struct 2718 * which contains the max number of elements to copy and where 2719 * to copy them to. 2720 * 2721 * NOTE: To be used by GetEnhMetaFilePaletteEntries only! 2722 */ 2723 static INT CALLBACK cbEnhPaletteCopy( HDC a, 2724 HANDLETABLE *b, 2725 const ENHMETARECORD *lpEMR, 2726 INT c, 2727 LPARAM lpData ) 2728 { 2729 2730 if ( lpEMR->iType == EMR_EOF ) 2731 { 2732 const EMREOF *lpEof = (const EMREOF *)lpEMR; 2733 EMF_PaletteCopy* info = (EMF_PaletteCopy*)lpData; 2734 DWORD dwNumPalToCopy = min( lpEof->nPalEntries, info->cEntries ); 2735 2736 TRACE( "copying 0x%08x palettes\n", dwNumPalToCopy ); 2737 2738 memcpy( info->lpPe, (LPCSTR)lpEof + lpEof->offPalEntries, 2739 sizeof( *(info->lpPe) ) * dwNumPalToCopy ); 2740 2741 /* Update the passed data as a return code */ 2742 info->lpPe = NULL; /* Palettes were copied! */ 2743 info->cEntries = dwNumPalToCopy; 2744 2745 return FALSE; /* That's all we need */ 2746 } 2747 2748 return TRUE; 2749 } 2750 2751 /***************************************************************************** 2752 * GetEnhMetaFilePaletteEntries (GDI32.@) 2753 * 2754 * Copy the palette and report size 2755 * 2756 * BUGS: Error codes (SetLastError) are not set on failures 2757 */ 2758 UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf, 2759 UINT cEntries, 2760 LPPALETTEENTRY lpPe ) 2761 { 2762 ENHMETAHEADER* enhHeader = EMF_GetEnhMetaHeader( hEmf ); 2763 EMF_PaletteCopy infoForCallBack; 2764 2765 TRACE( "(%p,%d,%p)\n", hEmf, cEntries, lpPe ); 2766 2767 if (!enhHeader) return 0; 2768 2769 /* First check if there are any palettes associated with 2770 this metafile. */ 2771 if ( enhHeader->nPalEntries == 0 ) return 0; 2772 2773 /* Is the user requesting the number of palettes? */ 2774 if ( lpPe == NULL ) return enhHeader->nPalEntries; 2775 2776 /* Copy cEntries worth of PALETTEENTRY structs into the buffer */ 2777 infoForCallBack.cEntries = cEntries; 2778 infoForCallBack.lpPe = lpPe; 2779 2780 if ( !EnumEnhMetaFile( 0, hEmf, cbEnhPaletteCopy, 2781 &infoForCallBack, 0 ) ) 2782 return GDI_ERROR; 2783 2784 /* Verify that the callback executed correctly */ 2785 if ( infoForCallBack.lpPe != NULL ) 2786 { 2787 /* Callback proc had error! */ 2788 ERR( "cbEnhPaletteCopy didn't execute correctly\n" ); 2789 return GDI_ERROR; 2790 } 2791 2792 return infoForCallBack.cEntries; 2793 } 2794 2795 /****************************************************************** 2796 * extract_emf_from_comment 2797 * 2798 * If the WMF was created by GetWinMetaFileBits, then extract the 2799 * original EMF that is stored in MFCOMMENT chunks. 2800 */ 2801 static HENHMETAFILE extract_emf_from_comment( const BYTE *buf, UINT mf_size ) 2802 { 2803 METAHEADER *mh = (METAHEADER *)buf; 2804 METARECORD *mr; 2805 emf_in_wmf_comment *chunk; 2806 WORD checksum = 0; 2807 DWORD size = 0, remaining, chunks; 2808 BYTE *emf_bits = NULL, *ptr; 2809 UINT offset; 2810 HENHMETAFILE emf = NULL; 2811 2812 if (mf_size < sizeof(*mh)) return NULL; 2813 2814 for (offset = mh->mtHeaderSize * 2; offset < mf_size; offset += (mr->rdSize * 2)) 2815 { 2816 mr = (METARECORD *)((char *)mh + offset); 2817 chunk = (emf_in_wmf_comment *)(mr->rdParm + 2); 2818 2819 if (mr->rdFunction != META_ESCAPE || mr->rdParm[0] != MFCOMMENT) goto done; 2820 if (chunk->magic != WMFC_MAGIC) goto done; 2821 2822 if (!emf_bits) 2823 { 2824 size = remaining = chunk->emf_size; 2825 chunks = chunk->num_chunks; 2826 emf_bits = ptr = HeapAlloc( GetProcessHeap(), 0, size ); 2827 if (!emf_bits) goto done; 2828 } 2829 if (chunk->chunk_size > remaining) goto done; 2830 remaining -= chunk->chunk_size; 2831 if (chunk->remaining_size != remaining) goto done; 2832 memcpy( ptr, chunk->emf_data, chunk->chunk_size ); 2833 ptr += chunk->chunk_size; 2834 if (--chunks == 0) break; 2835 } 2836 2837 for (offset = 0; offset < mf_size / 2; offset++) 2838 checksum += *((WORD *)buf + offset); 2839 if (checksum) goto done; 2840 2841 emf = SetEnhMetaFileBits( size, emf_bits ); 2842 2843 done: 2844 HeapFree( GetProcessHeap(), 0, emf_bits ); 2845 return emf; 2846 } 2847 2848 typedef struct wmf_in_emf_comment 2849 { 2850 DWORD ident; 2851 DWORD iComment; 2852 DWORD nVersion; 2853 DWORD nChecksum; 2854 DWORD fFlags; 2855 DWORD cbWinMetaFile; 2856 } wmf_in_emf_comment; 2857 2858 /****************************************************************** 2859 * SetWinMetaFileBits (GDI32.@) 2860 * 2861 * Translate from old style to new style. 2862 * 2863 */ 2864 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer, const BYTE *lpbBuffer, HDC hdcRef, 2865 const METAFILEPICT *lpmfp) 2866 { 2867 static const WCHAR szDisplayW[] = { 'D','I','S','P','L','A','Y','\0' }; 2868 HMETAFILE hmf = NULL; 2869 HENHMETAFILE ret = NULL; 2870 HDC hdc = NULL, hdcdisp = NULL; 2871 RECT rc, *prcFrame = NULL; 2872 LONG mm, xExt, yExt; 2873 INT horzsize, vertsize, horzres, vertres; 2874 2875 TRACE("(%d, %p, %p, %p)\n", cbBuffer, lpbBuffer, hdcRef, lpmfp); 2876 2877 hmf = SetMetaFileBitsEx(cbBuffer, lpbBuffer); 2878 if(!hmf) 2879 { 2880 WARN("SetMetaFileBitsEx failed\n"); 2881 return NULL; 2882 } 2883 2884 ret = extract_emf_from_comment( lpbBuffer, cbBuffer ); 2885 if (ret) return ret; 2886 2887 if(!hdcRef) 2888 hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL); 2889 2890 if (lpmfp) 2891 { 2892 TRACE("mm = %d %dx%d\n", lpmfp->mm, lpmfp->xExt, lpmfp->yExt); 2893 2894 mm = lpmfp->mm; 2895 xExt = lpmfp->xExt; 2896 yExt = lpmfp->yExt; 2897 } 2898 else 2899 { 2900 TRACE("lpmfp == NULL\n"); 2901 2902 /* Use the whole device surface */ 2903 mm = MM_ANISOTROPIC; 2904 xExt = 0; 2905 yExt = 0; 2906 } 2907 2908 if (mm == MM_ISOTROPIC || mm == MM_ANISOTROPIC) 2909 { 2910 if (xExt < 0 || yExt < 0) 2911 { 2912 /* Use the whole device surface */ 2913 xExt = 0; 2914 yExt = 0; 2915 } 2916 2917 /* Use the x and y extents as the frame box */ 2918 if (xExt && yExt) 2919 { 2920 rc.left = rc.top = 0; 2921 rc.right = xExt; 2922 rc.bottom = yExt; 2923 prcFrame = &rc; 2924 } 2925 } 2926 2927 if(!(hdc = CreateEnhMetaFileW(hdcRef, NULL, prcFrame, NULL))) 2928 { 2929 ERR("CreateEnhMetaFile failed\n"); 2930 goto end; 2931 } 2932 2933 /* 2934 * Write the original METAFILE into the enhanced metafile. 2935 * It is encapsulated in a GDICOMMENT_WINDOWS_METAFILE record. 2936 */ 2937 if (mm != MM_TEXT) 2938 { 2939 wmf_in_emf_comment *mfcomment; 2940 UINT mfcomment_size; 2941 2942 mfcomment_size = sizeof (*mfcomment) + cbBuffer; 2943 mfcomment = HeapAlloc(GetProcessHeap(), 0, mfcomment_size); 2944 if (mfcomment) 2945 { 2946 mfcomment->ident = GDICOMMENT_IDENTIFIER; 2947 mfcomment->iComment = GDICOMMENT_WINDOWS_METAFILE; 2948 mfcomment->nVersion = 0x00000300; 2949 mfcomment->nChecksum = 0; /* FIXME */ 2950 mfcomment->fFlags = 0; 2951 mfcomment->cbWinMetaFile = cbBuffer; 2952 memcpy(&mfcomment[1], lpbBuffer, cbBuffer); 2953 GdiComment(hdc, mfcomment_size, (BYTE*) mfcomment); 2954 HeapFree(GetProcessHeap(), 0, mfcomment); 2955 } 2956 SetMapMode(hdc, mm); 2957 } 2958 2959 2960 horzsize = GetDeviceCaps(hdcRef, HORZSIZE); 2961 vertsize = GetDeviceCaps(hdcRef, VERTSIZE); 2962 horzres = GetDeviceCaps(hdcRef, HORZRES); 2963 vertres = GetDeviceCaps(hdcRef, VERTRES); 2964 2965 if (!xExt || !yExt) 2966 { 2967 /* Use the whole device surface */ 2968 xExt = horzres; 2969 yExt = vertres; 2970 } 2971 else 2972 { 2973 xExt = MulDiv(xExt, horzres, 100 * horzsize); 2974 yExt = MulDiv(yExt, vertres, 100 * vertsize); 2975 } 2976 2977 /* set the initial viewport:window ratio as 1:1 */ 2978 SetViewportExtEx(hdc, xExt, yExt, NULL); 2979 SetWindowExtEx(hdc, xExt, yExt, NULL); 2980 2981 PlayMetaFile(hdc, hmf); 2982 2983 ret = CloseEnhMetaFile(hdc); 2984 end: 2985 if (hdcdisp) DeleteDC(hdcdisp); 2986 DeleteMetaFile(hmf); 2987 return ret; 2988 } 2989