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