blob: 08b81c44701a6c1b044dffabb275b9b17573a674 [file] [log] [blame]
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001/* vi:set ts=8 sts=4 sw=4 noet: */
2/*
3 * Author: MURAOKA Taro <koron.kaoriya@gmail.com>
4 *
5 * Contributors:
6 * - Ken Takata
7 *
8 * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
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
37extern "C" HINSTANCE vimLoadLib(char *name);
38
39typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
40typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
41 REFIID, const D2D1_FACTORY_OPTIONS *, void **);
42typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
43 REFIID, IUnknown **);
44
45static HINSTANCE hD2D1DLL = NULL;
46static HINSTANCE hDWriteDLL = NULL;
47
48static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
49static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
50static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
51
52#define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName)
53#define D2D1CreateFactory (*pD2D1CreateFactory)
54#define DWriteCreateFactory (*pDWriteCreateFactory)
55
56 static void
57unload(HINSTANCE &hinst)
58{
59 if (hinst != NULL)
60 {
61 FreeLibrary(hinst);
62 hinst = NULL;
63 }
64}
65#endif // DYNAMIC_DIRECTX
66
67template <class T> inline void SafeRelease(T **ppT)
68{
69 if (*ppT)
70 {
71 (*ppT)->Release();
72 *ppT = NULL;
73 }
74}
75
76struct 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
87ToPixelGeometry(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
102ToInt(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
118ToRenderingMode(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
141ToTextAntialiasMode(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
158ToInt(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
181class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
182{
183private:
184 FLOAT mDelta;
185 FLOAT *mAdjustedAdvances;
186
187public:
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
225class GdiTextRenderer : public IDWriteTextRenderer
226{
227public:
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
336public:
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
379private:
Bram Moolenaar0106b4b2014-08-07 13:55:10 +0200380 long cRefCount_;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200381 IDWriteBitmapRenderTarget* pRenderTarget_;
382 IDWriteRenderingParams* pRenderingParams_;
383};
384
385struct 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
432DWriteContext::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
505DWriteContext::~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
517DWriteContext::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
626DWriteContext::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
640DWriteContext::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
659DWriteContext::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 {
Bram Moolenaar5fa4d442016-01-10 13:25:55 +0100689 DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len };
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200690 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
716DWriteContext::PixelsToDipsX(int x)
717{
718 return x / mDpiScaleX;
719}
720
721 float
722DWriteContext::PixelsToDipsY(int y)
723{
724 return y / mDpiScaleY;
725}
726
727 void
728DWriteContext::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 *
757DWriteContext::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
776DWrite_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
798DWrite_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 *
810DWriteContext_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
821DWriteContext_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
832DWriteContext_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
842DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
843{
844 if (ctx != NULL)
845 {
846 ctx->SetFont(hFont);
847 }
848}
849
850 void
851DWriteContext_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
868DWriteContext_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
878DWriteContext_Close(DWriteContext *ctx)
879{
880 delete ctx;
881}
882
883 void
884DWriteContext_SetRenderingParams(
885 DWriteContext *ctx,
886 const DWriteRenderingParams *params)
887{
888 if (ctx != NULL)
889 ctx->SetRenderingParams(params);
890}
891
892 DWriteRenderingParams *
893DWriteContext_GetRenderingParams(
894 DWriteContext *ctx,
895 DWriteRenderingParams *params)
896{
897 if (ctx != NULL)
898 return ctx->GetRenderingParams(params);
899 else
900 return NULL;
901}