xref: /vim-8.2.3635/src/gui_dwrite.cpp (revision 1f271efb)
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
7d7ccc4d8SBram 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>
27d7ccc4d8SBram Moolenaar 
28d7ccc4d8SBram Moolenaar // Disable these macros to compile with old VC and newer SDK (V8.1 or later).
29d7ccc4d8SBram Moolenaar #if defined(_MSC_VER) && (_MSC_VER < 1700)
30d7ccc4d8SBram Moolenaar # define _COM_Outptr_ __out
31d7ccc4d8SBram Moolenaar # define _In_reads_(s)
32d7ccc4d8SBram Moolenaar # define _In_reads_opt_(s)
33d7ccc4d8SBram Moolenaar # define _Maybenull_
34d7ccc4d8SBram Moolenaar # define _Out_writes_(s)
35d7ccc4d8SBram Moolenaar # define _Out_writes_opt_(s)
36d7ccc4d8SBram Moolenaar # define _Out_writes_to_(x, y)
37d7ccc4d8SBram Moolenaar # define _Out_writes_to_opt_(x, y)
38d7ccc4d8SBram Moolenaar # define _Outptr_
39d7ccc4d8SBram Moolenaar #endif
40d7ccc4d8SBram Moolenaar 
417f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
42d7ccc4d8SBram Moolenaar # include <dwrite_2.h>
437f88b65fSBram Moolenaar #else
447f88b65fSBram Moolenaar # include <dwrite.h>
457f88b65fSBram Moolenaar #endif
46b5a7a8b5SBram Moolenaar 
47b5a7a8b5SBram Moolenaar #include "gui_dwrite.h"
48b5a7a8b5SBram Moolenaar 
49b5a7a8b5SBram Moolenaar #ifdef __MINGW32__
50b5a7a8b5SBram Moolenaar # define __maybenull	SAL__maybenull
51b5a7a8b5SBram Moolenaar # define __in		SAL__in
52b5a7a8b5SBram Moolenaar # define __out		SAL__out
53b5a7a8b5SBram Moolenaar #endif
54b5a7a8b5SBram Moolenaar 
55cc6cf9b9SBram Moolenaar #if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
56cc6cf9b9SBram Moolenaar # define FINAL final
57cc6cf9b9SBram Moolenaar #else
58cc6cf9b9SBram Moolenaar # define FINAL
59cc6cf9b9SBram Moolenaar #endif
60cc6cf9b9SBram Moolenaar 
61b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
62b5a7a8b5SBram Moolenaar extern "C" HINSTANCE vimLoadLib(char *name);
63b5a7a8b5SBram Moolenaar 
64b5a7a8b5SBram Moolenaar typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
65b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
66b5a7a8b5SBram Moolenaar 	REFIID, const D2D1_FACTORY_OPTIONS *, void **);
67b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
68b5a7a8b5SBram Moolenaar 	REFIID, IUnknown **);
69b5a7a8b5SBram Moolenaar 
70b5a7a8b5SBram Moolenaar static HINSTANCE hD2D1DLL = NULL;
71b5a7a8b5SBram Moolenaar static HINSTANCE hDWriteDLL = NULL;
72b5a7a8b5SBram Moolenaar 
73b5a7a8b5SBram Moolenaar static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
74b5a7a8b5SBram Moolenaar static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
75b5a7a8b5SBram Moolenaar static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
76b5a7a8b5SBram Moolenaar 
77b5a7a8b5SBram Moolenaar #define GetUserDefaultLocaleName	(*pGetUserDefaultLocaleName)
78b5a7a8b5SBram Moolenaar #define D2D1CreateFactory		(*pD2D1CreateFactory)
79b5a7a8b5SBram Moolenaar #define DWriteCreateFactory		(*pDWriteCreateFactory)
80b5a7a8b5SBram Moolenaar 
81b5a7a8b5SBram Moolenaar     static void
82b5a7a8b5SBram Moolenaar unload(HINSTANCE &hinst)
83b5a7a8b5SBram Moolenaar {
84b5a7a8b5SBram Moolenaar     if (hinst != NULL)
85b5a7a8b5SBram Moolenaar     {
86b5a7a8b5SBram Moolenaar 	FreeLibrary(hinst);
87b5a7a8b5SBram Moolenaar 	hinst = NULL;
88b5a7a8b5SBram Moolenaar     }
89b5a7a8b5SBram Moolenaar }
90b5a7a8b5SBram Moolenaar #endif // DYNAMIC_DIRECTX
91b5a7a8b5SBram Moolenaar 
92b5a7a8b5SBram Moolenaar template <class T> inline void SafeRelease(T **ppT)
93b5a7a8b5SBram Moolenaar {
94b5a7a8b5SBram Moolenaar     if (*ppT)
95b5a7a8b5SBram Moolenaar     {
96b5a7a8b5SBram Moolenaar 	(*ppT)->Release();
97b5a7a8b5SBram Moolenaar 	*ppT = NULL;
98b5a7a8b5SBram Moolenaar     }
99b5a7a8b5SBram Moolenaar }
100b5a7a8b5SBram Moolenaar 
101b5a7a8b5SBram Moolenaar     static DWRITE_PIXEL_GEOMETRY
102b5a7a8b5SBram Moolenaar ToPixelGeometry(int value)
103b5a7a8b5SBram Moolenaar {
104b5a7a8b5SBram Moolenaar     switch (value)
105b5a7a8b5SBram Moolenaar     {
106b5a7a8b5SBram Moolenaar 	default:
107b5a7a8b5SBram Moolenaar 	case 0:
108b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_FLAT;
109b5a7a8b5SBram Moolenaar 	case 1:
110b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_RGB;
111b5a7a8b5SBram Moolenaar 	case 2:
112b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_BGR;
113b5a7a8b5SBram Moolenaar     }
114b5a7a8b5SBram Moolenaar }
115b5a7a8b5SBram Moolenaar 
116b5a7a8b5SBram Moolenaar     static int
117b5a7a8b5SBram Moolenaar ToInt(DWRITE_PIXEL_GEOMETRY value)
118b5a7a8b5SBram Moolenaar {
119b5a7a8b5SBram Moolenaar     switch (value)
120b5a7a8b5SBram Moolenaar     {
121b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_FLAT:
122b5a7a8b5SBram Moolenaar 	    return 0;
123b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_RGB:
124b5a7a8b5SBram Moolenaar 	    return 1;
125b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_BGR:
126b5a7a8b5SBram Moolenaar 	    return 2;
127b5a7a8b5SBram Moolenaar 	default:
128b5a7a8b5SBram Moolenaar 	    return -1;
129b5a7a8b5SBram Moolenaar     }
130b5a7a8b5SBram Moolenaar }
131b5a7a8b5SBram Moolenaar 
132b5a7a8b5SBram Moolenaar     static DWRITE_RENDERING_MODE
133b5a7a8b5SBram Moolenaar ToRenderingMode(int value)
134b5a7a8b5SBram Moolenaar {
135b5a7a8b5SBram Moolenaar     switch (value)
136b5a7a8b5SBram Moolenaar     {
137b5a7a8b5SBram Moolenaar 	default:
138b5a7a8b5SBram Moolenaar 	case 0:
139b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_DEFAULT;
140b5a7a8b5SBram Moolenaar 	case 1:
141b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_ALIASED;
142b5a7a8b5SBram Moolenaar 	case 2:
143b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
144b5a7a8b5SBram Moolenaar 	case 3:
145b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
146b5a7a8b5SBram Moolenaar 	case 4:
147b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
148b5a7a8b5SBram Moolenaar 	case 5:
149b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
150b5a7a8b5SBram Moolenaar 	case 6:
151b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_OUTLINE;
152b5a7a8b5SBram Moolenaar     }
153b5a7a8b5SBram Moolenaar }
154b5a7a8b5SBram Moolenaar 
155b5a7a8b5SBram Moolenaar     static D2D1_TEXT_ANTIALIAS_MODE
156b5a7a8b5SBram Moolenaar ToTextAntialiasMode(int value)
157b5a7a8b5SBram Moolenaar {
158b5a7a8b5SBram Moolenaar     switch (value)
159b5a7a8b5SBram Moolenaar     {
160b5a7a8b5SBram Moolenaar 	default:
161b5a7a8b5SBram Moolenaar 	case 0:
162b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
163b5a7a8b5SBram Moolenaar 	case 1:
164b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
165b5a7a8b5SBram Moolenaar 	case 2:
166b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
167b5a7a8b5SBram Moolenaar 	case 3:
168b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
169b5a7a8b5SBram Moolenaar     }
170b5a7a8b5SBram Moolenaar }
171b5a7a8b5SBram Moolenaar 
172b5a7a8b5SBram Moolenaar     static int
173b5a7a8b5SBram Moolenaar ToInt(DWRITE_RENDERING_MODE value)
174b5a7a8b5SBram Moolenaar {
175b5a7a8b5SBram Moolenaar     switch (value)
176b5a7a8b5SBram Moolenaar     {
177b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_DEFAULT:
178b5a7a8b5SBram Moolenaar 	    return 0;
179b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_ALIASED:
180b5a7a8b5SBram Moolenaar 	    return 1;
181b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
182b5a7a8b5SBram Moolenaar 	    return 2;
183b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
184b5a7a8b5SBram Moolenaar 	    return 3;
185b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
186b5a7a8b5SBram Moolenaar 	    return 4;
187b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
188b5a7a8b5SBram Moolenaar 	    return 5;
189b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_OUTLINE:
190b5a7a8b5SBram Moolenaar 	    return 6;
191b5a7a8b5SBram Moolenaar 	default:
192b5a7a8b5SBram Moolenaar 	    return -1;
193b5a7a8b5SBram Moolenaar     }
194b5a7a8b5SBram Moolenaar }
195b5a7a8b5SBram Moolenaar 
196d7ccc4d8SBram Moolenaar class FontCache {
197d7ccc4d8SBram Moolenaar public:
198d7ccc4d8SBram Moolenaar     struct Item {
199d7ccc4d8SBram Moolenaar 	HFONT              hFont;
200d7ccc4d8SBram Moolenaar 	IDWriteTextFormat* pTextFormat;
201d7ccc4d8SBram Moolenaar 	DWRITE_FONT_WEIGHT fontWeight;
202d7ccc4d8SBram Moolenaar 	DWRITE_FONT_STYLE  fontStyle;
203d7ccc4d8SBram Moolenaar 	Item() : hFont(NULL), pTextFormat(NULL) {}
204d7ccc4d8SBram Moolenaar     };
205d7ccc4d8SBram Moolenaar 
206d7ccc4d8SBram Moolenaar private:
207d7ccc4d8SBram Moolenaar     int mSize;
208d7ccc4d8SBram Moolenaar     Item *mItems;
209d7ccc4d8SBram Moolenaar 
210d7ccc4d8SBram Moolenaar public:
211d7ccc4d8SBram Moolenaar     FontCache(int size = 2) :
212d7ccc4d8SBram Moolenaar 	mSize(size),
213d7ccc4d8SBram Moolenaar 	mItems(new Item[size])
214d7ccc4d8SBram Moolenaar     {
215d7ccc4d8SBram Moolenaar     }
216d7ccc4d8SBram Moolenaar 
217d7ccc4d8SBram Moolenaar     ~FontCache()
218d7ccc4d8SBram Moolenaar     {
219d7ccc4d8SBram Moolenaar 	for (int i = 0; i < mSize; ++i)
220d7ccc4d8SBram Moolenaar 	    SafeRelease(&mItems[i].pTextFormat);
221d7ccc4d8SBram Moolenaar 	delete[] mItems;
222d7ccc4d8SBram Moolenaar     }
223d7ccc4d8SBram Moolenaar 
224d7ccc4d8SBram Moolenaar     bool get(HFONT hFont, Item &item)
225d7ccc4d8SBram Moolenaar     {
226d7ccc4d8SBram Moolenaar 	int n = find(hFont);
227d7ccc4d8SBram Moolenaar 	if (n < 0)
228d7ccc4d8SBram Moolenaar 	    return false;
229d7ccc4d8SBram Moolenaar 	item = mItems[n];
230d7ccc4d8SBram Moolenaar 	slide(n);
231d7ccc4d8SBram Moolenaar 	return true;
232d7ccc4d8SBram Moolenaar     }
233d7ccc4d8SBram Moolenaar 
234d7ccc4d8SBram Moolenaar     void put(const Item& item)
235d7ccc4d8SBram Moolenaar     {
236d7ccc4d8SBram Moolenaar 	int n = find(item.hFont);
237d7ccc4d8SBram Moolenaar 	if (n < 0)
238d7ccc4d8SBram Moolenaar 	    n = mSize - 1;
239d7ccc4d8SBram Moolenaar 	if (mItems[n].pTextFormat != item.pTextFormat)
240d7ccc4d8SBram Moolenaar 	{
241d7ccc4d8SBram Moolenaar 	    SafeRelease(&mItems[n].pTextFormat);
242d7ccc4d8SBram Moolenaar 	    item.pTextFormat->AddRef();
243d7ccc4d8SBram Moolenaar 	}
244d7ccc4d8SBram Moolenaar 	mItems[n] = item;
245d7ccc4d8SBram Moolenaar 	slide(n);
246d7ccc4d8SBram Moolenaar     }
247d7ccc4d8SBram Moolenaar 
248d7ccc4d8SBram Moolenaar private:
249d7ccc4d8SBram Moolenaar     int find(HFONT hFont)
250d7ccc4d8SBram Moolenaar     {
251d7ccc4d8SBram Moolenaar 	for (int i = 0; i < mSize; ++i)
252d7ccc4d8SBram Moolenaar 	{
253d7ccc4d8SBram Moolenaar 	    if (mItems[i].hFont == hFont)
254d7ccc4d8SBram Moolenaar 		return i;
255d7ccc4d8SBram Moolenaar 	}
256d7ccc4d8SBram Moolenaar 	return -1;
257d7ccc4d8SBram Moolenaar     }
258d7ccc4d8SBram Moolenaar 
259d7ccc4d8SBram Moolenaar     void slide(int nextTop)
260d7ccc4d8SBram Moolenaar     {
261d7ccc4d8SBram Moolenaar 	if (nextTop == 0)
262d7ccc4d8SBram Moolenaar 	    return;
263d7ccc4d8SBram Moolenaar 	Item tmp = mItems[nextTop];
264d7ccc4d8SBram Moolenaar 	for (int i = nextTop - 1; i >= 0; --i)
265d7ccc4d8SBram Moolenaar 	    mItems[i + 1] = mItems[i];
266d7ccc4d8SBram Moolenaar 	mItems[0] = tmp;
267d7ccc4d8SBram Moolenaar     }
268d7ccc4d8SBram Moolenaar };
269d7ccc4d8SBram Moolenaar 
27092467d33SBram Moolenaar enum DrawingMode {
27192467d33SBram Moolenaar     DM_GDI = 0,
27292467d33SBram Moolenaar     DM_DIRECTX = 1,
27392467d33SBram Moolenaar     DM_INTEROP = 2,
27492467d33SBram Moolenaar };
27592467d33SBram Moolenaar 
276d7ccc4d8SBram Moolenaar struct DWriteContext {
277d7ccc4d8SBram Moolenaar     HDC mHDC;
27892467d33SBram Moolenaar     RECT mBindRect;
27992467d33SBram Moolenaar     DrawingMode mDMode;
28092467d33SBram Moolenaar     HDC mInteropHDC;
281d7ccc4d8SBram Moolenaar     bool mDrawing;
282d7ccc4d8SBram Moolenaar     bool mFallbackDC;
283d7ccc4d8SBram Moolenaar 
284d7ccc4d8SBram Moolenaar     ID2D1Factory *mD2D1Factory;
285d7ccc4d8SBram Moolenaar 
286d7ccc4d8SBram Moolenaar     ID2D1DCRenderTarget *mRT;
28792467d33SBram Moolenaar     ID2D1GdiInteropRenderTarget *mGDIRT;
288d7ccc4d8SBram Moolenaar     ID2D1SolidColorBrush *mBrush;
289a338adcfSBram Moolenaar     ID2D1Bitmap *mBitmap;
290d7ccc4d8SBram Moolenaar 
291d7ccc4d8SBram Moolenaar     IDWriteFactory *mDWriteFactory;
2927f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
293d7ccc4d8SBram Moolenaar     IDWriteFactory2 *mDWriteFactory2;
2947f88b65fSBram Moolenaar #endif
295d7ccc4d8SBram Moolenaar 
296d7ccc4d8SBram Moolenaar     IDWriteGdiInterop *mGdiInterop;
297d7ccc4d8SBram Moolenaar     IDWriteRenderingParams *mRenderingParams;
298d7ccc4d8SBram Moolenaar 
299d7ccc4d8SBram Moolenaar     FontCache mFontCache;
300d7ccc4d8SBram Moolenaar     IDWriteTextFormat *mTextFormat;
301d7ccc4d8SBram Moolenaar     DWRITE_FONT_WEIGHT mFontWeight;
302d7ccc4d8SBram Moolenaar     DWRITE_FONT_STYLE mFontStyle;
303d7ccc4d8SBram Moolenaar 
304d7ccc4d8SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
305d7ccc4d8SBram Moolenaar 
306d7ccc4d8SBram Moolenaar     // METHODS
307d7ccc4d8SBram Moolenaar 
308d7ccc4d8SBram Moolenaar     DWriteContext();
309d7ccc4d8SBram Moolenaar 
310d7ccc4d8SBram Moolenaar     virtual ~DWriteContext();
311d7ccc4d8SBram Moolenaar 
31292467d33SBram Moolenaar     HRESULT CreateDeviceResources();
31392467d33SBram Moolenaar 
31492467d33SBram Moolenaar     void DiscardDeviceResources();
31592467d33SBram Moolenaar 
316d7ccc4d8SBram Moolenaar     HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
317d7ccc4d8SBram Moolenaar 	    IDWriteTextFormat **ppTextFormat);
318d7ccc4d8SBram Moolenaar 
319d7ccc4d8SBram Moolenaar     HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
320d7ccc4d8SBram Moolenaar 
321d7ccc4d8SBram Moolenaar     void SetFont(HFONT hFont);
322d7ccc4d8SBram Moolenaar 
323a338adcfSBram Moolenaar     void Rebind();
324a338adcfSBram Moolenaar 
32592467d33SBram Moolenaar     void BindDC(HDC hdc, const RECT *rect);
326d7ccc4d8SBram Moolenaar 
32792467d33SBram Moolenaar     HRESULT SetDrawingMode(DrawingMode mode);
328d7ccc4d8SBram Moolenaar 
329d7ccc4d8SBram Moolenaar     ID2D1Brush* SolidBrush(COLORREF color);
330d7ccc4d8SBram Moolenaar 
331d7ccc4d8SBram Moolenaar     void DrawText(const WCHAR *text, int len,
332d7ccc4d8SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color,
33392467d33SBram Moolenaar 	UINT fuOptions, const RECT *lprc, const INT *lpDx);
334d7ccc4d8SBram Moolenaar 
33592467d33SBram Moolenaar     void FillRect(const RECT *rc, COLORREF color);
33692467d33SBram Moolenaar 
33792467d33SBram Moolenaar     void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
33892467d33SBram Moolenaar 
33992467d33SBram Moolenaar     void SetPixel(int x, int y, COLORREF color);
340d7ccc4d8SBram Moolenaar 
341a338adcfSBram Moolenaar     void Scroll(int x, int y, const RECT *rc);
342a338adcfSBram Moolenaar 
343d7ccc4d8SBram Moolenaar     void Flush();
344d7ccc4d8SBram Moolenaar 
345d7ccc4d8SBram Moolenaar     void SetRenderingParams(
346d7ccc4d8SBram Moolenaar 	    const DWriteRenderingParams *params);
347d7ccc4d8SBram Moolenaar 
348d7ccc4d8SBram Moolenaar     DWriteRenderingParams *GetRenderingParams(
349d7ccc4d8SBram Moolenaar 	    DWriteRenderingParams *params);
350d7ccc4d8SBram Moolenaar };
351d7ccc4d8SBram Moolenaar 
352b5a7a8b5SBram Moolenaar class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
353b5a7a8b5SBram Moolenaar {
354b5a7a8b5SBram Moolenaar private:
355d7ccc4d8SBram Moolenaar     FLOAT &mAccum;
356b5a7a8b5SBram Moolenaar     FLOAT mDelta;
357b5a7a8b5SBram Moolenaar     FLOAT *mAdjustedAdvances;
358b5a7a8b5SBram Moolenaar 
359b5a7a8b5SBram Moolenaar public:
360b5a7a8b5SBram Moolenaar     AdjustedGlyphRun(
361b5a7a8b5SBram Moolenaar 	    const DWRITE_GLYPH_RUN *glyphRun,
362d7ccc4d8SBram Moolenaar 	    FLOAT cellWidth,
363d7ccc4d8SBram Moolenaar 	    FLOAT &accum) :
364b5a7a8b5SBram Moolenaar 	DWRITE_GLYPH_RUN(*glyphRun),
365d7ccc4d8SBram Moolenaar 	mAccum(accum),
366b5a7a8b5SBram Moolenaar 	mDelta(0.0f),
367b5a7a8b5SBram Moolenaar 	mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
368b5a7a8b5SBram Moolenaar     {
369b5a7a8b5SBram Moolenaar 	assert(cellWidth != 0.0f);
370b5a7a8b5SBram Moolenaar 	for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
371b5a7a8b5SBram Moolenaar 	{
372b5a7a8b5SBram Moolenaar 	    FLOAT orig = glyphRun->glyphAdvances[i];
373b5a7a8b5SBram Moolenaar 	    FLOAT adjusted = adjustToCell(orig, cellWidth);
374b5a7a8b5SBram Moolenaar 	    mAdjustedAdvances[i] = adjusted;
375b5a7a8b5SBram Moolenaar 	    mDelta += adjusted - orig;
376b5a7a8b5SBram Moolenaar 	}
377b5a7a8b5SBram Moolenaar 	glyphAdvances = mAdjustedAdvances;
378b5a7a8b5SBram Moolenaar     }
379b5a7a8b5SBram Moolenaar 
380d7ccc4d8SBram Moolenaar     ~AdjustedGlyphRun()
381b5a7a8b5SBram Moolenaar     {
382d7ccc4d8SBram Moolenaar 	mAccum += mDelta;
383b5a7a8b5SBram Moolenaar 	delete[] mAdjustedAdvances;
384b5a7a8b5SBram Moolenaar     }
385b5a7a8b5SBram Moolenaar 
386b5a7a8b5SBram Moolenaar     static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
387b5a7a8b5SBram Moolenaar     {
388d7ccc4d8SBram Moolenaar 	int cellCount = int(floor(value / cellWidth + 0.5f));
389b5a7a8b5SBram Moolenaar 	if (cellCount < 1)
390b5a7a8b5SBram Moolenaar 	    cellCount = 1;
391b5a7a8b5SBram Moolenaar 	return cellCount * cellWidth;
392b5a7a8b5SBram Moolenaar     }
393b5a7a8b5SBram Moolenaar };
394b5a7a8b5SBram Moolenaar 
395d7ccc4d8SBram Moolenaar struct TextRendererContext {
396d7ccc4d8SBram Moolenaar     // const fields.
397d7ccc4d8SBram Moolenaar     COLORREF color;
398d7ccc4d8SBram Moolenaar     FLOAT cellWidth;
399d7ccc4d8SBram Moolenaar 
400d7ccc4d8SBram Moolenaar     // working fields.
401d7ccc4d8SBram Moolenaar     FLOAT offsetX;
402d7ccc4d8SBram Moolenaar };
403d7ccc4d8SBram Moolenaar 
404d7ccc4d8SBram Moolenaar class TextRenderer FINAL : public IDWriteTextRenderer
405b5a7a8b5SBram Moolenaar {
406b5a7a8b5SBram Moolenaar public:
407d7ccc4d8SBram Moolenaar     TextRenderer(
408d7ccc4d8SBram Moolenaar 	    DWriteContext* pDWC) :
409b5a7a8b5SBram Moolenaar 	cRefCount_(0),
410d7ccc4d8SBram Moolenaar 	pDWC_(pDWC)
411b5a7a8b5SBram Moolenaar     {
412b5a7a8b5SBram Moolenaar 	AddRef();
413b5a7a8b5SBram Moolenaar     }
414b5a7a8b5SBram Moolenaar 
415edb4f2b3SBram Moolenaar     // add "virtual" to avoid a compiler warning
416d7ccc4d8SBram Moolenaar     virtual ~TextRenderer()
417b5a7a8b5SBram Moolenaar     {
418b5a7a8b5SBram Moolenaar     }
419b5a7a8b5SBram Moolenaar 
420b5a7a8b5SBram Moolenaar     IFACEMETHOD(IsPixelSnappingDisabled)(
421b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
422b5a7a8b5SBram Moolenaar 	__out BOOL* isDisabled)
423b5a7a8b5SBram Moolenaar     {
424b5a7a8b5SBram Moolenaar 	*isDisabled = FALSE;
425b5a7a8b5SBram Moolenaar 	return S_OK;
426b5a7a8b5SBram Moolenaar     }
427b5a7a8b5SBram Moolenaar 
428b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetCurrentTransform)(
429b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
430b5a7a8b5SBram Moolenaar 	__out DWRITE_MATRIX* transform)
431b5a7a8b5SBram Moolenaar     {
432b5a7a8b5SBram Moolenaar 	// forward the render target's transform
433d7ccc4d8SBram Moolenaar 	pDWC_->mRT->GetTransform(
434d7ccc4d8SBram Moolenaar 		reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
435b5a7a8b5SBram Moolenaar 	return S_OK;
436b5a7a8b5SBram Moolenaar     }
437b5a7a8b5SBram Moolenaar 
438b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetPixelsPerDip)(
439b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
440b5a7a8b5SBram Moolenaar 	__out FLOAT* pixelsPerDip)
441b5a7a8b5SBram Moolenaar     {
442d7ccc4d8SBram Moolenaar 	float dpiX, unused;
443d7ccc4d8SBram Moolenaar 	pDWC_->mRT->GetDpi(&dpiX, &unused);
444d7ccc4d8SBram Moolenaar 	*pixelsPerDip = dpiX / 96.0f;
445b5a7a8b5SBram Moolenaar 	return S_OK;
446b5a7a8b5SBram Moolenaar     }
447b5a7a8b5SBram Moolenaar 
448b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawUnderline)(
449b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
450b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
451b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
452b5a7a8b5SBram Moolenaar 	__in DWRITE_UNDERLINE const* underline,
453b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
454b5a7a8b5SBram Moolenaar     {
455b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
456b5a7a8b5SBram Moolenaar     }
457b5a7a8b5SBram Moolenaar 
458b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawStrikethrough)(
459b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
460b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
461b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
462b5a7a8b5SBram Moolenaar 	__in DWRITE_STRIKETHROUGH const* strikethrough,
463b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
464b5a7a8b5SBram Moolenaar     {
465b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
466b5a7a8b5SBram Moolenaar     }
467b5a7a8b5SBram Moolenaar 
468b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawInlineObject)(
469b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
470b5a7a8b5SBram Moolenaar 	FLOAT originX,
471b5a7a8b5SBram Moolenaar 	FLOAT originY,
472b5a7a8b5SBram Moolenaar 	IDWriteInlineObject* inlineObject,
473b5a7a8b5SBram Moolenaar 	BOOL isSideways,
474b5a7a8b5SBram Moolenaar 	BOOL isRightToLeft,
475b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
476b5a7a8b5SBram Moolenaar     {
477b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
478b5a7a8b5SBram Moolenaar     }
479b5a7a8b5SBram Moolenaar 
480d7ccc4d8SBram Moolenaar     IFACEMETHOD(DrawGlyphRun)(
481d7ccc4d8SBram Moolenaar 	__maybenull void* clientDrawingContext,
482d7ccc4d8SBram Moolenaar 	FLOAT baselineOriginX,
483d7ccc4d8SBram Moolenaar 	FLOAT baselineOriginY,
484d7ccc4d8SBram Moolenaar 	DWRITE_MEASURING_MODE measuringMode,
485d7ccc4d8SBram Moolenaar 	__in DWRITE_GLYPH_RUN const* glyphRun,
486d7ccc4d8SBram Moolenaar 	__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
487d7ccc4d8SBram Moolenaar 	IUnknown* clientDrawingEffect)
488d7ccc4d8SBram Moolenaar     {
489d7ccc4d8SBram Moolenaar 	TextRendererContext *context =
490d7ccc4d8SBram Moolenaar 	    reinterpret_cast<TextRendererContext*>(clientDrawingContext);
491d7ccc4d8SBram Moolenaar 
492d7ccc4d8SBram Moolenaar 	AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
493d7ccc4d8SBram Moolenaar 		context->offsetX);
494d7ccc4d8SBram Moolenaar 
4957f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
496d7ccc4d8SBram Moolenaar 	if (pDWC_->mDWriteFactory2 != NULL)
497d7ccc4d8SBram Moolenaar 	{
498d7ccc4d8SBram Moolenaar 	    IDWriteColorGlyphRunEnumerator *enumerator = NULL;
499d7ccc4d8SBram Moolenaar 	    HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
500d7ccc4d8SBram Moolenaar 		baselineOriginX + context->offsetX,
501d7ccc4d8SBram Moolenaar 		baselineOriginY,
502d7ccc4d8SBram Moolenaar 		&adjustedGlyphRun,
503d7ccc4d8SBram Moolenaar 		NULL,
504d7ccc4d8SBram Moolenaar 		DWRITE_MEASURING_MODE_GDI_NATURAL,
505d7ccc4d8SBram Moolenaar 		NULL,
506d7ccc4d8SBram Moolenaar 		0,
507d7ccc4d8SBram Moolenaar 		&enumerator);
508d7ccc4d8SBram Moolenaar 	    if (SUCCEEDED(hr))
509d7ccc4d8SBram Moolenaar 	    {
510d7ccc4d8SBram Moolenaar 		// Draw by IDWriteFactory2 for color emoji
511d7ccc4d8SBram Moolenaar 		BOOL hasRun = TRUE;
512d7ccc4d8SBram Moolenaar 		enumerator->MoveNext(&hasRun);
513d7ccc4d8SBram Moolenaar 		while (hasRun)
514d7ccc4d8SBram Moolenaar 		{
515d7ccc4d8SBram Moolenaar 		    const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
516d7ccc4d8SBram Moolenaar 		    enumerator->GetCurrentRun(&colorGlyphRun);
517d7ccc4d8SBram Moolenaar 
518d7ccc4d8SBram Moolenaar 		    pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
519d7ccc4d8SBram Moolenaar 		    pDWC_->mRT->DrawGlyphRun(
520d7ccc4d8SBram Moolenaar 			    D2D1::Point2F(
521d7ccc4d8SBram Moolenaar 				colorGlyphRun->baselineOriginX,
522d7ccc4d8SBram Moolenaar 				colorGlyphRun->baselineOriginY),
523d7ccc4d8SBram Moolenaar 			    &colorGlyphRun->glyphRun,
524d7ccc4d8SBram Moolenaar 			    pDWC_->mBrush,
525d7ccc4d8SBram Moolenaar 			    DWRITE_MEASURING_MODE_NATURAL);
526d7ccc4d8SBram Moolenaar 		    enumerator->MoveNext(&hasRun);
527d7ccc4d8SBram Moolenaar 		}
528d7ccc4d8SBram Moolenaar 		SafeRelease(&enumerator);
529d7ccc4d8SBram Moolenaar 		return S_OK;
530d7ccc4d8SBram Moolenaar 	    }
531d7ccc4d8SBram Moolenaar 	}
5327f88b65fSBram Moolenaar #endif
533d7ccc4d8SBram Moolenaar 
534d7ccc4d8SBram Moolenaar 	// Draw by IDWriteFactory (without color emoji)
535d7ccc4d8SBram Moolenaar 	pDWC_->mRT->DrawGlyphRun(
536d7ccc4d8SBram Moolenaar 		D2D1::Point2F(
537d7ccc4d8SBram Moolenaar 		    baselineOriginX + context->offsetX,
538d7ccc4d8SBram Moolenaar 		    baselineOriginY),
539d7ccc4d8SBram Moolenaar 		&adjustedGlyphRun,
540d7ccc4d8SBram Moolenaar 		pDWC_->SolidBrush(context->color),
541d7ccc4d8SBram Moolenaar 		DWRITE_MEASURING_MODE_NATURAL);
542d7ccc4d8SBram Moolenaar 	return S_OK;
543d7ccc4d8SBram Moolenaar     }
544d7ccc4d8SBram Moolenaar 
545b5a7a8b5SBram Moolenaar public:
546b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, AddRef) ()
547b5a7a8b5SBram Moolenaar     {
548b5a7a8b5SBram Moolenaar 	return InterlockedIncrement(&cRefCount_);
549b5a7a8b5SBram Moolenaar     }
550b5a7a8b5SBram Moolenaar 
551b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, Release) ()
552b5a7a8b5SBram Moolenaar     {
553b5a7a8b5SBram Moolenaar 	long newCount = InterlockedDecrement(&cRefCount_);
554b5a7a8b5SBram Moolenaar 
555b5a7a8b5SBram Moolenaar 	if (newCount == 0)
556b5a7a8b5SBram Moolenaar 	{
557b5a7a8b5SBram Moolenaar 	    delete this;
558b5a7a8b5SBram Moolenaar 	    return 0;
559b5a7a8b5SBram Moolenaar 	}
560b5a7a8b5SBram Moolenaar 	return newCount;
561b5a7a8b5SBram Moolenaar     }
562b5a7a8b5SBram Moolenaar 
563b5a7a8b5SBram Moolenaar     IFACEMETHOD(QueryInterface)(
564b5a7a8b5SBram Moolenaar 	IID const& riid,
565b5a7a8b5SBram Moolenaar 	void** ppvObject)
566b5a7a8b5SBram Moolenaar     {
567b5a7a8b5SBram Moolenaar 	if (__uuidof(IDWriteTextRenderer) == riid)
568b5a7a8b5SBram Moolenaar 	{
569b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
570b5a7a8b5SBram Moolenaar 	}
571b5a7a8b5SBram Moolenaar 	else if (__uuidof(IDWritePixelSnapping) == riid)
572b5a7a8b5SBram Moolenaar 	{
573b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
574b5a7a8b5SBram Moolenaar 	}
575b5a7a8b5SBram Moolenaar 	else if (__uuidof(IUnknown) == riid)
576b5a7a8b5SBram Moolenaar 	{
577b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
578b5a7a8b5SBram Moolenaar 	}
579b5a7a8b5SBram Moolenaar 	else
580b5a7a8b5SBram Moolenaar 	{
581b5a7a8b5SBram Moolenaar 	    *ppvObject = NULL;
582b5a7a8b5SBram Moolenaar 	    return E_FAIL;
583b5a7a8b5SBram Moolenaar 	}
584b5a7a8b5SBram Moolenaar 
585b5a7a8b5SBram Moolenaar 	return S_OK;
586b5a7a8b5SBram Moolenaar     }
587b5a7a8b5SBram Moolenaar 
588b5a7a8b5SBram Moolenaar private:
5890106b4b8SBram Moolenaar     long cRefCount_;
590d7ccc4d8SBram Moolenaar     DWriteContext* pDWC_;
591b5a7a8b5SBram Moolenaar };
592b5a7a8b5SBram Moolenaar 
593b5a7a8b5SBram Moolenaar DWriteContext::DWriteContext() :
594d7ccc4d8SBram Moolenaar     mHDC(NULL),
59592467d33SBram Moolenaar     mBindRect(),
59692467d33SBram Moolenaar     mDMode(DM_GDI),
59792467d33SBram Moolenaar     mInteropHDC(NULL),
598b5a7a8b5SBram Moolenaar     mDrawing(false),
599d7ccc4d8SBram Moolenaar     mFallbackDC(false),
600b5a7a8b5SBram Moolenaar     mD2D1Factory(NULL),
601b5a7a8b5SBram Moolenaar     mRT(NULL),
60292467d33SBram Moolenaar     mGDIRT(NULL),
603b5a7a8b5SBram Moolenaar     mBrush(NULL),
604a338adcfSBram Moolenaar     mBitmap(NULL),
605b5a7a8b5SBram Moolenaar     mDWriteFactory(NULL),
6067f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
607d7ccc4d8SBram Moolenaar     mDWriteFactory2(NULL),
6087f88b65fSBram Moolenaar #endif
609b5a7a8b5SBram Moolenaar     mGdiInterop(NULL),
610b5a7a8b5SBram Moolenaar     mRenderingParams(NULL),
611d7ccc4d8SBram Moolenaar     mFontCache(8),
612b5a7a8b5SBram Moolenaar     mTextFormat(NULL),
613b5a7a8b5SBram Moolenaar     mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
614b5a7a8b5SBram Moolenaar     mFontStyle(DWRITE_FONT_STYLE_NORMAL),
615b5a7a8b5SBram Moolenaar     mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
616b5a7a8b5SBram Moolenaar {
617b5a7a8b5SBram Moolenaar     HRESULT hr;
618b5a7a8b5SBram Moolenaar 
619b5a7a8b5SBram Moolenaar     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
620b5a7a8b5SBram Moolenaar 	    __uuidof(ID2D1Factory), NULL,
621b5a7a8b5SBram Moolenaar 	    reinterpret_cast<void**>(&mD2D1Factory));
622b5a7a8b5SBram Moolenaar     _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
623b5a7a8b5SBram Moolenaar 
624b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
625b5a7a8b5SBram Moolenaar     {
626b5a7a8b5SBram Moolenaar 	hr = DWriteCreateFactory(
627b5a7a8b5SBram Moolenaar 		DWRITE_FACTORY_TYPE_SHARED,
628b5a7a8b5SBram Moolenaar 		__uuidof(IDWriteFactory),
629b5a7a8b5SBram Moolenaar 		reinterpret_cast<IUnknown**>(&mDWriteFactory));
630b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
631b5a7a8b5SBram Moolenaar 		mDWriteFactory);
632b5a7a8b5SBram Moolenaar     }
633b5a7a8b5SBram Moolenaar 
6347f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
635b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
636b5a7a8b5SBram Moolenaar     {
637d7ccc4d8SBram Moolenaar 	DWriteCreateFactory(
638d7ccc4d8SBram Moolenaar 		DWRITE_FACTORY_TYPE_SHARED,
639d7ccc4d8SBram Moolenaar 		__uuidof(IDWriteFactory2),
640d7ccc4d8SBram Moolenaar 		reinterpret_cast<IUnknown**>(&mDWriteFactory2));
641d7ccc4d8SBram Moolenaar 	_RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
642d7ccc4d8SBram Moolenaar     }
6437f88b65fSBram Moolenaar #endif
644d7ccc4d8SBram Moolenaar 
645d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
646d7ccc4d8SBram Moolenaar     {
647b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
648b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
649b5a7a8b5SBram Moolenaar     }
650b5a7a8b5SBram Moolenaar 
651b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
652b5a7a8b5SBram Moolenaar     {
653b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
654b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
655b5a7a8b5SBram Moolenaar 		mRenderingParams);
656b5a7a8b5SBram Moolenaar     }
657b5a7a8b5SBram Moolenaar }
658b5a7a8b5SBram Moolenaar 
659b5a7a8b5SBram Moolenaar DWriteContext::~DWriteContext()
660b5a7a8b5SBram Moolenaar {
661b5a7a8b5SBram Moolenaar     SafeRelease(&mTextFormat);
662b5a7a8b5SBram Moolenaar     SafeRelease(&mRenderingParams);
663b5a7a8b5SBram Moolenaar     SafeRelease(&mGdiInterop);
664b5a7a8b5SBram Moolenaar     SafeRelease(&mDWriteFactory);
6657f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
666d7ccc4d8SBram Moolenaar     SafeRelease(&mDWriteFactory2);
6677f88b65fSBram Moolenaar #endif
668a338adcfSBram Moolenaar     SafeRelease(&mBitmap);
669b5a7a8b5SBram Moolenaar     SafeRelease(&mBrush);
67092467d33SBram Moolenaar     SafeRelease(&mGDIRT);
671b5a7a8b5SBram Moolenaar     SafeRelease(&mRT);
672b5a7a8b5SBram Moolenaar     SafeRelease(&mD2D1Factory);
673b5a7a8b5SBram Moolenaar }
674b5a7a8b5SBram Moolenaar 
675b5a7a8b5SBram Moolenaar     HRESULT
67692467d33SBram Moolenaar DWriteContext::CreateDeviceResources()
67792467d33SBram Moolenaar {
67892467d33SBram Moolenaar     HRESULT hr;
67992467d33SBram Moolenaar 
68092467d33SBram Moolenaar     if (mRT != NULL)
68192467d33SBram Moolenaar 	return S_OK;
68292467d33SBram Moolenaar 
68392467d33SBram Moolenaar     D2D1_RENDER_TARGET_PROPERTIES props = {
68492467d33SBram Moolenaar 	D2D1_RENDER_TARGET_TYPE_DEFAULT,
68592467d33SBram Moolenaar 	{ DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
68692467d33SBram Moolenaar 	0, 0,
68792467d33SBram Moolenaar 	D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
68892467d33SBram Moolenaar 	D2D1_FEATURE_LEVEL_DEFAULT
68992467d33SBram Moolenaar     };
69092467d33SBram Moolenaar     hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
69192467d33SBram Moolenaar     _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
69292467d33SBram Moolenaar 
69392467d33SBram Moolenaar     if (SUCCEEDED(hr))
69492467d33SBram Moolenaar     {
69592467d33SBram Moolenaar 	// This always succeeds.
69692467d33SBram Moolenaar 	mRT->QueryInterface(
69792467d33SBram Moolenaar 		__uuidof(ID2D1GdiInteropRenderTarget),
69892467d33SBram Moolenaar 		reinterpret_cast<void**>(&mGDIRT));
69992467d33SBram Moolenaar 	_RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT);
70092467d33SBram Moolenaar     }
70192467d33SBram Moolenaar 
70292467d33SBram Moolenaar     if (SUCCEEDED(hr))
70392467d33SBram Moolenaar     {
70492467d33SBram Moolenaar 	hr = mRT->CreateSolidColorBrush(
70592467d33SBram Moolenaar 		D2D1::ColorF(D2D1::ColorF::Black),
70692467d33SBram Moolenaar 		&mBrush);
70792467d33SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
70892467d33SBram Moolenaar     }
70992467d33SBram Moolenaar 
71092467d33SBram Moolenaar     if (SUCCEEDED(hr))
711a338adcfSBram Moolenaar 	Rebind();
71292467d33SBram Moolenaar 
71392467d33SBram Moolenaar     return hr;
71492467d33SBram Moolenaar }
71592467d33SBram Moolenaar 
71692467d33SBram Moolenaar     void
71792467d33SBram Moolenaar DWriteContext::DiscardDeviceResources()
71892467d33SBram Moolenaar {
719a338adcfSBram Moolenaar     SafeRelease(&mBitmap);
72092467d33SBram Moolenaar     SafeRelease(&mBrush);
72192467d33SBram Moolenaar     SafeRelease(&mGDIRT);
72292467d33SBram Moolenaar     SafeRelease(&mRT);
72392467d33SBram Moolenaar }
72492467d33SBram Moolenaar 
72592467d33SBram Moolenaar     HRESULT
726d7ccc4d8SBram Moolenaar DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
727d7ccc4d8SBram Moolenaar 	IDWriteTextFormat **ppTextFormat)
728b5a7a8b5SBram Moolenaar {
729d7ccc4d8SBram Moolenaar     // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
730b5a7a8b5SBram Moolenaar     HRESULT hr = S_OK;
731d7ccc4d8SBram Moolenaar     IDWriteTextFormat *pTextFormat = NULL;
732b5a7a8b5SBram Moolenaar 
733b5a7a8b5SBram Moolenaar     IDWriteFont *font = NULL;
734b5a7a8b5SBram Moolenaar     IDWriteFontFamily *fontFamily = NULL;
735b5a7a8b5SBram Moolenaar     IDWriteLocalizedStrings *localizedFamilyNames = NULL;
736d7ccc4d8SBram Moolenaar     float fontSize = 0;
737b5a7a8b5SBram Moolenaar 
738b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
739b5a7a8b5SBram Moolenaar     {
740b5a7a8b5SBram Moolenaar 	hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
741b5a7a8b5SBram Moolenaar     }
742b5a7a8b5SBram Moolenaar 
743b5a7a8b5SBram Moolenaar     // Get the font family to which this font belongs.
744b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
745b5a7a8b5SBram Moolenaar     {
746b5a7a8b5SBram Moolenaar 	hr = font->GetFontFamily(&fontFamily);
747b5a7a8b5SBram Moolenaar     }
748b5a7a8b5SBram Moolenaar 
749b5a7a8b5SBram Moolenaar     // Get the family names. This returns an object that encapsulates one or
750b5a7a8b5SBram Moolenaar     // more names with the same meaning but in different languages.
751b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
752b5a7a8b5SBram Moolenaar     {
753b5a7a8b5SBram Moolenaar 	hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
754b5a7a8b5SBram Moolenaar     }
755b5a7a8b5SBram Moolenaar 
756b5a7a8b5SBram Moolenaar     // Get the family name at index zero. If we were going to display the name
757b5a7a8b5SBram Moolenaar     // we'd want to try to find one that matched the use locale, but for
758b5a7a8b5SBram Moolenaar     // purposes of creating a text format object any language will do.
759b5a7a8b5SBram Moolenaar 
760b5a7a8b5SBram Moolenaar     wchar_t familyName[100];
761b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
762b5a7a8b5SBram Moolenaar     {
763b5a7a8b5SBram Moolenaar 	hr = localizedFamilyNames->GetString(0, familyName,
764b5a7a8b5SBram Moolenaar 		ARRAYSIZE(familyName));
765b5a7a8b5SBram Moolenaar     }
766b5a7a8b5SBram Moolenaar 
767b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
768b5a7a8b5SBram Moolenaar     {
769d7ccc4d8SBram Moolenaar 	// Use lfHeight of the LOGFONT as font size.
770d7ccc4d8SBram Moolenaar 	fontSize = float(logFont.lfHeight);
771d7ccc4d8SBram Moolenaar 
772b5a7a8b5SBram Moolenaar 	if (fontSize < 0)
773b5a7a8b5SBram Moolenaar 	{
774b5a7a8b5SBram Moolenaar 	    // Negative lfHeight represents the size of the em unit.
775b5a7a8b5SBram Moolenaar 	    fontSize = -fontSize;
776b5a7a8b5SBram Moolenaar 	}
777b5a7a8b5SBram Moolenaar 	else
778b5a7a8b5SBram Moolenaar 	{
779b5a7a8b5SBram Moolenaar 	    // Positive lfHeight represents the cell height (ascent +
780b5a7a8b5SBram Moolenaar 	    // descent).
781b5a7a8b5SBram Moolenaar 	    DWRITE_FONT_METRICS fontMetrics;
782b5a7a8b5SBram Moolenaar 	    font->GetMetrics(&fontMetrics);
783b5a7a8b5SBram Moolenaar 
784b5a7a8b5SBram Moolenaar 	    // Convert the cell height (ascent + descent) from design units
785b5a7a8b5SBram Moolenaar 	    // to ems.
786b5a7a8b5SBram Moolenaar 	    float cellHeight = static_cast<float>(
787b5a7a8b5SBram Moolenaar 		    fontMetrics.ascent + fontMetrics.descent)
788b5a7a8b5SBram Moolenaar 		/ fontMetrics.designUnitsPerEm;
789b5a7a8b5SBram Moolenaar 
790b5a7a8b5SBram Moolenaar 	    // Divide the font size by the cell height to get the font em
791b5a7a8b5SBram Moolenaar 	    // size.
792b5a7a8b5SBram Moolenaar 	    fontSize /= cellHeight;
793b5a7a8b5SBram Moolenaar 	}
794b5a7a8b5SBram Moolenaar     }
795b5a7a8b5SBram Moolenaar 
796b5a7a8b5SBram Moolenaar     // The text format includes a locale name. Ideally, this would be the
797b5a7a8b5SBram Moolenaar     // language of the text, which may or may not be the same as the primary
798b5a7a8b5SBram Moolenaar     // language of the user. However, for our purposes the user locale will do.
799b5a7a8b5SBram Moolenaar     wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
800b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
801b5a7a8b5SBram Moolenaar     {
802b5a7a8b5SBram Moolenaar 	if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
803b5a7a8b5SBram Moolenaar 	    hr = HRESULT_FROM_WIN32(GetLastError());
804b5a7a8b5SBram Moolenaar     }
805b5a7a8b5SBram Moolenaar 
806b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
807b5a7a8b5SBram Moolenaar     {
808b5a7a8b5SBram Moolenaar 	// Create the text format object.
809b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateTextFormat(
810b5a7a8b5SBram Moolenaar 		familyName,
811b5a7a8b5SBram Moolenaar 		NULL, // no custom font collection
812b5a7a8b5SBram Moolenaar 		font->GetWeight(),
813b5a7a8b5SBram Moolenaar 		font->GetStyle(),
814b5a7a8b5SBram Moolenaar 		font->GetStretch(),
815b5a7a8b5SBram Moolenaar 		fontSize,
816b5a7a8b5SBram Moolenaar 		localeName,
817d7ccc4d8SBram Moolenaar 		&pTextFormat);
818b5a7a8b5SBram Moolenaar     }
819b5a7a8b5SBram Moolenaar 
820b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
821d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
822d7ccc4d8SBram Moolenaar 
823d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
824d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetParagraphAlignment(
825*1f271efbSBram Moolenaar 		DWRITE_PARAGRAPH_ALIGNMENT_FAR);
826d7ccc4d8SBram Moolenaar 
827d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
828d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
829b5a7a8b5SBram Moolenaar 
830b5a7a8b5SBram Moolenaar     SafeRelease(&localizedFamilyNames);
831b5a7a8b5SBram Moolenaar     SafeRelease(&fontFamily);
832b5a7a8b5SBram Moolenaar     SafeRelease(&font);
833b5a7a8b5SBram Moolenaar 
834d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
835d7ccc4d8SBram Moolenaar 	*ppTextFormat = pTextFormat;
836d7ccc4d8SBram Moolenaar     else
837d7ccc4d8SBram Moolenaar 	SafeRelease(&pTextFormat);
838d7ccc4d8SBram Moolenaar 
839d7ccc4d8SBram Moolenaar     return hr;
840d7ccc4d8SBram Moolenaar }
841d7ccc4d8SBram Moolenaar 
842d7ccc4d8SBram Moolenaar     HRESULT
843d7ccc4d8SBram Moolenaar DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
844d7ccc4d8SBram Moolenaar {
845d7ccc4d8SBram Moolenaar     HRESULT hr = S_OK;
846d7ccc4d8SBram Moolenaar     IDWriteTextFormat *pTextFormat = NULL;
847d7ccc4d8SBram Moolenaar 
848d7ccc4d8SBram Moolenaar     hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
849d7ccc4d8SBram Moolenaar 
850d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
851d7ccc4d8SBram Moolenaar     {
852d7ccc4d8SBram Moolenaar 	SafeRelease(&mTextFormat);
853d7ccc4d8SBram Moolenaar 	mTextFormat = pTextFormat;
854d7ccc4d8SBram Moolenaar 	mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
855d7ccc4d8SBram Moolenaar 	mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
856d7ccc4d8SBram Moolenaar 	    : DWRITE_FONT_STYLE_NORMAL;
857d7ccc4d8SBram Moolenaar     }
858d7ccc4d8SBram Moolenaar 
859b5a7a8b5SBram Moolenaar     return hr;
860b5a7a8b5SBram Moolenaar }
861b5a7a8b5SBram Moolenaar 
862b5a7a8b5SBram Moolenaar     void
863b5a7a8b5SBram Moolenaar DWriteContext::SetFont(HFONT hFont)
864b5a7a8b5SBram Moolenaar {
865d7ccc4d8SBram Moolenaar     FontCache::Item item;
866d7ccc4d8SBram Moolenaar     if (mFontCache.get(hFont, item))
867b5a7a8b5SBram Moolenaar     {
868d7ccc4d8SBram Moolenaar 	if (item.pTextFormat != NULL)
869d7ccc4d8SBram Moolenaar 	{
870d7ccc4d8SBram Moolenaar 	    item.pTextFormat->AddRef();
871d7ccc4d8SBram Moolenaar 	    SafeRelease(&mTextFormat);
872d7ccc4d8SBram Moolenaar 	    mTextFormat = item.pTextFormat;
873d7ccc4d8SBram Moolenaar 	    mFontWeight = item.fontWeight;
874d7ccc4d8SBram Moolenaar 	    mFontStyle = item.fontStyle;
875d7ccc4d8SBram Moolenaar 	    mFallbackDC = false;
876d7ccc4d8SBram Moolenaar 	}
877d7ccc4d8SBram Moolenaar 	else
878d7ccc4d8SBram Moolenaar 	    mFallbackDC = true;
879d7ccc4d8SBram Moolenaar 	return;
880d7ccc4d8SBram Moolenaar     }
881d7ccc4d8SBram Moolenaar 
882d7ccc4d8SBram Moolenaar     HRESULT hr = E_FAIL;
883b5a7a8b5SBram Moolenaar     LOGFONTW lf;
884b5a7a8b5SBram Moolenaar     if (GetObjectW(hFont, sizeof(lf), &lf))
885d7ccc4d8SBram Moolenaar 	hr = SetFontByLOGFONT(lf);
886d7ccc4d8SBram Moolenaar 
887d7ccc4d8SBram Moolenaar     item.hFont = hFont;
888d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
889b5a7a8b5SBram Moolenaar     {
890d7ccc4d8SBram Moolenaar 	item.pTextFormat = mTextFormat;
891d7ccc4d8SBram Moolenaar 	item.fontWeight = mFontWeight;
892d7ccc4d8SBram Moolenaar 	item.fontStyle = mFontStyle;
89392467d33SBram Moolenaar 	mFallbackDC = false;
894b5a7a8b5SBram Moolenaar     }
89592467d33SBram Moolenaar     else
89692467d33SBram Moolenaar 	mFallbackDC = true;
897d7ccc4d8SBram Moolenaar     mFontCache.put(item);
898b5a7a8b5SBram Moolenaar }
899b5a7a8b5SBram Moolenaar 
900b5a7a8b5SBram Moolenaar     void
901a338adcfSBram Moolenaar DWriteContext::Rebind()
902a338adcfSBram Moolenaar {
903a338adcfSBram Moolenaar     SafeRelease(&mBitmap);
904a338adcfSBram Moolenaar 
905a338adcfSBram Moolenaar     mRT->BindDC(mHDC, &mBindRect);
906a338adcfSBram Moolenaar     mRT->SetTransform(D2D1::IdentityMatrix());
907a338adcfSBram Moolenaar 
908a338adcfSBram Moolenaar     D2D1_BITMAP_PROPERTIES props = {
909a338adcfSBram Moolenaar 	{DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE},
910a338adcfSBram Moolenaar 	96.0f, 96.0f
911a338adcfSBram Moolenaar     };
912a338adcfSBram Moolenaar     mRT->CreateBitmap(
913a338adcfSBram Moolenaar 	    D2D1::SizeU(mBindRect.right - mBindRect.left,
914a338adcfSBram Moolenaar 		mBindRect.bottom - mBindRect.top),
915a338adcfSBram Moolenaar 	    props, &mBitmap);
916a338adcfSBram Moolenaar }
917a338adcfSBram Moolenaar 
918a338adcfSBram Moolenaar     void
91992467d33SBram Moolenaar DWriteContext::BindDC(HDC hdc, const RECT *rect)
920b5a7a8b5SBram Moolenaar {
921d7ccc4d8SBram Moolenaar     mHDC = hdc;
92292467d33SBram Moolenaar     mBindRect = *rect;
923a338adcfSBram Moolenaar 
924a338adcfSBram Moolenaar     if (mRT == NULL)
925a338adcfSBram Moolenaar 	CreateDeviceResources();
926a338adcfSBram Moolenaar     else
927a338adcfSBram Moolenaar     {
928a338adcfSBram Moolenaar 	Flush();
929a338adcfSBram Moolenaar 	Rebind();
930a338adcfSBram Moolenaar     }
931b5a7a8b5SBram Moolenaar }
932b5a7a8b5SBram Moolenaar 
93392467d33SBram Moolenaar     HRESULT
93492467d33SBram Moolenaar DWriteContext::SetDrawingMode(DrawingMode mode)
935b5a7a8b5SBram Moolenaar {
93692467d33SBram Moolenaar     HRESULT hr = S_OK;
93792467d33SBram Moolenaar 
93892467d33SBram Moolenaar     switch (mode)
939b5a7a8b5SBram Moolenaar     {
94092467d33SBram Moolenaar 	default:
94192467d33SBram Moolenaar 	case DM_GDI:
94292467d33SBram Moolenaar 	    if (mInteropHDC != NULL)
94392467d33SBram Moolenaar 	    {
94492467d33SBram Moolenaar 		mGDIRT->ReleaseDC(NULL);
94592467d33SBram Moolenaar 		mInteropHDC = NULL;
94692467d33SBram Moolenaar 	    }
94792467d33SBram Moolenaar 	    if (mDrawing)
94892467d33SBram Moolenaar 	    {
94992467d33SBram Moolenaar 		hr = mRT->EndDraw();
95092467d33SBram Moolenaar 		if (hr == D2DERR_RECREATE_TARGET)
95192467d33SBram Moolenaar 		{
95292467d33SBram Moolenaar 		    hr = S_OK;
95392467d33SBram Moolenaar 		    DiscardDeviceResources();
95492467d33SBram Moolenaar 		    CreateDeviceResources();
95592467d33SBram Moolenaar 		}
95692467d33SBram Moolenaar 		mDrawing = false;
95792467d33SBram Moolenaar 	    }
95892467d33SBram Moolenaar 	    break;
95992467d33SBram Moolenaar 
96092467d33SBram Moolenaar 	case DM_DIRECTX:
96192467d33SBram Moolenaar 	    if (mInteropHDC != NULL)
96292467d33SBram Moolenaar 	    {
96392467d33SBram Moolenaar 		mGDIRT->ReleaseDC(NULL);
96492467d33SBram Moolenaar 		mInteropHDC = NULL;
96592467d33SBram Moolenaar 	    }
96692467d33SBram Moolenaar 	    else if (mDrawing == false)
96792467d33SBram Moolenaar 	    {
96892467d33SBram Moolenaar 		CreateDeviceResources();
969d7ccc4d8SBram Moolenaar 		mRT->BeginDraw();
970d7ccc4d8SBram Moolenaar 		mDrawing = true;
971d7ccc4d8SBram Moolenaar 	    }
97292467d33SBram Moolenaar 	    break;
97392467d33SBram Moolenaar 
97492467d33SBram Moolenaar 	case DM_INTEROP:
97592467d33SBram Moolenaar 	    if (mDrawing == false)
97692467d33SBram Moolenaar 	    {
97792467d33SBram Moolenaar 		CreateDeviceResources();
97892467d33SBram Moolenaar 		mRT->BeginDraw();
97992467d33SBram Moolenaar 		mDrawing = true;
98092467d33SBram Moolenaar 	    }
98192467d33SBram Moolenaar 	    if (mInteropHDC == NULL)
98292467d33SBram Moolenaar 		hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC);
98392467d33SBram Moolenaar 	    break;
98492467d33SBram Moolenaar     }
98592467d33SBram Moolenaar     mDMode = mode;
98692467d33SBram Moolenaar     return hr;
987d7ccc4d8SBram Moolenaar }
988d7ccc4d8SBram Moolenaar 
989d7ccc4d8SBram Moolenaar     ID2D1Brush*
990d7ccc4d8SBram Moolenaar DWriteContext::SolidBrush(COLORREF color)
991d7ccc4d8SBram Moolenaar {
992d7ccc4d8SBram Moolenaar     mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
993d7ccc4d8SBram Moolenaar 		UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
994d7ccc4d8SBram Moolenaar     return mBrush;
995d7ccc4d8SBram Moolenaar }
996d7ccc4d8SBram Moolenaar 
997d7ccc4d8SBram Moolenaar     void
998d7ccc4d8SBram Moolenaar DWriteContext::DrawText(const WCHAR *text, int len,
999d7ccc4d8SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color,
100092467d33SBram Moolenaar 	UINT fuOptions, const RECT *lprc, const INT *lpDx)
1001d7ccc4d8SBram Moolenaar {
1002d7ccc4d8SBram Moolenaar     if (mFallbackDC)
1003d7ccc4d8SBram Moolenaar     {
100492467d33SBram Moolenaar 	// Fall back to GDI rendering.
100592467d33SBram Moolenaar 	HRESULT hr = SetDrawingMode(DM_INTEROP);
100692467d33SBram Moolenaar 	if (SUCCEEDED(hr))
100792467d33SBram Moolenaar 	{
100892467d33SBram Moolenaar 	    HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT);
100992467d33SBram Moolenaar 	    HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont);
101092467d33SBram Moolenaar 	    ::SetTextColor(mInteropHDC, color);
101192467d33SBram Moolenaar 	    ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC));
101292467d33SBram Moolenaar 	    ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx);
101392467d33SBram Moolenaar 	    ::SelectObject(mInteropHDC, hOldFont);
101492467d33SBram Moolenaar 	}
1015d7ccc4d8SBram Moolenaar 	return;
1016d7ccc4d8SBram Moolenaar     }
1017d7ccc4d8SBram Moolenaar 
1018d7ccc4d8SBram Moolenaar     HRESULT hr;
1019b5a7a8b5SBram Moolenaar     IDWriteTextLayout *textLayout = NULL;
1020b5a7a8b5SBram Moolenaar 
102192467d33SBram Moolenaar     SetDrawingMode(DM_DIRECTX);
102292467d33SBram Moolenaar 
1023d7ccc4d8SBram Moolenaar     hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
1024d7ccc4d8SBram Moolenaar 	    FLOAT(w), FLOAT(h), &textLayout);
1025b5a7a8b5SBram Moolenaar 
1026b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
1027b5a7a8b5SBram Moolenaar     {
1028d7ccc4d8SBram Moolenaar 	DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
1029b5a7a8b5SBram Moolenaar 	textLayout->SetFontWeight(mFontWeight, textRange);
1030b5a7a8b5SBram Moolenaar 	textLayout->SetFontStyle(mFontStyle, textRange);
1031b5a7a8b5SBram Moolenaar 
1032d7ccc4d8SBram Moolenaar 	TextRenderer renderer(this);
1033d7ccc4d8SBram Moolenaar 	TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
10347f88b65fSBram Moolenaar 	textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y) - 0.5f);
1035b5a7a8b5SBram Moolenaar     }
1036b5a7a8b5SBram Moolenaar 
1037b5a7a8b5SBram Moolenaar     SafeRelease(&textLayout);
1038b5a7a8b5SBram Moolenaar }
1039b5a7a8b5SBram Moolenaar 
1040d7ccc4d8SBram Moolenaar     void
104192467d33SBram Moolenaar DWriteContext::FillRect(const RECT *rc, COLORREF color)
1042d7ccc4d8SBram Moolenaar {
104392467d33SBram Moolenaar     if (mDMode == DM_INTEROP)
104492467d33SBram Moolenaar     {
104592467d33SBram Moolenaar 	// GDI functions are used before this call.  Keep using GDI.
104692467d33SBram Moolenaar 	// (Switching to Direct2D causes terrible slowdown.)
104792467d33SBram Moolenaar 	HBRUSH hbr = ::CreateSolidBrush(color);
104892467d33SBram Moolenaar 	::FillRect(mInteropHDC, rc, hbr);
104992467d33SBram Moolenaar 	::DeleteObject(HGDIOBJ(hbr));
105092467d33SBram Moolenaar     }
105192467d33SBram Moolenaar     else
105292467d33SBram Moolenaar     {
105392467d33SBram Moolenaar 	SetDrawingMode(DM_DIRECTX);
1054d7ccc4d8SBram Moolenaar 	mRT->FillRectangle(
1055d7ccc4d8SBram Moolenaar 		D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
1056d7ccc4d8SBram Moolenaar 		    FLOAT(rc->right), FLOAT(rc->bottom)),
1057d7ccc4d8SBram Moolenaar 		SolidBrush(color));
1058b5a7a8b5SBram Moolenaar     }
105992467d33SBram Moolenaar }
106092467d33SBram Moolenaar 
106192467d33SBram Moolenaar     void
106292467d33SBram Moolenaar DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
106392467d33SBram Moolenaar {
106492467d33SBram Moolenaar     if (mDMode == DM_INTEROP)
106592467d33SBram Moolenaar     {
106692467d33SBram Moolenaar 	// GDI functions are used before this call.  Keep using GDI.
106792467d33SBram Moolenaar 	// (Switching to Direct2D causes terrible slowdown.)
106892467d33SBram Moolenaar 	HPEN hpen = ::CreatePen(PS_SOLID, 1, color);
106992467d33SBram Moolenaar 	HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen));
107092467d33SBram Moolenaar 	::MoveToEx(mInteropHDC, x1, y1, NULL);
107192467d33SBram Moolenaar 	::LineTo(mInteropHDC, x2, y2);
107292467d33SBram Moolenaar 	::SelectObject(mInteropHDC, old_pen);
107392467d33SBram Moolenaar 	::DeleteObject(HGDIOBJ(hpen));
107492467d33SBram Moolenaar     }
107592467d33SBram Moolenaar     else
107692467d33SBram Moolenaar     {
107792467d33SBram Moolenaar 	SetDrawingMode(DM_DIRECTX);
107892467d33SBram Moolenaar 	mRT->DrawLine(
107992467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f),
108092467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f),
108192467d33SBram Moolenaar 		SolidBrush(color));
108292467d33SBram Moolenaar     }
108392467d33SBram Moolenaar }
108492467d33SBram Moolenaar 
108592467d33SBram Moolenaar     void
108692467d33SBram Moolenaar DWriteContext::SetPixel(int x, int y, COLORREF color)
108792467d33SBram Moolenaar {
108892467d33SBram Moolenaar     if (mDMode == DM_INTEROP)
108992467d33SBram Moolenaar     {
109092467d33SBram Moolenaar 	// GDI functions are used before this call.  Keep using GDI.
109192467d33SBram Moolenaar 	// (Switching to Direct2D causes terrible slowdown.)
109292467d33SBram Moolenaar 	::SetPixel(mInteropHDC, x, y, color);
109392467d33SBram Moolenaar     }
109492467d33SBram Moolenaar     else
109592467d33SBram Moolenaar     {
109692467d33SBram Moolenaar 	SetDrawingMode(DM_DIRECTX);
109792467d33SBram Moolenaar 	// Direct2D doesn't have SetPixel API.  Use DrawLine instead.
109892467d33SBram Moolenaar 	mRT->DrawLine(
109992467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f),
110092467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f),
110192467d33SBram Moolenaar 		SolidBrush(color));
110292467d33SBram Moolenaar     }
110392467d33SBram Moolenaar }
1104b5a7a8b5SBram Moolenaar 
1105d7ccc4d8SBram Moolenaar     void
1106a338adcfSBram Moolenaar DWriteContext::Scroll(int x, int y, const RECT *rc)
1107a338adcfSBram Moolenaar {
1108a338adcfSBram Moolenaar     SetDrawingMode(DM_DIRECTX);
1109a338adcfSBram Moolenaar     mRT->Flush();
1110a338adcfSBram Moolenaar 
1111a338adcfSBram Moolenaar     D2D1_RECT_U srcRect;
1112a338adcfSBram Moolenaar     D2D1_POINT_2U destPoint;
1113a338adcfSBram Moolenaar     if (x >= 0)
1114a338adcfSBram Moolenaar     {
1115a338adcfSBram Moolenaar 	srcRect.left = rc->left;
1116a338adcfSBram Moolenaar 	srcRect.right = rc->right - x;
1117a338adcfSBram Moolenaar 	destPoint.x = rc->left + x;
1118a338adcfSBram Moolenaar     }
1119a338adcfSBram Moolenaar     else
1120a338adcfSBram Moolenaar     {
1121a338adcfSBram Moolenaar 	srcRect.left = rc->left - x;
1122a338adcfSBram Moolenaar 	srcRect.right = rc->right;
1123a338adcfSBram Moolenaar 	destPoint.x = rc->left;
1124a338adcfSBram Moolenaar     }
1125a338adcfSBram Moolenaar     if (y >= 0)
1126a338adcfSBram Moolenaar     {
1127a338adcfSBram Moolenaar 	srcRect.top = rc->top;
1128a338adcfSBram Moolenaar 	srcRect.bottom = rc->bottom - y;
1129a338adcfSBram Moolenaar 	destPoint.y = rc->top + y;
1130a338adcfSBram Moolenaar     }
1131a338adcfSBram Moolenaar     else
1132a338adcfSBram Moolenaar     {
1133a338adcfSBram Moolenaar 	srcRect.top = rc->top - y;
1134a338adcfSBram Moolenaar 	srcRect.bottom = rc->bottom;
1135a338adcfSBram Moolenaar 	destPoint.y = rc->top;
1136a338adcfSBram Moolenaar     }
1137a338adcfSBram Moolenaar     mBitmap->CopyFromRenderTarget(&destPoint, mRT, &srcRect);
1138a338adcfSBram Moolenaar 
1139a338adcfSBram Moolenaar     D2D1_RECT_F destRect = {
1140a338adcfSBram Moolenaar 	    FLOAT(destPoint.x), FLOAT(destPoint.y),
1141a338adcfSBram Moolenaar 	    FLOAT(destPoint.x + srcRect.right - srcRect.left),
1142a338adcfSBram Moolenaar 	    FLOAT(destPoint.y + srcRect.bottom - srcRect.top)
1143a338adcfSBram Moolenaar     };
1144a338adcfSBram Moolenaar     mRT->DrawBitmap(mBitmap, destRect, 1.0F,
1145a338adcfSBram Moolenaar 	    D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, destRect);
1146a338adcfSBram Moolenaar }
1147a338adcfSBram Moolenaar 
1148a338adcfSBram Moolenaar     void
1149d7ccc4d8SBram Moolenaar DWriteContext::Flush()
1150b5a7a8b5SBram Moolenaar {
115192467d33SBram Moolenaar     SetDrawingMode(DM_GDI);
1152b5a7a8b5SBram Moolenaar }
1153b5a7a8b5SBram Moolenaar 
1154b5a7a8b5SBram Moolenaar     void
1155b5a7a8b5SBram Moolenaar DWriteContext::SetRenderingParams(
1156b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
1157b5a7a8b5SBram Moolenaar {
1158b5a7a8b5SBram Moolenaar     if (mDWriteFactory == NULL)
1159b5a7a8b5SBram Moolenaar 	return;
1160b5a7a8b5SBram Moolenaar 
1161b5a7a8b5SBram Moolenaar     IDWriteRenderingParams *renderingParams = NULL;
1162b5a7a8b5SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
1163b5a7a8b5SBram Moolenaar 	D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
1164b5a7a8b5SBram Moolenaar     HRESULT hr;
1165b5a7a8b5SBram Moolenaar     if (params != NULL)
1166b5a7a8b5SBram Moolenaar     {
1167b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
1168b5a7a8b5SBram Moolenaar 		params->enhancedContrast, params->clearTypeLevel,
1169b5a7a8b5SBram Moolenaar 		ToPixelGeometry(params->pixelGeometry),
1170b5a7a8b5SBram Moolenaar 		ToRenderingMode(params->renderingMode), &renderingParams);
1171b5a7a8b5SBram Moolenaar 	textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
1172b5a7a8b5SBram Moolenaar     }
1173b5a7a8b5SBram Moolenaar     else
1174b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
1175b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr) && renderingParams != NULL)
1176b5a7a8b5SBram Moolenaar     {
1177b5a7a8b5SBram Moolenaar 	SafeRelease(&mRenderingParams);
1178b5a7a8b5SBram Moolenaar 	mRenderingParams = renderingParams;
1179b5a7a8b5SBram Moolenaar 	mTextAntialiasMode = textAntialiasMode;
1180d7ccc4d8SBram Moolenaar 
1181d7ccc4d8SBram Moolenaar 	Flush();
1182d7ccc4d8SBram Moolenaar 	mRT->SetTextRenderingParams(mRenderingParams);
1183d7ccc4d8SBram Moolenaar 	mRT->SetTextAntialiasMode(mTextAntialiasMode);
1184b5a7a8b5SBram Moolenaar     }
1185b5a7a8b5SBram Moolenaar }
1186b5a7a8b5SBram Moolenaar 
1187b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
1188b5a7a8b5SBram Moolenaar DWriteContext::GetRenderingParams(
1189b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
1190b5a7a8b5SBram Moolenaar {
1191b5a7a8b5SBram Moolenaar     if (params != NULL && mRenderingParams != NULL)
1192b5a7a8b5SBram Moolenaar     {
1193b5a7a8b5SBram Moolenaar 	params->gamma = mRenderingParams->GetGamma();
1194b5a7a8b5SBram Moolenaar 	params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
1195b5a7a8b5SBram Moolenaar 	params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
1196b5a7a8b5SBram Moolenaar 	params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
1197b5a7a8b5SBram Moolenaar 	params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
1198b5a7a8b5SBram Moolenaar 	params->textAntialiasMode = mTextAntialiasMode;
1199b5a7a8b5SBram Moolenaar     }
1200b5a7a8b5SBram Moolenaar     return params;
1201b5a7a8b5SBram Moolenaar }
1202b5a7a8b5SBram Moolenaar 
1203b5a7a8b5SBram Moolenaar ////////////////////////////////////////////////////////////////////////////
1204b5a7a8b5SBram Moolenaar // PUBLIC C INTERFACES
1205b5a7a8b5SBram Moolenaar 
1206b5a7a8b5SBram Moolenaar     void
1207b5a7a8b5SBram Moolenaar DWrite_Init(void)
1208b5a7a8b5SBram Moolenaar {
1209b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1210b5a7a8b5SBram Moolenaar     // Load libraries.
1211b5a7a8b5SBram Moolenaar     hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
1212b5a7a8b5SBram Moolenaar     hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
1213b5a7a8b5SBram Moolenaar     if (hD2D1DLL == NULL || hDWriteDLL == NULL)
1214b5a7a8b5SBram Moolenaar     {
1215b5a7a8b5SBram Moolenaar 	DWrite_Final();
1216b5a7a8b5SBram Moolenaar 	return;
1217b5a7a8b5SBram Moolenaar     }
1218b5a7a8b5SBram Moolenaar     // Get address of procedures.
1219b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
1220b5a7a8b5SBram Moolenaar 	    GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
1221b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
1222b5a7a8b5SBram Moolenaar 	    "D2D1CreateFactory");
1223b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
1224b5a7a8b5SBram Moolenaar 	    "DWriteCreateFactory");
1225b5a7a8b5SBram Moolenaar #endif
1226b5a7a8b5SBram Moolenaar }
1227b5a7a8b5SBram Moolenaar 
1228b5a7a8b5SBram Moolenaar     void
1229b5a7a8b5SBram Moolenaar DWrite_Final(void)
1230b5a7a8b5SBram Moolenaar {
1231b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1232b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = NULL;
1233b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = NULL;
1234b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = NULL;
1235b5a7a8b5SBram Moolenaar     unload(hDWriteDLL);
1236b5a7a8b5SBram Moolenaar     unload(hD2D1DLL);
1237b5a7a8b5SBram Moolenaar #endif
1238b5a7a8b5SBram Moolenaar }
1239b5a7a8b5SBram Moolenaar 
1240b5a7a8b5SBram Moolenaar     DWriteContext *
1241b5a7a8b5SBram Moolenaar DWriteContext_Open(void)
1242b5a7a8b5SBram Moolenaar {
1243b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1244b5a7a8b5SBram Moolenaar     if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
1245b5a7a8b5SBram Moolenaar 	    || pDWriteCreateFactory == NULL)
1246b5a7a8b5SBram Moolenaar 	return NULL;
1247b5a7a8b5SBram Moolenaar #endif
1248b5a7a8b5SBram Moolenaar     return new DWriteContext();
1249b5a7a8b5SBram Moolenaar }
1250b5a7a8b5SBram Moolenaar 
1251b5a7a8b5SBram Moolenaar     void
125292467d33SBram Moolenaar DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
1253b5a7a8b5SBram Moolenaar {
1254d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1255d7ccc4d8SBram Moolenaar 	ctx->BindDC(hdc, rect);
1256b5a7a8b5SBram Moolenaar }
1257b5a7a8b5SBram Moolenaar 
1258b5a7a8b5SBram Moolenaar     void
1259b5a7a8b5SBram Moolenaar DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
1260b5a7a8b5SBram Moolenaar {
1261b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1262b5a7a8b5SBram Moolenaar 	ctx->SetFont(hFont);
1263b5a7a8b5SBram Moolenaar }
1264b5a7a8b5SBram Moolenaar 
1265b5a7a8b5SBram Moolenaar     void
1266b5a7a8b5SBram Moolenaar DWriteContext_DrawText(
1267b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1268b5a7a8b5SBram Moolenaar 	const WCHAR *text,
1269b5a7a8b5SBram Moolenaar 	int len,
1270b5a7a8b5SBram Moolenaar 	int x,
1271b5a7a8b5SBram Moolenaar 	int y,
1272b5a7a8b5SBram Moolenaar 	int w,
1273b5a7a8b5SBram Moolenaar 	int h,
1274b5a7a8b5SBram Moolenaar 	int cellWidth,
1275d7ccc4d8SBram Moolenaar 	COLORREF color,
1276d7ccc4d8SBram Moolenaar 	UINT fuOptions,
127792467d33SBram Moolenaar 	const RECT *lprc,
127892467d33SBram Moolenaar 	const INT *lpDx)
1279b5a7a8b5SBram Moolenaar {
1280b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1281d7ccc4d8SBram Moolenaar 	ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
1282d7ccc4d8SBram Moolenaar 		fuOptions, lprc, lpDx);
1283b5a7a8b5SBram Moolenaar }
1284b5a7a8b5SBram Moolenaar 
1285b5a7a8b5SBram Moolenaar     void
128692467d33SBram Moolenaar DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color)
1287b5a7a8b5SBram Moolenaar {
1288d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1289d7ccc4d8SBram Moolenaar 	ctx->FillRect(rc, color);
1290b5a7a8b5SBram Moolenaar }
1291d7ccc4d8SBram Moolenaar 
1292d7ccc4d8SBram Moolenaar     void
129392467d33SBram Moolenaar DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
129492467d33SBram Moolenaar 	COLORREF color)
129592467d33SBram Moolenaar {
129692467d33SBram Moolenaar     if (ctx != NULL)
129792467d33SBram Moolenaar 	ctx->DrawLine(x1, y1, x2, y2, color);
129892467d33SBram Moolenaar }
129992467d33SBram Moolenaar 
130092467d33SBram Moolenaar     void
130192467d33SBram Moolenaar DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color)
130292467d33SBram Moolenaar {
130392467d33SBram Moolenaar     if (ctx != NULL)
130492467d33SBram Moolenaar 	ctx->SetPixel(x, y, color);
130592467d33SBram Moolenaar }
130692467d33SBram Moolenaar 
130792467d33SBram Moolenaar     void
1308a338adcfSBram Moolenaar DWriteContext_Scroll(DWriteContext *ctx, int x, int y, const RECT *rc)
1309a338adcfSBram Moolenaar {
1310a338adcfSBram Moolenaar     if (ctx != NULL)
1311a338adcfSBram Moolenaar 	ctx->Scroll(x, y, rc);
1312a338adcfSBram Moolenaar }
1313a338adcfSBram Moolenaar 
1314a338adcfSBram Moolenaar     void
1315d7ccc4d8SBram Moolenaar DWriteContext_Flush(DWriteContext *ctx)
1316d7ccc4d8SBram Moolenaar {
1317d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1318d7ccc4d8SBram Moolenaar 	ctx->Flush();
1319b5a7a8b5SBram Moolenaar }
1320b5a7a8b5SBram Moolenaar 
1321b5a7a8b5SBram Moolenaar     void
1322b5a7a8b5SBram Moolenaar DWriteContext_Close(DWriteContext *ctx)
1323b5a7a8b5SBram Moolenaar {
1324b5a7a8b5SBram Moolenaar     delete ctx;
1325b5a7a8b5SBram Moolenaar }
1326b5a7a8b5SBram Moolenaar 
1327b5a7a8b5SBram Moolenaar     void
1328b5a7a8b5SBram Moolenaar DWriteContext_SetRenderingParams(
1329b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1330b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
1331b5a7a8b5SBram Moolenaar {
1332b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1333b5a7a8b5SBram Moolenaar 	ctx->SetRenderingParams(params);
1334b5a7a8b5SBram Moolenaar }
1335b5a7a8b5SBram Moolenaar 
1336b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
1337b5a7a8b5SBram Moolenaar DWriteContext_GetRenderingParams(
1338b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1339b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
1340b5a7a8b5SBram Moolenaar {
1341b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1342b5a7a8b5SBram Moolenaar 	return ctx->GetRenderingParams(params);
1343b5a7a8b5SBram Moolenaar     else
1344b5a7a8b5SBram Moolenaar 	return NULL;
1345b5a7a8b5SBram Moolenaar }
1346