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