1 /* 2 * Enhanced MetaFile recording functions 3 * 4 * Copyright 1999 Huw D M Davies 5 * Copyright 2016 Alexandre Julliard 6 * Copyright 2021 Jacek Caban for CodeWeavers 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 #include "config.h" 23 24 #include <stdarg.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <assert.h> 28 #include "windef.h" 29 #include "winbase.h" 30 #include "wingdi.h" 31 #include "winnls.h" 32 #include "winerror.h" 33 #include "gdi_private.h" 34 #include "wine/wingdi16.h" 35 #include "wine/debug.h" 36 #ifdef __REACTOS__ 37 #include "wine/winternl.h" 38 #else 39 #include "winternl.h" 40 #endif 41 42 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile); 43 44 struct emf 45 { 46 ENHMETAHEADER *emh; 47 WINEDC *dc_attr; 48 UINT handles_size, cur_handles; 49 HGDIOBJ *handles; 50 HANDLE file; 51 HBRUSH dc_brush; 52 HPEN dc_pen; 53 BOOL path; 54 }; 55 56 #define HANDLE_LIST_INC 20 57 static const RECTL empty_bounds = { 0, 0, -1, -1 }; 58 59 static BOOL emfdc_record( struct emf *emf, EMR *emr ) 60 { 61 DWORD len, size; 62 ENHMETAHEADER *emh; 63 64 TRACE( "record %d, size %d\n", emr->iType, emr->nSize ); 65 66 assert( !(emr->nSize & 3) ); 67 68 emf->emh->nBytes += emr->nSize; 69 emf->emh->nRecords++; 70 71 size = HeapSize( GetProcessHeap(), 0, emf->emh ); 72 len = emf->emh->nBytes; 73 if (len > size) 74 { 75 size += (size / 2) + emr->nSize; 76 emh = HeapReAlloc( GetProcessHeap(), 0, emf->emh, size ); 77 if (!emh) return FALSE; 78 emf->emh = emh; 79 } 80 memcpy( (char *)emf->emh + emf->emh->nBytes - emr->nSize, emr, emr->nSize ); 81 return TRUE; 82 } 83 84 static void emfdc_update_bounds( struct emf *emf, RECTL *rect ) 85 { 86 RECTL *bounds = &emf->dc_attr->emf_bounds; 87 RECTL vport_rect = *rect; 88 89 LPtoDP( emf->dc_attr->hdc, (POINT *)&vport_rect, 2 ); 90 91 /* The coordinate systems may be mirrored 92 (LPtoDP handles points, not rectangles) */ 93 if (vport_rect.left > vport_rect.right) 94 { 95 LONG temp = vport_rect.right; 96 vport_rect.right = vport_rect.left; 97 vport_rect.left = temp; 98 } 99 if (vport_rect.top > vport_rect.bottom) 100 { 101 LONG temp = vport_rect.bottom; 102 vport_rect.bottom = vport_rect.top; 103 vport_rect.top = temp; 104 } 105 106 if (bounds->left > bounds->right) 107 { 108 /* first bounding rectangle */ 109 *bounds = vport_rect; 110 } 111 else 112 { 113 bounds->left = min(bounds->left, vport_rect.left); 114 bounds->top = min(bounds->top, vport_rect.top); 115 bounds->right = max(bounds->right, vport_rect.right); 116 bounds->bottom = max(bounds->bottom, vport_rect.bottom); 117 } 118 } 119 120 static UINT get_bitmap_info( HDC *hdc, HBITMAP *bitmap, BITMAPINFO *info ) 121 { 122 HBITMAP blit_bitmap; 123 HDC blit_dc; 124 UINT info_size, bpp; 125 DIBSECTION dib; 126 127 if (!(info_size = GetObjectW( *bitmap, sizeof(dib), &dib ))) return 0; 128 129 if (info_size == sizeof(dib)) 130 { 131 blit_dc = *hdc; 132 blit_bitmap = *bitmap; 133 } 134 else 135 { 136 unsigned char dib_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors) 137 + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)]; 138 BITMAPINFO *dib_info = (BITMAPINFO *)dib_info_buffer; 139 BITMAP bmp = dib.dsBm; 140 HPALETTE palette; 141 void *bits; 142 143 assert( info_size == sizeof(BITMAP) ); 144 145 dib_info->bmiHeader.biSize = sizeof(dib_info->bmiHeader); 146 dib_info->bmiHeader.biWidth = bmp.bmWidth; 147 dib_info->bmiHeader.biHeight = bmp.bmHeight; 148 dib_info->bmiHeader.biPlanes = 1; 149 dib_info->bmiHeader.biBitCount = bmp.bmBitsPixel; 150 dib_info->bmiHeader.biCompression = BI_RGB; 151 dib_info->bmiHeader.biSizeImage = 0; 152 dib_info->bmiHeader.biXPelsPerMeter = 0; 153 dib_info->bmiHeader.biYPelsPerMeter = 0; 154 dib_info->bmiHeader.biClrUsed = 0; 155 dib_info->bmiHeader.biClrImportant = 0; 156 switch (dib_info->bmiHeader.biBitCount) 157 { 158 case 16: 159 ((DWORD *)dib_info->bmiColors)[0] = 0xf800; 160 ((DWORD *)dib_info->bmiColors)[1] = 0x07e0; 161 ((DWORD *)dib_info->bmiColors)[2] = 0x001f; 162 break; 163 case 32: 164 ((DWORD *)dib_info->bmiColors)[0] = 0xff0000; 165 ((DWORD *)dib_info->bmiColors)[1] = 0x00ff00; 166 ((DWORD *)dib_info->bmiColors)[2] = 0x0000ff; 167 break; 168 default: 169 if (dib_info->bmiHeader.biBitCount > 8) break; 170 if (!(palette = GetCurrentObject( *hdc, OBJ_PAL ))) return FALSE; 171 if (!GetPaletteEntries( palette, 0, 256, (PALETTEENTRY *)dib_info->bmiColors )) 172 return FALSE; 173 } 174 175 if (!(blit_dc = /*NtGdi*/CreateCompatibleDC( *hdc ))) return FALSE; 176 if (!(blit_bitmap = CreateDIBSection( blit_dc, dib_info, DIB_RGB_COLORS, &bits, NULL, 0 ))) 177 goto err; 178 if (!SelectObject( blit_dc, blit_bitmap )) goto err; 179 if (!BitBlt( blit_dc, 0, 0, bmp.bmWidth, bmp.bmHeight, *hdc, 0, 0, SRCCOPY )) 180 goto err; 181 } 182 if (!GetDIBits( blit_dc, blit_bitmap, 0, INT_MAX, NULL, info, DIB_RGB_COLORS )) 183 goto err; 184 185 bpp = info->bmiHeader.biBitCount; 186 if (bpp <= 8) 187 return sizeof(BITMAPINFOHEADER) + (1L << bpp) * sizeof(RGBQUAD); 188 else if (bpp == 16 || bpp == 32) 189 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD); 190 191 return sizeof(BITMAPINFOHEADER); 192 193 err: 194 if (blit_dc && blit_dc != *hdc) DeleteDC( blit_dc ); 195 if (blit_bitmap && blit_bitmap != *bitmap) DeleteObject( blit_bitmap ); 196 return 0; 197 } 198 199 static UINT emfdc_add_handle( struct emf *emf, HGDIOBJ obj ) 200 { 201 UINT index; 202 203 for (index = 0; index < emf->handles_size; index++) 204 if (emf->handles[index] == 0) break; 205 206 if (index == emf->handles_size) 207 { 208 emf->handles_size += HANDLE_LIST_INC; 209 emf->handles = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 210 emf->handles, 211 emf->handles_size * sizeof(emf->handles[0]) ); 212 } 213 emf->handles[index] = get_full_gdi_handle( obj ); 214 215 emf->cur_handles++; 216 if (emf->cur_handles > emf->emh->nHandles) 217 emf->emh->nHandles++; 218 219 return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */ 220 } 221 222 static UINT emfdc_find_object( struct emf *emf, HGDIOBJ obj ) 223 { 224 UINT index; 225 226 for (index = 0; index < emf->handles_size; index++) 227 if (emf->handles[index] == obj) return index + 1; 228 229 return 0; 230 } 231 232 void emfdc_delete_object( HDC hdc, HGDIOBJ obj ) 233 { 234 WINEDC *dc_attr = get_dc_ptr( hdc ); 235 struct emf *emf = dc_attr->emf; 236 EMRDELETEOBJECT emr; 237 UINT index; 238 239 if(!(index = emfdc_find_object( emf, obj ))) return; 240 241 emr.emr.iType = EMR_DELETEOBJECT; 242 emr.emr.nSize = sizeof(emr); 243 emr.ihObject = index; 244 245 emfdc_record( emf, &emr.emr ); 246 247 emf->handles[index - 1] = 0; 248 emf->cur_handles--; 249 } 250 251 static DWORD emfdc_create_brush( struct emf *emf, HBRUSH brush ) 252 { 253 DWORD index = 0; 254 LOGBRUSH logbrush; 255 256 if (!GetObjectA( brush, sizeof(logbrush), &logbrush )) return 0; 257 258 switch (logbrush.lbStyle) { 259 case BS_SOLID: 260 case BS_HATCHED: 261 case BS_NULL: 262 { 263 EMRCREATEBRUSHINDIRECT emr; 264 emr.emr.iType = EMR_CREATEBRUSHINDIRECT; 265 emr.emr.nSize = sizeof(emr); 266 emr.ihBrush = index = emfdc_add_handle( emf, brush ); 267 emr.lb.lbStyle = logbrush.lbStyle; 268 emr.lb.lbColor = logbrush.lbColor; 269 emr.lb.lbHatch = logbrush.lbHatch; 270 271 if(!emfdc_record( emf, &emr.emr )) 272 index = 0; 273 } 274 break; 275 case BS_PATTERN: 276 case BS_DIBPATTERN: 277 { 278 unsigned char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors) 279 + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)]; 280 BITMAPINFO *info = (BITMAPINFO *)buffer; 281 EMRCREATEDIBPATTERNBRUSHPT *emr; 282 DWORD info_size; 283 UINT usage; 284 285 if (!get_brush_bitmap_info( brush, info, NULL, &usage )) break; 286 info_size = get_dib_info_size( info, usage ); 287 288 emr = HeapAlloc( GetProcessHeap(), 0, 289 sizeof(EMRCREATEDIBPATTERNBRUSHPT) + sizeof(DWORD) + 290 info_size+info->bmiHeader.biSizeImage ); 291 if(!emr) break; 292 293 /* FIXME: There is an extra DWORD written by native before the BMI. 294 * Not sure what it's meant to contain. 295 */ 296 emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ) + sizeof(DWORD); 297 *(DWORD *)(emr + 1) = 0x20000000; 298 299 if (logbrush.lbStyle == BS_PATTERN && info->bmiHeader.biBitCount == 1) 300 { 301 /* Presumably to reduce the size of the written EMF, MS supports an 302 * undocumented iUsage value of 2, indicating a mono bitmap without the 303 * 8 byte 2 entry black/white palette. Stupidly, they could have saved 304 * over 20 bytes more by also ignoring the BITMAPINFO fields that are 305 * irrelevant/constant for monochrome bitmaps. 306 * FIXME: It may be that the DIB functions themselves accept this value. 307 */ 308 emr->emr.iType = EMR_CREATEMONOBRUSH; 309 usage = DIB_PAL_MONO; 310 emr->cbBmi = sizeof( BITMAPINFOHEADER ); 311 } 312 else 313 { 314 emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT; 315 emr->cbBmi = info_size; 316 } 317 emr->ihBrush = index = emfdc_add_handle( emf, brush ); 318 emr->iUsage = usage; 319 emr->offBits = emr->offBmi + emr->cbBmi; 320 emr->cbBits = info->bmiHeader.biSizeImage; 321 emr->emr.nSize = emr->offBits + emr->cbBits; 322 323 if (info->bmiHeader.biClrUsed == 1 << info->bmiHeader.biBitCount) 324 info->bmiHeader.biClrUsed = 0; 325 memcpy( (BYTE *)emr + emr->offBmi, info, emr->cbBmi ); 326 get_brush_bitmap_info( brush, NULL, (char *)emr + emr->offBits, NULL ); 327 328 if (!emfdc_record( emf, &emr->emr )) index = 0; 329 HeapFree( GetProcessHeap(), 0, emr ); 330 } 331 break; 332 333 default: 334 FIXME("Unknown style %x\n", logbrush.lbStyle); 335 break; 336 } 337 338 return index; 339 } 340 341 static BOOL emfdc_select_brush( WINEDC *dc_attr, HBRUSH brush ) 342 { 343 struct emf *emf = dc_attr->emf; 344 EMRSELECTOBJECT emr; 345 DWORD index = 0; 346 int i; 347 348 /* If the object is a stock brush object, do not need to create it. 349 * See definitions in wingdi.h for range of stock brushes. 350 * We do however have to handle setting the higher order bit to 351 * designate that this is a stock object. 352 */ 353 for (i = WHITE_BRUSH; i <= DC_BRUSH; i++) 354 { 355 if (brush == GetStockObject(i)) 356 { 357 index = i | 0x80000000; 358 break; 359 } 360 } 361 362 if (!index && !(index = emfdc_find_object( emf, brush ))) 363 { 364 if (!(index = emfdc_create_brush( emf, brush ))) return 0; 365 GDI_hdc_using_object( brush, dc_attr->hdc);//, emfdc_delete_object ); 366 } 367 368 emr.emr.iType = EMR_SELECTOBJECT; 369 emr.emr.nSize = sizeof(emr); 370 emr.ihObject = index; 371 return emfdc_record( emf, &emr.emr ); 372 } 373 374 static BOOL emfdc_create_font( struct emf *emf, HFONT font ) 375 { 376 DWORD index = 0; 377 EMREXTCREATEFONTINDIRECTW emr; 378 int i; 379 380 if (!GetObjectW( font, sizeof(emr.elfw.elfLogFont), &emr.elfw.elfLogFont )) return FALSE; 381 382 emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW; 383 emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4; 384 emr.ihFont = index = emfdc_add_handle( emf, font ); 385 emr.elfw.elfFullName[0] = '\0'; 386 emr.elfw.elfStyle[0] = '\0'; 387 emr.elfw.elfVersion = 0; 388 emr.elfw.elfStyleSize = 0; 389 emr.elfw.elfMatch = 0; 390 emr.elfw.elfReserved = 0; 391 for (i = 0; i < ELF_VENDOR_SIZE; i++) 392 emr.elfw.elfVendorId[i] = 0; 393 emr.elfw.elfCulture = PAN_CULTURE_LATIN; 394 emr.elfw.elfPanose.bFamilyType = PAN_NO_FIT; 395 emr.elfw.elfPanose.bSerifStyle = PAN_NO_FIT; 396 emr.elfw.elfPanose.bWeight = PAN_NO_FIT; 397 emr.elfw.elfPanose.bProportion = PAN_NO_FIT; 398 emr.elfw.elfPanose.bContrast = PAN_NO_FIT; 399 emr.elfw.elfPanose.bStrokeVariation = PAN_NO_FIT; 400 emr.elfw.elfPanose.bArmStyle = PAN_NO_FIT; 401 emr.elfw.elfPanose.bLetterform = PAN_NO_FIT; 402 emr.elfw.elfPanose.bMidline = PAN_NO_FIT; 403 emr.elfw.elfPanose.bXHeight = PAN_NO_FIT; 404 405 return emfdc_record( emf, &emr.emr ) ? index : 0; 406 } 407 408 static BOOL emfdc_select_font( WINEDC *dc_attr, HFONT font ) 409 { 410 struct emf *emf = dc_attr->emf; 411 EMRSELECTOBJECT emr; 412 DWORD index; 413 int i; 414 415 /* If the object is a stock font object, do not need to create it. 416 * See definitions in wingdi.h for range of stock fonts. 417 * We do however have to handle setting the higher order bit to 418 * designate that this is a stock object. 419 */ 420 421 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++) 422 { 423 if (i != DEFAULT_PALETTE && font == GetStockObject(i)) 424 { 425 index = i | 0x80000000; 426 goto found; 427 } 428 } 429 430 if (!(index = emfdc_find_object( emf, font ))) 431 { 432 if (!(index = emfdc_create_font( emf, font ))) return FALSE; 433 GDI_hdc_using_object( font, dc_attr->hdc);//, emfdc_delete_object ); 434 } 435 436 found: 437 emr.emr.iType = EMR_SELECTOBJECT; 438 emr.emr.nSize = sizeof(emr); 439 emr.ihObject = index; 440 return emfdc_record( emf, &emr.emr ); 441 } 442 443 static DWORD emfdc_create_pen( struct emf *emf, HPEN hPen ) 444 { 445 EMRCREATEPEN emr; 446 DWORD index = 0; 447 448 if (!GetObjectW( hPen, sizeof(emr.lopn), &emr.lopn )) 449 { 450 /* must be an extended pen */ 451 EXTLOGPEN *elp; 452 INT size = GetObjectW( hPen, 0, NULL ); 453 454 if (!size) return 0; 455 456 elp = HeapAlloc( GetProcessHeap(), 0, size ); 457 458 GetObjectW( hPen, size, elp ); 459 /* FIXME: add support for user style pens */ 460 emr.lopn.lopnStyle = elp->elpPenStyle; 461 emr.lopn.lopnWidth.x = elp->elpWidth; 462 emr.lopn.lopnWidth.y = 0; 463 emr.lopn.lopnColor = elp->elpColor; 464 465 HeapFree( GetProcessHeap(), 0, elp ); 466 } 467 468 emr.emr.iType = EMR_CREATEPEN; 469 emr.emr.nSize = sizeof(emr); 470 emr.ihPen = index = emfdc_add_handle( emf, hPen ); 471 return emfdc_record( emf, &emr.emr ) ? index : 0; 472 } 473 474 static BOOL emfdc_select_pen( WINEDC *dc_attr, HPEN pen ) 475 { 476 struct emf *emf = dc_attr->emf; 477 EMRSELECTOBJECT emr; 478 DWORD index = 0; 479 int i; 480 481 /* If the object is a stock pen object, do not need to create it. 482 * See definitions in wingdi.h for range of stock pens. 483 * We do however have to handle setting the higher order bit to 484 * designate that this is a stock object. 485 */ 486 487 for (i = WHITE_PEN; i <= DC_PEN; i++) 488 { 489 if (pen == GetStockObject(i)) 490 { 491 index = i | 0x80000000; 492 break; 493 } 494 } 495 if (!index && !(index = emfdc_find_object( emf, pen ))) 496 { 497 if (!(index = emfdc_create_pen( emf, pen ))) return FALSE; 498 GDI_hdc_using_object( pen, dc_attr->hdc);//, emfdc_delete_object ); 499 } 500 501 emr.emr.iType = EMR_SELECTOBJECT; 502 emr.emr.nSize = sizeof(emr); 503 emr.ihObject = index; 504 return emfdc_record( emf, &emr.emr ); 505 } 506 507 static DWORD emfdc_create_palette( struct emf *emf, HPALETTE hPal ) 508 { 509 WORD i; 510 struct { 511 EMRCREATEPALETTE hdr; 512 PALETTEENTRY entry[255]; 513 } pal; 514 515 memset( &pal, 0, sizeof(pal) ); 516 517 if (!GetObjectW( hPal, sizeof(pal.hdr.lgpl) + sizeof(pal.entry), &pal.hdr.lgpl )) 518 return 0; 519 520 for (i = 0; i < pal.hdr.lgpl.palNumEntries; i++) 521 pal.hdr.lgpl.palPalEntry[i].peFlags = 0; 522 523 pal.hdr.emr.iType = EMR_CREATEPALETTE; 524 pal.hdr.emr.nSize = sizeof(pal.hdr) + pal.hdr.lgpl.palNumEntries * sizeof(PALETTEENTRY); 525 pal.hdr.ihPal = emfdc_add_handle( emf, hPal ); 526 527 if (!emfdc_record( emf, &pal.hdr.emr )) 528 pal.hdr.ihPal = 0; 529 return pal.hdr.ihPal; 530 } 531 532 BOOL EMFDC_SelectPalette( WINEDC *dc_attr, HPALETTE palette ) 533 { 534 struct emf *emf = dc_attr->emf; 535 EMRSELECTPALETTE emr; 536 DWORD index = 0; 537 538 if (palette == GetStockObject( DEFAULT_PALETTE )) 539 { 540 index = DEFAULT_PALETTE | 0x80000000; 541 } 542 else if (!(index = emfdc_find_object( emf, palette ))) 543 { 544 if (!(index = emfdc_create_palette( emf, palette ))) return 0; 545 GDI_hdc_using_object( palette, dc_attr->hdc);//, emfdc_delete_object ); 546 } 547 548 emr.emr.iType = EMR_SELECTPALETTE; 549 emr.emr.nSize = sizeof(emr); 550 emr.ihPal = index; 551 return emfdc_record( emf, &emr.emr ); 552 } 553 554 BOOL EMFDC_SelectObject( WINEDC *dc_attr, HGDIOBJ obj ) 555 { 556 switch (GDI_HANDLE_GET_TYPE( obj )) 557 { 558 case GDILoObjType_LO_BRUSH_TYPE: 559 return emfdc_select_brush( dc_attr, obj ); 560 case GDILoObjType_LO_FONT_TYPE: 561 return emfdc_select_font( dc_attr, obj ); 562 case GDILoObjType_LO_PEN_TYPE: 563 case GDILoObjType_LO_EXTPEN_TYPE: 564 return emfdc_select_pen( dc_attr, obj ); 565 default: 566 return TRUE; 567 } 568 } 569 570 /* determine if we can use 16-bit points to store all the input points */ 571 static BOOL can_use_short_points( const POINT *pts, UINT count ) 572 { 573 UINT i; 574 575 for (i = 0; i < count; i++) 576 if (((pts[i].x + 0x8000) & ~0xffff) || ((pts[i].y + 0x8000) & ~0xffff)) 577 return FALSE; 578 return TRUE; 579 } 580 581 /* store points in either long or short format; return a pointer to the end of the stored data */ 582 static void *store_points( POINTL *dest, const POINT *pts, UINT count, BOOL short_points ) 583 { 584 if (short_points) 585 { 586 UINT i; 587 POINTS *dest_short = (POINTS *)dest; 588 589 for (i = 0; i < count; i++) 590 { 591 dest_short[i].x = pts[i].x; 592 dest_short[i].y = pts[i].y; 593 } 594 return dest_short + count; 595 } 596 else 597 { 598 memcpy( dest, pts, count * sizeof(*dest) ); 599 return dest + count; 600 } 601 } 602 603 /* compute the bounds of an array of points, optionally including the current position */ 604 static void get_points_bounds( RECTL *bounds, const POINT *pts, UINT count, WINEDC *dc_attr ) 605 { 606 UINT i; 607 608 if (dc_attr) 609 { 610 POINT cur_pos; 611 GetCurrentPositionEx(dc_attr->hdc, &cur_pos); 612 bounds->left = bounds->right = cur_pos.x; 613 bounds->top = bounds->bottom = cur_pos.y; 614 } 615 else if (count) 616 { 617 bounds->left = bounds->right = pts[0].x; 618 bounds->top = bounds->bottom = pts[0].y; 619 } 620 else *bounds = empty_bounds; 621 622 for (i = 0; i < count; i++) 623 { 624 bounds->left = min( bounds->left, pts[i].x ); 625 bounds->right = max( bounds->right, pts[i].x ); 626 bounds->top = min( bounds->top, pts[i].y ); 627 bounds->bottom = max( bounds->bottom, pts[i].y ); 628 } 629 } 630 631 /* helper for path stroke and fill functions */ 632 #ifdef __REACTOS__ 633 static BOOL emfdrv_stroke_and_fill_path( struct emf *emf, INT type ) 634 { 635 EMRSTROKEANDFILLPATH emr; 636 LPPOINT Points; 637 LPBYTE Types; 638 INT nSize; 639 640 emr.emr.iType = type; 641 emr.emr.nSize = sizeof(emr); 642 643 nSize = GetPath(emf->dc_attr->hdc, NULL, NULL, 0); 644 if (nSize != -1) 645 { 646 Points = HeapAlloc( GetProcessHeap(), 0, nSize*sizeof(POINT) ); 647 Types = HeapAlloc( GetProcessHeap(), 0, nSize*sizeof(BYTE) ); 648 649 GetPath(emf->dc_attr->hdc, Points, Types, nSize); 650 get_points_bounds( &emr.rclBounds, Points, nSize, 0 ); 651 652 HeapFree( GetProcessHeap(), 0, Points ); 653 HeapFree( GetProcessHeap(), 0, Types ); 654 655 TRACE("GetBounds l %d t %d r %d b %d\n",emr.rclBounds.left, emr.rclBounds.top, emr.rclBounds.right, emr.rclBounds.bottom); 656 } 657 else emr.rclBounds = empty_bounds; 658 659 if (!emfdc_record( emf, &emr.emr )) return FALSE; 660 if (nSize == -1 ) return FALSE; 661 emfdc_update_bounds( emf, &emr.rclBounds ); 662 return TRUE; 663 } 664 #else 665 static BOOL emfdrv_stroke_and_fill_path( struct emf *emf, INT type ) 666 { 667 EMRSTROKEANDFILLPATH emr; 668 HRGN region; 669 670 emr.emr.iType = type; 671 emr.emr.nSize = sizeof(emr); 672 emr.rclBounds = empty_bounds; 673 674 if ((region = NtGdiPathToRegion( emf->dc_attr->hdc ))) // WTF are you doing? This removes path!!! 675 { 676 NtGdiGetRgnBox( region, (RECT *)&emr.rclBounds ); 677 DeleteObject( region ); 678 } 679 if (!emfdc_record( emf, &emr.emr )) return FALSE; 680 if (!region) return FALSE; 681 emfdc_update_bounds( emf, &emr.rclBounds ); 682 return TRUE; 683 } 684 #endif 685 BOOL EMFDC_MoveTo( WINEDC *dc_attr, INT x, INT y ) 686 { 687 struct emf *emf = dc_attr->emf; 688 EMRMOVETOEX emr; 689 690 emr.emr.iType = EMR_MOVETOEX; 691 emr.emr.nSize = sizeof(emr); 692 emr.ptl.x = x; 693 emr.ptl.y = y; 694 return emfdc_record( emf, &emr.emr ); 695 } 696 697 BOOL EMFDC_LineTo( WINEDC *dc_attr, INT x, INT y ) 698 { 699 EMRLINETO emr; 700 BOOL Ret; 701 702 emr.emr.iType = EMR_LINETO; 703 emr.emr.nSize = sizeof(emr); 704 emr.ptl.x = x; 705 emr.ptl.y = y; 706 Ret = emfdc_record( dc_attr->emf, &emr.emr ); 707 EMFDRV_LineTo( dc_attr, x, y ); 708 return Ret; 709 } 710 711 BOOL EMFDC_ArcChordPie( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom, 712 INT xstart, INT ystart, INT xend, INT yend, DWORD type ) 713 { 714 struct emf *emf = dc_attr->emf; 715 EMRARC emr; 716 INT temp; 717 BOOL Ret; 718 719 if (left == right || top == bottom) return FALSE; 720 721 if (left > right) { temp = left; left = right; right = temp; } 722 if (top > bottom) { temp = top; top = bottom; bottom = temp; } 723 724 if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE) 725 { 726 right--; 727 bottom--; 728 } 729 730 emr.emr.iType = type; 731 emr.emr.nSize = sizeof(emr); 732 emr.rclBox.left = left; 733 emr.rclBox.top = top; 734 emr.rclBox.right = right; 735 emr.rclBox.bottom = bottom; 736 emr.ptlStart.x = xstart; 737 emr.ptlStart.y = ystart; 738 emr.ptlEnd.x = xend; 739 emr.ptlEnd.y = yend; 740 Ret = emfdc_record( emf, &emr.emr ); 741 EMFDRV_ArcChordPie( dc_attr, left, top, right, bottom, xstart, ystart, xend, yend, type ); 742 return Ret; 743 } 744 745 BOOL EMFDC_AngleArc( WINEDC *dc_attr, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep ) 746 { 747 EMRANGLEARC emr; 748 749 emr.emr.iType = EMR_ANGLEARC; 750 emr.emr.nSize = sizeof( emr ); 751 emr.ptlCenter.x = x; 752 emr.ptlCenter.y = y; 753 emr.nRadius = radius; 754 emr.eStartAngle = start; 755 emr.eSweepAngle = sweep; 756 return emfdc_record( dc_attr->emf, &emr.emr ); 757 } 758 759 BOOL EMFDC_Ellipse( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom ) 760 { 761 struct emf *emf = dc_attr->emf; 762 EMRELLIPSE emr; 763 BOOL Ret; 764 765 if (left == right || top == bottom) return FALSE; 766 767 emr.emr.iType = EMR_ELLIPSE; 768 emr.emr.nSize = sizeof(emr); 769 emr.rclBox.left = min( left, right ); 770 emr.rclBox.top = min( top, bottom ); 771 emr.rclBox.right = max( left, right ); 772 emr.rclBox.bottom = max( top, bottom ); 773 if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE) 774 { 775 emr.rclBox.right--; 776 emr.rclBox.bottom--; 777 } 778 Ret = emfdc_record( emf, &emr.emr ); 779 EMFDRV_Ellipse( dc_attr, left, top, right, bottom ); 780 return Ret; 781 } 782 783 BOOL EMFDC_Rectangle( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom ) 784 { 785 struct emf *emf = dc_attr->emf; 786 EMRRECTANGLE emr; 787 BOOL Ret; 788 789 if(left == right || top == bottom) return FALSE; 790 791 emr.emr.iType = EMR_RECTANGLE; 792 emr.emr.nSize = sizeof(emr); 793 emr.rclBox.left = min( left, right ); 794 emr.rclBox.top = min( top, bottom ); 795 emr.rclBox.right = max( left, right ); 796 emr.rclBox.bottom = max( top, bottom ); 797 if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE) 798 { 799 emr.rclBox.right--; 800 emr.rclBox.bottom--; 801 } 802 Ret = emfdc_record( emf, &emr.emr ); 803 EMFDRV_Rectangle( dc_attr, left, top, right, bottom ); 804 return Ret; 805 } 806 807 BOOL EMFDC_RoundRect( WINEDC *dc_attr, INT left, INT top, INT right, 808 INT bottom, INT ell_width, INT ell_height ) 809 { 810 struct emf *emf = dc_attr->emf; 811 EMRROUNDRECT emr; 812 BOOL Ret; 813 814 if (left == right || top == bottom) return FALSE; 815 816 emr.emr.iType = EMR_ROUNDRECT; 817 emr.emr.nSize = sizeof(emr); 818 emr.rclBox.left = min( left, right ); 819 emr.rclBox.top = min( top, bottom ); 820 emr.rclBox.right = max( left, right ); 821 emr.rclBox.bottom = max( top, bottom ); 822 emr.szlCorner.cx = ell_width; 823 emr.szlCorner.cy = ell_height; 824 if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE) 825 { 826 emr.rclBox.right--; 827 emr.rclBox.bottom--; 828 } 829 Ret = emfdc_record( emf, &emr.emr ); 830 EMFDRV_RoundRect( dc_attr, left, top, right, bottom, ell_width, ell_height ); 831 return Ret; 832 } 833 834 BOOL EMFDC_SetPixel( WINEDC *dc_attr, INT x, INT y, COLORREF color ) 835 { 836 EMRSETPIXELV emr; 837 BOOL Ret; 838 839 emr.emr.iType = EMR_SETPIXELV; 840 emr.emr.nSize = sizeof(emr); 841 emr.ptlPixel.x = x; 842 emr.ptlPixel.y = y; 843 emr.crColor = color; 844 Ret = emfdc_record( dc_attr->emf, &emr.emr ); 845 EMFDRV_SetPixel( dc_attr, x, y, color ); 846 return Ret; 847 } 848 849 static BOOL emfdc_polylinegon( WINEDC *dc_attr, const POINT *points, INT count, DWORD type ) 850 { 851 struct emf *emf = dc_attr->emf; 852 EMRPOLYLINE *emr; 853 DWORD size; 854 BOOL ret, use_small_emr = can_use_short_points( points, count ); 855 856 size = use_small_emr ? (DWORD)offsetof( EMRPOLYLINE16, apts[count] ) : (DWORD)offsetof( EMRPOLYLINE, aptl[count] ); 857 858 emr = HeapAlloc( GetProcessHeap(), 0, size ); 859 emr->emr.iType = use_small_emr ? type + EMR_POLYLINE16 - EMR_POLYLINE : type; 860 emr->emr.nSize = size; 861 emr->cptl = count; 862 863 store_points( emr->aptl, points, count, use_small_emr ); 864 865 if (!emf->path) 866 get_points_bounds( &emr->rclBounds, points, count, 867 (type == EMR_POLYBEZIERTO || type == EMR_POLYLINETO) ? dc_attr : 0 ); 868 else 869 emr->rclBounds = empty_bounds; 870 871 ret = emfdc_record( emf, &emr->emr ); 872 if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds ); 873 HeapFree( GetProcessHeap(), 0, emr ); 874 return ret; 875 } 876 877 BOOL EMFDC_Polyline( WINEDC *dc_attr, const POINT *points, INT count ) 878 { 879 return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINE ); 880 } 881 882 BOOL EMFDC_PolylineTo( WINEDC *dc_attr, const POINT *points, INT count ) 883 { 884 return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINETO ); 885 } 886 887 BOOL EMFDC_Polygon( WINEDC *dc_attr, const POINT *pt, INT count ) 888 { 889 if(count < 2) return FALSE; 890 return emfdc_polylinegon( dc_attr, pt, count, EMR_POLYGON ); 891 } 892 893 BOOL EMFDC_PolyBezier( WINEDC *dc_attr, const POINT *pts, DWORD count ) 894 { 895 return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIER ); 896 } 897 898 BOOL EMFDC_PolyBezierTo( WINEDC *dc_attr, const POINT *pts, DWORD count ) 899 { 900 return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIERTO ); 901 } 902 903 static BOOL emfdc_poly_polylinegon( struct emf *emf, const POINT *pt, const INT *counts, 904 UINT polys, DWORD type) 905 { 906 EMRPOLYPOLYLINE *emr; 907 DWORD cptl = 0, poly, size; 908 BOOL ret, use_small_emr, bounds_valid = TRUE; 909 910 for(poly = 0; poly < polys; poly++) { 911 cptl += counts[poly]; 912 if(counts[poly] < 2) bounds_valid = FALSE; 913 } 914 if(!cptl) bounds_valid = FALSE; 915 use_small_emr = can_use_short_points( pt, cptl ); 916 917 size = FIELD_OFFSET(EMRPOLYPOLYLINE, aPolyCounts[polys]); 918 if(use_small_emr) 919 size += cptl * sizeof(POINTS); 920 else 921 size += cptl * sizeof(POINTL); 922 923 emr = HeapAlloc( GetProcessHeap(), 0, size ); 924 925 emr->emr.iType = type; 926 if(use_small_emr) emr->emr.iType += EMR_POLYPOLYLINE16 - EMR_POLYPOLYLINE; 927 928 emr->emr.nSize = size; 929 if(bounds_valid && !emf->path) 930 get_points_bounds( &emr->rclBounds, pt, cptl, 0 ); 931 else 932 emr->rclBounds = empty_bounds; 933 emr->nPolys = polys; 934 emr->cptl = cptl; 935 936 if(polys) 937 { 938 memcpy( emr->aPolyCounts, counts, polys * sizeof(DWORD) ); 939 store_points( (POINTL *)(emr->aPolyCounts + polys), pt, cptl, use_small_emr ); 940 } 941 942 ret = emfdc_record( emf, &emr->emr ); 943 if(ret && !bounds_valid) 944 { 945 ret = FALSE; 946 SetLastError( ERROR_INVALID_PARAMETER ); 947 } 948 if(ret && !emf->path) 949 emfdc_update_bounds( emf, &emr->rclBounds ); 950 HeapFree( GetProcessHeap(), 0, emr ); 951 return ret; 952 } 953 954 BOOL EMFDC_PolyPolyline( WINEDC *dc_attr, const POINT *pt, const DWORD *counts, DWORD polys) 955 { 956 return emfdc_poly_polylinegon( dc_attr->emf, pt, (const INT *)counts, polys, EMR_POLYPOLYLINE ); 957 } 958 959 BOOL EMFDC_PolyPolygon( WINEDC *dc_attr, const POINT *pt, const INT *counts, UINT polys ) 960 { 961 return emfdc_poly_polylinegon( dc_attr->emf, pt, counts, polys, EMR_POLYPOLYGON ); 962 } 963 964 BOOL EMFDC_PolyDraw( WINEDC *dc_attr, const POINT *pts, const BYTE *types, DWORD count ) 965 { 966 struct emf *emf = dc_attr->emf; 967 EMRPOLYDRAW *emr; 968 BOOL ret; 969 BYTE *types_dest; 970 BOOL use_small_emr = can_use_short_points( pts, count ); 971 DWORD size; 972 973 size = use_small_emr ? (DWORD)offsetof( EMRPOLYDRAW16, apts[count] ) 974 : (DWORD)offsetof( EMRPOLYDRAW, aptl[count] ); 975 size += (count + 3) & ~3; 976 977 if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; 978 979 emr->emr.iType = use_small_emr ? EMR_POLYDRAW16 : EMR_POLYDRAW; 980 emr->emr.nSize = size; 981 emr->cptl = count; 982 983 types_dest = store_points( emr->aptl, pts, count, use_small_emr ); 984 memcpy( types_dest, types, count ); 985 if (count & 3) memset( types_dest + count, 0, 4 - (count & 3) ); 986 987 if (!emf->path) 988 get_points_bounds( &emr->rclBounds, pts, count, 0 ); 989 else 990 emr->rclBounds = empty_bounds; 991 992 ret = emfdc_record( emf, &emr->emr ); 993 if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds ); 994 HeapFree( GetProcessHeap(), 0, emr ); 995 return ret; 996 } 997 998 BOOL EMFDC_ExtFloodFill( WINEDC *dc_attr, INT x, INT y, COLORREF color, UINT fill_type ) 999 { 1000 EMREXTFLOODFILL emr; 1001 1002 emr.emr.iType = EMR_EXTFLOODFILL; 1003 emr.emr.nSize = sizeof(emr); 1004 emr.ptlStart.x = x; 1005 emr.ptlStart.y = y; 1006 emr.crColor = color; 1007 emr.iMode = fill_type; 1008 return emfdc_record( dc_attr->emf, &emr.emr ); 1009 } 1010 1011 BOOL EMFDC_FillRgn( WINEDC *dc_attr, HRGN hrgn, HBRUSH hbrush ) 1012 { 1013 struct emf *emf = dc_attr->emf; 1014 EMRFILLRGN *emr; 1015 DWORD size, rgnsize, index; 1016 BOOL ret; 1017 1018 if (!(index = emfdc_create_brush( emf, hbrush ))) return FALSE; 1019 1020 rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL ); 1021 size = rgnsize + offsetof(EMRFILLRGN,RgnData); 1022 emr = HeapAlloc( GetProcessHeap(), 0, size ); 1023 1024 /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData ); 1025 1026 emr->emr.iType = EMR_FILLRGN; 1027 emr->emr.nSize = size; 1028 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left; 1029 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top; 1030 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1; 1031 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1; 1032 emr->cbRgnData = rgnsize; 1033 emr->ihBrush = index; 1034 1035 ret = emfdc_record( emf, &emr->emr ); 1036 if (ret) emfdc_update_bounds( emf, &emr->rclBounds ); 1037 HeapFree( GetProcessHeap(), 0, emr ); 1038 return ret; 1039 } 1040 1041 BOOL EMFDC_FrameRgn( WINEDC *dc_attr, HRGN hrgn, HBRUSH hbrush, INT width, INT height ) 1042 { 1043 struct emf *emf = dc_attr->emf; 1044 EMRFRAMERGN *emr; 1045 DWORD size, rgnsize, index; 1046 BOOL ret; 1047 1048 index = emfdc_create_brush( emf, hbrush ); 1049 if(!index) return FALSE; 1050 1051 rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL ); 1052 size = rgnsize + offsetof(EMRFRAMERGN,RgnData); 1053 emr = HeapAlloc( GetProcessHeap(), 0, size ); 1054 1055 /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData ); 1056 1057 emr->emr.iType = EMR_FRAMERGN; 1058 emr->emr.nSize = size; 1059 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left; 1060 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top; 1061 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1; 1062 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1; 1063 emr->cbRgnData = rgnsize; 1064 emr->ihBrush = index; 1065 emr->szlStroke.cx = width; 1066 emr->szlStroke.cy = height; 1067 1068 ret = emfdc_record( emf, &emr->emr ); 1069 if (ret) emfdc_update_bounds( emf, &emr->rclBounds ); 1070 HeapFree( GetProcessHeap(), 0, emr ); 1071 return ret; 1072 } 1073 1074 static BOOL emfdc_paint_invert_region( struct emf *emf, HRGN hrgn, DWORD iType ) 1075 { 1076 EMRINVERTRGN *emr; 1077 DWORD size, rgnsize; 1078 BOOL ret; 1079 1080 rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL ); 1081 size = rgnsize + offsetof(EMRINVERTRGN,RgnData); 1082 emr = HeapAlloc( GetProcessHeap(), 0, size ); 1083 1084 /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData ); 1085 1086 emr->emr.iType = iType; 1087 emr->emr.nSize = size; 1088 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left; 1089 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top; 1090 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1; 1091 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1; 1092 emr->cbRgnData = rgnsize; 1093 1094 ret = emfdc_record( emf, &emr->emr ); 1095 if (ret) emfdc_update_bounds( emf, &emr->rclBounds ); 1096 HeapFree( GetProcessHeap(), 0, emr ); 1097 return ret; 1098 } 1099 1100 BOOL EMFDC_PaintRgn( WINEDC *dc_attr, HRGN hrgn ) 1101 { 1102 return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_PAINTRGN ); 1103 } 1104 1105 BOOL EMFDC_InvertRgn( WINEDC *dc_attr, HRGN hrgn ) 1106 { 1107 return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_INVERTRGN ); 1108 } 1109 1110 BOOL EMFDC_ExtTextOut( WINEDC *dc_attr, INT x, INT y, UINT flags, const RECT *rect, 1111 const WCHAR *str, UINT count, const INT *dx ) 1112 { 1113 struct emf *emf = dc_attr->emf; 1114 FLOAT ex_scale, ey_scale; 1115 EMREXTTEXTOUTW *emr; 1116 int text_height = 0; 1117 int text_width = 0; 1118 TEXTMETRICW tm; 1119 DWORD size; 1120 BOOL ret; 1121 1122 if (count > INT_MAX) return FALSE; 1123 1124 size = sizeof(*emr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(INT); 1125 1126 TRACE( "%s %s count %d size = %d\n", debugstr_wn(str, count), 1127 wine_dbgstr_rect(rect), count, size ); 1128 emr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); 1129 1130 if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE) 1131 { 1132 const INT horzSize = GetDeviceCaps( dc_attr->hdc, HORZSIZE ); 1133 const INT horzRes = GetDeviceCaps( dc_attr->hdc, HORZRES ); 1134 const INT vertSize = GetDeviceCaps( dc_attr->hdc, VERTSIZE ); 1135 const INT vertRes = GetDeviceCaps( dc_attr->hdc, VERTRES ); 1136 SIZE wndext, vportext; 1137 1138 GetViewportExtEx( dc_attr->hdc, &vportext ); 1139 GetWindowExtEx( dc_attr->hdc, &wndext ); 1140 ex_scale = 100.0 * ((FLOAT)horzSize / (FLOAT)horzRes) / 1141 ((FLOAT)wndext.cx / (FLOAT)vportext.cx); 1142 ey_scale = 100.0 * ((FLOAT)vertSize / (FLOAT)vertRes) / 1143 ((FLOAT)wndext.cy / (FLOAT)vportext.cy); 1144 } 1145 else 1146 { 1147 ex_scale = 0.0; 1148 ey_scale = 0.0; 1149 } 1150 1151 emr->emr.iType = EMR_EXTTEXTOUTW; 1152 emr->emr.nSize = size; 1153 emr->iGraphicsMode = GetGraphicsMode(dc_attr->hdc); 1154 emr->exScale = ex_scale; 1155 emr->eyScale = ey_scale; 1156 emr->emrtext.ptlReference.x = x; 1157 emr->emrtext.ptlReference.y = y; 1158 emr->emrtext.nChars = count; 1159 emr->emrtext.offString = sizeof(*emr); 1160 memcpy( (char*)emr + emr->emrtext.offString, str, count * sizeof(WCHAR) ); 1161 emr->emrtext.fOptions = flags; 1162 if (!rect) 1163 { 1164 emr->emrtext.rcl.left = emr->emrtext.rcl.top = 0; 1165 emr->emrtext.rcl.right = emr->emrtext.rcl.bottom = -1; 1166 } 1167 else 1168 { 1169 emr->emrtext.rcl.left = rect->left; 1170 emr->emrtext.rcl.top = rect->top; 1171 emr->emrtext.rcl.right = rect->right; 1172 emr->emrtext.rcl.bottom = rect->bottom; 1173 } 1174 1175 emr->emrtext.offDx = emr->emrtext.offString + ((count+1) & ~1) * sizeof(WCHAR); 1176 if (dx) 1177 { 1178 UINT i; 1179 SIZE str_size; 1180 memcpy( (char*)emr + emr->emrtext.offDx, dx, count * sizeof(INT) ); 1181 for (i = 0; i < count; i++) text_width += dx[i]; 1182 if (GetTextExtentPoint32W( dc_attr->hdc, str, count, &str_size )) 1183 text_height = str_size.cy; 1184 } 1185 else 1186 { 1187 UINT i; 1188 INT *emf_dx = (INT *)((char*)emr + emr->emrtext.offDx); 1189 SIZE charSize; 1190 for (i = 0; i < count; i++) 1191 { 1192 if (GetTextExtentPoint32W( dc_attr->hdc, str + i, 1, &charSize )) 1193 { 1194 emf_dx[i] = charSize.cx; 1195 text_width += charSize.cx; 1196 text_height = max( text_height, charSize.cy ); 1197 } 1198 } 1199 } 1200 1201 if (emf->path) 1202 { 1203 emr->rclBounds.left = emr->rclBounds.top = 0; 1204 emr->rclBounds.right = emr->rclBounds.bottom = -1; 1205 goto no_bounds; 1206 } 1207 1208 /* FIXME: handle font escapement */ 1209 switch (GetTextAlign(dc_attr->hdc) & (TA_LEFT | TA_RIGHT | TA_CENTER)) 1210 { 1211 case TA_CENTER: 1212 emr->rclBounds.left = x - (text_width / 2) - 1; 1213 emr->rclBounds.right = x + (text_width / 2) + 1; 1214 break; 1215 1216 case TA_RIGHT: 1217 emr->rclBounds.left = x - text_width - 1; 1218 emr->rclBounds.right = x; 1219 break; 1220 1221 default: /* TA_LEFT */ 1222 emr->rclBounds.left = x; 1223 emr->rclBounds.right = x + text_width + 1; 1224 } 1225 1226 switch (GetTextAlign(dc_attr->hdc) & (TA_TOP | TA_BOTTOM | TA_BASELINE)) 1227 { 1228 case TA_BASELINE: 1229 if (!GetTextMetricsW( dc_attr->hdc, &tm )) tm.tmDescent = 0; 1230 /* Play safe here... it's better to have a bounding box */ 1231 /* that is too big than too small. */ 1232 emr->rclBounds.top = y - text_height - 1; 1233 emr->rclBounds.bottom = y + tm.tmDescent + 1; 1234 break; 1235 1236 case TA_BOTTOM: 1237 emr->rclBounds.top = y - text_height - 1; 1238 emr->rclBounds.bottom = y; 1239 break; 1240 1241 default: /* TA_TOP */ 1242 emr->rclBounds.top = y; 1243 emr->rclBounds.bottom = y + text_height + 1; 1244 } 1245 emfdc_update_bounds( emf, &emr->rclBounds ); 1246 1247 no_bounds: 1248 ret = emfdc_record( emf, &emr->emr ); 1249 HeapFree( GetProcessHeap(), 0, emr ); 1250 return ret; 1251 } 1252 1253 BOOL EMFDC_GradientFill( WINEDC *dc_attr, TRIVERTEX *vert_array, ULONG nvert, 1254 void *grad_array, ULONG ngrad, ULONG mode ) 1255 { 1256 EMRGRADIENTFILL *emr; 1257 ULONG i, pt, size, num_pts = ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); 1258 const ULONG *pts = (const ULONG *)grad_array; 1259 BOOL ret; 1260 1261 size = FIELD_OFFSET(EMRGRADIENTFILL, Ver[nvert]) + num_pts * sizeof(pts[0]); 1262 1263 emr = HeapAlloc( GetProcessHeap(), 0, size ); 1264 if (!emr) return FALSE; 1265 1266 for (i = 0; i < num_pts; i++) 1267 { 1268 pt = pts[i]; 1269 1270 if (i == 0) 1271 { 1272 emr->rclBounds.left = emr->rclBounds.right = vert_array[pt].x; 1273 emr->rclBounds.top = emr->rclBounds.bottom = vert_array[pt].y; 1274 } 1275 else 1276 { 1277 if (vert_array[pt].x < emr->rclBounds.left) 1278 emr->rclBounds.left = vert_array[pt].x; 1279 else if (vert_array[pt].x > emr->rclBounds.right) 1280 emr->rclBounds.right = vert_array[pt].x; 1281 if (vert_array[pt].y < emr->rclBounds.top) 1282 emr->rclBounds.top = vert_array[pt].y; 1283 else if (vert_array[pt].y > emr->rclBounds.bottom) 1284 emr->rclBounds.bottom = vert_array[pt].y; 1285 } 1286 } 1287 emr->rclBounds.right--; 1288 emr->rclBounds.bottom--; 1289 1290 emr->emr.iType = EMR_GRADIENTFILL; 1291 emr->emr.nSize = size; 1292 emr->nVer = nvert; 1293 emr->nTri = ngrad; 1294 emr->ulMode = mode; 1295 memcpy( emr->Ver, vert_array, nvert * sizeof(vert_array[0]) ); 1296 memcpy( emr->Ver + nvert, pts, num_pts * sizeof(pts[0]) ); 1297 1298 emfdc_update_bounds( dc_attr->emf, &emr->rclBounds ); 1299 ret = emfdc_record( dc_attr->emf, &emr->emr ); 1300 HeapFree( GetProcessHeap(), 0, emr ); 1301 return ret; 1302 } 1303 1304 BOOL EMFDC_FillPath( WINEDC *dc_attr ) 1305 { 1306 return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_FILLPATH ); 1307 } 1308 1309 BOOL EMFDC_StrokeAndFillPath( WINEDC *dc_attr ) 1310 { 1311 return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEANDFILLPATH ); 1312 } 1313 1314 BOOL EMFDC_StrokePath( WINEDC *dc_attr ) 1315 { 1316 return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEPATH ); 1317 } 1318 1319 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */ 1320 static BOOL emfdrv_stretchblt( struct emf *emf, INT x_dst, INT y_dst, INT width_dst, INT height_dst, 1321 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src, 1322 DWORD rop, DWORD type ) 1323 { 1324 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }}; 1325 UINT bmi_size, emr_size, size; 1326 HBITMAP bitmap, blit_bitmap = NULL; 1327 EMRBITBLT *emr = NULL; 1328 BITMAPINFO *bmi; 1329 HDC blit_dc; 1330 BOOL ret = FALSE; 1331 1332 if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE) 1333 { 1334 WINEDC * pldc = get_dc_ptr(hdc_src); 1335 1336 if (pldc->iType == LDC_EMFLDC) 1337 { 1338 return FALSE; 1339 } 1340 } 1341 1342 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE; 1343 1344 blit_dc = hdc_src; 1345 blit_bitmap = bitmap; 1346 if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE; 1347 1348 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */ 1349 emr_size = type == EMR_BITBLT ? sizeof(EMRBITBLT) : sizeof(EMRSTRETCHBLT); 1350 size = emr_size + bmi_size + src_info.bmiHeader.biSizeImage; 1351 1352 if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err; 1353 1354 emr->emr.iType = type; 1355 emr->emr.nSize = size; 1356 emr->rclBounds.left = x_dst; 1357 emr->rclBounds.top = y_dst; 1358 emr->rclBounds.right = x_dst + width_dst - 1; 1359 emr->rclBounds.bottom = y_dst + height_dst - 1; 1360 emr->xDest = x_dst; 1361 emr->yDest = y_dst; 1362 emr->cxDest = width_dst; 1363 emr->cyDest = height_dst; 1364 emr->xSrc = x_src; 1365 emr->ySrc = y_src; 1366 if (type != EMR_BITBLT) 1367 { 1368 EMRSTRETCHBLT *emr_stretchblt = (EMRSTRETCHBLT *)emr; 1369 emr_stretchblt->cxSrc = width_src; 1370 emr_stretchblt->cySrc = height_src; 1371 } 1372 emr->dwRop = rop; 1373 NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc ); 1374 emr->crBkColorSrc = GetBkColor( hdc_src ); 1375 emr->iUsageSrc = DIB_RGB_COLORS; 1376 emr->offBmiSrc = emr_size; 1377 emr->cbBmiSrc = bmi_size; 1378 emr->offBitsSrc = emr_size + bmi_size; 1379 emr->cbBitsSrc = src_info.bmiHeader.biSizeImage; 1380 1381 bmi = (BITMAPINFO *)((BYTE *)emr + emr->offBmiSrc); 1382 bmi->bmiHeader = src_info.bmiHeader; 1383 ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight, 1384 (BYTE *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS ); 1385 1386 if (ret) 1387 { 1388 ret = emfdc_record( emf, (EMR *)emr ); 1389 if (ret) emfdc_update_bounds( emf, &emr->rclBounds ); 1390 } 1391 1392 err: 1393 HeapFree( GetProcessHeap(), 0, emr ); 1394 if (blit_bitmap != bitmap) DeleteObject( blit_bitmap ); 1395 if (blit_dc != hdc_src) DeleteDC( blit_dc ); 1396 return ret; 1397 } 1398 1399 BOOL EMFDC_AlphaBlend( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst, 1400 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src, 1401 BLENDFUNCTION blend_function ) 1402 { 1403 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst, hdc_src, 1404 x_src, y_src, width_src, height_src, *(DWORD *)&blend_function, 1405 EMR_ALPHABLEND ); 1406 } 1407 1408 BOOL EMFDC_PatBlt( WINEDC *dc_attr, INT left, INT top, INT width, INT height, DWORD rop ) 1409 { 1410 struct emf *emf = dc_attr->emf; 1411 EMRBITBLT emr; 1412 BOOL ret; 1413 1414 emr.emr.iType = EMR_BITBLT; 1415 emr.emr.nSize = sizeof(emr); 1416 emr.rclBounds.left = left; 1417 emr.rclBounds.top = top; 1418 emr.rclBounds.right = left + width - 1; 1419 emr.rclBounds.bottom = top + height - 1; 1420 emr.xDest = left; 1421 emr.yDest = top; 1422 emr.cxDest = width; 1423 emr.cyDest = height; 1424 emr.dwRop = rop; 1425 emr.xSrc = 0; 1426 emr.ySrc = 0; 1427 emr.xformSrc.eM11 = 1.0; 1428 emr.xformSrc.eM12 = 0.0; 1429 emr.xformSrc.eM21 = 0.0; 1430 emr.xformSrc.eM22 = 1.0; 1431 emr.xformSrc.eDx = 0.0; 1432 emr.xformSrc.eDy = 0.0; 1433 emr.crBkColorSrc = 0; 1434 emr.iUsageSrc = 0; 1435 emr.offBmiSrc = 0; 1436 emr.cbBmiSrc = 0; 1437 emr.offBitsSrc = 0; 1438 emr.cbBitsSrc = 0; 1439 1440 ret = emfdc_record( emf, &emr.emr ); 1441 if (ret) emfdc_update_bounds( emf, &emr.rclBounds ); 1442 return ret; 1443 } 1444 1445 static inline BOOL rop_uses_src( DWORD rop ) 1446 { 1447 return ((rop >> 2) & 0x330000) != (rop & 0x330000); 1448 } 1449 1450 BOOL EMFDC_BitBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width, INT height, 1451 HDC hdc_src, INT x_src, INT y_src, DWORD rop ) 1452 { 1453 if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width, height, rop ); 1454 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width, height, 1455 hdc_src, x_src, y_src, width, height, rop, EMR_BITBLT ); 1456 } 1457 1458 BOOL EMFDC_StretchBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst, 1459 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src, 1460 DWORD rop ) 1461 { 1462 if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop ); 1463 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst, 1464 hdc_src, x_src, y_src, width_src, 1465 height_src, rop, EMR_STRETCHBLT ); 1466 } 1467 1468 BOOL EMFDC_TransparentBlt( WINEDC *dc_attr, int x_dst, int y_dst, int width_dst, int height_dst, 1469 HDC hdc_src, int x_src, int y_src, int width_src, int height_src, 1470 UINT color ) 1471 { 1472 return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst, 1473 hdc_src, x_src, y_src, width_src, 1474 height_src, color, EMR_TRANSPARENTBLT ); 1475 } 1476 1477 BOOL EMFDC_MaskBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst, 1478 HDC hdc_src, INT x_src, INT y_src, HBITMAP mask, 1479 INT x_mask, INT y_mask, DWORD rop ) 1480 { 1481 unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors) 1482 + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)]; 1483 BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer; 1484 struct emf *emf = dc_attr->emf; 1485 BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }}; 1486 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }}; 1487 HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL; 1488 UINT bmi_size, size, mask_info_size = 0; 1489 EMRMASKBLT *emr = NULL; 1490 BITMAPINFO *bmi; 1491 HDC blit_dc, mask_dc = NULL; 1492 BOOL ret = FALSE; 1493 1494 if (!rop_uses_src( rop )) 1495 return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop ); 1496 1497 if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE) 1498 { 1499 WINEDC * pldc = get_dc_ptr(hdc_src); 1500 1501 if (pldc->iType == LDC_EMFLDC) 1502 { 1503 return FALSE; 1504 } 1505 } 1506 1507 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE; 1508 blit_dc = hdc_src; 1509 blit_bitmap = bitmap; 1510 if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE; 1511 1512 if (mask) 1513 { 1514 mask_dc = hdc_src; 1515 mask_bitmap = mask; 1516 if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err; 1517 if (mask_info.bmiHeader.biBitCount == 1) 1518 mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */ 1519 } 1520 else mask_info.bmiHeader.biSizeImage = 0; 1521 1522 size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage + 1523 mask_info_size + mask_info.bmiHeader.biSizeImage; 1524 1525 if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err; 1526 1527 emr->emr.iType = EMR_MASKBLT; 1528 emr->emr.nSize = size; 1529 emr->rclBounds.left = x_dst; 1530 emr->rclBounds.top = y_dst; 1531 emr->rclBounds.right = x_dst + width_dst - 1; 1532 emr->rclBounds.bottom = y_dst + height_dst - 1; 1533 emr->xDest = x_dst; 1534 emr->yDest = y_dst; 1535 emr->cxDest = width_dst; 1536 emr->cyDest = height_dst; 1537 emr->dwRop = rop; 1538 emr->xSrc = x_src; 1539 emr->ySrc = y_src; 1540 NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc ); 1541 emr->crBkColorSrc = GetBkColor( hdc_src ); 1542 emr->iUsageSrc = DIB_RGB_COLORS; 1543 emr->offBmiSrc = sizeof(*emr); 1544 emr->cbBmiSrc = bmi_size; 1545 emr->offBitsSrc = emr->offBmiSrc + bmi_size; 1546 emr->cbBitsSrc = src_info.bmiHeader.biSizeImage; 1547 emr->xMask = x_mask; 1548 emr->yMask = y_mask; 1549 emr->iUsageMask = DIB_PAL_MONO; 1550 emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0; 1551 emr->cbBmiMask = mask_info_size; 1552 emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask; 1553 emr->cbBitsMask = mask_info.bmiHeader.biSizeImage; 1554 1555 bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc); 1556 bmi->bmiHeader = src_info.bmiHeader; 1557 ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight, 1558 (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS ); 1559 if (!ret) goto err; 1560 1561 if (mask_info_size) 1562 { 1563 mask_bits_info->bmiHeader = mask_info.bmiHeader; 1564 ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight, 1565 (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS ); 1566 if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size ); 1567 } 1568 1569 if (ret) 1570 { 1571 ret = emfdc_record( emf, (EMR *)emr ); 1572 if (ret) emfdc_update_bounds( emf, &emr->rclBounds ); 1573 } 1574 1575 err: 1576 HeapFree( GetProcessHeap(), 0, emr ); 1577 if (mask_bitmap != mask) DeleteObject( mask_bitmap ); 1578 if (mask_dc != hdc_src) DeleteObject( mask_dc ); 1579 if (blit_bitmap != bitmap) DeleteObject( blit_bitmap ); 1580 if (blit_dc != hdc_src) DeleteDC( blit_dc ); 1581 return ret; 1582 } 1583 1584 BOOL EMFDC_PlgBlt( WINEDC *dc_attr, const POINT *points, HDC hdc_src, INT x_src, INT y_src, 1585 INT width, INT height, HBITMAP mask, INT x_mask, INT y_mask ) 1586 { 1587 unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors) 1588 + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)]; 1589 BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer; 1590 struct emf *emf = dc_attr->emf; 1591 BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }}; 1592 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }}; 1593 HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL; 1594 UINT bmi_size, size, mask_info_size = 0; 1595 EMRPLGBLT *emr = NULL; 1596 BITMAPINFO *bmi; 1597 HDC blit_dc, mask_dc = NULL; 1598 int x_min, y_min, x_max, y_max, i; 1599 BOOL ret = FALSE; 1600 1601 if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE) 1602 { 1603 WINEDC * pldc = get_dc_ptr(hdc_src); 1604 1605 if (pldc->iType == LDC_EMFLDC) 1606 { 1607 return FALSE; 1608 } 1609 } 1610 1611 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE; 1612 1613 blit_dc = hdc_src; 1614 blit_bitmap = bitmap; 1615 if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE; 1616 1617 if (mask) 1618 { 1619 mask_dc = hdc_src; 1620 mask_bitmap = mask; 1621 if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err; 1622 if (mask_info.bmiHeader.biBitCount == 1) 1623 mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */ 1624 } 1625 else mask_info.bmiHeader.biSizeImage = 0; 1626 1627 size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage + 1628 mask_info_size + mask_info.bmiHeader.biSizeImage; 1629 1630 if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err; 1631 1632 emr->emr.iType = EMR_PLGBLT; 1633 emr->emr.nSize = size; 1634 1635 /* FIXME: not exactly what native does */ 1636 x_min = x_max = points[1].x + points[2].x - points[0].x; 1637 y_min = y_max = points[1].y + points[2].y - points[0].y; 1638 for (i = 0; i < ARRAYSIZE(emr->aptlDest); i++) 1639 { 1640 x_min = min( x_min, points[i].x ); 1641 y_min = min( y_min, points[i].y ); 1642 x_max = max( x_max, points[i].x ); 1643 y_max = max( y_min, points[i].y ); 1644 } 1645 emr->rclBounds.left = x_min; 1646 emr->rclBounds.top = y_min; 1647 emr->rclBounds.right = x_max; 1648 emr->rclBounds.bottom = y_max; 1649 memcpy( emr->aptlDest, points, sizeof(emr->aptlDest) ); 1650 emr->xSrc = x_src; 1651 emr->ySrc = y_src; 1652 emr->cxSrc = width; 1653 emr->cySrc = height; 1654 NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc ); 1655 emr->crBkColorSrc = GetBkColor( hdc_src ); 1656 emr->iUsageSrc = DIB_RGB_COLORS; 1657 emr->offBmiSrc = sizeof(*emr); 1658 emr->cbBmiSrc = bmi_size; 1659 emr->offBitsSrc = emr->offBmiSrc + bmi_size; 1660 emr->cbBitsSrc = src_info.bmiHeader.biSizeImage; 1661 emr->xMask = x_mask; 1662 emr->yMask = y_mask; 1663 emr->iUsageMask = DIB_PAL_MONO; 1664 emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0; 1665 emr->cbBmiMask = mask_info_size; 1666 emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask; 1667 emr->cbBitsMask = mask_info.bmiHeader.biSizeImage; 1668 1669 bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc); 1670 bmi->bmiHeader = src_info.bmiHeader; 1671 ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight, 1672 (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS ); 1673 if (!ret) goto err; 1674 1675 if (mask_info_size) 1676 { 1677 mask_bits_info->bmiHeader = mask_info.bmiHeader; 1678 ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight, 1679 (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS ); 1680 if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size ); 1681 } 1682 1683 if (ret) 1684 { 1685 ret = emfdc_record( emf, (EMR *)emr ); 1686 if (ret) emfdc_update_bounds( emf, &emr->rclBounds ); 1687 } 1688 1689 err: 1690 HeapFree( GetProcessHeap(), 0, emr ); 1691 if (mask_bitmap != mask) DeleteObject( mask_bitmap ); 1692 if (mask_dc != hdc_src) DeleteObject( mask_dc ); 1693 if (blit_bitmap != bitmap) DeleteObject( blit_bitmap ); 1694 if (blit_dc != hdc_src) DeleteDC( blit_dc ); 1695 return ret; 1696 } 1697 1698 BOOL EMFDC_StretchDIBits( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst, 1699 INT x_src, INT y_src, INT width_src, INT height_src, const void *bits, 1700 const BITMAPINFO *info, UINT usage, DWORD rop ) 1701 { 1702 EMRSTRETCHDIBITS *emr; 1703 BOOL ret; 1704 UINT bmi_size, emr_size; 1705 1706 /* calculate the size of the colour table */ 1707 bmi_size = get_dib_info_size( info, usage ); 1708 1709 emr_size = sizeof (EMRSTRETCHDIBITS) + bmi_size + info->bmiHeader.biSizeImage; 1710 if (!(emr = HeapAlloc(GetProcessHeap(), 0, emr_size ))) return 0; 1711 1712 /* write a bitmap info header (with colours) to the record */ 1713 memcpy( &emr[1], info, bmi_size); 1714 1715 /* write bitmap bits to the record */ 1716 memcpy ( (BYTE *)&emr[1] + bmi_size, bits, info->bmiHeader.biSizeImage ); 1717 1718 /* fill in the EMR header at the front of our piece of memory */ 1719 emr->emr.iType = EMR_STRETCHDIBITS; 1720 emr->emr.nSize = emr_size; 1721 1722 emr->xDest = x_dst; 1723 emr->yDest = y_dst; 1724 emr->cxDest = width_dst; 1725 emr->cyDest = height_dst; 1726 emr->dwRop = rop; 1727 emr->xSrc = x_src; 1728 emr->ySrc = y_src; 1729 1730 emr->iUsageSrc = usage; 1731 emr->offBmiSrc = sizeof (EMRSTRETCHDIBITS); 1732 emr->cbBmiSrc = bmi_size; 1733 emr->offBitsSrc = emr->offBmiSrc + bmi_size; 1734 emr->cbBitsSrc = info->bmiHeader.biSizeImage; 1735 1736 emr->cxSrc = width_src; 1737 emr->cySrc = height_src; 1738 1739 emr->rclBounds.left = x_dst; 1740 emr->rclBounds.top = y_dst; 1741 emr->rclBounds.right = x_dst + width_dst; 1742 emr->rclBounds.bottom = y_dst + height_dst; 1743 1744 /* save the record we just created */ 1745 ret = emfdc_record( dc_attr->emf, &emr->emr ); 1746 if (ret) emfdc_update_bounds( dc_attr->emf, &emr->rclBounds ); 1747 HeapFree( GetProcessHeap(), 0, emr ); 1748 return ret; 1749 } 1750 1751 BOOL EMFDC_SetDIBitsToDevice( WINEDC *dc_attr, INT x_dst, INT y_dst, DWORD width, DWORD height, 1752 INT x_src, INT y_src, UINT startscan, UINT lines, 1753 const void *bits, const BITMAPINFO *info, UINT usage ) 1754 { 1755 EMRSETDIBITSTODEVICE *emr; 1756 DWORD bmiSize = get_dib_info_size( info, usage ); 1757 DWORD size = sizeof(EMRSETDIBITSTODEVICE) + bmiSize + info->bmiHeader.biSizeImage; 1758 BOOL ret; 1759 1760 if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE; 1761 1762 emr->emr.iType = EMR_SETDIBITSTODEVICE; 1763 emr->emr.nSize = size; 1764 emr->rclBounds.left = x_dst; 1765 emr->rclBounds.top = y_dst; 1766 emr->rclBounds.right = x_dst + width - 1; 1767 emr->rclBounds.bottom = y_dst + height - 1; 1768 emr->xDest = x_dst; 1769 emr->yDest = y_dst; 1770 emr->xSrc = x_src; 1771 emr->ySrc = y_src; 1772 emr->cxSrc = width; 1773 emr->cySrc = height; 1774 emr->offBmiSrc = sizeof(EMRSETDIBITSTODEVICE); 1775 emr->cbBmiSrc = bmiSize; 1776 emr->offBitsSrc = sizeof(EMRSETDIBITSTODEVICE) + bmiSize; 1777 emr->cbBitsSrc = info->bmiHeader.biSizeImage; 1778 emr->iUsageSrc = usage; 1779 emr->iStartScan = startscan; 1780 emr->cScans = lines; 1781 memcpy( (BYTE*)emr + emr->offBmiSrc, info, bmiSize ); 1782 memcpy( (BYTE*)emr + emr->offBitsSrc, bits, info->bmiHeader.biSizeImage ); 1783 1784 if ((ret = emfdc_record( dc_attr->emf, (EMR*)emr ))) 1785 emfdc_update_bounds( dc_attr->emf, &emr->rclBounds ); 1786 1787 HeapFree( GetProcessHeap(), 0, emr ); 1788 return ret; 1789 } 1790 1791 BOOL EMFDC_SetDCBrushColor( WINEDC *dc_attr, COLORREF color ) 1792 { 1793 struct emf *emf = dc_attr->emf; 1794 EMRSELECTOBJECT emr; 1795 DWORD index; 1796 1797 if (GetCurrentObject( dc_attr->hdc, OBJ_BRUSH ) != GetStockObject( DC_BRUSH )) return TRUE; 1798 1799 if (emf->dc_brush) DeleteObject( emf->dc_brush ); 1800 if (!(emf->dc_brush = CreateSolidBrush( color ))) return FALSE; 1801 if (!(index = emfdc_create_brush( emf, emf->dc_brush ))) return FALSE; 1802 GDI_hdc_using_object( emf->dc_brush, dc_attr->hdc);//, emfdc_delete_object ); 1803 emr.emr.iType = EMR_SELECTOBJECT; 1804 emr.emr.nSize = sizeof(emr); 1805 emr.ihObject = index; 1806 return emfdc_record( emf, &emr.emr ); 1807 } 1808 1809 BOOL EMFDC_SetDCPenColor( WINEDC *dc_attr, COLORREF color ) 1810 { 1811 struct emf *emf = dc_attr->emf; 1812 EMRSELECTOBJECT emr; 1813 DWORD index; 1814 LOGPEN logpen = { PS_SOLID, { 0, 0 }, color }; 1815 1816 if (GetCurrentObject( dc_attr->hdc, OBJ_PEN ) != GetStockObject( DC_PEN )) return TRUE; 1817 1818 if (emf->dc_pen) DeleteObject( emf->dc_pen ); 1819 if (!(emf->dc_pen = CreatePenIndirect( &logpen ))) return FALSE; 1820 if (!(index = emfdc_create_pen( emf, emf->dc_pen ))) return FALSE; 1821 GDI_hdc_using_object( emf->dc_pen, dc_attr->hdc);//, emfdc_delete_object ); 1822 emr.emr.iType = EMR_SELECTOBJECT; 1823 emr.emr.nSize = sizeof(emr); 1824 emr.ihObject = index; 1825 return emfdc_record( emf, &emr.emr ); 1826 } 1827 1828 BOOL EMFDC_SaveDC( WINEDC *dc_attr ) 1829 { 1830 EMRSAVEDC emr; 1831 1832 emr.emr.iType = EMR_SAVEDC; 1833 emr.emr.nSize = sizeof(emr); 1834 return emfdc_record( dc_attr->emf, &emr.emr ); 1835 } 1836 #define GdiGetEMFRestorDc 5 1837 BOOL EMFDC_RestoreDC( WINEDC *dc_attr, INT level ) 1838 { 1839 EMRRESTOREDC emr; 1840 1841 /* The Restore DC function needs the save level to be set correctly. 1842 Note that wine's level is 0 based, while our's is (like win) 1 based. */ 1843 dc_attr->save_level = GetDCDWord(dc_attr->hdc, GdiGetEMFRestorDc, 0) - 1; 1844 1845 if (abs(level) > dc_attr->save_level || level == 0) return FALSE; 1846 1847 emr.emr.iType = EMR_RESTOREDC; 1848 emr.emr.nSize = sizeof(emr); 1849 if (level < 0) 1850 emr.iRelative = level; 1851 else 1852 emr.iRelative = level - dc_attr->save_level - 1; 1853 return emfdc_record( dc_attr->emf, &emr.emr ); 1854 } 1855 1856 BOOL EMFDC_SetTextAlign( WINEDC *dc_attr, UINT align ) 1857 { 1858 EMRSETTEXTALIGN emr; 1859 1860 emr.emr.iType = EMR_SETTEXTALIGN; 1861 emr.emr.nSize = sizeof(emr); 1862 emr.iMode = align; 1863 return emfdc_record( dc_attr->emf, &emr.emr ); 1864 } 1865 1866 BOOL EMFDC_SetTextJustification( WINEDC *dc_attr, INT extra, INT breaks ) 1867 { 1868 EMRSETTEXTJUSTIFICATION emr; 1869 1870 emr.emr.iType = EMR_SETTEXTJUSTIFICATION; 1871 emr.emr.nSize = sizeof(emr); 1872 emr.nBreakExtra = extra; 1873 emr.nBreakCount = breaks; 1874 return emfdc_record( dc_attr->emf, &emr.emr ); 1875 } 1876 1877 BOOL EMFDC_SetBkMode( WINEDC *dc_attr, INT mode ) 1878 { 1879 EMRSETBKMODE emr; 1880 1881 emr.emr.iType = EMR_SETBKMODE; 1882 emr.emr.nSize = sizeof(emr); 1883 emr.iMode = mode; 1884 return emfdc_record( dc_attr->emf, &emr.emr ); 1885 } 1886 1887 BOOL EMFDC_SetBkColor( WINEDC *dc_attr, COLORREF color ) 1888 { 1889 EMRSETBKCOLOR emr; 1890 1891 emr.emr.iType = EMR_SETBKCOLOR; 1892 emr.emr.nSize = sizeof(emr); 1893 emr.crColor = color; 1894 return emfdc_record( dc_attr->emf, &emr.emr ); 1895 } 1896 1897 BOOL EMFDC_SetTextColor( WINEDC *dc_attr, COLORREF color ) 1898 { 1899 EMRSETTEXTCOLOR emr; 1900 1901 emr.emr.iType = EMR_SETTEXTCOLOR; 1902 emr.emr.nSize = sizeof(emr); 1903 emr.crColor = color; 1904 return emfdc_record( dc_attr->emf, &emr.emr ); 1905 } 1906 1907 BOOL EMFDC_SetROP2( WINEDC *dc_attr, INT rop ) 1908 { 1909 EMRSETROP2 emr; 1910 1911 emr.emr.iType = EMR_SETROP2; 1912 emr.emr.nSize = sizeof(emr); 1913 emr.iMode = rop; 1914 return emfdc_record( dc_attr->emf, &emr.emr ); 1915 } 1916 1917 BOOL EMFDC_SetPolyFillMode( WINEDC *dc_attr, INT mode ) 1918 { 1919 EMRSETPOLYFILLMODE emr; 1920 1921 emr.emr.iType = EMR_SETPOLYFILLMODE; 1922 emr.emr.nSize = sizeof(emr); 1923 emr.iMode = mode; 1924 return emfdc_record( dc_attr->emf, &emr.emr ); 1925 } 1926 1927 BOOL EMFDC_SetStretchBltMode( WINEDC *dc_attr, INT mode ) 1928 { 1929 EMRSETSTRETCHBLTMODE emr; 1930 1931 emr.emr.iType = EMR_SETSTRETCHBLTMODE; 1932 emr.emr.nSize = sizeof(emr); 1933 emr.iMode = mode; 1934 return emfdc_record( dc_attr->emf, &emr.emr ); 1935 } 1936 1937 BOOL EMFDC_SetArcDirection( WINEDC *dc_attr, INT dir ) 1938 { 1939 EMRSETARCDIRECTION emr; 1940 1941 emr.emr.iType = EMR_SETARCDIRECTION; 1942 emr.emr.nSize = sizeof(emr); 1943 emr.iArcDirection = dir; 1944 return emfdc_record( dc_attr->emf, &emr.emr ); 1945 } 1946 1947 BOOL EMFDC_ExcludeClipRect( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom ) 1948 { 1949 EMREXCLUDECLIPRECT emr; 1950 1951 emr.emr.iType = EMR_EXCLUDECLIPRECT; 1952 emr.emr.nSize = sizeof(emr); 1953 emr.rclClip.left = left; 1954 emr.rclClip.top = top; 1955 emr.rclClip.right = right; 1956 emr.rclClip.bottom = bottom; 1957 return emfdc_record( dc_attr->emf, &emr.emr ); 1958 } 1959 1960 BOOL EMFDC_IntersectClipRect( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom) 1961 { 1962 EMRINTERSECTCLIPRECT emr; 1963 1964 emr.emr.iType = EMR_INTERSECTCLIPRECT; 1965 emr.emr.nSize = sizeof(emr); 1966 emr.rclClip.left = left; 1967 emr.rclClip.top = top; 1968 emr.rclClip.right = right; 1969 emr.rclClip.bottom = bottom; 1970 return emfdc_record( dc_attr->emf, &emr.emr ); 1971 } 1972 1973 BOOL EMFDC_OffsetClipRgn( WINEDC *dc_attr, INT x, INT y ) 1974 { 1975 EMROFFSETCLIPRGN emr; 1976 1977 emr.emr.iType = EMR_OFFSETCLIPRGN; 1978 emr.emr.nSize = sizeof(emr); 1979 emr.ptlOffset.x = x; 1980 emr.ptlOffset.y = y; 1981 return emfdc_record( dc_attr->emf, &emr.emr ); 1982 } 1983 1984 BOOL EMFDC_ExtSelectClipRgn( WINEDC *dc_attr, HRGN hrgn, INT mode ) 1985 { 1986 EMREXTSELECTCLIPRGN *emr; 1987 DWORD size, rgnsize; 1988 BOOL ret; 1989 1990 if (!hrgn) 1991 { 1992 if (mode != RGN_COPY) return ERROR; 1993 rgnsize = 0; 1994 } 1995 else rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL ); 1996 1997 size = rgnsize + offsetof(EMREXTSELECTCLIPRGN,RgnData); 1998 emr = HeapAlloc( GetProcessHeap(), 0, size ); 1999 if (rgnsize) /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData ); 2000 2001 emr->emr.iType = EMR_EXTSELECTCLIPRGN; 2002 emr->emr.nSize = size; 2003 emr->cbRgnData = rgnsize; 2004 emr->iMode = mode; 2005 2006 ret = emfdc_record( dc_attr->emf, &emr->emr ); 2007 HeapFree( GetProcessHeap(), 0, emr ); 2008 return ret; 2009 } 2010 2011 BOOL EMFDC_SetMapMode( WINEDC *dc_attr, INT mode ) 2012 { 2013 EMRSETMAPMODE emr; 2014 2015 emr.emr.iType = EMR_SETMAPMODE; 2016 emr.emr.nSize = sizeof(emr); 2017 emr.iMode = mode; 2018 return emfdc_record( dc_attr->emf, &emr.emr ); 2019 } 2020 2021 BOOL EMFDC_SetViewportExtEx( WINEDC *dc_attr, INT cx, INT cy ) 2022 { 2023 EMRSETVIEWPORTEXTEX emr; 2024 2025 emr.emr.iType = EMR_SETVIEWPORTEXTEX; 2026 emr.emr.nSize = sizeof(emr); 2027 emr.szlExtent.cx = cx; 2028 emr.szlExtent.cy = cy; 2029 return emfdc_record( dc_attr->emf, &emr.emr ); 2030 } 2031 2032 BOOL EMFDC_SetWindowExtEx( WINEDC *dc_attr, INT cx, INT cy ) 2033 { 2034 EMRSETWINDOWEXTEX emr; 2035 2036 emr.emr.iType = EMR_SETWINDOWEXTEX; 2037 emr.emr.nSize = sizeof(emr); 2038 emr.szlExtent.cx = cx; 2039 emr.szlExtent.cy = cy; 2040 return emfdc_record( dc_attr->emf, &emr.emr ); 2041 } 2042 2043 BOOL EMFDC_SetViewportOrgEx( WINEDC *dc_attr, INT x, INT y ) 2044 { 2045 EMRSETVIEWPORTORGEX emr; 2046 2047 emr.emr.iType = EMR_SETVIEWPORTORGEX; 2048 emr.emr.nSize = sizeof(emr); 2049 emr.ptlOrigin.x = x; 2050 emr.ptlOrigin.y = y; 2051 return emfdc_record( dc_attr->emf, &emr.emr ); 2052 } 2053 2054 BOOL EMFDC_SetWindowOrgEx( WINEDC *dc_attr, INT x, INT y ) 2055 { 2056 EMRSETWINDOWORGEX emr; 2057 2058 emr.emr.iType = EMR_SETWINDOWORGEX; 2059 emr.emr.nSize = sizeof(emr); 2060 emr.ptlOrigin.x = x; 2061 emr.ptlOrigin.y = y; 2062 return emfdc_record( dc_attr->emf, &emr.emr ); 2063 } 2064 2065 BOOL EMFDC_ScaleViewportExtEx( WINEDC *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom ) 2066 { 2067 EMRSCALEVIEWPORTEXTEX emr; 2068 2069 emr.emr.iType = EMR_SCALEVIEWPORTEXTEX; 2070 emr.emr.nSize = sizeof(emr); 2071 emr.xNum = x_num; 2072 emr.xDenom = x_denom; 2073 emr.yNum = y_num; 2074 emr.yDenom = y_denom; 2075 return emfdc_record( dc_attr->emf, &emr.emr ); 2076 } 2077 2078 BOOL EMFDC_ScaleWindowExtEx( WINEDC *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom ) 2079 { 2080 EMRSCALEWINDOWEXTEX emr; 2081 2082 emr.emr.iType = EMR_SCALEWINDOWEXTEX; 2083 emr.emr.nSize = sizeof(emr); 2084 emr.xNum = x_num; 2085 emr.xDenom = x_denom; 2086 emr.yNum = y_num; 2087 emr.yDenom = y_denom; 2088 return emfdc_record( dc_attr->emf, &emr.emr ); 2089 } 2090 2091 BOOL EMFDC_SetLayout( WINEDC *dc_attr, DWORD layout ) 2092 { 2093 EMRSETLAYOUT emr; 2094 2095 emr.emr.iType = EMR_SETLAYOUT; 2096 emr.emr.nSize = sizeof(emr); 2097 emr.iMode = layout; 2098 return emfdc_record( dc_attr->emf, &emr.emr ); 2099 } 2100 2101 BOOL EMFDC_SetWorldTransform( WINEDC *dc_attr, const XFORM *xform ) 2102 { 2103 EMRSETWORLDTRANSFORM emr; 2104 2105 emr.emr.iType = EMR_SETWORLDTRANSFORM; 2106 emr.emr.nSize = sizeof(emr); 2107 emr.xform = *xform; 2108 return emfdc_record( dc_attr->emf, &emr.emr ); 2109 } 2110 2111 BOOL EMFDC_ModifyWorldTransform( WINEDC *dc_attr, const XFORM *xform, DWORD mode ) 2112 { 2113 EMRMODIFYWORLDTRANSFORM emr; 2114 2115 emr.emr.iType = EMR_MODIFYWORLDTRANSFORM; 2116 emr.emr.nSize = sizeof(emr); 2117 if (mode == MWT_IDENTITY) 2118 { 2119 emr.xform.eM11 = 1.0f; 2120 emr.xform.eM12 = 0.0f; 2121 emr.xform.eM21 = 0.0f; 2122 emr.xform.eM22 = 1.0f; 2123 emr.xform.eDx = 0.0f; 2124 emr.xform.eDy = 0.0f; 2125 } 2126 else 2127 { 2128 emr.xform = *xform; 2129 } 2130 emr.iMode = mode; 2131 return emfdc_record( dc_attr->emf, &emr.emr ); 2132 } 2133 2134 BOOL EMFDC_SetMapperFlags( WINEDC *dc_attr, DWORD flags ) 2135 { 2136 EMRSETMAPPERFLAGS emr; 2137 2138 emr.emr.iType = EMR_SETMAPPERFLAGS; 2139 emr.emr.nSize = sizeof(emr); 2140 emr.dwFlags = flags; 2141 return emfdc_record( dc_attr->emf, &emr.emr ); 2142 } 2143 2144 BOOL EMFDC_AbortPath( WINEDC *dc_attr ) 2145 { 2146 struct emf *emf = dc_attr->emf; 2147 EMRABORTPATH emr; 2148 2149 emr.emr.iType = EMR_ABORTPATH; 2150 emr.emr.nSize = sizeof(emr); 2151 2152 emf->path = FALSE; 2153 return emfdc_record( dc_attr->emf, &emr.emr ); 2154 } 2155 2156 BOOL EMFDC_BeginPath( WINEDC *dc_attr ) 2157 { 2158 struct emf *emf = dc_attr->emf; 2159 EMRBEGINPATH emr; 2160 2161 emr.emr.iType = EMR_BEGINPATH; 2162 emr.emr.nSize = sizeof(emr); 2163 if (!emfdc_record( emf, &emr.emr )) return FALSE; 2164 2165 emf->path = TRUE; 2166 return TRUE; 2167 } 2168 2169 BOOL EMFDC_CloseFigure( WINEDC *dc_attr ) 2170 { 2171 EMRCLOSEFIGURE emr; 2172 2173 emr.emr.iType = EMR_CLOSEFIGURE; 2174 emr.emr.nSize = sizeof(emr); 2175 return emfdc_record( dc_attr->emf, &emr.emr ); 2176 } 2177 2178 BOOL EMFDC_EndPath( WINEDC *dc_attr ) 2179 { 2180 struct emf *emf = dc_attr->emf; 2181 EMRENDPATH emr; 2182 2183 emf->path = FALSE; 2184 2185 emr.emr.iType = EMR_ENDPATH; 2186 emr.emr.nSize = sizeof(emr); 2187 return emfdc_record( emf, &emr.emr ); 2188 } 2189 2190 BOOL EMFDC_FlattenPath( WINEDC *dc_attr ) 2191 { 2192 EMRFLATTENPATH emr; 2193 2194 emr.emr.iType = EMR_FLATTENPATH; 2195 emr.emr.nSize = sizeof(emr); 2196 return emfdc_record( dc_attr->emf, &emr.emr ); 2197 } 2198 2199 BOOL EMFDC_SelectClipPath( WINEDC *dc_attr, INT mode ) 2200 { 2201 EMRSELECTCLIPPATH emr; 2202 2203 emr.emr.iType = EMR_SELECTCLIPPATH; 2204 emr.emr.nSize = sizeof(emr); 2205 emr.iMode = mode; 2206 return emfdc_record( dc_attr->emf, &emr.emr ); 2207 } 2208 2209 BOOL EMFDC_WidenPath( WINEDC *dc_attr ) 2210 { 2211 EMRWIDENPATH emr; 2212 2213 emr.emr.iType = EMR_WIDENPATH; 2214 emr.emr.nSize = sizeof(emr); 2215 return emfdc_record( dc_attr->emf, &emr.emr ); 2216 } 2217 2218 BOOL EMFDC_DeleteDC( WINEDC *dc_attr ) 2219 { 2220 struct emf *emf = dc_attr->emf; 2221 UINT index; 2222 2223 HeapFree( GetProcessHeap(), 0, emf->emh ); 2224 for (index = 0; index < emf->handles_size; index++) 2225 if (emf->handles[index]) 2226 GDI_hdc_not_using_object( emf->handles[index], emf->dc_attr->hdc ); 2227 HeapFree( GetProcessHeap(), 0, emf->handles ); 2228 return TRUE; 2229 } 2230 2231 // 2232 // Waiting on wine support.... 2233 // 2234 2235 2236 // 2237 // ReactOS Print Support 2238 // 2239 BOOL EMFDC_WriteEscape( WINEDC *dc_attr, INT nEscape, INT cbInput, LPSTR lpszInData, DWORD emrType) 2240 { 2241 PEMRESCAPE pemr; 2242 UINT total, rounded_size; 2243 BOOL ret; 2244 2245 rounded_size = (cbInput+3) & ~3; 2246 total = offsetof(EMRESCAPE,Data) + rounded_size; 2247 2248 pemr = RtlAllocateHeap( GetProcessHeap(), 0, total ); 2249 if ( !pemr ) 2250 return 0; 2251 2252 RtlZeroMemory( pemr, total ); 2253 2254 pemr->emr.iType = emrType; 2255 pemr->emr.nSize = total; 2256 pemr->iEsc = nEscape; 2257 pemr->cjIn = cbInput; 2258 2259 RtlCopyMemory( &pemr->Data[0], lpszInData, cbInput ); 2260 2261 ret = emfdc_record( dc_attr->emf, &pemr->emr ); 2262 2263 RtlFreeHeap( GetProcessHeap(), 0, pemr ); 2264 return ret; 2265 } 2266 2267 BOOL EMFDC_WriteNamedEscape( WINEDC *dc_attr, PWCHAR pDriver, INT nEscape, INT cbInput, LPCSTR lpszInData) 2268 { 2269 PEMRNAMEDESCAPE pemr; 2270 UINT sizestr, total, rounded_size; 2271 INT ret; 2272 2273 rounded_size = (cbInput+3) & ~3; 2274 total = offsetof(EMRNAMEDESCAPE,Data) + rounded_size; 2275 2276 total += sizestr = (UINT)((wcslen(pDriver) + 1 ) * sizeof(WCHAR)); 2277 2278 pemr = RtlAllocateHeap( GetProcessHeap(), 0, total ); 2279 if ( !pemr ) 2280 return 0; 2281 2282 RtlZeroMemory( pemr, total ); 2283 2284 pemr->emr.iType = EMR_NAMEDESCAPE; 2285 pemr->emr.nSize = total; 2286 pemr->iEsc = nEscape; 2287 pemr->cjIn = cbInput; 2288 2289 RtlCopyMemory( &pemr->Data[0], lpszInData, cbInput ); 2290 // 2291 // WARNING : 2292 // Need to remember with wine, theses headers are relocatable. 2293 RtlCopyMemory( &pemr->Data[rounded_size], pDriver, sizestr ); 2294 2295 ret = emfdc_record( dc_attr->emf, &pemr->emr ); 2296 2297 RtlFreeHeap( GetProcessHeap(), 0, pemr ); 2298 return ret; 2299 } 2300 2301 BOOL EMFDC_SetMetaRgn( WINEDC *dc_attr ) 2302 { 2303 EMRSETMETARGN emr; 2304 2305 emr.emr.iType = EMR_SETMETARGN; 2306 emr.emr.nSize = sizeof(emr); 2307 2308 return emfdc_record( dc_attr->emf, &emr.emr ); 2309 } 2310 2311 BOOL EMFDC_SetBrushOrg( WINEDC *dc_attr, INT x, INT y) 2312 { 2313 EMRSETBRUSHORGEX emr; 2314 2315 emr.emr.iType = EMR_SETBRUSHORGEX; 2316 emr.emr.nSize = sizeof(emr); 2317 emr.ptlOrigin.x = x; 2318 emr.ptlOrigin.y = y; 2319 2320 return emfdc_record( dc_attr->emf, &emr.emr ); 2321 } 2322 2323 /******************************************************************* 2324 * GdiComment (GDI32.@) 2325 */ 2326 BOOL WINAPI EMFDC_GdiComment( HDC hdc, UINT bytes, const BYTE *buffer ) 2327 { 2328 WINEDC *dc_attr; 2329 EMRGDICOMMENT *emr; 2330 UINT total, rounded_size; 2331 BOOL ret; 2332 2333 if (!(dc_attr = get_dc_ptr( hdc )) || !dc_attr->emf) return FALSE; 2334 2335 rounded_size = (bytes+3) & ~3; 2336 total = offsetof(EMRGDICOMMENT,Data) + rounded_size; 2337 2338 emr = HeapAlloc(GetProcessHeap(), 0, total); 2339 emr->emr.iType = EMR_GDICOMMENT; 2340 emr->emr.nSize = total; 2341 emr->cbData = bytes; 2342 memset(&emr->Data[bytes], 0, rounded_size - bytes); 2343 memcpy(&emr->Data[0], buffer, bytes); 2344 2345 ret = emfdc_record( dc_attr->emf, &emr->emr ); 2346 2347 HeapFree(GetProcessHeap(), 0, emr); 2348 2349 return ret; 2350 } 2351 2352 /********************************************************************** 2353 * CreateEnhMetaFileA (GDI32.@) 2354 */ 2355 HDC WINAPI CreateEnhMetaFileA( HDC hdc, const char *filename, const RECT *rect, 2356 const char *description ) 2357 { 2358 WCHAR *filenameW = NULL; 2359 WCHAR *descriptionW = NULL; 2360 DWORD len1, len2, total; 2361 HDC ret; 2362 2363 if (filename) 2364 { 2365 total = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 ); 2366 filenameW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) ); 2367 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, total ); 2368 } 2369 2370 if(description) 2371 { 2372 len1 = (DWORD)strlen(description); 2373 len2 = (DWORD)strlen(description + len1 + 1); 2374 total = MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, NULL, 0 ); 2375 descriptionW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) ); 2376 MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, descriptionW, total ); 2377 } 2378 2379 ret = CreateEnhMetaFileW( hdc, filenameW, rect, descriptionW ); 2380 2381 HeapFree( GetProcessHeap(), 0, filenameW ); 2382 HeapFree( GetProcessHeap(), 0, descriptionW ); 2383 return ret; 2384 } 2385 2386 /********************************************************************** 2387 * CreateEnhMetaFileW (GDI32.@) 2388 */ 2389 HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect, 2390 const WCHAR *description ) 2391 { 2392 HDC ret; 2393 struct emf *emf; 2394 WINEDC *dc_attr; 2395 HANDLE file; 2396 DWORD size = 0, length = 0; 2397 2398 TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect), 2399 debugstr_w(description) ); 2400 2401 //if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0; 2402 if(!(dc_attr = alloc_dc_ptr(OBJ_ENHMETADC))) 2403 { 2404 if (dc_attr->hdc) DeleteDC( dc_attr->hdc ); 2405 return 0; 2406 } 2407 2408 ret = dc_attr->hdc; 2409 2410 if (/*!(dc_attr = get_dc_ptr( ret )) ||*/ !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) ))) 2411 { 2412 DeleteDC( ret ); 2413 return 0; 2414 } 2415 2416 emf->dc_attr = dc_attr; 2417 dc_attr->emf = emf; 2418 2419 if (description) /* App name\0Title\0\0 */ 2420 { 2421 length = lstrlenW( description ); 2422 length += lstrlenW( description + length + 1 ); 2423 length += 3; 2424 length *= 2; 2425 } 2426 size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4; 2427 2428 if (!(emf->emh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size))) 2429 { 2430 DeleteDC( ret ); 2431 return 0; 2432 } 2433 emf->dc_attr = dc_attr; 2434 2435 emf->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 2436 HANDLE_LIST_INC * sizeof(emf->handles[0]) ); 2437 emf->handles_size = HANDLE_LIST_INC; 2438 emf->cur_handles = 1; 2439 emf->file = 0; 2440 emf->dc_brush = 0; 2441 emf->dc_pen = 0; 2442 emf->path = FALSE; 2443 2444 emf->emh->iType = EMR_HEADER; 2445 emf->emh->nSize = size; 2446 2447 dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0; 2448 dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1; 2449 2450 if (rect) 2451 { 2452 emf->emh->rclFrame.left = rect->left; 2453 emf->emh->rclFrame.top = rect->top; 2454 emf->emh->rclFrame.right = rect->right; 2455 emf->emh->rclFrame.bottom = rect->bottom; 2456 } 2457 else 2458 { 2459 /* Set this to {0,0 - -1,-1} and update it at the end */ 2460 emf->emh->rclFrame.left = emf->emh->rclFrame.top = 0; 2461 emf->emh->rclFrame.right = emf->emh->rclFrame.bottom = -1; 2462 } 2463 2464 emf->emh->dSignature = ENHMETA_SIGNATURE; 2465 emf->emh->nVersion = 0x10000; 2466 emf->emh->nBytes = emf->emh->nSize; 2467 emf->emh->nRecords = 1; 2468 emf->emh->nHandles = 1; 2469 2470 emf->emh->sReserved = 0; /* According to docs, this is reserved and must be 0 */ 2471 emf->emh->nDescription = length / 2; 2472 2473 emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0; 2474 2475 emf->emh->nPalEntries = 0; /* I guess this should start at 0 */ 2476 2477 /* Size in pixels */ 2478 emf->emh->szlDevice.cx = GetDeviceCaps( ret, HORZRES ); 2479 emf->emh->szlDevice.cy = GetDeviceCaps( ret, VERTRES ); 2480 2481 /* Size in millimeters */ 2482 emf->emh->szlMillimeters.cx = GetDeviceCaps( ret, HORZSIZE ); 2483 emf->emh->szlMillimeters.cy = GetDeviceCaps( ret, VERTSIZE ); 2484 2485 /* Size in micrometers */ 2486 emf->emh->szlMicrometers.cx = emf->emh->szlMillimeters.cx * 1000; 2487 emf->emh->szlMicrometers.cy = emf->emh->szlMillimeters.cy * 1000; 2488 2489 memcpy( (char *)emf->emh + sizeof(ENHMETAHEADER), description, length ); 2490 2491 if (filename) /* disk based metafile */ 2492 { 2493 if ((file = CreateFileW( filename, GENERIC_WRITE | GENERIC_READ, 0, 2494 NULL, CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) 2495 { 2496 DeleteDC( ret ); 2497 return 0; 2498 } 2499 emf->file = file; 2500 } 2501 2502 TRACE( "returning %p\n", ret ); 2503 return ret; 2504 } 2505 2506 /****************************************************************** 2507 * CloseEnhMetaFile (GDI32.@) 2508 */ 2509 HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc ) 2510 { 2511 HENHMETAFILE hmf; 2512 struct emf *emf; 2513 WINEDC *dc_attr; 2514 EMREOF emr; 2515 HANDLE mapping = 0; 2516 2517 if (!(dc_attr = get_dc_ptr( hdc )) || !dc_attr->emf) return 0; 2518 emf = dc_attr->emf; 2519 2520 if (dc_attr->save_level) 2521 RestoreDC( hdc, 1 ); 2522 2523 if (emf->dc_brush) DeleteObject( emf->dc_brush ); 2524 if (emf->dc_pen) DeleteObject( emf->dc_pen ); 2525 2526 emr.emr.iType = EMR_EOF; 2527 emr.emr.nSize = sizeof(emr); 2528 emr.nPalEntries = 0; 2529 emr.offPalEntries = FIELD_OFFSET(EMREOF, nSizeLast); 2530 emr.nSizeLast = emr.emr.nSize; 2531 emfdc_record( emf, &emr.emr ); 2532 2533 emf->emh->rclBounds = dc_attr->emf_bounds; 2534 2535 /* Update rclFrame if not initialized in CreateEnhMetaFile */ 2536 if (emf->emh->rclFrame.left > emf->emh->rclFrame.right) 2537 { 2538 emf->emh->rclFrame.left = emf->emh->rclBounds.left * 2539 emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx; 2540 emf->emh->rclFrame.top = emf->emh->rclBounds.top * 2541 emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy; 2542 emf->emh->rclFrame.right = emf->emh->rclBounds.right * 2543 emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx; 2544 emf->emh->rclFrame.bottom = emf->emh->rclBounds.bottom * 2545 emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy; 2546 } 2547 2548 if (emf->file) /* disk based metafile */ 2549 { 2550 DWORD bytes_written; 2551 2552 if (!WriteFile( emf->file, emf->emh, emf->emh->nBytes, &bytes_written, NULL )) 2553 { 2554 CloseHandle( emf->file ); 2555 return 0; 2556 } 2557 HeapFree( GetProcessHeap(), 0, emf->emh ); 2558 mapping = CreateFileMappingA( emf->file, NULL, PAGE_READONLY, 0, 0, NULL ); 2559 TRACE( "mapping = %p\n", mapping ); 2560 emf->emh = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); 2561 TRACE( "view = %p\n", emf->emh ); 2562 CloseHandle( mapping ); 2563 CloseHandle( emf->file ); 2564 } 2565 2566 hmf = EMF_Create_HENHMETAFILE( emf->emh, emf->emh->nBytes, emf->file != 0 ); 2567 emf->emh = NULL; /* So it won't be deleted */ 2568 DeleteDC( hdc ); 2569 return hmf; 2570 } 2571