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