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