1 /* vi:set ts=8 sts=4 sw=4 noet: */ 2 /* 3 * Author: MURAOKA Taro <[email protected]> 4 * 5 * Contributors: 6 * - Ken Takata 7 * 8 * Copyright (C) 2013 MURAOKA Taro <[email protected]> 9 * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. 10 */ 11 12 #define WIN32_LEAN_AND_MEAN 13 14 #ifndef DYNAMIC_DIRECTX 15 # if WINVER < 0x0600 16 # error WINVER must be 0x0600 or above to use DirectWrite(DirectX) 17 # endif 18 #endif 19 20 #include <windows.h> 21 #include <crtdbg.h> 22 #include <assert.h> 23 #include <math.h> 24 #include <d2d1.h> 25 #include <d2d1helper.h> 26 #include <dwrite.h> 27 28 #include "gui_dwrite.h" 29 30 #ifdef __MINGW32__ 31 # define __maybenull SAL__maybenull 32 # define __in SAL__in 33 # define __out SAL__out 34 #endif 35 36 #if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L) 37 # define FINAL final 38 #else 39 # define FINAL 40 #endif 41 42 #ifdef DYNAMIC_DIRECTX 43 extern "C" HINSTANCE vimLoadLib(char *name); 44 45 typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int); 46 typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE, 47 REFIID, const D2D1_FACTORY_OPTIONS *, void **); 48 typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE, 49 REFIID, IUnknown **); 50 51 static HINSTANCE hD2D1DLL = NULL; 52 static HINSTANCE hDWriteDLL = NULL; 53 54 static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL; 55 static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL; 56 static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL; 57 58 #define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName) 59 #define D2D1CreateFactory (*pD2D1CreateFactory) 60 #define DWriteCreateFactory (*pDWriteCreateFactory) 61 62 static void 63 unload(HINSTANCE &hinst) 64 { 65 if (hinst != NULL) 66 { 67 FreeLibrary(hinst); 68 hinst = NULL; 69 } 70 } 71 #endif // DYNAMIC_DIRECTX 72 73 template <class T> inline void SafeRelease(T **ppT) 74 { 75 if (*ppT) 76 { 77 (*ppT)->Release(); 78 *ppT = NULL; 79 } 80 } 81 82 struct GdiTextRendererContext 83 { 84 // const fields. 85 COLORREF color; 86 FLOAT cellWidth; 87 88 // working fields. 89 FLOAT offsetX; 90 }; 91 92 static DWRITE_PIXEL_GEOMETRY 93 ToPixelGeometry(int value) 94 { 95 switch (value) 96 { 97 default: 98 case 0: 99 return DWRITE_PIXEL_GEOMETRY_FLAT; 100 case 1: 101 return DWRITE_PIXEL_GEOMETRY_RGB; 102 case 2: 103 return DWRITE_PIXEL_GEOMETRY_BGR; 104 } 105 } 106 107 static int 108 ToInt(DWRITE_PIXEL_GEOMETRY value) 109 { 110 switch (value) 111 { 112 case DWRITE_PIXEL_GEOMETRY_FLAT: 113 return 0; 114 case DWRITE_PIXEL_GEOMETRY_RGB: 115 return 1; 116 case DWRITE_PIXEL_GEOMETRY_BGR: 117 return 2; 118 default: 119 return -1; 120 } 121 } 122 123 static DWRITE_RENDERING_MODE 124 ToRenderingMode(int value) 125 { 126 switch (value) 127 { 128 default: 129 case 0: 130 return DWRITE_RENDERING_MODE_DEFAULT; 131 case 1: 132 return DWRITE_RENDERING_MODE_ALIASED; 133 case 2: 134 return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; 135 case 3: 136 return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL; 137 case 4: 138 return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; 139 case 5: 140 return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; 141 case 6: 142 return DWRITE_RENDERING_MODE_OUTLINE; 143 } 144 } 145 146 static D2D1_TEXT_ANTIALIAS_MODE 147 ToTextAntialiasMode(int value) 148 { 149 switch (value) 150 { 151 default: 152 case 0: 153 return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; 154 case 1: 155 return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; 156 case 2: 157 return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; 158 case 3: 159 return D2D1_TEXT_ANTIALIAS_MODE_ALIASED; 160 } 161 } 162 163 static int 164 ToInt(DWRITE_RENDERING_MODE value) 165 { 166 switch (value) 167 { 168 case DWRITE_RENDERING_MODE_DEFAULT: 169 return 0; 170 case DWRITE_RENDERING_MODE_ALIASED: 171 return 1; 172 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC: 173 return 2; 174 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL: 175 return 3; 176 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL: 177 return 4; 178 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC: 179 return 5; 180 case DWRITE_RENDERING_MODE_OUTLINE: 181 return 6; 182 default: 183 return -1; 184 } 185 } 186 187 class AdjustedGlyphRun : public DWRITE_GLYPH_RUN 188 { 189 private: 190 FLOAT mDelta; 191 FLOAT *mAdjustedAdvances; 192 193 public: 194 AdjustedGlyphRun( 195 const DWRITE_GLYPH_RUN *glyphRun, 196 FLOAT cellWidth) : 197 DWRITE_GLYPH_RUN(*glyphRun), 198 mDelta(0.0f), 199 mAdjustedAdvances(new FLOAT[glyphRun->glyphCount]) 200 { 201 assert(cellWidth != 0.0f); 202 for (UINT32 i = 0; i < glyphRun->glyphCount; ++i) 203 { 204 FLOAT orig = glyphRun->glyphAdvances[i]; 205 FLOAT adjusted = adjustToCell(orig, cellWidth); 206 mAdjustedAdvances[i] = adjusted; 207 mDelta += adjusted - orig; 208 } 209 glyphAdvances = mAdjustedAdvances; 210 } 211 212 ~AdjustedGlyphRun(void) 213 { 214 delete[] mAdjustedAdvances; 215 } 216 217 FLOAT getDelta(void) const 218 { 219 return mDelta; 220 } 221 222 static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth) 223 { 224 int cellCount = (int)floor(value / cellWidth + 0.5f); 225 if (cellCount < 1) 226 cellCount = 1; 227 return cellCount * cellWidth; 228 } 229 }; 230 231 class GdiTextRenderer FINAL : public IDWriteTextRenderer 232 { 233 public: 234 GdiTextRenderer( 235 IDWriteBitmapRenderTarget* bitmapRenderTarget, 236 IDWriteRenderingParams* renderingParams) : 237 cRefCount_(0), 238 pRenderTarget_(bitmapRenderTarget), 239 pRenderingParams_(renderingParams) 240 { 241 pRenderTarget_->AddRef(); 242 pRenderingParams_->AddRef(); 243 AddRef(); 244 } 245 246 // add "virtual" to avoid a compiler warning 247 virtual ~GdiTextRenderer() 248 { 249 SafeRelease(&pRenderTarget_); 250 SafeRelease(&pRenderingParams_); 251 } 252 253 IFACEMETHOD(IsPixelSnappingDisabled)( 254 __maybenull void* clientDrawingContext, 255 __out BOOL* isDisabled) 256 { 257 *isDisabled = FALSE; 258 return S_OK; 259 } 260 261 IFACEMETHOD(GetCurrentTransform)( 262 __maybenull void* clientDrawingContext, 263 __out DWRITE_MATRIX* transform) 264 { 265 // forward the render target's transform 266 pRenderTarget_->GetCurrentTransform(transform); 267 return S_OK; 268 } 269 270 IFACEMETHOD(GetPixelsPerDip)( 271 __maybenull void* clientDrawingContext, 272 __out FLOAT* pixelsPerDip) 273 { 274 *pixelsPerDip = pRenderTarget_->GetPixelsPerDip(); 275 return S_OK; 276 } 277 278 IFACEMETHOD(DrawGlyphRun)( 279 __maybenull void* clientDrawingContext, 280 FLOAT baselineOriginX, 281 FLOAT baselineOriginY, 282 DWRITE_MEASURING_MODE measuringMode, 283 __in DWRITE_GLYPH_RUN const* glyphRun, 284 __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, 285 IUnknown* clientDrawingEffect) 286 { 287 HRESULT hr = S_OK; 288 289 GdiTextRendererContext *context = 290 reinterpret_cast<GdiTextRendererContext*>(clientDrawingContext); 291 292 AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth); 293 294 // Pass on the drawing call to the render target to do the real work. 295 RECT dirtyRect = {0}; 296 297 hr = pRenderTarget_->DrawGlyphRun( 298 baselineOriginX + context->offsetX, 299 baselineOriginY, 300 measuringMode, 301 &adjustedGlyphRun, 302 pRenderingParams_, 303 context->color, 304 &dirtyRect); 305 306 context->offsetX += adjustedGlyphRun.getDelta(); 307 308 return hr; 309 } 310 311 IFACEMETHOD(DrawUnderline)( 312 __maybenull void* clientDrawingContext, 313 FLOAT baselineOriginX, 314 FLOAT baselineOriginY, 315 __in DWRITE_UNDERLINE const* underline, 316 IUnknown* clientDrawingEffect) 317 { 318 return E_NOTIMPL; 319 } 320 321 IFACEMETHOD(DrawStrikethrough)( 322 __maybenull void* clientDrawingContext, 323 FLOAT baselineOriginX, 324 FLOAT baselineOriginY, 325 __in DWRITE_STRIKETHROUGH const* strikethrough, 326 IUnknown* clientDrawingEffect) 327 { 328 return E_NOTIMPL; 329 } 330 331 IFACEMETHOD(DrawInlineObject)( 332 __maybenull void* clientDrawingContext, 333 FLOAT originX, 334 FLOAT originY, 335 IDWriteInlineObject* inlineObject, 336 BOOL isSideways, 337 BOOL isRightToLeft, 338 IUnknown* clientDrawingEffect) 339 { 340 return E_NOTIMPL; 341 } 342 343 public: 344 IFACEMETHOD_(unsigned long, AddRef) () 345 { 346 return InterlockedIncrement(&cRefCount_); 347 } 348 349 IFACEMETHOD_(unsigned long, Release) () 350 { 351 long newCount = InterlockedDecrement(&cRefCount_); 352 353 if (newCount == 0) 354 { 355 delete this; 356 return 0; 357 } 358 return newCount; 359 } 360 361 IFACEMETHOD(QueryInterface)( 362 IID const& riid, 363 void** ppvObject) 364 { 365 if (__uuidof(IDWriteTextRenderer) == riid) 366 { 367 *ppvObject = this; 368 } 369 else if (__uuidof(IDWritePixelSnapping) == riid) 370 { 371 *ppvObject = this; 372 } 373 else if (__uuidof(IUnknown) == riid) 374 { 375 *ppvObject = this; 376 } 377 else 378 { 379 *ppvObject = NULL; 380 return E_FAIL; 381 } 382 383 return S_OK; 384 } 385 386 private: 387 long cRefCount_; 388 IDWriteBitmapRenderTarget* pRenderTarget_; 389 IDWriteRenderingParams* pRenderingParams_; 390 }; 391 392 struct DWriteContext { 393 FLOAT mDpiScaleX; 394 FLOAT mDpiScaleY; 395 bool mDrawing; 396 397 ID2D1Factory *mD2D1Factory; 398 399 ID2D1DCRenderTarget *mRT; 400 ID2D1SolidColorBrush *mBrush; 401 402 IDWriteFactory *mDWriteFactory; 403 IDWriteGdiInterop *mGdiInterop; 404 IDWriteRenderingParams *mRenderingParams; 405 IDWriteTextFormat *mTextFormat; 406 407 HFONT mLastHFont; 408 DWRITE_FONT_WEIGHT mFontWeight; 409 DWRITE_FONT_STYLE mFontStyle; 410 411 D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode; 412 413 // METHODS 414 415 DWriteContext(); 416 417 virtual ~DWriteContext(); 418 419 HRESULT SetLOGFONT(const LOGFONTW &logFont, float fontSize); 420 421 void SetFont(HFONT hFont); 422 423 void SetFont(const LOGFONTW &logFont); 424 425 void DrawText(HDC hdc, const WCHAR* text, int len, 426 int x, int y, int w, int h, int cellWidth, COLORREF color); 427 428 float PixelsToDipsX(int x); 429 430 float PixelsToDipsY(int y); 431 432 void SetRenderingParams( 433 const DWriteRenderingParams *params); 434 435 DWriteRenderingParams *GetRenderingParams( 436 DWriteRenderingParams *params); 437 }; 438 439 DWriteContext::DWriteContext() : 440 mDpiScaleX(1.f), 441 mDpiScaleY(1.f), 442 mDrawing(false), 443 mD2D1Factory(NULL), 444 mRT(NULL), 445 mBrush(NULL), 446 mDWriteFactory(NULL), 447 mGdiInterop(NULL), 448 mRenderingParams(NULL), 449 mTextFormat(NULL), 450 mLastHFont(NULL), 451 mFontWeight(DWRITE_FONT_WEIGHT_NORMAL), 452 mFontStyle(DWRITE_FONT_STYLE_NORMAL), 453 mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT) 454 { 455 HRESULT hr; 456 457 HDC screen = ::GetDC(0); 458 mDpiScaleX = ::GetDeviceCaps(screen, LOGPIXELSX) / 96.0f; 459 mDpiScaleY = ::GetDeviceCaps(screen, LOGPIXELSY) / 96.0f; 460 ::ReleaseDC(0, screen); 461 462 hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, 463 __uuidof(ID2D1Factory), NULL, 464 reinterpret_cast<void**>(&mD2D1Factory)); 465 _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory); 466 467 if (SUCCEEDED(hr)) 468 { 469 D2D1_RENDER_TARGET_PROPERTIES props = { 470 D2D1_RENDER_TARGET_TYPE_DEFAULT, 471 { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE }, 472 0, 0, 473 D2D1_RENDER_TARGET_USAGE_NONE, 474 D2D1_FEATURE_LEVEL_DEFAULT 475 }; 476 hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT); 477 _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT); 478 } 479 480 if (SUCCEEDED(hr)) 481 { 482 hr = mRT->CreateSolidColorBrush( 483 D2D1::ColorF(D2D1::ColorF::Black), 484 &mBrush); 485 _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush); 486 } 487 488 if (SUCCEEDED(hr)) 489 { 490 hr = DWriteCreateFactory( 491 DWRITE_FACTORY_TYPE_SHARED, 492 __uuidof(IDWriteFactory), 493 reinterpret_cast<IUnknown**>(&mDWriteFactory)); 494 _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr, 495 mDWriteFactory); 496 } 497 498 if (SUCCEEDED(hr)) 499 { 500 hr = mDWriteFactory->GetGdiInterop(&mGdiInterop); 501 _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop); 502 } 503 504 if (SUCCEEDED(hr)) 505 { 506 hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams); 507 _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr, 508 mRenderingParams); 509 } 510 } 511 512 DWriteContext::~DWriteContext() 513 { 514 SafeRelease(&mTextFormat); 515 SafeRelease(&mRenderingParams); 516 SafeRelease(&mGdiInterop); 517 SafeRelease(&mDWriteFactory); 518 SafeRelease(&mBrush); 519 SafeRelease(&mRT); 520 SafeRelease(&mD2D1Factory); 521 } 522 523 HRESULT 524 DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize) 525 { 526 // Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx 527 HRESULT hr = S_OK; 528 529 IDWriteFont *font = NULL; 530 IDWriteFontFamily *fontFamily = NULL; 531 IDWriteLocalizedStrings *localizedFamilyNames = NULL; 532 533 if (SUCCEEDED(hr)) 534 { 535 hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font); 536 } 537 538 // Get the font family to which this font belongs. 539 if (SUCCEEDED(hr)) 540 { 541 hr = font->GetFontFamily(&fontFamily); 542 } 543 544 // Get the family names. This returns an object that encapsulates one or 545 // more names with the same meaning but in different languages. 546 if (SUCCEEDED(hr)) 547 { 548 hr = fontFamily->GetFamilyNames(&localizedFamilyNames); 549 } 550 551 // Get the family name at index zero. If we were going to display the name 552 // we'd want to try to find one that matched the use locale, but for 553 // purposes of creating a text format object any language will do. 554 555 wchar_t familyName[100]; 556 if (SUCCEEDED(hr)) 557 { 558 hr = localizedFamilyNames->GetString(0, familyName, 559 ARRAYSIZE(familyName)); 560 } 561 562 if (SUCCEEDED(hr)) 563 { 564 // If no font size was passed in use the lfHeight of the LOGFONT. 565 if (fontSize == 0) 566 { 567 // Convert from pixels to DIPs. 568 fontSize = PixelsToDipsY(logFont.lfHeight); 569 if (fontSize < 0) 570 { 571 // Negative lfHeight represents the size of the em unit. 572 fontSize = -fontSize; 573 } 574 else 575 { 576 // Positive lfHeight represents the cell height (ascent + 577 // descent). 578 DWRITE_FONT_METRICS fontMetrics; 579 font->GetMetrics(&fontMetrics); 580 581 // Convert the cell height (ascent + descent) from design units 582 // to ems. 583 float cellHeight = static_cast<float>( 584 fontMetrics.ascent + fontMetrics.descent) 585 / fontMetrics.designUnitsPerEm; 586 587 // Divide the font size by the cell height to get the font em 588 // size. 589 fontSize /= cellHeight; 590 } 591 } 592 } 593 594 // The text format includes a locale name. Ideally, this would be the 595 // language of the text, which may or may not be the same as the primary 596 // language of the user. However, for our purposes the user locale will do. 597 wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; 598 if (SUCCEEDED(hr)) 599 { 600 if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0) 601 hr = HRESULT_FROM_WIN32(GetLastError()); 602 } 603 604 if (SUCCEEDED(hr)) 605 { 606 // Create the text format object. 607 hr = mDWriteFactory->CreateTextFormat( 608 familyName, 609 NULL, // no custom font collection 610 font->GetWeight(), 611 font->GetStyle(), 612 font->GetStretch(), 613 fontSize, 614 localeName, 615 &mTextFormat); 616 } 617 618 if (SUCCEEDED(hr)) 619 { 620 mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight); 621 mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC 622 : DWRITE_FONT_STYLE_NORMAL; 623 } 624 625 SafeRelease(&localizedFamilyNames); 626 SafeRelease(&fontFamily); 627 SafeRelease(&font); 628 629 return hr; 630 } 631 632 void 633 DWriteContext::SetFont(HFONT hFont) 634 { 635 if (mLastHFont != hFont) 636 { 637 LOGFONTW lf; 638 if (GetObjectW(hFont, sizeof(lf), &lf)) 639 { 640 SetFont(lf); 641 mLastHFont = hFont; 642 } 643 } 644 } 645 646 void 647 DWriteContext::SetFont(const LOGFONTW &logFont) 648 { 649 SafeRelease(&mTextFormat); 650 mLastHFont = NULL; 651 652 HRESULT hr = SetLOGFONT(logFont, 0.f); 653 654 if (SUCCEEDED(hr)) 655 hr = mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); 656 657 if (SUCCEEDED(hr)) 658 hr = mTextFormat->SetParagraphAlignment( 659 DWRITE_PARAGRAPH_ALIGNMENT_CENTER); 660 661 if (SUCCEEDED(hr)) 662 hr = mTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); 663 } 664 665 void 666 DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len, 667 int x, int y, int w, int h, int cellWidth, COLORREF color) 668 { 669 HRESULT hr = S_OK; 670 IDWriteBitmapRenderTarget *bmpRT = NULL; 671 672 // Skip when any fonts are not set. 673 if (mTextFormat == NULL) 674 return; 675 676 // Check possibility of zero divided error. 677 if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f) 678 return; 679 680 if (SUCCEEDED(hr)) 681 hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT); 682 683 if (SUCCEEDED(hr)) 684 { 685 IDWriteTextLayout *textLayout = NULL; 686 687 HDC memdc = bmpRT->GetMemoryDC(); 688 BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY); 689 690 hr = mDWriteFactory->CreateGdiCompatibleTextLayout( 691 text, len, mTextFormat, PixelsToDipsX(w), 692 PixelsToDipsY(h), mDpiScaleX, NULL, TRUE, &textLayout); 693 694 if (SUCCEEDED(hr)) 695 { 696 DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len }; 697 textLayout->SetFontWeight(mFontWeight, textRange); 698 textLayout->SetFontStyle(mFontStyle, textRange); 699 } 700 701 if (SUCCEEDED(hr)) 702 { 703 GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT, 704 mRenderingParams); 705 GdiTextRendererContext data = { 706 color, 707 PixelsToDipsX(cellWidth), 708 0.0f 709 }; 710 textLayout->Draw(&data, renderer, 0, 0); 711 SafeRelease(&renderer); 712 } 713 714 BitBlt(hdc, x, y, w, h, memdc, 0, 0, SRCCOPY); 715 716 SafeRelease(&textLayout); 717 } 718 719 SafeRelease(&bmpRT); 720 } 721 722 float 723 DWriteContext::PixelsToDipsX(int x) 724 { 725 return x / mDpiScaleX; 726 } 727 728 float 729 DWriteContext::PixelsToDipsY(int y) 730 { 731 return y / mDpiScaleY; 732 } 733 734 void 735 DWriteContext::SetRenderingParams( 736 const DWriteRenderingParams *params) 737 { 738 if (mDWriteFactory == NULL) 739 return; 740 741 IDWriteRenderingParams *renderingParams = NULL; 742 D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode = 743 D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; 744 HRESULT hr; 745 if (params != NULL) 746 { 747 hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma, 748 params->enhancedContrast, params->clearTypeLevel, 749 ToPixelGeometry(params->pixelGeometry), 750 ToRenderingMode(params->renderingMode), &renderingParams); 751 textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode); 752 } 753 else 754 hr = mDWriteFactory->CreateRenderingParams(&renderingParams); 755 if (SUCCEEDED(hr) && renderingParams != NULL) 756 { 757 SafeRelease(&mRenderingParams); 758 mRenderingParams = renderingParams; 759 mTextAntialiasMode = textAntialiasMode; 760 } 761 } 762 763 DWriteRenderingParams * 764 DWriteContext::GetRenderingParams( 765 DWriteRenderingParams *params) 766 { 767 if (params != NULL && mRenderingParams != NULL) 768 { 769 params->gamma = mRenderingParams->GetGamma(); 770 params->enhancedContrast = mRenderingParams->GetEnhancedContrast(); 771 params->clearTypeLevel = mRenderingParams->GetClearTypeLevel(); 772 params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry()); 773 params->renderingMode = ToInt(mRenderingParams->GetRenderingMode()); 774 params->textAntialiasMode = mTextAntialiasMode; 775 } 776 return params; 777 } 778 779 //////////////////////////////////////////////////////////////////////////// 780 // PUBLIC C INTERFACES 781 782 void 783 DWrite_Init(void) 784 { 785 #ifdef DYNAMIC_DIRECTX 786 // Load libraries. 787 hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll")); 788 hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll")); 789 if (hD2D1DLL == NULL || hDWriteDLL == NULL) 790 { 791 DWrite_Final(); 792 return; 793 } 794 // Get address of procedures. 795 pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress( 796 GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName"); 797 pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL, 798 "D2D1CreateFactory"); 799 pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL, 800 "DWriteCreateFactory"); 801 #endif 802 } 803 804 void 805 DWrite_Final(void) 806 { 807 #ifdef DYNAMIC_DIRECTX 808 pGetUserDefaultLocaleName = NULL; 809 pD2D1CreateFactory = NULL; 810 pDWriteCreateFactory = NULL; 811 unload(hDWriteDLL); 812 unload(hD2D1DLL); 813 #endif 814 } 815 816 DWriteContext * 817 DWriteContext_Open(void) 818 { 819 #ifdef DYNAMIC_DIRECTX 820 if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL 821 || pDWriteCreateFactory == NULL) 822 return NULL; 823 #endif 824 return new DWriteContext(); 825 } 826 827 void 828 DWriteContext_BeginDraw(DWriteContext *ctx) 829 { 830 if (ctx != NULL && ctx->mRT != NULL) 831 { 832 ctx->mRT->BeginDraw(); 833 ctx->mRT->SetTransform(D2D1::IdentityMatrix()); 834 ctx->mDrawing = true; 835 } 836 } 837 838 void 839 DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect) 840 { 841 if (ctx != NULL && ctx->mRT != NULL) 842 { 843 ctx->mRT->BindDC(hdc, rect); 844 ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode); 845 } 846 } 847 848 void 849 DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont) 850 { 851 if (ctx != NULL) 852 { 853 ctx->SetFont(hFont); 854 } 855 } 856 857 void 858 DWriteContext_DrawText( 859 DWriteContext *ctx, 860 HDC hdc, 861 const WCHAR* text, 862 int len, 863 int x, 864 int y, 865 int w, 866 int h, 867 int cellWidth, 868 COLORREF color) 869 { 870 if (ctx != NULL) 871 ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color); 872 } 873 874 void 875 DWriteContext_EndDraw(DWriteContext *ctx) 876 { 877 if (ctx != NULL && ctx->mRT != NULL) 878 { 879 ctx->mRT->EndDraw(); 880 ctx->mDrawing = false; 881 } 882 } 883 884 void 885 DWriteContext_Close(DWriteContext *ctx) 886 { 887 delete ctx; 888 } 889 890 void 891 DWriteContext_SetRenderingParams( 892 DWriteContext *ctx, 893 const DWriteRenderingParams *params) 894 { 895 if (ctx != NULL) 896 ctx->SetRenderingParams(params); 897 } 898 899 DWriteRenderingParams * 900 DWriteContext_GetRenderingParams( 901 DWriteContext *ctx, 902 DWriteRenderingParams *params) 903 { 904 if (ctx != NULL) 905 return ctx->GetRenderingParams(params); 906 else 907 return NULL; 908 } 909