1 /* 2 * Enhanced MetaFile objects 3 * 4 * Copyright 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 21 #include <stdlib.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 #include "enhmfdrv/enhmetafiledrv.h" 26 #include "gdi_private.h" 27 #include "wine/debug.h" 28 29 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile); 30 31 32 /****************************************************************** 33 * EMFDRV_AddHandle 34 */ 35 static UINT EMFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj ) 36 { 37 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 38 UINT index; 39 40 for(index = 0; index < physDev->handles_size; index++) 41 if(physDev->handles[index] == 0) break; 42 if(index == physDev->handles_size) { 43 physDev->handles_size += HANDLE_LIST_INC; 44 physDev->handles = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 45 physDev->handles, 46 physDev->handles_size * sizeof(physDev->handles[0])); 47 } 48 physDev->handles[index] = get_full_gdi_handle( obj ); 49 50 physDev->cur_handles++; 51 if(physDev->cur_handles > physDev->emh->nHandles) 52 physDev->emh->nHandles++; 53 54 return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */ 55 } 56 57 /****************************************************************** 58 * EMFDRV_FindObject 59 */ 60 static UINT EMFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj ) 61 { 62 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 63 UINT index; 64 65 for(index = 0; index < physDev->handles_size; index++) 66 if(physDev->handles[index] == obj) break; 67 68 if(index == physDev->handles_size) return 0; 69 70 return index + 1; 71 } 72 73 74 /****************************************************************** 75 * EMFDRV_DeleteObject 76 */ 77 BOOL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj ) 78 { 79 EMRDELETEOBJECT emr; 80 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 81 UINT index; 82 BOOL ret = TRUE; 83 84 if(!(index = EMFDRV_FindObject(dev, obj))) return FALSE; 85 86 emr.emr.iType = EMR_DELETEOBJECT; 87 emr.emr.nSize = sizeof(emr); 88 emr.ihObject = index; 89 90 if(!EMFDRV_WriteRecord( dev, &emr.emr )) 91 ret = FALSE; 92 93 physDev->handles[index - 1] = 0; 94 physDev->cur_handles--; 95 return ret; 96 } 97 98 99 /*********************************************************************** 100 * EMFDRV_SelectBitmap 101 */ 102 HBITMAP EMFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap ) 103 { 104 return 0; 105 } 106 107 108 /*********************************************************************** 109 * EMFDRV_CreateBrushIndirect 110 */ 111 DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush ) 112 { 113 DWORD index = 0; 114 LOGBRUSH logbrush; 115 116 if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return 0; 117 118 switch (logbrush.lbStyle) { 119 case BS_SOLID: 120 case BS_HATCHED: 121 case BS_NULL: 122 { 123 EMRCREATEBRUSHINDIRECT emr; 124 emr.emr.iType = EMR_CREATEBRUSHINDIRECT; 125 emr.emr.nSize = sizeof(emr); 126 emr.ihBrush = index = EMFDRV_AddHandle( dev, hBrush ); 127 emr.lb.lbStyle = logbrush.lbStyle; 128 emr.lb.lbColor = logbrush.lbColor; 129 emr.lb.lbHatch = logbrush.lbHatch; 130 131 if(!EMFDRV_WriteRecord( dev, &emr.emr )) 132 index = 0; 133 } 134 break; 135 case BS_PATTERN: 136 case BS_DIBPATTERN: 137 { 138 EMRCREATEDIBPATTERNBRUSHPT *emr; 139 #ifdef __REACTOS__ 140 char buffer[sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD)]; // ros 141 #else 142 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; 143 #endif 144 BITMAPINFO *info = (BITMAPINFO *)buffer; 145 DWORD info_size; 146 void *bits; 147 UINT usage; 148 149 if (!get_brush_bitmap_info( hBrush, info, &bits, &usage )) break; 150 info_size = get_dib_info_size( info, usage ); 151 152 emr = HeapAlloc( GetProcessHeap(), 0, 153 sizeof(EMRCREATEDIBPATTERNBRUSHPT)+info_size+info->bmiHeader.biSizeImage ); 154 if(!emr) break; 155 156 if (logbrush.lbStyle == BS_PATTERN && info->bmiHeader.biBitCount == 1) 157 { 158 /* Presumably to reduce the size of the written EMF, MS supports an 159 * undocumented iUsage value of 2, indicating a mono bitmap without the 160 * 8 byte 2 entry black/white palette. Stupidly, they could have saved 161 * over 20 bytes more by also ignoring the BITMAPINFO fields that are 162 * irrelevant/constant for monochrome bitmaps. 163 * FIXME: It may be that the DIB functions themselves accept this value. 164 */ 165 emr->emr.iType = EMR_CREATEMONOBRUSH; 166 usage = DIB_PAL_MONO; 167 /* FIXME: There is an extra DWORD written by native before the BMI. 168 * Not sure what it's meant to contain. 169 */ 170 emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ) + sizeof(DWORD); 171 emr->cbBmi = sizeof( BITMAPINFOHEADER ); 172 } 173 else 174 { 175 emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT; 176 emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ); 177 emr->cbBmi = info_size; 178 } 179 emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush ); 180 emr->iUsage = usage; 181 emr->offBits = emr->offBmi + emr->cbBmi; 182 emr->cbBits = info->bmiHeader.biSizeImage; 183 emr->emr.nSize = emr->offBits + emr->cbBits; 184 185 memcpy( (BYTE *)emr + emr->offBmi, info, emr->cbBmi ); 186 memcpy( (BYTE *)emr + emr->offBits, bits, emr->cbBits ); 187 188 if(!EMFDRV_WriteRecord( dev, &emr->emr )) 189 index = 0; 190 HeapFree( GetProcessHeap(), 0, emr ); 191 } 192 break; 193 194 default: 195 FIXME("Unknown style %x\n", logbrush.lbStyle); 196 break; 197 } 198 return index; 199 } 200 201 202 /*********************************************************************** 203 * EMFDRV_SelectBrush 204 */ 205 HBRUSH EMFDRV_SelectBrush( PHYSDEV dev, HBRUSH hBrush, const struct brush_pattern *pattern ) 206 { 207 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 208 EMRSELECTOBJECT emr; 209 DWORD index; 210 int i; 211 212 if (physDev->restoring) return hBrush; /* don't output SelectObject records during RestoreDC */ 213 214 /* If the object is a stock brush object, do not need to create it. 215 * See definitions in wingdi.h for range of stock brushes. 216 * We do however have to handle setting the higher order bit to 217 * designate that this is a stock object. 218 */ 219 for (i = WHITE_BRUSH; i <= DC_BRUSH; i++) 220 { 221 if (hBrush == GetStockObject(i)) 222 { 223 index = i | 0x80000000; 224 goto found; 225 } 226 } 227 if((index = EMFDRV_FindObject(dev, hBrush)) != 0) 228 goto found; 229 230 if (!(index = EMFDRV_CreateBrushIndirect(dev, hBrush ))) return 0; 231 GDI_hdc_using_object(hBrush, dev->hdc); 232 233 found: 234 emr.emr.iType = EMR_SELECTOBJECT; 235 emr.emr.nSize = sizeof(emr); 236 emr.ihObject = index; 237 return EMFDRV_WriteRecord( dev, &emr.emr ) ? hBrush : 0; 238 } 239 240 241 /****************************************************************** 242 * EMFDRV_CreateFontIndirect 243 */ 244 static BOOL EMFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont ) 245 { 246 DWORD index = 0; 247 EMREXTCREATEFONTINDIRECTW emr; 248 int i; 249 250 if (!GetObjectW( hFont, sizeof(emr.elfw.elfLogFont), &emr.elfw.elfLogFont )) return FALSE; 251 252 emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW; 253 emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4; 254 emr.ihFont = index = EMFDRV_AddHandle( dev, hFont ); 255 emr.elfw.elfFullName[0] = '\0'; 256 emr.elfw.elfStyle[0] = '\0'; 257 emr.elfw.elfVersion = 0; 258 emr.elfw.elfStyleSize = 0; 259 emr.elfw.elfMatch = 0; 260 emr.elfw.elfReserved = 0; 261 for(i = 0; i < ELF_VENDOR_SIZE; i++) 262 emr.elfw.elfVendorId[i] = 0; 263 emr.elfw.elfCulture = PAN_CULTURE_LATIN; 264 emr.elfw.elfPanose.bFamilyType = PAN_NO_FIT; 265 emr.elfw.elfPanose.bSerifStyle = PAN_NO_FIT; 266 emr.elfw.elfPanose.bWeight = PAN_NO_FIT; 267 emr.elfw.elfPanose.bProportion = PAN_NO_FIT; 268 emr.elfw.elfPanose.bContrast = PAN_NO_FIT; 269 emr.elfw.elfPanose.bStrokeVariation = PAN_NO_FIT; 270 emr.elfw.elfPanose.bArmStyle = PAN_NO_FIT; 271 emr.elfw.elfPanose.bLetterform = PAN_NO_FIT; 272 emr.elfw.elfPanose.bMidline = PAN_NO_FIT; 273 emr.elfw.elfPanose.bXHeight = PAN_NO_FIT; 274 275 if(!EMFDRV_WriteRecord( dev, &emr.emr )) 276 index = 0; 277 return index; 278 } 279 280 281 /*********************************************************************** 282 * EMFDRV_SelectFont 283 */ 284 HFONT EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont, UINT *aa_flags ) 285 { 286 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 287 EMRSELECTOBJECT emr; 288 DWORD index; 289 int i; 290 291 if (physDev->restoring) goto done; /* don't output SelectObject records during RestoreDC */ 292 293 /* If the object is a stock font object, do not need to create it. 294 * See definitions in wingdi.h for range of stock fonts. 295 * We do however have to handle setting the higher order bit to 296 * designate that this is a stock object. 297 */ 298 299 for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++) 300 { 301 if (i != DEFAULT_PALETTE && hFont == GetStockObject(i)) 302 { 303 index = i | 0x80000000; 304 goto found; 305 } 306 } 307 308 if((index = EMFDRV_FindObject(dev, hFont)) != 0) 309 goto found; 310 311 if (!(index = EMFDRV_CreateFontIndirect(dev, hFont ))) return 0; 312 GDI_hdc_using_object(hFont, dev->hdc); 313 314 found: 315 emr.emr.iType = EMR_SELECTOBJECT; 316 emr.emr.nSize = sizeof(emr); 317 emr.ihObject = index; 318 if(!EMFDRV_WriteRecord( dev, &emr.emr )) 319 return 0; 320 done: 321 *aa_flags = GGO_BITMAP; /* no point in anti-aliasing on metafiles */ 322 dev = GET_NEXT_PHYSDEV( dev, pSelectFont ); 323 dev->funcs->pSelectFont( dev, hFont, aa_flags ); 324 return hFont; 325 } 326 327 328 329 /****************************************************************** 330 * EMFDRV_CreatePenIndirect 331 */ 332 static DWORD EMFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen) 333 { 334 EMRCREATEPEN emr; 335 DWORD index = 0; 336 337 if (!GetObjectW( hPen, sizeof(emr.lopn), &emr.lopn )) 338 { 339 /* must be an extended pen */ 340 EXTLOGPEN *elp; 341 INT size = GetObjectW( hPen, 0, NULL ); 342 343 if (!size) return 0; 344 345 elp = HeapAlloc( GetProcessHeap(), 0, size ); 346 347 GetObjectW( hPen, size, elp ); 348 /* FIXME: add support for user style pens */ 349 emr.lopn.lopnStyle = elp->elpPenStyle; 350 emr.lopn.lopnWidth.x = elp->elpWidth; 351 emr.lopn.lopnWidth.y = 0; 352 emr.lopn.lopnColor = elp->elpColor; 353 354 HeapFree( GetProcessHeap(), 0, elp ); 355 } 356 357 emr.emr.iType = EMR_CREATEPEN; 358 emr.emr.nSize = sizeof(emr); 359 emr.ihPen = index = EMFDRV_AddHandle( dev, hPen ); 360 361 if(!EMFDRV_WriteRecord( dev, &emr.emr )) 362 index = 0; 363 return index; 364 } 365 366 /****************************************************************** 367 * EMFDRV_SelectPen 368 */ 369 HPEN EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen, const struct brush_pattern *pattern ) 370 { 371 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 372 EMRSELECTOBJECT emr; 373 DWORD index; 374 int i; 375 376 if (physDev->restoring) return hPen; /* don't output SelectObject records during RestoreDC */ 377 378 /* If the object is a stock pen object, do not need to create it. 379 * See definitions in wingdi.h for range of stock pens. 380 * We do however have to handle setting the higher order bit to 381 * designate that this is a stock object. 382 */ 383 384 for (i = WHITE_PEN; i <= DC_PEN; i++) 385 { 386 if (hPen == GetStockObject(i)) 387 { 388 index = i | 0x80000000; 389 goto found; 390 } 391 } 392 if((index = EMFDRV_FindObject(dev, hPen)) != 0) 393 goto found; 394 395 if (!(index = EMFDRV_CreatePenIndirect(dev, hPen))) return 0; 396 GDI_hdc_using_object(hPen, dev->hdc); 397 398 found: 399 emr.emr.iType = EMR_SELECTOBJECT; 400 emr.emr.nSize = sizeof(emr); 401 emr.ihObject = index; 402 return EMFDRV_WriteRecord( dev, &emr.emr ) ? hPen : 0; 403 } 404 405 406 /****************************************************************** 407 * EMFDRV_CreatePalette 408 */ 409 static DWORD EMFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPal) 410 { 411 WORD i; 412 struct { 413 EMRCREATEPALETTE hdr; 414 PALETTEENTRY entry[255]; 415 } pal; 416 417 memset( &pal, 0, sizeof(pal) ); 418 419 if (!GetObjectW( hPal, sizeof(pal.hdr.lgpl) + sizeof(pal.entry), &pal.hdr.lgpl )) 420 return 0; 421 422 for (i = 0; i < pal.hdr.lgpl.palNumEntries; i++) 423 pal.hdr.lgpl.palPalEntry[i].peFlags = 0; 424 425 pal.hdr.emr.iType = EMR_CREATEPALETTE; 426 pal.hdr.emr.nSize = sizeof(pal.hdr) + pal.hdr.lgpl.palNumEntries * sizeof(PALETTEENTRY); 427 pal.hdr.ihPal = EMFDRV_AddHandle( dev, hPal ); 428 429 if (!EMFDRV_WriteRecord( dev, &pal.hdr.emr )) 430 pal.hdr.ihPal = 0; 431 return pal.hdr.ihPal; 432 } 433 434 /****************************************************************** 435 * EMFDRV_SelectPalette 436 */ 437 HPALETTE EMFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPal, BOOL force ) 438 { 439 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 440 EMRSELECTPALETTE emr; 441 DWORD index; 442 443 if (physDev->restoring) return hPal; /* don't output SelectObject records during RestoreDC */ 444 445 if (hPal == GetStockObject( DEFAULT_PALETTE )) 446 { 447 index = DEFAULT_PALETTE | 0x80000000; 448 goto found; 449 } 450 451 if ((index = EMFDRV_FindObject( dev, hPal )) != 0) 452 goto found; 453 454 if (!(index = EMFDRV_CreatePalette( dev, hPal ))) return 0; 455 GDI_hdc_using_object( hPal, dev->hdc ); 456 457 found: 458 emr.emr.iType = EMR_SELECTPALETTE; 459 emr.emr.nSize = sizeof(emr); 460 emr.ihPal = index; 461 return EMFDRV_WriteRecord( dev, &emr.emr ) ? hPal : 0; 462 } 463 464 /****************************************************************** 465 * EMFDRV_SetDCBrushColor 466 */ 467 COLORREF EMFDRV_SetDCBrushColor( PHYSDEV dev, COLORREF color ) 468 { 469 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 470 #ifndef __REACTOS__ 471 DC *dc = get_physdev_dc( dev ); 472 #endif 473 EMRSELECTOBJECT emr; 474 DWORD index; 475 #ifdef __REACTOS__ 476 if (GetCurrentObject( dev->hdc, OBJ_BRUSH ) != GetStockObject( DC_BRUSH )) return color; 477 #else 478 if (dc->hBrush != GetStockObject( DC_BRUSH )) return color; 479 #endif 480 if (physDev->dc_brush) DeleteObject( physDev->dc_brush ); 481 if (!(physDev->dc_brush = CreateSolidBrush( color ))) return CLR_INVALID; 482 if (!(index = EMFDRV_CreateBrushIndirect(dev, physDev->dc_brush ))) return CLR_INVALID; 483 GDI_hdc_using_object( physDev->dc_brush, dev->hdc ); 484 emr.emr.iType = EMR_SELECTOBJECT; 485 emr.emr.nSize = sizeof(emr); 486 emr.ihObject = index; 487 return EMFDRV_WriteRecord( dev, &emr.emr ) ? color : CLR_INVALID; 488 } 489 490 /****************************************************************** 491 * EMFDRV_SetDCPenColor 492 */ 493 COLORREF EMFDRV_SetDCPenColor( PHYSDEV dev, COLORREF color ) 494 { 495 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 496 #ifndef __REACTOS__ 497 DC *dc = get_physdev_dc( dev ); 498 #endif 499 EMRSELECTOBJECT emr; 500 DWORD index; 501 LOGPEN logpen = { PS_SOLID, { 0, 0 }, color }; 502 #ifdef __REACTOS__ 503 if (GetCurrentObject( dev->hdc, OBJ_PEN ) != GetStockObject( DC_PEN )) return color; 504 #else 505 if (dc->hPen != GetStockObject( DC_PEN )) return color; 506 #endif 507 if (physDev->dc_pen) DeleteObject( physDev->dc_pen ); 508 if (!(physDev->dc_pen = CreatePenIndirect( &logpen ))) return CLR_INVALID; 509 if (!(index = EMFDRV_CreatePenIndirect(dev, physDev->dc_pen))) return CLR_INVALID; 510 GDI_hdc_using_object( physDev->dc_pen, dev->hdc ); 511 emr.emr.iType = EMR_SELECTOBJECT; 512 emr.emr.nSize = sizeof(emr); 513 emr.ihObject = index; 514 return EMFDRV_WriteRecord( dev, &emr.emr ) ? color : CLR_INVALID; 515 } 516 517 /****************************************************************** 518 * EMFDRV_GdiComment 519 */ 520 BOOL EMFDRV_GdiComment(PHYSDEV dev, UINT bytes, const BYTE *buffer) 521 { 522 EMRGDICOMMENT *emr; 523 UINT total, rounded_size; 524 BOOL ret; 525 526 rounded_size = (bytes+3) & ~3; 527 total = offsetof(EMRGDICOMMENT,Data) + rounded_size; 528 529 emr = HeapAlloc(GetProcessHeap(), 0, total); 530 emr->emr.iType = EMR_GDICOMMENT; 531 emr->emr.nSize = total; 532 emr->cbData = bytes; 533 memset(&emr->Data[bytes], 0, rounded_size - bytes); 534 memcpy(&emr->Data[0], buffer, bytes); 535 536 ret = EMFDRV_WriteRecord( dev, &emr->emr ); 537 538 HeapFree(GetProcessHeap(), 0, emr); 539 540 return ret; 541 } 542