xref: /vim-8.2.3635/src/gui_dwrite.cpp (revision d7ccc4d8)
1b5a7a8b5SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet: */
2b5a7a8b5SBram Moolenaar /*
3b5a7a8b5SBram Moolenaar  * Author: MURAOKA Taro <[email protected]>
4b5a7a8b5SBram Moolenaar  *
5b5a7a8b5SBram Moolenaar  * Contributors:
6b5a7a8b5SBram Moolenaar  *  - Ken Takata
7*d7ccc4d8SBram Moolenaar  *  - Yasuhiro Matsumoto
8b5a7a8b5SBram Moolenaar  *
9b5a7a8b5SBram Moolenaar  * Copyright (C) 2013 MURAOKA Taro <[email protected]>
10b5a7a8b5SBram Moolenaar  * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
11b5a7a8b5SBram Moolenaar  */
12b5a7a8b5SBram Moolenaar 
13b5a7a8b5SBram Moolenaar #define WIN32_LEAN_AND_MEAN
14b5a7a8b5SBram Moolenaar 
15b5a7a8b5SBram Moolenaar #ifndef DYNAMIC_DIRECTX
16b5a7a8b5SBram Moolenaar # if WINVER < 0x0600
17b5a7a8b5SBram Moolenaar #  error WINVER must be 0x0600 or above to use DirectWrite(DirectX)
18b5a7a8b5SBram Moolenaar # endif
19b5a7a8b5SBram Moolenaar #endif
20b5a7a8b5SBram Moolenaar 
21b5a7a8b5SBram Moolenaar #include <windows.h>
22b5a7a8b5SBram Moolenaar #include <crtdbg.h>
23b5a7a8b5SBram Moolenaar #include <assert.h>
24b5a7a8b5SBram Moolenaar #include <math.h>
25b5a7a8b5SBram Moolenaar #include <d2d1.h>
26b5a7a8b5SBram Moolenaar #include <d2d1helper.h>
27*d7ccc4d8SBram Moolenaar 
28*d7ccc4d8SBram Moolenaar // Disable these macros to compile with old VC and newer SDK (V8.1 or later).
29*d7ccc4d8SBram Moolenaar #if defined(_MSC_VER) && (_MSC_VER < 1700)
30*d7ccc4d8SBram Moolenaar # define _COM_Outptr_ __out
31*d7ccc4d8SBram Moolenaar # define _In_reads_(s)
32*d7ccc4d8SBram Moolenaar # define _In_reads_opt_(s)
33*d7ccc4d8SBram Moolenaar # define _Maybenull_
34*d7ccc4d8SBram Moolenaar # define _Out_writes_(s)
35*d7ccc4d8SBram Moolenaar # define _Out_writes_opt_(s)
36*d7ccc4d8SBram Moolenaar # define _Out_writes_to_(x, y)
37*d7ccc4d8SBram Moolenaar # define _Out_writes_to_opt_(x, y)
38*d7ccc4d8SBram Moolenaar # define _Outptr_
39*d7ccc4d8SBram Moolenaar #endif
40*d7ccc4d8SBram Moolenaar 
41*d7ccc4d8SBram Moolenaar #include <dwrite_2.h>
42b5a7a8b5SBram Moolenaar 
43b5a7a8b5SBram Moolenaar #include "gui_dwrite.h"
44b5a7a8b5SBram Moolenaar 
45b5a7a8b5SBram Moolenaar #ifdef __MINGW32__
46b5a7a8b5SBram Moolenaar # define __maybenull	SAL__maybenull
47b5a7a8b5SBram Moolenaar # define __in		SAL__in
48b5a7a8b5SBram Moolenaar # define __out		SAL__out
49b5a7a8b5SBram Moolenaar #endif
50b5a7a8b5SBram Moolenaar 
51cc6cf9b9SBram Moolenaar #if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
52cc6cf9b9SBram Moolenaar # define FINAL final
53cc6cf9b9SBram Moolenaar #else
54cc6cf9b9SBram Moolenaar # define FINAL
55cc6cf9b9SBram Moolenaar #endif
56cc6cf9b9SBram Moolenaar 
57b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
58b5a7a8b5SBram Moolenaar extern "C" HINSTANCE vimLoadLib(char *name);
59b5a7a8b5SBram Moolenaar 
60b5a7a8b5SBram Moolenaar typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
61b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
62b5a7a8b5SBram Moolenaar 	REFIID, const D2D1_FACTORY_OPTIONS *, void **);
63b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
64b5a7a8b5SBram Moolenaar 	REFIID, IUnknown **);
65b5a7a8b5SBram Moolenaar 
66b5a7a8b5SBram Moolenaar static HINSTANCE hD2D1DLL = NULL;
67b5a7a8b5SBram Moolenaar static HINSTANCE hDWriteDLL = NULL;
68b5a7a8b5SBram Moolenaar 
69b5a7a8b5SBram Moolenaar static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
70b5a7a8b5SBram Moolenaar static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
71b5a7a8b5SBram Moolenaar static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
72b5a7a8b5SBram Moolenaar 
73b5a7a8b5SBram Moolenaar #define GetUserDefaultLocaleName	(*pGetUserDefaultLocaleName)
74b5a7a8b5SBram Moolenaar #define D2D1CreateFactory		(*pD2D1CreateFactory)
75b5a7a8b5SBram Moolenaar #define DWriteCreateFactory		(*pDWriteCreateFactory)
76b5a7a8b5SBram Moolenaar 
77b5a7a8b5SBram Moolenaar     static void
78b5a7a8b5SBram Moolenaar unload(HINSTANCE &hinst)
79b5a7a8b5SBram Moolenaar {
80b5a7a8b5SBram Moolenaar     if (hinst != NULL)
81b5a7a8b5SBram Moolenaar     {
82b5a7a8b5SBram Moolenaar 	FreeLibrary(hinst);
83b5a7a8b5SBram Moolenaar 	hinst = NULL;
84b5a7a8b5SBram Moolenaar     }
85b5a7a8b5SBram Moolenaar }
86b5a7a8b5SBram Moolenaar #endif // DYNAMIC_DIRECTX
87b5a7a8b5SBram Moolenaar 
88b5a7a8b5SBram Moolenaar template <class T> inline void SafeRelease(T **ppT)
89b5a7a8b5SBram Moolenaar {
90b5a7a8b5SBram Moolenaar     if (*ppT)
91b5a7a8b5SBram Moolenaar     {
92b5a7a8b5SBram Moolenaar 	(*ppT)->Release();
93b5a7a8b5SBram Moolenaar 	*ppT = NULL;
94b5a7a8b5SBram Moolenaar     }
95b5a7a8b5SBram Moolenaar }
96b5a7a8b5SBram Moolenaar 
97b5a7a8b5SBram Moolenaar     static DWRITE_PIXEL_GEOMETRY
98b5a7a8b5SBram Moolenaar ToPixelGeometry(int value)
99b5a7a8b5SBram Moolenaar {
100b5a7a8b5SBram Moolenaar     switch (value)
101b5a7a8b5SBram Moolenaar     {
102b5a7a8b5SBram Moolenaar 	default:
103b5a7a8b5SBram Moolenaar 	case 0:
104b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_FLAT;
105b5a7a8b5SBram Moolenaar 	case 1:
106b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_RGB;
107b5a7a8b5SBram Moolenaar 	case 2:
108b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_BGR;
109b5a7a8b5SBram Moolenaar     }
110b5a7a8b5SBram Moolenaar }
111b5a7a8b5SBram Moolenaar 
112b5a7a8b5SBram Moolenaar     static int
113b5a7a8b5SBram Moolenaar ToInt(DWRITE_PIXEL_GEOMETRY value)
114b5a7a8b5SBram Moolenaar {
115b5a7a8b5SBram Moolenaar     switch (value)
116b5a7a8b5SBram Moolenaar     {
117b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_FLAT:
118b5a7a8b5SBram Moolenaar 	    return 0;
119b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_RGB:
120b5a7a8b5SBram Moolenaar 	    return 1;
121b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_BGR:
122b5a7a8b5SBram Moolenaar 	    return 2;
123b5a7a8b5SBram Moolenaar 	default:
124b5a7a8b5SBram Moolenaar 	    return -1;
125b5a7a8b5SBram Moolenaar     }
126b5a7a8b5SBram Moolenaar }
127b5a7a8b5SBram Moolenaar 
128b5a7a8b5SBram Moolenaar     static DWRITE_RENDERING_MODE
129b5a7a8b5SBram Moolenaar ToRenderingMode(int value)
130b5a7a8b5SBram Moolenaar {
131b5a7a8b5SBram Moolenaar     switch (value)
132b5a7a8b5SBram Moolenaar     {
133b5a7a8b5SBram Moolenaar 	default:
134b5a7a8b5SBram Moolenaar 	case 0:
135b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_DEFAULT;
136b5a7a8b5SBram Moolenaar 	case 1:
137b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_ALIASED;
138b5a7a8b5SBram Moolenaar 	case 2:
139b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
140b5a7a8b5SBram Moolenaar 	case 3:
141b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
142b5a7a8b5SBram Moolenaar 	case 4:
143b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
144b5a7a8b5SBram Moolenaar 	case 5:
145b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
146b5a7a8b5SBram Moolenaar 	case 6:
147b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_OUTLINE;
148b5a7a8b5SBram Moolenaar     }
149b5a7a8b5SBram Moolenaar }
150b5a7a8b5SBram Moolenaar 
151b5a7a8b5SBram Moolenaar     static D2D1_TEXT_ANTIALIAS_MODE
152b5a7a8b5SBram Moolenaar ToTextAntialiasMode(int value)
153b5a7a8b5SBram Moolenaar {
154b5a7a8b5SBram Moolenaar     switch (value)
155b5a7a8b5SBram Moolenaar     {
156b5a7a8b5SBram Moolenaar 	default:
157b5a7a8b5SBram Moolenaar 	case 0:
158b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
159b5a7a8b5SBram Moolenaar 	case 1:
160b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
161b5a7a8b5SBram Moolenaar 	case 2:
162b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
163b5a7a8b5SBram Moolenaar 	case 3:
164b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
165b5a7a8b5SBram Moolenaar     }
166b5a7a8b5SBram Moolenaar }
167b5a7a8b5SBram Moolenaar 
168b5a7a8b5SBram Moolenaar     static int
169b5a7a8b5SBram Moolenaar ToInt(DWRITE_RENDERING_MODE value)
170b5a7a8b5SBram Moolenaar {
171b5a7a8b5SBram Moolenaar     switch (value)
172b5a7a8b5SBram Moolenaar     {
173b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_DEFAULT:
174b5a7a8b5SBram Moolenaar 	    return 0;
175b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_ALIASED:
176b5a7a8b5SBram Moolenaar 	    return 1;
177b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
178b5a7a8b5SBram Moolenaar 	    return 2;
179b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
180b5a7a8b5SBram Moolenaar 	    return 3;
181b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
182b5a7a8b5SBram Moolenaar 	    return 4;
183b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
184b5a7a8b5SBram Moolenaar 	    return 5;
185b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_OUTLINE:
186b5a7a8b5SBram Moolenaar 	    return 6;
187b5a7a8b5SBram Moolenaar 	default:
188b5a7a8b5SBram Moolenaar 	    return -1;
189b5a7a8b5SBram Moolenaar     }
190b5a7a8b5SBram Moolenaar }
191b5a7a8b5SBram Moolenaar 
192*d7ccc4d8SBram Moolenaar class FontCache {
193*d7ccc4d8SBram Moolenaar public:
194*d7ccc4d8SBram Moolenaar     struct Item {
195*d7ccc4d8SBram Moolenaar 	HFONT              hFont;
196*d7ccc4d8SBram Moolenaar 	IDWriteTextFormat* pTextFormat;
197*d7ccc4d8SBram Moolenaar 	DWRITE_FONT_WEIGHT fontWeight;
198*d7ccc4d8SBram Moolenaar 	DWRITE_FONT_STYLE  fontStyle;
199*d7ccc4d8SBram Moolenaar 	Item() : hFont(NULL), pTextFormat(NULL) {}
200*d7ccc4d8SBram Moolenaar     };
201*d7ccc4d8SBram Moolenaar 
202*d7ccc4d8SBram Moolenaar private:
203*d7ccc4d8SBram Moolenaar     int mSize;
204*d7ccc4d8SBram Moolenaar     Item *mItems;
205*d7ccc4d8SBram Moolenaar 
206*d7ccc4d8SBram Moolenaar public:
207*d7ccc4d8SBram Moolenaar     FontCache(int size = 2) :
208*d7ccc4d8SBram Moolenaar 	mSize(size),
209*d7ccc4d8SBram Moolenaar 	mItems(new Item[size])
210*d7ccc4d8SBram Moolenaar     {
211*d7ccc4d8SBram Moolenaar     }
212*d7ccc4d8SBram Moolenaar 
213*d7ccc4d8SBram Moolenaar     ~FontCache()
214*d7ccc4d8SBram Moolenaar     {
215*d7ccc4d8SBram Moolenaar 	for (int i = 0; i < mSize; ++i)
216*d7ccc4d8SBram Moolenaar 	    SafeRelease(&mItems[i].pTextFormat);
217*d7ccc4d8SBram Moolenaar 	delete[] mItems;
218*d7ccc4d8SBram Moolenaar     }
219*d7ccc4d8SBram Moolenaar 
220*d7ccc4d8SBram Moolenaar     bool get(HFONT hFont, Item &item)
221*d7ccc4d8SBram Moolenaar     {
222*d7ccc4d8SBram Moolenaar 	int n = find(hFont);
223*d7ccc4d8SBram Moolenaar 	if (n < 0)
224*d7ccc4d8SBram Moolenaar 	    return false;
225*d7ccc4d8SBram Moolenaar 	item = mItems[n];
226*d7ccc4d8SBram Moolenaar 	slide(n);
227*d7ccc4d8SBram Moolenaar 	return true;
228*d7ccc4d8SBram Moolenaar     }
229*d7ccc4d8SBram Moolenaar 
230*d7ccc4d8SBram Moolenaar     void put(const Item& item)
231*d7ccc4d8SBram Moolenaar     {
232*d7ccc4d8SBram Moolenaar 	int n = find(item.hFont);
233*d7ccc4d8SBram Moolenaar 	if (n < 0)
234*d7ccc4d8SBram Moolenaar 	    n = mSize - 1;
235*d7ccc4d8SBram Moolenaar 	if (mItems[n].pTextFormat != item.pTextFormat)
236*d7ccc4d8SBram Moolenaar 	{
237*d7ccc4d8SBram Moolenaar 	    SafeRelease(&mItems[n].pTextFormat);
238*d7ccc4d8SBram Moolenaar 	    item.pTextFormat->AddRef();
239*d7ccc4d8SBram Moolenaar 	}
240*d7ccc4d8SBram Moolenaar 	mItems[n] = item;
241*d7ccc4d8SBram Moolenaar 	slide(n);
242*d7ccc4d8SBram Moolenaar     }
243*d7ccc4d8SBram Moolenaar 
244*d7ccc4d8SBram Moolenaar private:
245*d7ccc4d8SBram Moolenaar     int find(HFONT hFont)
246*d7ccc4d8SBram Moolenaar     {
247*d7ccc4d8SBram Moolenaar 	for (int i = 0; i < mSize; ++i)
248*d7ccc4d8SBram Moolenaar 	{
249*d7ccc4d8SBram Moolenaar 	    if (mItems[i].hFont == hFont)
250*d7ccc4d8SBram Moolenaar 		return i;
251*d7ccc4d8SBram Moolenaar 	}
252*d7ccc4d8SBram Moolenaar 	return -1;
253*d7ccc4d8SBram Moolenaar     }
254*d7ccc4d8SBram Moolenaar 
255*d7ccc4d8SBram Moolenaar     void slide(int nextTop)
256*d7ccc4d8SBram Moolenaar     {
257*d7ccc4d8SBram Moolenaar 	if (nextTop == 0)
258*d7ccc4d8SBram Moolenaar 	    return;
259*d7ccc4d8SBram Moolenaar 	Item tmp = mItems[nextTop];
260*d7ccc4d8SBram Moolenaar 	for (int i = nextTop - 1; i >= 0; --i)
261*d7ccc4d8SBram Moolenaar 	    mItems[i + 1] = mItems[i];
262*d7ccc4d8SBram Moolenaar 	mItems[0] = tmp;
263*d7ccc4d8SBram Moolenaar     }
264*d7ccc4d8SBram Moolenaar };
265*d7ccc4d8SBram Moolenaar 
266*d7ccc4d8SBram Moolenaar struct DWriteContext {
267*d7ccc4d8SBram Moolenaar     HDC mHDC;
268*d7ccc4d8SBram Moolenaar     bool mDrawing;
269*d7ccc4d8SBram Moolenaar     bool mFallbackDC;
270*d7ccc4d8SBram Moolenaar 
271*d7ccc4d8SBram Moolenaar     ID2D1Factory *mD2D1Factory;
272*d7ccc4d8SBram Moolenaar 
273*d7ccc4d8SBram Moolenaar     ID2D1DCRenderTarget *mRT;
274*d7ccc4d8SBram Moolenaar     ID2D1SolidColorBrush *mBrush;
275*d7ccc4d8SBram Moolenaar 
276*d7ccc4d8SBram Moolenaar     IDWriteFactory *mDWriteFactory;
277*d7ccc4d8SBram Moolenaar     IDWriteFactory2 *mDWriteFactory2;
278*d7ccc4d8SBram Moolenaar 
279*d7ccc4d8SBram Moolenaar     IDWriteGdiInterop *mGdiInterop;
280*d7ccc4d8SBram Moolenaar     IDWriteRenderingParams *mRenderingParams;
281*d7ccc4d8SBram Moolenaar 
282*d7ccc4d8SBram Moolenaar     FontCache mFontCache;
283*d7ccc4d8SBram Moolenaar     IDWriteTextFormat *mTextFormat;
284*d7ccc4d8SBram Moolenaar     DWRITE_FONT_WEIGHT mFontWeight;
285*d7ccc4d8SBram Moolenaar     DWRITE_FONT_STYLE mFontStyle;
286*d7ccc4d8SBram Moolenaar 
287*d7ccc4d8SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
288*d7ccc4d8SBram Moolenaar 
289*d7ccc4d8SBram Moolenaar     // METHODS
290*d7ccc4d8SBram Moolenaar 
291*d7ccc4d8SBram Moolenaar     DWriteContext();
292*d7ccc4d8SBram Moolenaar 
293*d7ccc4d8SBram Moolenaar     virtual ~DWriteContext();
294*d7ccc4d8SBram Moolenaar 
295*d7ccc4d8SBram Moolenaar     HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
296*d7ccc4d8SBram Moolenaar 	    IDWriteTextFormat **ppTextFormat);
297*d7ccc4d8SBram Moolenaar 
298*d7ccc4d8SBram Moolenaar     HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
299*d7ccc4d8SBram Moolenaar 
300*d7ccc4d8SBram Moolenaar     void SetFont(HFONT hFont);
301*d7ccc4d8SBram Moolenaar 
302*d7ccc4d8SBram Moolenaar     void BindDC(HDC hdc, RECT *rect);
303*d7ccc4d8SBram Moolenaar 
304*d7ccc4d8SBram Moolenaar     void AssureDrawing();
305*d7ccc4d8SBram Moolenaar 
306*d7ccc4d8SBram Moolenaar     ID2D1Brush* SolidBrush(COLORREF color);
307*d7ccc4d8SBram Moolenaar 
308*d7ccc4d8SBram Moolenaar     void DrawText(const WCHAR* text, int len,
309*d7ccc4d8SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color,
310*d7ccc4d8SBram Moolenaar 	UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx);
311*d7ccc4d8SBram Moolenaar 
312*d7ccc4d8SBram Moolenaar     void FillRect(RECT *rc, COLORREF color);
313*d7ccc4d8SBram Moolenaar 
314*d7ccc4d8SBram Moolenaar     void Flush();
315*d7ccc4d8SBram Moolenaar 
316*d7ccc4d8SBram Moolenaar     void SetRenderingParams(
317*d7ccc4d8SBram Moolenaar 	    const DWriteRenderingParams *params);
318*d7ccc4d8SBram Moolenaar 
319*d7ccc4d8SBram Moolenaar     DWriteRenderingParams *GetRenderingParams(
320*d7ccc4d8SBram Moolenaar 	    DWriteRenderingParams *params);
321*d7ccc4d8SBram Moolenaar };
322*d7ccc4d8SBram Moolenaar 
323b5a7a8b5SBram Moolenaar class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
324b5a7a8b5SBram Moolenaar {
325b5a7a8b5SBram Moolenaar private:
326*d7ccc4d8SBram Moolenaar     FLOAT &mAccum;
327b5a7a8b5SBram Moolenaar     FLOAT mDelta;
328b5a7a8b5SBram Moolenaar     FLOAT *mAdjustedAdvances;
329b5a7a8b5SBram Moolenaar 
330b5a7a8b5SBram Moolenaar public:
331b5a7a8b5SBram Moolenaar     AdjustedGlyphRun(
332b5a7a8b5SBram Moolenaar 	    const DWRITE_GLYPH_RUN *glyphRun,
333*d7ccc4d8SBram Moolenaar 	    FLOAT cellWidth,
334*d7ccc4d8SBram Moolenaar 	    FLOAT &accum) :
335b5a7a8b5SBram Moolenaar 	DWRITE_GLYPH_RUN(*glyphRun),
336*d7ccc4d8SBram Moolenaar 	mAccum(accum),
337b5a7a8b5SBram Moolenaar 	mDelta(0.0f),
338b5a7a8b5SBram Moolenaar 	mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
339b5a7a8b5SBram Moolenaar     {
340b5a7a8b5SBram Moolenaar 	assert(cellWidth != 0.0f);
341b5a7a8b5SBram Moolenaar 	for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
342b5a7a8b5SBram Moolenaar 	{
343b5a7a8b5SBram Moolenaar 	    FLOAT orig = glyphRun->glyphAdvances[i];
344b5a7a8b5SBram Moolenaar 	    FLOAT adjusted = adjustToCell(orig, cellWidth);
345b5a7a8b5SBram Moolenaar 	    mAdjustedAdvances[i] = adjusted;
346b5a7a8b5SBram Moolenaar 	    mDelta += adjusted - orig;
347b5a7a8b5SBram Moolenaar 	}
348b5a7a8b5SBram Moolenaar 	glyphAdvances = mAdjustedAdvances;
349b5a7a8b5SBram Moolenaar     }
350b5a7a8b5SBram Moolenaar 
351*d7ccc4d8SBram Moolenaar     ~AdjustedGlyphRun()
352b5a7a8b5SBram Moolenaar     {
353*d7ccc4d8SBram Moolenaar 	mAccum += mDelta;
354b5a7a8b5SBram Moolenaar 	delete[] mAdjustedAdvances;
355b5a7a8b5SBram Moolenaar     }
356b5a7a8b5SBram Moolenaar 
357b5a7a8b5SBram Moolenaar     static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
358b5a7a8b5SBram Moolenaar     {
359*d7ccc4d8SBram Moolenaar 	int cellCount = int(floor(value / cellWidth + 0.5f));
360b5a7a8b5SBram Moolenaar 	if (cellCount < 1)
361b5a7a8b5SBram Moolenaar 	    cellCount = 1;
362b5a7a8b5SBram Moolenaar 	return cellCount * cellWidth;
363b5a7a8b5SBram Moolenaar     }
364b5a7a8b5SBram Moolenaar };
365b5a7a8b5SBram Moolenaar 
366*d7ccc4d8SBram Moolenaar struct TextRendererContext {
367*d7ccc4d8SBram Moolenaar     // const fields.
368*d7ccc4d8SBram Moolenaar     COLORREF color;
369*d7ccc4d8SBram Moolenaar     FLOAT cellWidth;
370*d7ccc4d8SBram Moolenaar 
371*d7ccc4d8SBram Moolenaar     // working fields.
372*d7ccc4d8SBram Moolenaar     FLOAT offsetX;
373*d7ccc4d8SBram Moolenaar };
374*d7ccc4d8SBram Moolenaar 
375*d7ccc4d8SBram Moolenaar class TextRenderer FINAL : public IDWriteTextRenderer
376b5a7a8b5SBram Moolenaar {
377b5a7a8b5SBram Moolenaar public:
378*d7ccc4d8SBram Moolenaar     TextRenderer(
379*d7ccc4d8SBram Moolenaar 	    DWriteContext* pDWC) :
380b5a7a8b5SBram Moolenaar 	cRefCount_(0),
381*d7ccc4d8SBram Moolenaar 	pDWC_(pDWC)
382b5a7a8b5SBram Moolenaar     {
383b5a7a8b5SBram Moolenaar 	AddRef();
384b5a7a8b5SBram Moolenaar     }
385b5a7a8b5SBram Moolenaar 
386edb4f2b3SBram Moolenaar     // add "virtual" to avoid a compiler warning
387*d7ccc4d8SBram Moolenaar     virtual ~TextRenderer()
388b5a7a8b5SBram Moolenaar     {
389b5a7a8b5SBram Moolenaar     }
390b5a7a8b5SBram Moolenaar 
391b5a7a8b5SBram Moolenaar     IFACEMETHOD(IsPixelSnappingDisabled)(
392b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
393b5a7a8b5SBram Moolenaar 	__out BOOL* isDisabled)
394b5a7a8b5SBram Moolenaar     {
395b5a7a8b5SBram Moolenaar 	*isDisabled = FALSE;
396b5a7a8b5SBram Moolenaar 	return S_OK;
397b5a7a8b5SBram Moolenaar     }
398b5a7a8b5SBram Moolenaar 
399b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetCurrentTransform)(
400b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
401b5a7a8b5SBram Moolenaar 	__out DWRITE_MATRIX* transform)
402b5a7a8b5SBram Moolenaar     {
403b5a7a8b5SBram Moolenaar 	// forward the render target's transform
404*d7ccc4d8SBram Moolenaar 	pDWC_->mRT->GetTransform(
405*d7ccc4d8SBram Moolenaar 		reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
406b5a7a8b5SBram Moolenaar 	return S_OK;
407b5a7a8b5SBram Moolenaar     }
408b5a7a8b5SBram Moolenaar 
409b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetPixelsPerDip)(
410b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
411b5a7a8b5SBram Moolenaar 	__out FLOAT* pixelsPerDip)
412b5a7a8b5SBram Moolenaar     {
413*d7ccc4d8SBram Moolenaar 	float dpiX, unused;
414*d7ccc4d8SBram Moolenaar 	pDWC_->mRT->GetDpi(&dpiX, &unused);
415*d7ccc4d8SBram Moolenaar 	*pixelsPerDip = dpiX / 96.0f;
416b5a7a8b5SBram Moolenaar 	return S_OK;
417b5a7a8b5SBram Moolenaar     }
418b5a7a8b5SBram Moolenaar 
419b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawUnderline)(
420b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
421b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
422b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
423b5a7a8b5SBram Moolenaar 	__in DWRITE_UNDERLINE const* underline,
424b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
425b5a7a8b5SBram Moolenaar     {
426b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
427b5a7a8b5SBram Moolenaar     }
428b5a7a8b5SBram Moolenaar 
429b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawStrikethrough)(
430b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
431b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
432b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
433b5a7a8b5SBram Moolenaar 	__in DWRITE_STRIKETHROUGH const* strikethrough,
434b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
435b5a7a8b5SBram Moolenaar     {
436b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
437b5a7a8b5SBram Moolenaar     }
438b5a7a8b5SBram Moolenaar 
439b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawInlineObject)(
440b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
441b5a7a8b5SBram Moolenaar 	FLOAT originX,
442b5a7a8b5SBram Moolenaar 	FLOAT originY,
443b5a7a8b5SBram Moolenaar 	IDWriteInlineObject* inlineObject,
444b5a7a8b5SBram Moolenaar 	BOOL isSideways,
445b5a7a8b5SBram Moolenaar 	BOOL isRightToLeft,
446b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
447b5a7a8b5SBram Moolenaar     {
448b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
449b5a7a8b5SBram Moolenaar     }
450b5a7a8b5SBram Moolenaar 
451*d7ccc4d8SBram Moolenaar     IFACEMETHOD(DrawGlyphRun)(
452*d7ccc4d8SBram Moolenaar 	__maybenull void* clientDrawingContext,
453*d7ccc4d8SBram Moolenaar 	FLOAT baselineOriginX,
454*d7ccc4d8SBram Moolenaar 	FLOAT baselineOriginY,
455*d7ccc4d8SBram Moolenaar 	DWRITE_MEASURING_MODE measuringMode,
456*d7ccc4d8SBram Moolenaar 	__in DWRITE_GLYPH_RUN const* glyphRun,
457*d7ccc4d8SBram Moolenaar 	__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
458*d7ccc4d8SBram Moolenaar 	IUnknown* clientDrawingEffect)
459*d7ccc4d8SBram Moolenaar     {
460*d7ccc4d8SBram Moolenaar 	TextRendererContext *context =
461*d7ccc4d8SBram Moolenaar 	    reinterpret_cast<TextRendererContext*>(clientDrawingContext);
462*d7ccc4d8SBram Moolenaar 
463*d7ccc4d8SBram Moolenaar 	AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
464*d7ccc4d8SBram Moolenaar 		context->offsetX);
465*d7ccc4d8SBram Moolenaar 
466*d7ccc4d8SBram Moolenaar 	if (pDWC_->mDWriteFactory2 != NULL)
467*d7ccc4d8SBram Moolenaar 	{
468*d7ccc4d8SBram Moolenaar 	    IDWriteColorGlyphRunEnumerator *enumerator = NULL;
469*d7ccc4d8SBram Moolenaar 	    HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
470*d7ccc4d8SBram Moolenaar 		baselineOriginX + context->offsetX,
471*d7ccc4d8SBram Moolenaar 		baselineOriginY,
472*d7ccc4d8SBram Moolenaar 		&adjustedGlyphRun,
473*d7ccc4d8SBram Moolenaar 		NULL,
474*d7ccc4d8SBram Moolenaar 		DWRITE_MEASURING_MODE_GDI_NATURAL,
475*d7ccc4d8SBram Moolenaar 		NULL,
476*d7ccc4d8SBram Moolenaar 		0,
477*d7ccc4d8SBram Moolenaar 		&enumerator);
478*d7ccc4d8SBram Moolenaar 	    if (SUCCEEDED(hr))
479*d7ccc4d8SBram Moolenaar 	    {
480*d7ccc4d8SBram Moolenaar 		// Draw by IDWriteFactory2 for color emoji
481*d7ccc4d8SBram Moolenaar 		BOOL hasRun = TRUE;
482*d7ccc4d8SBram Moolenaar 		enumerator->MoveNext(&hasRun);
483*d7ccc4d8SBram Moolenaar 		while (hasRun)
484*d7ccc4d8SBram Moolenaar 		{
485*d7ccc4d8SBram Moolenaar 		    const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
486*d7ccc4d8SBram Moolenaar 		    enumerator->GetCurrentRun(&colorGlyphRun);
487*d7ccc4d8SBram Moolenaar 
488*d7ccc4d8SBram Moolenaar 		    pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
489*d7ccc4d8SBram Moolenaar 		    pDWC_->mRT->DrawGlyphRun(
490*d7ccc4d8SBram Moolenaar 			    D2D1::Point2F(
491*d7ccc4d8SBram Moolenaar 				colorGlyphRun->baselineOriginX,
492*d7ccc4d8SBram Moolenaar 				colorGlyphRun->baselineOriginY),
493*d7ccc4d8SBram Moolenaar 			    &colorGlyphRun->glyphRun,
494*d7ccc4d8SBram Moolenaar 			    pDWC_->mBrush,
495*d7ccc4d8SBram Moolenaar 			    DWRITE_MEASURING_MODE_NATURAL);
496*d7ccc4d8SBram Moolenaar 		    enumerator->MoveNext(&hasRun);
497*d7ccc4d8SBram Moolenaar 		}
498*d7ccc4d8SBram Moolenaar 		SafeRelease(&enumerator);
499*d7ccc4d8SBram Moolenaar 		return S_OK;
500*d7ccc4d8SBram Moolenaar 	    }
501*d7ccc4d8SBram Moolenaar 	}
502*d7ccc4d8SBram Moolenaar 
503*d7ccc4d8SBram Moolenaar 	// Draw by IDWriteFactory (without color emoji)
504*d7ccc4d8SBram Moolenaar 	pDWC_->mRT->DrawGlyphRun(
505*d7ccc4d8SBram Moolenaar 		D2D1::Point2F(
506*d7ccc4d8SBram Moolenaar 		    baselineOriginX + context->offsetX,
507*d7ccc4d8SBram Moolenaar 		    baselineOriginY),
508*d7ccc4d8SBram Moolenaar 		&adjustedGlyphRun,
509*d7ccc4d8SBram Moolenaar 		pDWC_->SolidBrush(context->color),
510*d7ccc4d8SBram Moolenaar 		DWRITE_MEASURING_MODE_NATURAL);
511*d7ccc4d8SBram Moolenaar 	return S_OK;
512*d7ccc4d8SBram Moolenaar     }
513*d7ccc4d8SBram Moolenaar 
514b5a7a8b5SBram Moolenaar public:
515b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, AddRef) ()
516b5a7a8b5SBram Moolenaar     {
517b5a7a8b5SBram Moolenaar 	return InterlockedIncrement(&cRefCount_);
518b5a7a8b5SBram Moolenaar     }
519b5a7a8b5SBram Moolenaar 
520b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, Release) ()
521b5a7a8b5SBram Moolenaar     {
522b5a7a8b5SBram Moolenaar 	long newCount = InterlockedDecrement(&cRefCount_);
523b5a7a8b5SBram Moolenaar 
524b5a7a8b5SBram Moolenaar 	if (newCount == 0)
525b5a7a8b5SBram Moolenaar 	{
526b5a7a8b5SBram Moolenaar 	    delete this;
527b5a7a8b5SBram Moolenaar 	    return 0;
528b5a7a8b5SBram Moolenaar 	}
529b5a7a8b5SBram Moolenaar 	return newCount;
530b5a7a8b5SBram Moolenaar     }
531b5a7a8b5SBram Moolenaar 
532b5a7a8b5SBram Moolenaar     IFACEMETHOD(QueryInterface)(
533b5a7a8b5SBram Moolenaar 	IID const& riid,
534b5a7a8b5SBram Moolenaar 	void** ppvObject)
535b5a7a8b5SBram Moolenaar     {
536b5a7a8b5SBram Moolenaar 	if (__uuidof(IDWriteTextRenderer) == riid)
537b5a7a8b5SBram Moolenaar 	{
538b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
539b5a7a8b5SBram Moolenaar 	}
540b5a7a8b5SBram Moolenaar 	else if (__uuidof(IDWritePixelSnapping) == riid)
541b5a7a8b5SBram Moolenaar 	{
542b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
543b5a7a8b5SBram Moolenaar 	}
544b5a7a8b5SBram Moolenaar 	else if (__uuidof(IUnknown) == riid)
545b5a7a8b5SBram Moolenaar 	{
546b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
547b5a7a8b5SBram Moolenaar 	}
548b5a7a8b5SBram Moolenaar 	else
549b5a7a8b5SBram Moolenaar 	{
550b5a7a8b5SBram Moolenaar 	    *ppvObject = NULL;
551b5a7a8b5SBram Moolenaar 	    return E_FAIL;
552b5a7a8b5SBram Moolenaar 	}
553b5a7a8b5SBram Moolenaar 
554b5a7a8b5SBram Moolenaar 	return S_OK;
555b5a7a8b5SBram Moolenaar     }
556b5a7a8b5SBram Moolenaar 
557b5a7a8b5SBram Moolenaar private:
5580106b4b8SBram Moolenaar     long cRefCount_;
559*d7ccc4d8SBram Moolenaar     DWriteContext* pDWC_;
560b5a7a8b5SBram Moolenaar };
561b5a7a8b5SBram Moolenaar 
562b5a7a8b5SBram Moolenaar DWriteContext::DWriteContext() :
563*d7ccc4d8SBram Moolenaar     mHDC(NULL),
564b5a7a8b5SBram Moolenaar     mDrawing(false),
565*d7ccc4d8SBram Moolenaar     mFallbackDC(false),
566b5a7a8b5SBram Moolenaar     mD2D1Factory(NULL),
567b5a7a8b5SBram Moolenaar     mRT(NULL),
568b5a7a8b5SBram Moolenaar     mBrush(NULL),
569b5a7a8b5SBram Moolenaar     mDWriteFactory(NULL),
570*d7ccc4d8SBram Moolenaar     mDWriteFactory2(NULL),
571b5a7a8b5SBram Moolenaar     mGdiInterop(NULL),
572b5a7a8b5SBram Moolenaar     mRenderingParams(NULL),
573*d7ccc4d8SBram Moolenaar     mFontCache(8),
574b5a7a8b5SBram Moolenaar     mTextFormat(NULL),
575b5a7a8b5SBram Moolenaar     mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
576b5a7a8b5SBram Moolenaar     mFontStyle(DWRITE_FONT_STYLE_NORMAL),
577b5a7a8b5SBram Moolenaar     mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
578b5a7a8b5SBram Moolenaar {
579b5a7a8b5SBram Moolenaar     HRESULT hr;
580b5a7a8b5SBram Moolenaar 
581b5a7a8b5SBram Moolenaar     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
582b5a7a8b5SBram Moolenaar 	    __uuidof(ID2D1Factory), NULL,
583b5a7a8b5SBram Moolenaar 	    reinterpret_cast<void**>(&mD2D1Factory));
584b5a7a8b5SBram Moolenaar     _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
585b5a7a8b5SBram Moolenaar 
586b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
587b5a7a8b5SBram Moolenaar     {
588b5a7a8b5SBram Moolenaar 	D2D1_RENDER_TARGET_PROPERTIES props = {
589b5a7a8b5SBram Moolenaar 	    D2D1_RENDER_TARGET_TYPE_DEFAULT,
590b5a7a8b5SBram Moolenaar 	    { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
591b5a7a8b5SBram Moolenaar 	    0, 0,
592b5a7a8b5SBram Moolenaar 	    D2D1_RENDER_TARGET_USAGE_NONE,
593b5a7a8b5SBram Moolenaar 	    D2D1_FEATURE_LEVEL_DEFAULT
594b5a7a8b5SBram Moolenaar 	};
595b5a7a8b5SBram Moolenaar 	hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
596b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
597b5a7a8b5SBram Moolenaar     }
598b5a7a8b5SBram Moolenaar 
599b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
600b5a7a8b5SBram Moolenaar     {
601b5a7a8b5SBram Moolenaar 	hr = mRT->CreateSolidColorBrush(
602b5a7a8b5SBram Moolenaar 		D2D1::ColorF(D2D1::ColorF::Black),
603b5a7a8b5SBram Moolenaar 		&mBrush);
604b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
605b5a7a8b5SBram Moolenaar     }
606b5a7a8b5SBram Moolenaar 
607b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
608b5a7a8b5SBram Moolenaar     {
609b5a7a8b5SBram Moolenaar 	hr = DWriteCreateFactory(
610b5a7a8b5SBram Moolenaar 		DWRITE_FACTORY_TYPE_SHARED,
611b5a7a8b5SBram Moolenaar 		__uuidof(IDWriteFactory),
612b5a7a8b5SBram Moolenaar 		reinterpret_cast<IUnknown**>(&mDWriteFactory));
613b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
614b5a7a8b5SBram Moolenaar 		mDWriteFactory);
615b5a7a8b5SBram Moolenaar     }
616b5a7a8b5SBram Moolenaar 
617b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
618b5a7a8b5SBram Moolenaar     {
619*d7ccc4d8SBram Moolenaar 	DWriteCreateFactory(
620*d7ccc4d8SBram Moolenaar 		DWRITE_FACTORY_TYPE_SHARED,
621*d7ccc4d8SBram Moolenaar 		__uuidof(IDWriteFactory2),
622*d7ccc4d8SBram Moolenaar 		reinterpret_cast<IUnknown**>(&mDWriteFactory2));
623*d7ccc4d8SBram Moolenaar 	_RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
624*d7ccc4d8SBram Moolenaar     }
625*d7ccc4d8SBram Moolenaar 
626*d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
627*d7ccc4d8SBram Moolenaar     {
628b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
629b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
630b5a7a8b5SBram Moolenaar     }
631b5a7a8b5SBram Moolenaar 
632b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
633b5a7a8b5SBram Moolenaar     {
634b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
635b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
636b5a7a8b5SBram Moolenaar 		mRenderingParams);
637b5a7a8b5SBram Moolenaar     }
638b5a7a8b5SBram Moolenaar }
639b5a7a8b5SBram Moolenaar 
640b5a7a8b5SBram Moolenaar DWriteContext::~DWriteContext()
641b5a7a8b5SBram Moolenaar {
642b5a7a8b5SBram Moolenaar     SafeRelease(&mTextFormat);
643b5a7a8b5SBram Moolenaar     SafeRelease(&mRenderingParams);
644b5a7a8b5SBram Moolenaar     SafeRelease(&mGdiInterop);
645b5a7a8b5SBram Moolenaar     SafeRelease(&mDWriteFactory);
646*d7ccc4d8SBram Moolenaar     SafeRelease(&mDWriteFactory2);
647b5a7a8b5SBram Moolenaar     SafeRelease(&mBrush);
648b5a7a8b5SBram Moolenaar     SafeRelease(&mRT);
649b5a7a8b5SBram Moolenaar     SafeRelease(&mD2D1Factory);
650b5a7a8b5SBram Moolenaar }
651b5a7a8b5SBram Moolenaar 
652b5a7a8b5SBram Moolenaar     HRESULT
653*d7ccc4d8SBram Moolenaar DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
654*d7ccc4d8SBram Moolenaar 	IDWriteTextFormat **ppTextFormat)
655b5a7a8b5SBram Moolenaar {
656*d7ccc4d8SBram Moolenaar     // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
657b5a7a8b5SBram Moolenaar     HRESULT hr = S_OK;
658*d7ccc4d8SBram Moolenaar     IDWriteTextFormat *pTextFormat = NULL;
659b5a7a8b5SBram Moolenaar 
660b5a7a8b5SBram Moolenaar     IDWriteFont *font = NULL;
661b5a7a8b5SBram Moolenaar     IDWriteFontFamily *fontFamily = NULL;
662b5a7a8b5SBram Moolenaar     IDWriteLocalizedStrings *localizedFamilyNames = NULL;
663*d7ccc4d8SBram Moolenaar     float fontSize = 0;
664b5a7a8b5SBram Moolenaar 
665b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
666b5a7a8b5SBram Moolenaar     {
667b5a7a8b5SBram Moolenaar 	hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
668b5a7a8b5SBram Moolenaar     }
669b5a7a8b5SBram Moolenaar 
670b5a7a8b5SBram Moolenaar     // Get the font family to which this font belongs.
671b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
672b5a7a8b5SBram Moolenaar     {
673b5a7a8b5SBram Moolenaar 	hr = font->GetFontFamily(&fontFamily);
674b5a7a8b5SBram Moolenaar     }
675b5a7a8b5SBram Moolenaar 
676b5a7a8b5SBram Moolenaar     // Get the family names. This returns an object that encapsulates one or
677b5a7a8b5SBram Moolenaar     // more names with the same meaning but in different languages.
678b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
679b5a7a8b5SBram Moolenaar     {
680b5a7a8b5SBram Moolenaar 	hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
681b5a7a8b5SBram Moolenaar     }
682b5a7a8b5SBram Moolenaar 
683b5a7a8b5SBram Moolenaar     // Get the family name at index zero. If we were going to display the name
684b5a7a8b5SBram Moolenaar     // we'd want to try to find one that matched the use locale, but for
685b5a7a8b5SBram Moolenaar     // purposes of creating a text format object any language will do.
686b5a7a8b5SBram Moolenaar 
687b5a7a8b5SBram Moolenaar     wchar_t familyName[100];
688b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
689b5a7a8b5SBram Moolenaar     {
690b5a7a8b5SBram Moolenaar 	hr = localizedFamilyNames->GetString(0, familyName,
691b5a7a8b5SBram Moolenaar 		ARRAYSIZE(familyName));
692b5a7a8b5SBram Moolenaar     }
693b5a7a8b5SBram Moolenaar 
694b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
695b5a7a8b5SBram Moolenaar     {
696*d7ccc4d8SBram Moolenaar 	// Use lfHeight of the LOGFONT as font size.
697*d7ccc4d8SBram Moolenaar 	fontSize = float(logFont.lfHeight);
698*d7ccc4d8SBram Moolenaar 
699b5a7a8b5SBram Moolenaar 	if (fontSize < 0)
700b5a7a8b5SBram Moolenaar 	{
701b5a7a8b5SBram Moolenaar 	    // Negative lfHeight represents the size of the em unit.
702b5a7a8b5SBram Moolenaar 	    fontSize = -fontSize;
703b5a7a8b5SBram Moolenaar 	}
704b5a7a8b5SBram Moolenaar 	else
705b5a7a8b5SBram Moolenaar 	{
706b5a7a8b5SBram Moolenaar 	    // Positive lfHeight represents the cell height (ascent +
707b5a7a8b5SBram Moolenaar 	    // descent).
708b5a7a8b5SBram Moolenaar 	    DWRITE_FONT_METRICS fontMetrics;
709b5a7a8b5SBram Moolenaar 	    font->GetMetrics(&fontMetrics);
710b5a7a8b5SBram Moolenaar 
711b5a7a8b5SBram Moolenaar 	    // Convert the cell height (ascent + descent) from design units
712b5a7a8b5SBram Moolenaar 	    // to ems.
713b5a7a8b5SBram Moolenaar 	    float cellHeight = static_cast<float>(
714b5a7a8b5SBram Moolenaar 		    fontMetrics.ascent + fontMetrics.descent)
715b5a7a8b5SBram Moolenaar 		/ fontMetrics.designUnitsPerEm;
716b5a7a8b5SBram Moolenaar 
717b5a7a8b5SBram Moolenaar 	    // Divide the font size by the cell height to get the font em
718b5a7a8b5SBram Moolenaar 	    // size.
719b5a7a8b5SBram Moolenaar 	    fontSize /= cellHeight;
720b5a7a8b5SBram Moolenaar 	}
721b5a7a8b5SBram Moolenaar     }
722b5a7a8b5SBram Moolenaar 
723b5a7a8b5SBram Moolenaar     // The text format includes a locale name. Ideally, this would be the
724b5a7a8b5SBram Moolenaar     // language of the text, which may or may not be the same as the primary
725b5a7a8b5SBram Moolenaar     // language of the user. However, for our purposes the user locale will do.
726b5a7a8b5SBram Moolenaar     wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
727b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
728b5a7a8b5SBram Moolenaar     {
729b5a7a8b5SBram Moolenaar 	if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
730b5a7a8b5SBram Moolenaar 	    hr = HRESULT_FROM_WIN32(GetLastError());
731b5a7a8b5SBram Moolenaar     }
732b5a7a8b5SBram Moolenaar 
733b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
734b5a7a8b5SBram Moolenaar     {
735b5a7a8b5SBram Moolenaar 	// Create the text format object.
736b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateTextFormat(
737b5a7a8b5SBram Moolenaar 		familyName,
738b5a7a8b5SBram Moolenaar 		NULL, // no custom font collection
739b5a7a8b5SBram Moolenaar 		font->GetWeight(),
740b5a7a8b5SBram Moolenaar 		font->GetStyle(),
741b5a7a8b5SBram Moolenaar 		font->GetStretch(),
742b5a7a8b5SBram Moolenaar 		fontSize,
743b5a7a8b5SBram Moolenaar 		localeName,
744*d7ccc4d8SBram Moolenaar 		&pTextFormat);
745b5a7a8b5SBram Moolenaar     }
746b5a7a8b5SBram Moolenaar 
747b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
748*d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
749*d7ccc4d8SBram Moolenaar 
750*d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
751*d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetParagraphAlignment(
752*d7ccc4d8SBram Moolenaar 		DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
753*d7ccc4d8SBram Moolenaar 
754*d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
755*d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
756b5a7a8b5SBram Moolenaar 
757b5a7a8b5SBram Moolenaar     SafeRelease(&localizedFamilyNames);
758b5a7a8b5SBram Moolenaar     SafeRelease(&fontFamily);
759b5a7a8b5SBram Moolenaar     SafeRelease(&font);
760b5a7a8b5SBram Moolenaar 
761*d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
762*d7ccc4d8SBram Moolenaar 	*ppTextFormat = pTextFormat;
763*d7ccc4d8SBram Moolenaar     else
764*d7ccc4d8SBram Moolenaar 	SafeRelease(&pTextFormat);
765*d7ccc4d8SBram Moolenaar 
766*d7ccc4d8SBram Moolenaar     return hr;
767*d7ccc4d8SBram Moolenaar }
768*d7ccc4d8SBram Moolenaar 
769*d7ccc4d8SBram Moolenaar     HRESULT
770*d7ccc4d8SBram Moolenaar DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
771*d7ccc4d8SBram Moolenaar {
772*d7ccc4d8SBram Moolenaar     HRESULT hr = S_OK;
773*d7ccc4d8SBram Moolenaar     IDWriteTextFormat *pTextFormat = NULL;
774*d7ccc4d8SBram Moolenaar 
775*d7ccc4d8SBram Moolenaar     hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
776*d7ccc4d8SBram Moolenaar 
777*d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
778*d7ccc4d8SBram Moolenaar     {
779*d7ccc4d8SBram Moolenaar 	SafeRelease(&mTextFormat);
780*d7ccc4d8SBram Moolenaar 	mTextFormat = pTextFormat;
781*d7ccc4d8SBram Moolenaar 	mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
782*d7ccc4d8SBram Moolenaar 	mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
783*d7ccc4d8SBram Moolenaar 	    : DWRITE_FONT_STYLE_NORMAL;
784*d7ccc4d8SBram Moolenaar     }
785*d7ccc4d8SBram Moolenaar 
786b5a7a8b5SBram Moolenaar     return hr;
787b5a7a8b5SBram Moolenaar }
788b5a7a8b5SBram Moolenaar 
789b5a7a8b5SBram Moolenaar     void
790b5a7a8b5SBram Moolenaar DWriteContext::SetFont(HFONT hFont)
791b5a7a8b5SBram Moolenaar {
792*d7ccc4d8SBram Moolenaar     FontCache::Item item;
793*d7ccc4d8SBram Moolenaar     if (mFontCache.get(hFont, item))
794b5a7a8b5SBram Moolenaar     {
795*d7ccc4d8SBram Moolenaar 	if (item.pTextFormat != NULL)
796*d7ccc4d8SBram Moolenaar 	{
797*d7ccc4d8SBram Moolenaar 	    item.pTextFormat->AddRef();
798*d7ccc4d8SBram Moolenaar 	    SafeRelease(&mTextFormat);
799*d7ccc4d8SBram Moolenaar 	    mTextFormat = item.pTextFormat;
800*d7ccc4d8SBram Moolenaar 	    mFontWeight = item.fontWeight;
801*d7ccc4d8SBram Moolenaar 	    mFontStyle = item.fontStyle;
802*d7ccc4d8SBram Moolenaar 	    mFallbackDC = false;
803*d7ccc4d8SBram Moolenaar 	}
804*d7ccc4d8SBram Moolenaar 	else
805*d7ccc4d8SBram Moolenaar 	    mFallbackDC = true;
806*d7ccc4d8SBram Moolenaar 	return;
807*d7ccc4d8SBram Moolenaar     }
808*d7ccc4d8SBram Moolenaar 
809*d7ccc4d8SBram Moolenaar     HRESULT hr = E_FAIL;
810b5a7a8b5SBram Moolenaar     LOGFONTW lf;
811b5a7a8b5SBram Moolenaar     if (GetObjectW(hFont, sizeof(lf), &lf))
812*d7ccc4d8SBram Moolenaar 	hr = SetFontByLOGFONT(lf);
813*d7ccc4d8SBram Moolenaar 
814*d7ccc4d8SBram Moolenaar     item.hFont = hFont;
815*d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
816b5a7a8b5SBram Moolenaar     {
817*d7ccc4d8SBram Moolenaar 	item.pTextFormat = mTextFormat;
818*d7ccc4d8SBram Moolenaar 	item.fontWeight = mFontWeight;
819*d7ccc4d8SBram Moolenaar 	item.fontStyle = mFontStyle;
820b5a7a8b5SBram Moolenaar     }
821*d7ccc4d8SBram Moolenaar     mFontCache.put(item);
822b5a7a8b5SBram Moolenaar }
823b5a7a8b5SBram Moolenaar 
824b5a7a8b5SBram Moolenaar     void
825*d7ccc4d8SBram Moolenaar DWriteContext::BindDC(HDC hdc, RECT *rect)
826b5a7a8b5SBram Moolenaar {
827*d7ccc4d8SBram Moolenaar     Flush();
828*d7ccc4d8SBram Moolenaar     mRT->BindDC(hdc, rect);
829*d7ccc4d8SBram Moolenaar     mRT->SetTransform(D2D1::IdentityMatrix());
830*d7ccc4d8SBram Moolenaar     mHDC = hdc;
831b5a7a8b5SBram Moolenaar }
832b5a7a8b5SBram Moolenaar 
833b5a7a8b5SBram Moolenaar     void
834*d7ccc4d8SBram Moolenaar DWriteContext::AssureDrawing()
835b5a7a8b5SBram Moolenaar {
836*d7ccc4d8SBram Moolenaar     if (mDrawing == false)
837b5a7a8b5SBram Moolenaar     {
838*d7ccc4d8SBram Moolenaar 	mRT->BeginDraw();
839*d7ccc4d8SBram Moolenaar 	mDrawing = true;
840*d7ccc4d8SBram Moolenaar     }
841*d7ccc4d8SBram Moolenaar }
842*d7ccc4d8SBram Moolenaar 
843*d7ccc4d8SBram Moolenaar     ID2D1Brush*
844*d7ccc4d8SBram Moolenaar DWriteContext::SolidBrush(COLORREF color)
845*d7ccc4d8SBram Moolenaar {
846*d7ccc4d8SBram Moolenaar     mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
847*d7ccc4d8SBram Moolenaar 		UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
848*d7ccc4d8SBram Moolenaar     return mBrush;
849*d7ccc4d8SBram Moolenaar }
850*d7ccc4d8SBram Moolenaar 
851*d7ccc4d8SBram Moolenaar     void
852*d7ccc4d8SBram Moolenaar DWriteContext::DrawText(const WCHAR* text, int len,
853*d7ccc4d8SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color,
854*d7ccc4d8SBram Moolenaar 	UINT fuOptions, CONST RECT *lprc, CONST INT * lpDx)
855*d7ccc4d8SBram Moolenaar {
856*d7ccc4d8SBram Moolenaar     if (mFallbackDC)
857*d7ccc4d8SBram Moolenaar     {
858*d7ccc4d8SBram Moolenaar 	Flush();
859*d7ccc4d8SBram Moolenaar 	ExtTextOutW(mHDC, x, y, fuOptions, lprc, text, len, lpDx);
860*d7ccc4d8SBram Moolenaar 	return;
861*d7ccc4d8SBram Moolenaar     }
862*d7ccc4d8SBram Moolenaar 
863*d7ccc4d8SBram Moolenaar     AssureDrawing();
864*d7ccc4d8SBram Moolenaar 
865*d7ccc4d8SBram Moolenaar     HRESULT hr;
866b5a7a8b5SBram Moolenaar     IDWriteTextLayout *textLayout = NULL;
867b5a7a8b5SBram Moolenaar 
868*d7ccc4d8SBram Moolenaar     hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
869*d7ccc4d8SBram Moolenaar 	    FLOAT(w), FLOAT(h), &textLayout);
870b5a7a8b5SBram Moolenaar 
871b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
872b5a7a8b5SBram Moolenaar     {
873*d7ccc4d8SBram Moolenaar 	DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
874b5a7a8b5SBram Moolenaar 	textLayout->SetFontWeight(mFontWeight, textRange);
875b5a7a8b5SBram Moolenaar 	textLayout->SetFontStyle(mFontStyle, textRange);
876b5a7a8b5SBram Moolenaar 
877*d7ccc4d8SBram Moolenaar 	TextRenderer renderer(this);
878*d7ccc4d8SBram Moolenaar 	TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
879*d7ccc4d8SBram Moolenaar 	textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
880b5a7a8b5SBram Moolenaar     }
881b5a7a8b5SBram Moolenaar 
882b5a7a8b5SBram Moolenaar     SafeRelease(&textLayout);
883b5a7a8b5SBram Moolenaar }
884b5a7a8b5SBram Moolenaar 
885*d7ccc4d8SBram Moolenaar     void
886*d7ccc4d8SBram Moolenaar DWriteContext::FillRect(RECT *rc, COLORREF color)
887*d7ccc4d8SBram Moolenaar {
888*d7ccc4d8SBram Moolenaar     AssureDrawing();
889*d7ccc4d8SBram Moolenaar     mRT->FillRectangle(
890*d7ccc4d8SBram Moolenaar 	    D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
891*d7ccc4d8SBram Moolenaar 		FLOAT(rc->right), FLOAT(rc->bottom)),
892*d7ccc4d8SBram Moolenaar 	    SolidBrush(color));
893b5a7a8b5SBram Moolenaar }
894b5a7a8b5SBram Moolenaar 
895*d7ccc4d8SBram Moolenaar     void
896*d7ccc4d8SBram Moolenaar DWriteContext::Flush()
897b5a7a8b5SBram Moolenaar {
898*d7ccc4d8SBram Moolenaar     if (mDrawing)
899*d7ccc4d8SBram Moolenaar     {
900*d7ccc4d8SBram Moolenaar 	mRT->EndDraw();
901*d7ccc4d8SBram Moolenaar 	mDrawing = false;
902b5a7a8b5SBram Moolenaar     }
903b5a7a8b5SBram Moolenaar }
904b5a7a8b5SBram Moolenaar 
905b5a7a8b5SBram Moolenaar     void
906b5a7a8b5SBram Moolenaar DWriteContext::SetRenderingParams(
907b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
908b5a7a8b5SBram Moolenaar {
909b5a7a8b5SBram Moolenaar     if (mDWriteFactory == NULL)
910b5a7a8b5SBram Moolenaar 	return;
911b5a7a8b5SBram Moolenaar 
912b5a7a8b5SBram Moolenaar     IDWriteRenderingParams *renderingParams = NULL;
913b5a7a8b5SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
914b5a7a8b5SBram Moolenaar 	D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
915b5a7a8b5SBram Moolenaar     HRESULT hr;
916b5a7a8b5SBram Moolenaar     if (params != NULL)
917b5a7a8b5SBram Moolenaar     {
918b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
919b5a7a8b5SBram Moolenaar 		params->enhancedContrast, params->clearTypeLevel,
920b5a7a8b5SBram Moolenaar 		ToPixelGeometry(params->pixelGeometry),
921b5a7a8b5SBram Moolenaar 		ToRenderingMode(params->renderingMode), &renderingParams);
922b5a7a8b5SBram Moolenaar 	textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
923b5a7a8b5SBram Moolenaar     }
924b5a7a8b5SBram Moolenaar     else
925b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
926b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr) && renderingParams != NULL)
927b5a7a8b5SBram Moolenaar     {
928b5a7a8b5SBram Moolenaar 	SafeRelease(&mRenderingParams);
929b5a7a8b5SBram Moolenaar 	mRenderingParams = renderingParams;
930b5a7a8b5SBram Moolenaar 	mTextAntialiasMode = textAntialiasMode;
931*d7ccc4d8SBram Moolenaar 
932*d7ccc4d8SBram Moolenaar 	Flush();
933*d7ccc4d8SBram Moolenaar 	mRT->SetTextRenderingParams(mRenderingParams);
934*d7ccc4d8SBram Moolenaar 	mRT->SetTextAntialiasMode(mTextAntialiasMode);
935b5a7a8b5SBram Moolenaar     }
936b5a7a8b5SBram Moolenaar }
937b5a7a8b5SBram Moolenaar 
938b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
939b5a7a8b5SBram Moolenaar DWriteContext::GetRenderingParams(
940b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
941b5a7a8b5SBram Moolenaar {
942b5a7a8b5SBram Moolenaar     if (params != NULL && mRenderingParams != NULL)
943b5a7a8b5SBram Moolenaar     {
944b5a7a8b5SBram Moolenaar 	params->gamma = mRenderingParams->GetGamma();
945b5a7a8b5SBram Moolenaar 	params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
946b5a7a8b5SBram Moolenaar 	params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
947b5a7a8b5SBram Moolenaar 	params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
948b5a7a8b5SBram Moolenaar 	params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
949b5a7a8b5SBram Moolenaar 	params->textAntialiasMode = mTextAntialiasMode;
950b5a7a8b5SBram Moolenaar     }
951b5a7a8b5SBram Moolenaar     return params;
952b5a7a8b5SBram Moolenaar }
953b5a7a8b5SBram Moolenaar 
954b5a7a8b5SBram Moolenaar ////////////////////////////////////////////////////////////////////////////
955b5a7a8b5SBram Moolenaar // PUBLIC C INTERFACES
956b5a7a8b5SBram Moolenaar 
957b5a7a8b5SBram Moolenaar     void
958b5a7a8b5SBram Moolenaar DWrite_Init(void)
959b5a7a8b5SBram Moolenaar {
960b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
961b5a7a8b5SBram Moolenaar     // Load libraries.
962b5a7a8b5SBram Moolenaar     hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
963b5a7a8b5SBram Moolenaar     hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
964b5a7a8b5SBram Moolenaar     if (hD2D1DLL == NULL || hDWriteDLL == NULL)
965b5a7a8b5SBram Moolenaar     {
966b5a7a8b5SBram Moolenaar 	DWrite_Final();
967b5a7a8b5SBram Moolenaar 	return;
968b5a7a8b5SBram Moolenaar     }
969b5a7a8b5SBram Moolenaar     // Get address of procedures.
970b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
971b5a7a8b5SBram Moolenaar 	    GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
972b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
973b5a7a8b5SBram Moolenaar 	    "D2D1CreateFactory");
974b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
975b5a7a8b5SBram Moolenaar 	    "DWriteCreateFactory");
976b5a7a8b5SBram Moolenaar #endif
977b5a7a8b5SBram Moolenaar }
978b5a7a8b5SBram Moolenaar 
979b5a7a8b5SBram Moolenaar     void
980b5a7a8b5SBram Moolenaar DWrite_Final(void)
981b5a7a8b5SBram Moolenaar {
982b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
983b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = NULL;
984b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = NULL;
985b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = NULL;
986b5a7a8b5SBram Moolenaar     unload(hDWriteDLL);
987b5a7a8b5SBram Moolenaar     unload(hD2D1DLL);
988b5a7a8b5SBram Moolenaar #endif
989b5a7a8b5SBram Moolenaar }
990b5a7a8b5SBram Moolenaar 
991b5a7a8b5SBram Moolenaar     DWriteContext *
992b5a7a8b5SBram Moolenaar DWriteContext_Open(void)
993b5a7a8b5SBram Moolenaar {
994b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
995b5a7a8b5SBram Moolenaar     if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
996b5a7a8b5SBram Moolenaar 	    || pDWriteCreateFactory == NULL)
997b5a7a8b5SBram Moolenaar 	return NULL;
998b5a7a8b5SBram Moolenaar #endif
999b5a7a8b5SBram Moolenaar     return new DWriteContext();
1000b5a7a8b5SBram Moolenaar }
1001b5a7a8b5SBram Moolenaar 
1002b5a7a8b5SBram Moolenaar     void
1003b5a7a8b5SBram Moolenaar DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
1004b5a7a8b5SBram Moolenaar {
1005*d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1006*d7ccc4d8SBram Moolenaar 	ctx->BindDC(hdc, rect);
1007b5a7a8b5SBram Moolenaar }
1008b5a7a8b5SBram Moolenaar 
1009b5a7a8b5SBram Moolenaar     void
1010b5a7a8b5SBram Moolenaar DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
1011b5a7a8b5SBram Moolenaar {
1012b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1013b5a7a8b5SBram Moolenaar 	ctx->SetFont(hFont);
1014b5a7a8b5SBram Moolenaar }
1015b5a7a8b5SBram Moolenaar 
1016b5a7a8b5SBram Moolenaar     void
1017b5a7a8b5SBram Moolenaar DWriteContext_DrawText(
1018b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1019b5a7a8b5SBram Moolenaar 	const WCHAR* text,
1020b5a7a8b5SBram Moolenaar 	int len,
1021b5a7a8b5SBram Moolenaar 	int x,
1022b5a7a8b5SBram Moolenaar 	int y,
1023b5a7a8b5SBram Moolenaar 	int w,
1024b5a7a8b5SBram Moolenaar 	int h,
1025b5a7a8b5SBram Moolenaar 	int cellWidth,
1026*d7ccc4d8SBram Moolenaar 	COLORREF color,
1027*d7ccc4d8SBram Moolenaar 	UINT fuOptions,
1028*d7ccc4d8SBram Moolenaar 	CONST RECT *lprc,
1029*d7ccc4d8SBram Moolenaar 	CONST INT * lpDx)
1030b5a7a8b5SBram Moolenaar {
1031b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1032*d7ccc4d8SBram Moolenaar 	ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
1033*d7ccc4d8SBram Moolenaar 		fuOptions, lprc, lpDx);
1034b5a7a8b5SBram Moolenaar }
1035b5a7a8b5SBram Moolenaar 
1036b5a7a8b5SBram Moolenaar     void
1037*d7ccc4d8SBram Moolenaar DWriteContext_FillRect(DWriteContext *ctx, RECT *rc, COLORREF color)
1038b5a7a8b5SBram Moolenaar {
1039*d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1040*d7ccc4d8SBram Moolenaar 	ctx->FillRect(rc, color);
1041b5a7a8b5SBram Moolenaar }
1042*d7ccc4d8SBram Moolenaar 
1043*d7ccc4d8SBram Moolenaar     void
1044*d7ccc4d8SBram Moolenaar DWriteContext_Flush(DWriteContext *ctx)
1045*d7ccc4d8SBram Moolenaar {
1046*d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1047*d7ccc4d8SBram Moolenaar 	ctx->Flush();
1048b5a7a8b5SBram Moolenaar }
1049b5a7a8b5SBram Moolenaar 
1050b5a7a8b5SBram Moolenaar     void
1051b5a7a8b5SBram Moolenaar DWriteContext_Close(DWriteContext *ctx)
1052b5a7a8b5SBram Moolenaar {
1053b5a7a8b5SBram Moolenaar     delete ctx;
1054b5a7a8b5SBram Moolenaar }
1055b5a7a8b5SBram Moolenaar 
1056b5a7a8b5SBram Moolenaar     void
1057b5a7a8b5SBram Moolenaar DWriteContext_SetRenderingParams(
1058b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1059b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
1060b5a7a8b5SBram Moolenaar {
1061b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1062b5a7a8b5SBram Moolenaar 	ctx->SetRenderingParams(params);
1063b5a7a8b5SBram Moolenaar }
1064b5a7a8b5SBram Moolenaar 
1065b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
1066b5a7a8b5SBram Moolenaar DWriteContext_GetRenderingParams(
1067b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1068b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
1069b5a7a8b5SBram Moolenaar {
1070b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1071b5a7a8b5SBram Moolenaar 	return ctx->GetRenderingParams(params);
1072b5a7a8b5SBram Moolenaar     else
1073b5a7a8b5SBram Moolenaar 	return NULL;
1074b5a7a8b5SBram Moolenaar }
1075