1 /* 2 * Enhanced MetaFile driver initialisation functions 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 <assert.h> 22 #include <stdarg.h> 23 #include <string.h> 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "wingdi.h" 28 #include "winnls.h" 29 #include "gdi_private.h" 30 #include "enhmfdrv/enhmetafiledrv.h" 31 #include "wine/debug.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile); 34 35 static BOOL EMFDRV_DeleteDC( PHYSDEV dev ); 36 37 static const struct gdi_dc_funcs emfdrv_driver = 38 { 39 NULL, /* pAbortDoc */ 40 EMFDRV_AbortPath, /* pAbortPath */ 41 NULL, /* pAlphaBlend */ 42 EMFDRV_AngleArc, /* pAngleArc */ 43 EMFDRV_Arc, /* pArc */ 44 EMFDRV_ArcTo, /* pArcTo */ 45 EMFDRV_BeginPath, /* pBeginPath */ 46 NULL, /* pBlendImage */ 47 EMFDRV_Chord, /* pChord */ 48 EMFDRV_CloseFigure, /* pCloseFigure */ 49 NULL, /* pCreateCompatibleDC */ 50 NULL, /* pCreateDC */ 51 EMFDRV_DeleteDC, /* pDeleteDC */ 52 EMFDRV_DeleteObject, /* pDeleteObject */ 53 NULL, /* pDeviceCapabilities */ 54 EMFDRV_Ellipse, /* pEllipse */ 55 NULL, /* pEndDoc */ 56 NULL, /* pEndPage */ 57 EMFDRV_EndPath, /* pEndPath */ 58 NULL, /* pEnumFonts */ 59 NULL, /* pEnumICMProfiles */ 60 EMFDRV_ExcludeClipRect, /* pExcludeClipRect */ 61 NULL, /* pExtDeviceMode */ 62 NULL, /* pExtEscape */ 63 EMFDRV_ExtFloodFill, /* pExtFloodFill */ 64 EMFDRV_ExtSelectClipRgn, /* pExtSelectClipRgn */ 65 EMFDRV_ExtTextOut, /* pExtTextOut */ 66 EMFDRV_FillPath, /* pFillPath */ 67 EMFDRV_FillRgn, /* pFillRgn */ 68 EMFDRV_FlattenPath, /* pFlattenPath */ 69 NULL, /* pFontIsLinked */ 70 EMFDRV_FrameRgn, /* pFrameRgn */ 71 EMFDRV_GdiComment, /* pGdiComment */ 72 NULL, /* pGetBoundsRect */ 73 NULL, /* pGetCharABCWidths */ 74 NULL, /* pGetCharABCWidthsI */ 75 NULL, /* pGetCharWidth */ 76 EMFDRV_GetDeviceCaps, /* pGetDeviceCaps */ 77 NULL, /* pGetDeviceGammaRamp */ 78 NULL, /* pGetFontData */ 79 NULL, /* pGetFontRealizationInfo */ 80 NULL, /* pGetFontUnicodeRanges */ 81 NULL, /* pGetGlyphIndices */ 82 NULL, /* pGetGlyphOutline */ 83 NULL, /* pGetICMProfile */ 84 NULL, /* pGetImage */ 85 NULL, /* pGetKerningPairs */ 86 NULL, /* pGetNearestColor */ 87 NULL, /* pGetOutlineTextMetrics */ 88 NULL, /* pGetPixel */ 89 NULL, /* pGetSystemPaletteEntries */ 90 NULL, /* pGetTextCharsetInfo */ 91 NULL, /* pGetTextExtentExPoint */ 92 NULL, /* pGetTextExtentExPointI */ 93 NULL, /* pGetTextFace */ 94 NULL, /* pGetTextMetrics */ 95 EMFDRV_GradientFill, /* pGradientFill */ 96 EMFDRV_IntersectClipRect, /* pIntersectClipRect */ 97 EMFDRV_InvertRgn, /* pInvertRgn */ 98 EMFDRV_LineTo, /* pLineTo */ 99 EMFDRV_ModifyWorldTransform, /* pModifyWorldTransform */ 100 EMFDRV_MoveTo, /* pMoveTo */ 101 EMFDRV_OffsetClipRgn, /* pOffsetClipRgn */ 102 EMFDRV_OffsetViewportOrgEx, /* pOffsetViewportOrgEx */ 103 EMFDRV_OffsetWindowOrgEx, /* pOffsetWindowOrgEx */ 104 EMFDRV_PaintRgn, /* pPaintRgn */ 105 EMFDRV_PatBlt, /* pPatBlt */ 106 EMFDRV_Pie, /* pPie */ 107 EMFDRV_PolyBezier, /* pPolyBezier */ 108 EMFDRV_PolyBezierTo, /* pPolyBezierTo */ 109 EMFDRV_PolyDraw, /* pPolyDraw */ 110 EMFDRV_PolyPolygon, /* pPolyPolygon */ 111 EMFDRV_PolyPolyline, /* pPolyPolyline */ 112 EMFDRV_Polygon, /* pPolygon */ 113 EMFDRV_Polyline, /* pPolyline */ 114 EMFDRV_PolylineTo, /* pPolylineTo */ 115 NULL, /* pPutImage */ 116 NULL, /* pRealizeDefaultPalette */ 117 NULL, /* pRealizePalette */ 118 EMFDRV_Rectangle, /* pRectangle */ 119 NULL, /* pResetDC */ 120 EMFDRV_RestoreDC, /* pRestoreDC */ 121 EMFDRV_RoundRect, /* pRoundRect */ 122 EMFDRV_SaveDC, /* pSaveDC */ 123 EMFDRV_ScaleViewportExtEx, /* pScaleViewportExtEx */ 124 EMFDRV_ScaleWindowExtEx, /* pScaleWindowExtEx */ 125 EMFDRV_SelectBitmap, /* pSelectBitmap */ 126 EMFDRV_SelectBrush, /* pSelectBrush */ 127 EMFDRV_SelectClipPath, /* pSelectClipPath */ 128 EMFDRV_SelectFont, /* pSelectFont */ 129 EMFDRV_SelectPalette, /* pSelectPalette */ 130 EMFDRV_SelectPen, /* pSelectPen */ 131 EMFDRV_SetArcDirection, /* pSetArcDirection */ 132 EMFDRV_SetBkColor, /* pSetBkColor */ 133 EMFDRV_SetBkMode, /* pSetBkMode */ 134 NULL, /* pSetBoundsRect */ 135 EMFDRV_SetDCBrushColor, /* pSetDCBrushColor*/ 136 EMFDRV_SetDCPenColor, /* pSetDCPenColor*/ 137 EMFDRV_SetDIBitsToDevice, /* pSetDIBitsToDevice */ 138 NULL, /* pSetDeviceClipping */ 139 NULL, /* pSetDeviceGammaRamp */ 140 EMFDRV_SetLayout, /* pSetLayout */ 141 EMFDRV_SetMapMode, /* pSetMapMode */ 142 EMFDRV_SetMapperFlags, /* pSetMapperFlags */ 143 EMFDRV_SetPixel, /* pSetPixel */ 144 EMFDRV_SetPolyFillMode, /* pSetPolyFillMode */ 145 EMFDRV_SetROP2, /* pSetROP2 */ 146 NULL, /* pSetRelAbs */ 147 EMFDRV_SetStretchBltMode, /* pSetStretchBltMode */ 148 EMFDRV_SetTextAlign, /* pSetTextAlign */ 149 NULL, /* pSetTextCharacterExtra */ 150 EMFDRV_SetTextColor, /* pSetTextColor */ 151 EMFDRV_SetTextJustification, /* pSetTextJustification */ 152 EMFDRV_SetViewportExtEx, /* pSetViewportExtEx */ 153 EMFDRV_SetViewportOrgEx, /* pSetViewportOrgEx */ 154 EMFDRV_SetWindowExtEx, /* pSetWindowExtEx */ 155 EMFDRV_SetWindowOrgEx, /* pSetWindowOrgEx */ 156 EMFDRV_SetWorldTransform, /* pSetWorldTransform */ 157 NULL, /* pStartDoc */ 158 NULL, /* pStartPage */ 159 EMFDRV_StretchBlt, /* pStretchBlt */ 160 EMFDRV_StretchDIBits, /* pStretchDIBits */ 161 EMFDRV_StrokeAndFillPath, /* pStrokeAndFillPath */ 162 EMFDRV_StrokePath, /* pStrokePath */ 163 NULL, /* pUnrealizePalette */ 164 EMFDRV_WidenPath, /* pWidenPath */ 165 NULL, /* wine_get_wgl_driver */ 166 GDI_PRIORITY_GRAPHICS_DRV /* priority */ 167 }; 168 169 170 /********************************************************************** 171 * EMFDRV_DeleteDC 172 */ 173 static BOOL EMFDRV_DeleteDC( PHYSDEV dev ) 174 { 175 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 176 UINT index; 177 178 HeapFree( GetProcessHeap(), 0, physDev->emh ); 179 for(index = 0; index < physDev->handles_size; index++) 180 if(physDev->handles[index]) 181 GDI_hdc_not_using_object(physDev->handles[index], dev->hdc); 182 HeapFree( GetProcessHeap(), 0, physDev->handles ); 183 HeapFree( GetProcessHeap(), 0, physDev ); 184 return TRUE; 185 } 186 187 188 /****************************************************************** 189 * EMFDRV_WriteRecord 190 * 191 * Warning: this function can change the pointer to the metafile header. 192 */ 193 BOOL EMFDRV_WriteRecord( PHYSDEV dev, EMR *emr ) 194 { 195 DWORD len; 196 DWORD bytes_written; 197 ENHMETAHEADER *emh; 198 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 199 200 TRACE("record %d, size %d %s\n", 201 emr->iType, emr->nSize, physDev->hFile ? "(to disk)" : ""); 202 203 assert( !(emr->nSize & 3) ); 204 205 physDev->emh->nBytes += emr->nSize; 206 physDev->emh->nRecords++; 207 208 if(physDev->hFile) { 209 if (!WriteFile(physDev->hFile, emr, emr->nSize, &bytes_written, NULL)) 210 return FALSE; 211 } else { 212 DWORD nEmfSize = HeapSize(GetProcessHeap(), 0, physDev->emh); 213 len = physDev->emh->nBytes; 214 if (len > nEmfSize) { 215 nEmfSize += (nEmfSize / 2) + emr->nSize; 216 emh = HeapReAlloc(GetProcessHeap(), 0, physDev->emh, nEmfSize); 217 if (!emh) return FALSE; 218 physDev->emh = emh; 219 } 220 memcpy((CHAR *)physDev->emh + physDev->emh->nBytes - emr->nSize, emr, 221 emr->nSize); 222 } 223 return TRUE; 224 } 225 226 227 /****************************************************************** 228 * EMFDRV_UpdateBBox 229 */ 230 void EMFDRV_UpdateBBox( PHYSDEV dev, RECTL *rect ) 231 { 232 EMFDRV_PDEVICE *physDev = get_emf_physdev( dev ); 233 RECTL *bounds = &physDev->emh->rclBounds; 234 RECTL vportRect = *rect; 235 236 LPtoDP( dev->hdc, (LPPOINT)&vportRect, 2 ); 237 238 /* The coordinate systems may be mirrored 239 (LPtoDP handles points, not rectangles) */ 240 if (vportRect.left > vportRect.right) 241 { 242 LONG temp = vportRect.right; 243 vportRect.right = vportRect.left; 244 vportRect.left = temp; 245 } 246 if (vportRect.top > vportRect.bottom) 247 { 248 LONG temp = vportRect.bottom; 249 vportRect.bottom = vportRect.top; 250 vportRect.top = temp; 251 } 252 253 if (bounds->left > bounds->right) 254 { 255 /* first bounding rectangle */ 256 *bounds = vportRect; 257 } 258 else 259 { 260 bounds->left = min(bounds->left, vportRect.left); 261 bounds->top = min(bounds->top, vportRect.top); 262 bounds->right = max(bounds->right, vportRect.right); 263 bounds->bottom = max(bounds->bottom, vportRect.bottom); 264 } 265 } 266 267 /********************************************************************** 268 * CreateEnhMetaFileA (GDI32.@) 269 */ 270 HDC WINAPI CreateEnhMetaFileA( 271 HDC hdc, /* [in] optional reference DC */ 272 LPCSTR filename, /* [in] optional filename for disk metafiles */ 273 const RECT *rect, /* [in] optional bounding rectangle */ 274 LPCSTR description /* [in] optional description */ 275 ) 276 { 277 LPWSTR filenameW = NULL; 278 LPWSTR descriptionW = NULL; 279 HDC hReturnDC; 280 DWORD len1, len2, total; 281 282 if(filename) 283 { 284 total = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 ); 285 filenameW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) ); 286 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, total ); 287 } 288 if(description) { 289 len1 = strlen(description); 290 len2 = strlen(description + len1 + 1); 291 total = MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, NULL, 0 ); 292 descriptionW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) ); 293 MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, descriptionW, total ); 294 } 295 296 hReturnDC = CreateEnhMetaFileW(hdc, filenameW, rect, descriptionW); 297 298 HeapFree( GetProcessHeap(), 0, filenameW ); 299 HeapFree( GetProcessHeap(), 0, descriptionW ); 300 301 return hReturnDC; 302 } 303 304 /********************************************************************** 305 * CreateEnhMetaFileW (GDI32.@) 306 */ 307 HDC WINAPI CreateEnhMetaFileW( 308 HDC hdc, /* [in] optional reference DC */ 309 LPCWSTR filename, /* [in] optional filename for disk metafiles */ 310 const RECT* rect, /* [in] optional bounding rectangle */ 311 LPCWSTR description /* [in] optional description */ 312 ) 313 { 314 static const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0}; 315 HDC ret; 316 DC *dc; 317 EMFDRV_PDEVICE *physDev; 318 HANDLE hFile; 319 DWORD size = 0, length = 0; 320 DWORD bytes_written; 321 322 TRACE("(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect), debugstr_w(description) ); 323 324 if (!(dc = alloc_dc_ptr( OBJ_ENHMETADC ))) return 0; 325 326 physDev = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*physDev)); 327 if (!physDev) { 328 free_dc_ptr( dc ); 329 return 0; 330 } 331 if(description) { /* App name\0Title\0\0 */ 332 length = lstrlenW(description); 333 length += lstrlenW(description + length + 1); 334 length += 3; 335 length *= 2; 336 } 337 size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4; 338 339 if (!(physDev->emh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size))) { 340 HeapFree( GetProcessHeap(), 0, physDev ); 341 free_dc_ptr( dc ); 342 return 0; 343 } 344 345 push_dc_driver( &dc->physDev, &physDev->dev, &emfdrv_driver ); 346 347 physDev->handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, HANDLE_LIST_INC * sizeof(physDev->handles[0])); 348 physDev->handles_size = HANDLE_LIST_INC; 349 physDev->cur_handles = 1; 350 physDev->hFile = 0; 351 physDev->dc_brush = 0; 352 physDev->dc_pen = 0; 353 physDev->screen_dc = 0; 354 physDev->restoring = 0; 355 physDev->path = FALSE; 356 if (hdc) /* if no ref, use current display */ 357 physDev->ref_dc = hdc; 358 else 359 physDev->ref_dc = physDev->screen_dc = CreateDCW( displayW, NULL, NULL, NULL ); 360 361 SetVirtualResolution(physDev->dev.hdc, 0, 0, 0, 0); 362 363 physDev->emh->iType = EMR_HEADER; 364 physDev->emh->nSize = size; 365 366 physDev->emh->rclBounds.left = physDev->emh->rclBounds.top = 0; 367 physDev->emh->rclBounds.right = physDev->emh->rclBounds.bottom = -1; 368 369 if(rect) { 370 physDev->emh->rclFrame.left = rect->left; 371 physDev->emh->rclFrame.top = rect->top; 372 physDev->emh->rclFrame.right = rect->right; 373 physDev->emh->rclFrame.bottom = rect->bottom; 374 } else { /* Set this to {0,0 - -1,-1} and update it at the end */ 375 physDev->emh->rclFrame.left = physDev->emh->rclFrame.top = 0; 376 physDev->emh->rclFrame.right = physDev->emh->rclFrame.bottom = -1; 377 } 378 379 physDev->emh->dSignature = ENHMETA_SIGNATURE; 380 physDev->emh->nVersion = 0x10000; 381 physDev->emh->nBytes = physDev->emh->nSize; 382 physDev->emh->nRecords = 1; 383 physDev->emh->nHandles = 1; 384 385 physDev->emh->sReserved = 0; /* According to docs, this is reserved and must be 0 */ 386 physDev->emh->nDescription = length / 2; 387 388 physDev->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0; 389 390 physDev->emh->nPalEntries = 0; /* I guess this should start at 0 */ 391 392 /* Size in pixels */ 393 physDev->emh->szlDevice.cx = GetDeviceCaps( physDev->ref_dc, HORZRES ); 394 physDev->emh->szlDevice.cy = GetDeviceCaps( physDev->ref_dc, VERTRES ); 395 396 /* Size in millimeters */ 397 physDev->emh->szlMillimeters.cx = GetDeviceCaps( physDev->ref_dc, HORZSIZE ); 398 physDev->emh->szlMillimeters.cy = GetDeviceCaps( physDev->ref_dc, VERTSIZE ); 399 400 /* Size in micrometers */ 401 physDev->emh->szlMicrometers.cx = physDev->emh->szlMillimeters.cx * 1000; 402 physDev->emh->szlMicrometers.cy = physDev->emh->szlMillimeters.cy * 1000; 403 404 memcpy((char *)physDev->emh + sizeof(ENHMETAHEADER), description, length); 405 406 if (filename) /* disk based metafile */ 407 { 408 if ((hFile = CreateFileW(filename, GENERIC_WRITE | GENERIC_READ, 0, 409 NULL, CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) { 410 free_dc_ptr( dc ); 411 return 0; 412 } 413 if (!WriteFile( hFile, physDev->emh, size, &bytes_written, NULL )) { 414 free_dc_ptr( dc ); 415 CloseHandle( hFile ); 416 return 0; 417 } 418 physDev->hFile = hFile; 419 } 420 421 TRACE("returning %p\n", physDev->dev.hdc); 422 ret = physDev->dev.hdc; 423 release_dc_ptr( dc ); 424 425 return ret; 426 } 427 428 /****************************************************************** 429 * CloseEnhMetaFile (GDI32.@) 430 */ 431 HENHMETAFILE WINAPI CloseEnhMetaFile(HDC hdc) /* [in] metafile DC */ 432 { 433 HENHMETAFILE hmf; 434 EMFDRV_PDEVICE *physDev; 435 DC *dc; 436 EMREOF emr; 437 HANDLE hMapping = 0; 438 439 TRACE("(%p)\n", hdc ); 440 441 if (!(dc = get_dc_ptr( hdc ))) return NULL; 442 if (GetObjectType( hdc ) != OBJ_ENHMETADC) 443 { 444 release_dc_ptr( dc ); 445 return NULL; 446 } 447 if (dc->refcount != 1) 448 { 449 FIXME( "not deleting busy DC %p refcount %u\n", hdc, dc->refcount ); 450 release_dc_ptr( dc ); 451 return NULL; 452 } 453 physDev = get_emf_physdev( find_dc_driver( dc, &emfdrv_driver )); 454 455 if(dc->saveLevel) 456 RestoreDC(hdc, 1); 457 458 if (physDev->dc_brush) DeleteObject( physDev->dc_brush ); 459 if (physDev->dc_pen) DeleteObject( physDev->dc_pen ); 460 if (physDev->screen_dc) DeleteDC( physDev->screen_dc ); 461 462 emr.emr.iType = EMR_EOF; 463 emr.emr.nSize = sizeof(emr); 464 emr.nPalEntries = 0; 465 emr.offPalEntries = FIELD_OFFSET(EMREOF, nSizeLast); 466 emr.nSizeLast = emr.emr.nSize; 467 EMFDRV_WriteRecord( &physDev->dev, &emr.emr ); 468 469 /* Update rclFrame if not initialized in CreateEnhMetaFile */ 470 if(physDev->emh->rclFrame.left > physDev->emh->rclFrame.right) { 471 physDev->emh->rclFrame.left = physDev->emh->rclBounds.left * 472 physDev->emh->szlMillimeters.cx * 100 / physDev->emh->szlDevice.cx; 473 physDev->emh->rclFrame.top = physDev->emh->rclBounds.top * 474 physDev->emh->szlMillimeters.cy * 100 / physDev->emh->szlDevice.cy; 475 physDev->emh->rclFrame.right = physDev->emh->rclBounds.right * 476 physDev->emh->szlMillimeters.cx * 100 / physDev->emh->szlDevice.cx; 477 physDev->emh->rclFrame.bottom = physDev->emh->rclBounds.bottom * 478 physDev->emh->szlMillimeters.cy * 100 / physDev->emh->szlDevice.cy; 479 } 480 481 if (physDev->hFile) /* disk based metafile */ 482 { 483 if (SetFilePointer(physDev->hFile, 0, NULL, FILE_BEGIN) != 0) 484 { 485 CloseHandle( physDev->hFile ); 486 free_dc_ptr( dc ); 487 return 0; 488 } 489 490 if (!WriteFile(physDev->hFile, physDev->emh, sizeof(*physDev->emh), 491 NULL, NULL)) 492 { 493 CloseHandle( physDev->hFile ); 494 free_dc_ptr( dc ); 495 return 0; 496 } 497 HeapFree( GetProcessHeap(), 0, physDev->emh ); 498 hMapping = CreateFileMappingA(physDev->hFile, NULL, PAGE_READONLY, 0, 499 0, NULL); 500 TRACE("hMapping = %p\n", hMapping ); 501 physDev->emh = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); 502 TRACE("view = %p\n", physDev->emh ); 503 CloseHandle( hMapping ); 504 CloseHandle( physDev->hFile ); 505 } 506 507 hmf = EMF_Create_HENHMETAFILE( physDev->emh, (physDev->hFile != 0) ); 508 physDev->emh = NULL; /* So it won't be deleted */ 509 free_dc_ptr( dc ); 510 return hmf; 511 } 512