xref: /vim-8.2.3635/src/gui_dwrite.cpp (revision 7f88b65f)
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 
41*7f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
42d7ccc4d8SBram Moolenaar # include <dwrite_2.h>
43*7f88b65fSBram Moolenaar #else
44*7f88b65fSBram Moolenaar # include <dwrite.h>
45*7f88b65fSBram 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;
289d7ccc4d8SBram Moolenaar 
290d7ccc4d8SBram Moolenaar     IDWriteFactory *mDWriteFactory;
291*7f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
292d7ccc4d8SBram Moolenaar     IDWriteFactory2 *mDWriteFactory2;
293*7f88b65fSBram Moolenaar #endif
294d7ccc4d8SBram Moolenaar 
295d7ccc4d8SBram Moolenaar     IDWriteGdiInterop *mGdiInterop;
296d7ccc4d8SBram Moolenaar     IDWriteRenderingParams *mRenderingParams;
297d7ccc4d8SBram Moolenaar 
298d7ccc4d8SBram Moolenaar     FontCache mFontCache;
299d7ccc4d8SBram Moolenaar     IDWriteTextFormat *mTextFormat;
300d7ccc4d8SBram Moolenaar     DWRITE_FONT_WEIGHT mFontWeight;
301d7ccc4d8SBram Moolenaar     DWRITE_FONT_STYLE mFontStyle;
302d7ccc4d8SBram Moolenaar 
303d7ccc4d8SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
304d7ccc4d8SBram Moolenaar 
305d7ccc4d8SBram Moolenaar     // METHODS
306d7ccc4d8SBram Moolenaar 
307d7ccc4d8SBram Moolenaar     DWriteContext();
308d7ccc4d8SBram Moolenaar 
309d7ccc4d8SBram Moolenaar     virtual ~DWriteContext();
310d7ccc4d8SBram Moolenaar 
31192467d33SBram Moolenaar     HRESULT CreateDeviceResources();
31292467d33SBram Moolenaar 
31392467d33SBram Moolenaar     void DiscardDeviceResources();
31492467d33SBram Moolenaar 
315d7ccc4d8SBram Moolenaar     HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
316d7ccc4d8SBram Moolenaar 	    IDWriteTextFormat **ppTextFormat);
317d7ccc4d8SBram Moolenaar 
318d7ccc4d8SBram Moolenaar     HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
319d7ccc4d8SBram Moolenaar 
320d7ccc4d8SBram Moolenaar     void SetFont(HFONT hFont);
321d7ccc4d8SBram Moolenaar 
32292467d33SBram Moolenaar     void BindDC(HDC hdc, const RECT *rect);
323d7ccc4d8SBram Moolenaar 
32492467d33SBram Moolenaar     HRESULT SetDrawingMode(DrawingMode mode);
325d7ccc4d8SBram Moolenaar 
326d7ccc4d8SBram Moolenaar     ID2D1Brush* SolidBrush(COLORREF color);
327d7ccc4d8SBram Moolenaar 
328d7ccc4d8SBram Moolenaar     void DrawText(const WCHAR *text, int len,
329d7ccc4d8SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color,
33092467d33SBram Moolenaar 	UINT fuOptions, const RECT *lprc, const INT *lpDx);
331d7ccc4d8SBram Moolenaar 
33292467d33SBram Moolenaar     void FillRect(const RECT *rc, COLORREF color);
33392467d33SBram Moolenaar 
33492467d33SBram Moolenaar     void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
33592467d33SBram Moolenaar 
33692467d33SBram Moolenaar     void SetPixel(int x, int y, COLORREF color);
337d7ccc4d8SBram Moolenaar 
338d7ccc4d8SBram Moolenaar     void Flush();
339d7ccc4d8SBram Moolenaar 
340d7ccc4d8SBram Moolenaar     void SetRenderingParams(
341d7ccc4d8SBram Moolenaar 	    const DWriteRenderingParams *params);
342d7ccc4d8SBram Moolenaar 
343d7ccc4d8SBram Moolenaar     DWriteRenderingParams *GetRenderingParams(
344d7ccc4d8SBram Moolenaar 	    DWriteRenderingParams *params);
345d7ccc4d8SBram Moolenaar };
346d7ccc4d8SBram Moolenaar 
347b5a7a8b5SBram Moolenaar class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
348b5a7a8b5SBram Moolenaar {
349b5a7a8b5SBram Moolenaar private:
350d7ccc4d8SBram Moolenaar     FLOAT &mAccum;
351b5a7a8b5SBram Moolenaar     FLOAT mDelta;
352b5a7a8b5SBram Moolenaar     FLOAT *mAdjustedAdvances;
353b5a7a8b5SBram Moolenaar 
354b5a7a8b5SBram Moolenaar public:
355b5a7a8b5SBram Moolenaar     AdjustedGlyphRun(
356b5a7a8b5SBram Moolenaar 	    const DWRITE_GLYPH_RUN *glyphRun,
357d7ccc4d8SBram Moolenaar 	    FLOAT cellWidth,
358d7ccc4d8SBram Moolenaar 	    FLOAT &accum) :
359b5a7a8b5SBram Moolenaar 	DWRITE_GLYPH_RUN(*glyphRun),
360d7ccc4d8SBram Moolenaar 	mAccum(accum),
361b5a7a8b5SBram Moolenaar 	mDelta(0.0f),
362b5a7a8b5SBram Moolenaar 	mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
363b5a7a8b5SBram Moolenaar     {
364b5a7a8b5SBram Moolenaar 	assert(cellWidth != 0.0f);
365b5a7a8b5SBram Moolenaar 	for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
366b5a7a8b5SBram Moolenaar 	{
367b5a7a8b5SBram Moolenaar 	    FLOAT orig = glyphRun->glyphAdvances[i];
368b5a7a8b5SBram Moolenaar 	    FLOAT adjusted = adjustToCell(orig, cellWidth);
369b5a7a8b5SBram Moolenaar 	    mAdjustedAdvances[i] = adjusted;
370b5a7a8b5SBram Moolenaar 	    mDelta += adjusted - orig;
371b5a7a8b5SBram Moolenaar 	}
372b5a7a8b5SBram Moolenaar 	glyphAdvances = mAdjustedAdvances;
373b5a7a8b5SBram Moolenaar     }
374b5a7a8b5SBram Moolenaar 
375d7ccc4d8SBram Moolenaar     ~AdjustedGlyphRun()
376b5a7a8b5SBram Moolenaar     {
377d7ccc4d8SBram Moolenaar 	mAccum += mDelta;
378b5a7a8b5SBram Moolenaar 	delete[] mAdjustedAdvances;
379b5a7a8b5SBram Moolenaar     }
380b5a7a8b5SBram Moolenaar 
381b5a7a8b5SBram Moolenaar     static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
382b5a7a8b5SBram Moolenaar     {
383d7ccc4d8SBram Moolenaar 	int cellCount = int(floor(value / cellWidth + 0.5f));
384b5a7a8b5SBram Moolenaar 	if (cellCount < 1)
385b5a7a8b5SBram Moolenaar 	    cellCount = 1;
386b5a7a8b5SBram Moolenaar 	return cellCount * cellWidth;
387b5a7a8b5SBram Moolenaar     }
388b5a7a8b5SBram Moolenaar };
389b5a7a8b5SBram Moolenaar 
390d7ccc4d8SBram Moolenaar struct TextRendererContext {
391d7ccc4d8SBram Moolenaar     // const fields.
392d7ccc4d8SBram Moolenaar     COLORREF color;
393d7ccc4d8SBram Moolenaar     FLOAT cellWidth;
394d7ccc4d8SBram Moolenaar 
395d7ccc4d8SBram Moolenaar     // working fields.
396d7ccc4d8SBram Moolenaar     FLOAT offsetX;
397d7ccc4d8SBram Moolenaar };
398d7ccc4d8SBram Moolenaar 
399d7ccc4d8SBram Moolenaar class TextRenderer FINAL : public IDWriteTextRenderer
400b5a7a8b5SBram Moolenaar {
401b5a7a8b5SBram Moolenaar public:
402d7ccc4d8SBram Moolenaar     TextRenderer(
403d7ccc4d8SBram Moolenaar 	    DWriteContext* pDWC) :
404b5a7a8b5SBram Moolenaar 	cRefCount_(0),
405d7ccc4d8SBram Moolenaar 	pDWC_(pDWC)
406b5a7a8b5SBram Moolenaar     {
407b5a7a8b5SBram Moolenaar 	AddRef();
408b5a7a8b5SBram Moolenaar     }
409b5a7a8b5SBram Moolenaar 
410edb4f2b3SBram Moolenaar     // add "virtual" to avoid a compiler warning
411d7ccc4d8SBram Moolenaar     virtual ~TextRenderer()
412b5a7a8b5SBram Moolenaar     {
413b5a7a8b5SBram Moolenaar     }
414b5a7a8b5SBram Moolenaar 
415b5a7a8b5SBram Moolenaar     IFACEMETHOD(IsPixelSnappingDisabled)(
416b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
417b5a7a8b5SBram Moolenaar 	__out BOOL* isDisabled)
418b5a7a8b5SBram Moolenaar     {
419b5a7a8b5SBram Moolenaar 	*isDisabled = FALSE;
420b5a7a8b5SBram Moolenaar 	return S_OK;
421b5a7a8b5SBram Moolenaar     }
422b5a7a8b5SBram Moolenaar 
423b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetCurrentTransform)(
424b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
425b5a7a8b5SBram Moolenaar 	__out DWRITE_MATRIX* transform)
426b5a7a8b5SBram Moolenaar     {
427b5a7a8b5SBram Moolenaar 	// forward the render target's transform
428d7ccc4d8SBram Moolenaar 	pDWC_->mRT->GetTransform(
429d7ccc4d8SBram Moolenaar 		reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
430b5a7a8b5SBram Moolenaar 	return S_OK;
431b5a7a8b5SBram Moolenaar     }
432b5a7a8b5SBram Moolenaar 
433b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetPixelsPerDip)(
434b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
435b5a7a8b5SBram Moolenaar 	__out FLOAT* pixelsPerDip)
436b5a7a8b5SBram Moolenaar     {
437d7ccc4d8SBram Moolenaar 	float dpiX, unused;
438d7ccc4d8SBram Moolenaar 	pDWC_->mRT->GetDpi(&dpiX, &unused);
439d7ccc4d8SBram Moolenaar 	*pixelsPerDip = dpiX / 96.0f;
440b5a7a8b5SBram Moolenaar 	return S_OK;
441b5a7a8b5SBram Moolenaar     }
442b5a7a8b5SBram Moolenaar 
443b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawUnderline)(
444b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
445b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
446b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
447b5a7a8b5SBram Moolenaar 	__in DWRITE_UNDERLINE const* underline,
448b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
449b5a7a8b5SBram Moolenaar     {
450b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
451b5a7a8b5SBram Moolenaar     }
452b5a7a8b5SBram Moolenaar 
453b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawStrikethrough)(
454b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
455b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
456b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
457b5a7a8b5SBram Moolenaar 	__in DWRITE_STRIKETHROUGH const* strikethrough,
458b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
459b5a7a8b5SBram Moolenaar     {
460b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
461b5a7a8b5SBram Moolenaar     }
462b5a7a8b5SBram Moolenaar 
463b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawInlineObject)(
464b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
465b5a7a8b5SBram Moolenaar 	FLOAT originX,
466b5a7a8b5SBram Moolenaar 	FLOAT originY,
467b5a7a8b5SBram Moolenaar 	IDWriteInlineObject* inlineObject,
468b5a7a8b5SBram Moolenaar 	BOOL isSideways,
469b5a7a8b5SBram Moolenaar 	BOOL isRightToLeft,
470b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
471b5a7a8b5SBram Moolenaar     {
472b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
473b5a7a8b5SBram Moolenaar     }
474b5a7a8b5SBram Moolenaar 
475d7ccc4d8SBram Moolenaar     IFACEMETHOD(DrawGlyphRun)(
476d7ccc4d8SBram Moolenaar 	__maybenull void* clientDrawingContext,
477d7ccc4d8SBram Moolenaar 	FLOAT baselineOriginX,
478d7ccc4d8SBram Moolenaar 	FLOAT baselineOriginY,
479d7ccc4d8SBram Moolenaar 	DWRITE_MEASURING_MODE measuringMode,
480d7ccc4d8SBram Moolenaar 	__in DWRITE_GLYPH_RUN const* glyphRun,
481d7ccc4d8SBram Moolenaar 	__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
482d7ccc4d8SBram Moolenaar 	IUnknown* clientDrawingEffect)
483d7ccc4d8SBram Moolenaar     {
484d7ccc4d8SBram Moolenaar 	TextRendererContext *context =
485d7ccc4d8SBram Moolenaar 	    reinterpret_cast<TextRendererContext*>(clientDrawingContext);
486d7ccc4d8SBram Moolenaar 
487d7ccc4d8SBram Moolenaar 	AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
488d7ccc4d8SBram Moolenaar 		context->offsetX);
489d7ccc4d8SBram Moolenaar 
490*7f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
491d7ccc4d8SBram Moolenaar 	if (pDWC_->mDWriteFactory2 != NULL)
492d7ccc4d8SBram Moolenaar 	{
493d7ccc4d8SBram Moolenaar 	    IDWriteColorGlyphRunEnumerator *enumerator = NULL;
494d7ccc4d8SBram Moolenaar 	    HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
495d7ccc4d8SBram Moolenaar 		baselineOriginX + context->offsetX,
496d7ccc4d8SBram Moolenaar 		baselineOriginY,
497d7ccc4d8SBram Moolenaar 		&adjustedGlyphRun,
498d7ccc4d8SBram Moolenaar 		NULL,
499d7ccc4d8SBram Moolenaar 		DWRITE_MEASURING_MODE_GDI_NATURAL,
500d7ccc4d8SBram Moolenaar 		NULL,
501d7ccc4d8SBram Moolenaar 		0,
502d7ccc4d8SBram Moolenaar 		&enumerator);
503d7ccc4d8SBram Moolenaar 	    if (SUCCEEDED(hr))
504d7ccc4d8SBram Moolenaar 	    {
505d7ccc4d8SBram Moolenaar 		// Draw by IDWriteFactory2 for color emoji
506d7ccc4d8SBram Moolenaar 		BOOL hasRun = TRUE;
507d7ccc4d8SBram Moolenaar 		enumerator->MoveNext(&hasRun);
508d7ccc4d8SBram Moolenaar 		while (hasRun)
509d7ccc4d8SBram Moolenaar 		{
510d7ccc4d8SBram Moolenaar 		    const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
511d7ccc4d8SBram Moolenaar 		    enumerator->GetCurrentRun(&colorGlyphRun);
512d7ccc4d8SBram Moolenaar 
513d7ccc4d8SBram Moolenaar 		    pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
514d7ccc4d8SBram Moolenaar 		    pDWC_->mRT->DrawGlyphRun(
515d7ccc4d8SBram Moolenaar 			    D2D1::Point2F(
516d7ccc4d8SBram Moolenaar 				colorGlyphRun->baselineOriginX,
517d7ccc4d8SBram Moolenaar 				colorGlyphRun->baselineOriginY),
518d7ccc4d8SBram Moolenaar 			    &colorGlyphRun->glyphRun,
519d7ccc4d8SBram Moolenaar 			    pDWC_->mBrush,
520d7ccc4d8SBram Moolenaar 			    DWRITE_MEASURING_MODE_NATURAL);
521d7ccc4d8SBram Moolenaar 		    enumerator->MoveNext(&hasRun);
522d7ccc4d8SBram Moolenaar 		}
523d7ccc4d8SBram Moolenaar 		SafeRelease(&enumerator);
524d7ccc4d8SBram Moolenaar 		return S_OK;
525d7ccc4d8SBram Moolenaar 	    }
526d7ccc4d8SBram Moolenaar 	}
527*7f88b65fSBram Moolenaar #endif
528d7ccc4d8SBram Moolenaar 
529d7ccc4d8SBram Moolenaar 	// Draw by IDWriteFactory (without color emoji)
530d7ccc4d8SBram Moolenaar 	pDWC_->mRT->DrawGlyphRun(
531d7ccc4d8SBram Moolenaar 		D2D1::Point2F(
532d7ccc4d8SBram Moolenaar 		    baselineOriginX + context->offsetX,
533d7ccc4d8SBram Moolenaar 		    baselineOriginY),
534d7ccc4d8SBram Moolenaar 		&adjustedGlyphRun,
535d7ccc4d8SBram Moolenaar 		pDWC_->SolidBrush(context->color),
536d7ccc4d8SBram Moolenaar 		DWRITE_MEASURING_MODE_NATURAL);
537d7ccc4d8SBram Moolenaar 	return S_OK;
538d7ccc4d8SBram Moolenaar     }
539d7ccc4d8SBram Moolenaar 
540b5a7a8b5SBram Moolenaar public:
541b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, AddRef) ()
542b5a7a8b5SBram Moolenaar     {
543b5a7a8b5SBram Moolenaar 	return InterlockedIncrement(&cRefCount_);
544b5a7a8b5SBram Moolenaar     }
545b5a7a8b5SBram Moolenaar 
546b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, Release) ()
547b5a7a8b5SBram Moolenaar     {
548b5a7a8b5SBram Moolenaar 	long newCount = InterlockedDecrement(&cRefCount_);
549b5a7a8b5SBram Moolenaar 
550b5a7a8b5SBram Moolenaar 	if (newCount == 0)
551b5a7a8b5SBram Moolenaar 	{
552b5a7a8b5SBram Moolenaar 	    delete this;
553b5a7a8b5SBram Moolenaar 	    return 0;
554b5a7a8b5SBram Moolenaar 	}
555b5a7a8b5SBram Moolenaar 	return newCount;
556b5a7a8b5SBram Moolenaar     }
557b5a7a8b5SBram Moolenaar 
558b5a7a8b5SBram Moolenaar     IFACEMETHOD(QueryInterface)(
559b5a7a8b5SBram Moolenaar 	IID const& riid,
560b5a7a8b5SBram Moolenaar 	void** ppvObject)
561b5a7a8b5SBram Moolenaar     {
562b5a7a8b5SBram Moolenaar 	if (__uuidof(IDWriteTextRenderer) == riid)
563b5a7a8b5SBram Moolenaar 	{
564b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
565b5a7a8b5SBram Moolenaar 	}
566b5a7a8b5SBram Moolenaar 	else if (__uuidof(IDWritePixelSnapping) == riid)
567b5a7a8b5SBram Moolenaar 	{
568b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
569b5a7a8b5SBram Moolenaar 	}
570b5a7a8b5SBram Moolenaar 	else if (__uuidof(IUnknown) == riid)
571b5a7a8b5SBram Moolenaar 	{
572b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
573b5a7a8b5SBram Moolenaar 	}
574b5a7a8b5SBram Moolenaar 	else
575b5a7a8b5SBram Moolenaar 	{
576b5a7a8b5SBram Moolenaar 	    *ppvObject = NULL;
577b5a7a8b5SBram Moolenaar 	    return E_FAIL;
578b5a7a8b5SBram Moolenaar 	}
579b5a7a8b5SBram Moolenaar 
580b5a7a8b5SBram Moolenaar 	return S_OK;
581b5a7a8b5SBram Moolenaar     }
582b5a7a8b5SBram Moolenaar 
583b5a7a8b5SBram Moolenaar private:
5840106b4b8SBram Moolenaar     long cRefCount_;
585d7ccc4d8SBram Moolenaar     DWriteContext* pDWC_;
586b5a7a8b5SBram Moolenaar };
587b5a7a8b5SBram Moolenaar 
588b5a7a8b5SBram Moolenaar DWriteContext::DWriteContext() :
589d7ccc4d8SBram Moolenaar     mHDC(NULL),
59092467d33SBram Moolenaar     mBindRect(),
59192467d33SBram Moolenaar     mDMode(DM_GDI),
59292467d33SBram Moolenaar     mInteropHDC(NULL),
593b5a7a8b5SBram Moolenaar     mDrawing(false),
594d7ccc4d8SBram Moolenaar     mFallbackDC(false),
595b5a7a8b5SBram Moolenaar     mD2D1Factory(NULL),
596b5a7a8b5SBram Moolenaar     mRT(NULL),
59792467d33SBram Moolenaar     mGDIRT(NULL),
598b5a7a8b5SBram Moolenaar     mBrush(NULL),
599b5a7a8b5SBram Moolenaar     mDWriteFactory(NULL),
600*7f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
601d7ccc4d8SBram Moolenaar     mDWriteFactory2(NULL),
602*7f88b65fSBram Moolenaar #endif
603b5a7a8b5SBram Moolenaar     mGdiInterop(NULL),
604b5a7a8b5SBram Moolenaar     mRenderingParams(NULL),
605d7ccc4d8SBram Moolenaar     mFontCache(8),
606b5a7a8b5SBram Moolenaar     mTextFormat(NULL),
607b5a7a8b5SBram Moolenaar     mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
608b5a7a8b5SBram Moolenaar     mFontStyle(DWRITE_FONT_STYLE_NORMAL),
609b5a7a8b5SBram Moolenaar     mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
610b5a7a8b5SBram Moolenaar {
611b5a7a8b5SBram Moolenaar     HRESULT hr;
612b5a7a8b5SBram Moolenaar 
613b5a7a8b5SBram Moolenaar     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
614b5a7a8b5SBram Moolenaar 	    __uuidof(ID2D1Factory), NULL,
615b5a7a8b5SBram Moolenaar 	    reinterpret_cast<void**>(&mD2D1Factory));
616b5a7a8b5SBram Moolenaar     _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
617b5a7a8b5SBram Moolenaar 
618b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
61992467d33SBram Moolenaar 	hr = CreateDeviceResources();
620b5a7a8b5SBram Moolenaar 
621b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
622b5a7a8b5SBram Moolenaar     {
623b5a7a8b5SBram Moolenaar 	hr = DWriteCreateFactory(
624b5a7a8b5SBram Moolenaar 		DWRITE_FACTORY_TYPE_SHARED,
625b5a7a8b5SBram Moolenaar 		__uuidof(IDWriteFactory),
626b5a7a8b5SBram Moolenaar 		reinterpret_cast<IUnknown**>(&mDWriteFactory));
627b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
628b5a7a8b5SBram Moolenaar 		mDWriteFactory);
629b5a7a8b5SBram Moolenaar     }
630b5a7a8b5SBram Moolenaar 
631*7f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
632b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
633b5a7a8b5SBram Moolenaar     {
634d7ccc4d8SBram Moolenaar 	DWriteCreateFactory(
635d7ccc4d8SBram Moolenaar 		DWRITE_FACTORY_TYPE_SHARED,
636d7ccc4d8SBram Moolenaar 		__uuidof(IDWriteFactory2),
637d7ccc4d8SBram Moolenaar 		reinterpret_cast<IUnknown**>(&mDWriteFactory2));
638d7ccc4d8SBram Moolenaar 	_RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
639d7ccc4d8SBram Moolenaar     }
640*7f88b65fSBram Moolenaar #endif
641d7ccc4d8SBram Moolenaar 
642d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
643d7ccc4d8SBram Moolenaar     {
644b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
645b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
646b5a7a8b5SBram Moolenaar     }
647b5a7a8b5SBram Moolenaar 
648b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
649b5a7a8b5SBram Moolenaar     {
650b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
651b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
652b5a7a8b5SBram Moolenaar 		mRenderingParams);
653b5a7a8b5SBram Moolenaar     }
654b5a7a8b5SBram Moolenaar }
655b5a7a8b5SBram Moolenaar 
656b5a7a8b5SBram Moolenaar DWriteContext::~DWriteContext()
657b5a7a8b5SBram Moolenaar {
658b5a7a8b5SBram Moolenaar     SafeRelease(&mTextFormat);
659b5a7a8b5SBram Moolenaar     SafeRelease(&mRenderingParams);
660b5a7a8b5SBram Moolenaar     SafeRelease(&mGdiInterop);
661b5a7a8b5SBram Moolenaar     SafeRelease(&mDWriteFactory);
662*7f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
663d7ccc4d8SBram Moolenaar     SafeRelease(&mDWriteFactory2);
664*7f88b65fSBram Moolenaar #endif
665b5a7a8b5SBram Moolenaar     SafeRelease(&mBrush);
66692467d33SBram Moolenaar     SafeRelease(&mGDIRT);
667b5a7a8b5SBram Moolenaar     SafeRelease(&mRT);
668b5a7a8b5SBram Moolenaar     SafeRelease(&mD2D1Factory);
669b5a7a8b5SBram Moolenaar }
670b5a7a8b5SBram Moolenaar 
671b5a7a8b5SBram Moolenaar     HRESULT
67292467d33SBram Moolenaar DWriteContext::CreateDeviceResources()
67392467d33SBram Moolenaar {
67492467d33SBram Moolenaar     HRESULT hr;
67592467d33SBram Moolenaar 
67692467d33SBram Moolenaar     if (mRT != NULL)
67792467d33SBram Moolenaar 	return S_OK;
67892467d33SBram Moolenaar 
67992467d33SBram Moolenaar     D2D1_RENDER_TARGET_PROPERTIES props = {
68092467d33SBram Moolenaar 	D2D1_RENDER_TARGET_TYPE_DEFAULT,
68192467d33SBram Moolenaar 	{ DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
68292467d33SBram Moolenaar 	0, 0,
68392467d33SBram Moolenaar 	D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
68492467d33SBram Moolenaar 	D2D1_FEATURE_LEVEL_DEFAULT
68592467d33SBram Moolenaar     };
68692467d33SBram Moolenaar     hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
68792467d33SBram Moolenaar     _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
68892467d33SBram Moolenaar 
68992467d33SBram Moolenaar     if (SUCCEEDED(hr))
69092467d33SBram Moolenaar     {
69192467d33SBram Moolenaar 	// This always succeeds.
69292467d33SBram Moolenaar 	mRT->QueryInterface(
69392467d33SBram Moolenaar 		__uuidof(ID2D1GdiInteropRenderTarget),
69492467d33SBram Moolenaar 		reinterpret_cast<void**>(&mGDIRT));
69592467d33SBram Moolenaar 	_RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT);
69692467d33SBram Moolenaar     }
69792467d33SBram Moolenaar 
69892467d33SBram Moolenaar     if (SUCCEEDED(hr))
69992467d33SBram Moolenaar     {
70092467d33SBram Moolenaar 	hr = mRT->CreateSolidColorBrush(
70192467d33SBram Moolenaar 		D2D1::ColorF(D2D1::ColorF::Black),
70292467d33SBram Moolenaar 		&mBrush);
70392467d33SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
70492467d33SBram Moolenaar     }
70592467d33SBram Moolenaar 
70692467d33SBram Moolenaar     if (SUCCEEDED(hr))
70792467d33SBram Moolenaar     {
70892467d33SBram Moolenaar 	if (mHDC != NULL)
70992467d33SBram Moolenaar 	{
71092467d33SBram Moolenaar 	    mRT->BindDC(mHDC, &mBindRect);
71192467d33SBram Moolenaar 	    mRT->SetTransform(D2D1::IdentityMatrix());
71292467d33SBram Moolenaar 	}
71392467d33SBram Moolenaar     }
71492467d33SBram Moolenaar 
71592467d33SBram Moolenaar     return hr;
71692467d33SBram Moolenaar }
71792467d33SBram Moolenaar 
71892467d33SBram Moolenaar     void
71992467d33SBram Moolenaar DWriteContext::DiscardDeviceResources()
72092467d33SBram Moolenaar {
72192467d33SBram Moolenaar     SafeRelease(&mBrush);
72292467d33SBram Moolenaar     SafeRelease(&mGDIRT);
72392467d33SBram Moolenaar     SafeRelease(&mRT);
72492467d33SBram Moolenaar }
72592467d33SBram Moolenaar 
72692467d33SBram Moolenaar     HRESULT
727d7ccc4d8SBram Moolenaar DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
728d7ccc4d8SBram Moolenaar 	IDWriteTextFormat **ppTextFormat)
729b5a7a8b5SBram Moolenaar {
730d7ccc4d8SBram Moolenaar     // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
731b5a7a8b5SBram Moolenaar     HRESULT hr = S_OK;
732d7ccc4d8SBram Moolenaar     IDWriteTextFormat *pTextFormat = NULL;
733b5a7a8b5SBram Moolenaar 
734b5a7a8b5SBram Moolenaar     IDWriteFont *font = NULL;
735b5a7a8b5SBram Moolenaar     IDWriteFontFamily *fontFamily = NULL;
736b5a7a8b5SBram Moolenaar     IDWriteLocalizedStrings *localizedFamilyNames = NULL;
737d7ccc4d8SBram Moolenaar     float fontSize = 0;
738b5a7a8b5SBram Moolenaar 
739b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
740b5a7a8b5SBram Moolenaar     {
741b5a7a8b5SBram Moolenaar 	hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
742b5a7a8b5SBram Moolenaar     }
743b5a7a8b5SBram Moolenaar 
744b5a7a8b5SBram Moolenaar     // Get the font family to which this font belongs.
745b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
746b5a7a8b5SBram Moolenaar     {
747b5a7a8b5SBram Moolenaar 	hr = font->GetFontFamily(&fontFamily);
748b5a7a8b5SBram Moolenaar     }
749b5a7a8b5SBram Moolenaar 
750b5a7a8b5SBram Moolenaar     // Get the family names. This returns an object that encapsulates one or
751b5a7a8b5SBram Moolenaar     // more names with the same meaning but in different languages.
752b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
753b5a7a8b5SBram Moolenaar     {
754b5a7a8b5SBram Moolenaar 	hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
755b5a7a8b5SBram Moolenaar     }
756b5a7a8b5SBram Moolenaar 
757b5a7a8b5SBram Moolenaar     // Get the family name at index zero. If we were going to display the name
758b5a7a8b5SBram Moolenaar     // we'd want to try to find one that matched the use locale, but for
759b5a7a8b5SBram Moolenaar     // purposes of creating a text format object any language will do.
760b5a7a8b5SBram Moolenaar 
761b5a7a8b5SBram Moolenaar     wchar_t familyName[100];
762b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
763b5a7a8b5SBram Moolenaar     {
764b5a7a8b5SBram Moolenaar 	hr = localizedFamilyNames->GetString(0, familyName,
765b5a7a8b5SBram Moolenaar 		ARRAYSIZE(familyName));
766b5a7a8b5SBram Moolenaar     }
767b5a7a8b5SBram Moolenaar 
768b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
769b5a7a8b5SBram Moolenaar     {
770d7ccc4d8SBram Moolenaar 	// Use lfHeight of the LOGFONT as font size.
771d7ccc4d8SBram Moolenaar 	fontSize = float(logFont.lfHeight);
772d7ccc4d8SBram Moolenaar 
773b5a7a8b5SBram Moolenaar 	if (fontSize < 0)
774b5a7a8b5SBram Moolenaar 	{
775b5a7a8b5SBram Moolenaar 	    // Negative lfHeight represents the size of the em unit.
776b5a7a8b5SBram Moolenaar 	    fontSize = -fontSize;
777b5a7a8b5SBram Moolenaar 	}
778b5a7a8b5SBram Moolenaar 	else
779b5a7a8b5SBram Moolenaar 	{
780b5a7a8b5SBram Moolenaar 	    // Positive lfHeight represents the cell height (ascent +
781b5a7a8b5SBram Moolenaar 	    // descent).
782b5a7a8b5SBram Moolenaar 	    DWRITE_FONT_METRICS fontMetrics;
783b5a7a8b5SBram Moolenaar 	    font->GetMetrics(&fontMetrics);
784b5a7a8b5SBram Moolenaar 
785b5a7a8b5SBram Moolenaar 	    // Convert the cell height (ascent + descent) from design units
786b5a7a8b5SBram Moolenaar 	    // to ems.
787b5a7a8b5SBram Moolenaar 	    float cellHeight = static_cast<float>(
788b5a7a8b5SBram Moolenaar 		    fontMetrics.ascent + fontMetrics.descent)
789b5a7a8b5SBram Moolenaar 		/ fontMetrics.designUnitsPerEm;
790b5a7a8b5SBram Moolenaar 
791b5a7a8b5SBram Moolenaar 	    // Divide the font size by the cell height to get the font em
792b5a7a8b5SBram Moolenaar 	    // size.
793b5a7a8b5SBram Moolenaar 	    fontSize /= cellHeight;
794b5a7a8b5SBram Moolenaar 	}
795b5a7a8b5SBram Moolenaar     }
796b5a7a8b5SBram Moolenaar 
797b5a7a8b5SBram Moolenaar     // The text format includes a locale name. Ideally, this would be the
798b5a7a8b5SBram Moolenaar     // language of the text, which may or may not be the same as the primary
799b5a7a8b5SBram Moolenaar     // language of the user. However, for our purposes the user locale will do.
800b5a7a8b5SBram Moolenaar     wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
801b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
802b5a7a8b5SBram Moolenaar     {
803b5a7a8b5SBram Moolenaar 	if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
804b5a7a8b5SBram Moolenaar 	    hr = HRESULT_FROM_WIN32(GetLastError());
805b5a7a8b5SBram Moolenaar     }
806b5a7a8b5SBram Moolenaar 
807b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
808b5a7a8b5SBram Moolenaar     {
809b5a7a8b5SBram Moolenaar 	// Create the text format object.
810b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateTextFormat(
811b5a7a8b5SBram Moolenaar 		familyName,
812b5a7a8b5SBram Moolenaar 		NULL, // no custom font collection
813b5a7a8b5SBram Moolenaar 		font->GetWeight(),
814b5a7a8b5SBram Moolenaar 		font->GetStyle(),
815b5a7a8b5SBram Moolenaar 		font->GetStretch(),
816b5a7a8b5SBram Moolenaar 		fontSize,
817b5a7a8b5SBram Moolenaar 		localeName,
818d7ccc4d8SBram Moolenaar 		&pTextFormat);
819b5a7a8b5SBram Moolenaar     }
820b5a7a8b5SBram Moolenaar 
821b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
822d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
823d7ccc4d8SBram Moolenaar 
824d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
825d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetParagraphAlignment(
826d7ccc4d8SBram Moolenaar 		DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
827d7ccc4d8SBram Moolenaar 
828d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
829d7ccc4d8SBram Moolenaar 	hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
830b5a7a8b5SBram Moolenaar 
831b5a7a8b5SBram Moolenaar     SafeRelease(&localizedFamilyNames);
832b5a7a8b5SBram Moolenaar     SafeRelease(&fontFamily);
833b5a7a8b5SBram Moolenaar     SafeRelease(&font);
834b5a7a8b5SBram Moolenaar 
835d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
836d7ccc4d8SBram Moolenaar 	*ppTextFormat = pTextFormat;
837d7ccc4d8SBram Moolenaar     else
838d7ccc4d8SBram Moolenaar 	SafeRelease(&pTextFormat);
839d7ccc4d8SBram Moolenaar 
840d7ccc4d8SBram Moolenaar     return hr;
841d7ccc4d8SBram Moolenaar }
842d7ccc4d8SBram Moolenaar 
843d7ccc4d8SBram Moolenaar     HRESULT
844d7ccc4d8SBram Moolenaar DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
845d7ccc4d8SBram Moolenaar {
846d7ccc4d8SBram Moolenaar     HRESULT hr = S_OK;
847d7ccc4d8SBram Moolenaar     IDWriteTextFormat *pTextFormat = NULL;
848d7ccc4d8SBram Moolenaar 
849d7ccc4d8SBram Moolenaar     hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
850d7ccc4d8SBram Moolenaar 
851d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
852d7ccc4d8SBram Moolenaar     {
853d7ccc4d8SBram Moolenaar 	SafeRelease(&mTextFormat);
854d7ccc4d8SBram Moolenaar 	mTextFormat = pTextFormat;
855d7ccc4d8SBram Moolenaar 	mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
856d7ccc4d8SBram Moolenaar 	mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
857d7ccc4d8SBram Moolenaar 	    : DWRITE_FONT_STYLE_NORMAL;
858d7ccc4d8SBram Moolenaar     }
859d7ccc4d8SBram Moolenaar 
860b5a7a8b5SBram Moolenaar     return hr;
861b5a7a8b5SBram Moolenaar }
862b5a7a8b5SBram Moolenaar 
863b5a7a8b5SBram Moolenaar     void
864b5a7a8b5SBram Moolenaar DWriteContext::SetFont(HFONT hFont)
865b5a7a8b5SBram Moolenaar {
866d7ccc4d8SBram Moolenaar     FontCache::Item item;
867d7ccc4d8SBram Moolenaar     if (mFontCache.get(hFont, item))
868b5a7a8b5SBram Moolenaar     {
869d7ccc4d8SBram Moolenaar 	if (item.pTextFormat != NULL)
870d7ccc4d8SBram Moolenaar 	{
871d7ccc4d8SBram Moolenaar 	    item.pTextFormat->AddRef();
872d7ccc4d8SBram Moolenaar 	    SafeRelease(&mTextFormat);
873d7ccc4d8SBram Moolenaar 	    mTextFormat = item.pTextFormat;
874d7ccc4d8SBram Moolenaar 	    mFontWeight = item.fontWeight;
875d7ccc4d8SBram Moolenaar 	    mFontStyle = item.fontStyle;
876d7ccc4d8SBram Moolenaar 	    mFallbackDC = false;
877d7ccc4d8SBram Moolenaar 	}
878d7ccc4d8SBram Moolenaar 	else
879d7ccc4d8SBram Moolenaar 	    mFallbackDC = true;
880d7ccc4d8SBram Moolenaar 	return;
881d7ccc4d8SBram Moolenaar     }
882d7ccc4d8SBram Moolenaar 
883d7ccc4d8SBram Moolenaar     HRESULT hr = E_FAIL;
884b5a7a8b5SBram Moolenaar     LOGFONTW lf;
885b5a7a8b5SBram Moolenaar     if (GetObjectW(hFont, sizeof(lf), &lf))
886d7ccc4d8SBram Moolenaar 	hr = SetFontByLOGFONT(lf);
887d7ccc4d8SBram Moolenaar 
888d7ccc4d8SBram Moolenaar     item.hFont = hFont;
889d7ccc4d8SBram Moolenaar     if (SUCCEEDED(hr))
890b5a7a8b5SBram Moolenaar     {
891d7ccc4d8SBram Moolenaar 	item.pTextFormat = mTextFormat;
892d7ccc4d8SBram Moolenaar 	item.fontWeight = mFontWeight;
893d7ccc4d8SBram Moolenaar 	item.fontStyle = mFontStyle;
89492467d33SBram Moolenaar 	mFallbackDC = false;
895b5a7a8b5SBram Moolenaar     }
89692467d33SBram Moolenaar     else
89792467d33SBram Moolenaar 	mFallbackDC = true;
898d7ccc4d8SBram Moolenaar     mFontCache.put(item);
899b5a7a8b5SBram Moolenaar }
900b5a7a8b5SBram Moolenaar 
901b5a7a8b5SBram Moolenaar     void
90292467d33SBram Moolenaar DWriteContext::BindDC(HDC hdc, const RECT *rect)
903b5a7a8b5SBram Moolenaar {
904d7ccc4d8SBram Moolenaar     Flush();
905d7ccc4d8SBram Moolenaar     mRT->BindDC(hdc, rect);
906d7ccc4d8SBram Moolenaar     mRT->SetTransform(D2D1::IdentityMatrix());
907d7ccc4d8SBram Moolenaar     mHDC = hdc;
90892467d33SBram Moolenaar     mBindRect = *rect;
909b5a7a8b5SBram Moolenaar }
910b5a7a8b5SBram Moolenaar 
91192467d33SBram Moolenaar     HRESULT
91292467d33SBram Moolenaar DWriteContext::SetDrawingMode(DrawingMode mode)
913b5a7a8b5SBram Moolenaar {
91492467d33SBram Moolenaar     HRESULT hr = S_OK;
91592467d33SBram Moolenaar 
91692467d33SBram Moolenaar     switch (mode)
917b5a7a8b5SBram Moolenaar     {
91892467d33SBram Moolenaar 	default:
91992467d33SBram Moolenaar 	case DM_GDI:
92092467d33SBram Moolenaar 	    if (mInteropHDC != NULL)
92192467d33SBram Moolenaar 	    {
92292467d33SBram Moolenaar 		mGDIRT->ReleaseDC(NULL);
92392467d33SBram Moolenaar 		mInteropHDC = NULL;
92492467d33SBram Moolenaar 	    }
92592467d33SBram Moolenaar 	    if (mDrawing)
92692467d33SBram Moolenaar 	    {
92792467d33SBram Moolenaar 		hr = mRT->EndDraw();
92892467d33SBram Moolenaar 		if (hr == D2DERR_RECREATE_TARGET)
92992467d33SBram Moolenaar 		{
93092467d33SBram Moolenaar 		    hr = S_OK;
93192467d33SBram Moolenaar 		    DiscardDeviceResources();
93292467d33SBram Moolenaar 		    CreateDeviceResources();
93392467d33SBram Moolenaar 		}
93492467d33SBram Moolenaar 		mDrawing = false;
93592467d33SBram Moolenaar 	    }
93692467d33SBram Moolenaar 	    break;
93792467d33SBram Moolenaar 
93892467d33SBram Moolenaar 	case DM_DIRECTX:
93992467d33SBram Moolenaar 	    if (mInteropHDC != NULL)
94092467d33SBram Moolenaar 	    {
94192467d33SBram Moolenaar 		mGDIRT->ReleaseDC(NULL);
94292467d33SBram Moolenaar 		mInteropHDC = NULL;
94392467d33SBram Moolenaar 	    }
94492467d33SBram Moolenaar 	    else if (mDrawing == false)
94592467d33SBram Moolenaar 	    {
94692467d33SBram Moolenaar 		CreateDeviceResources();
947d7ccc4d8SBram Moolenaar 		mRT->BeginDraw();
948d7ccc4d8SBram Moolenaar 		mDrawing = true;
949d7ccc4d8SBram Moolenaar 	    }
95092467d33SBram Moolenaar 	    break;
95192467d33SBram Moolenaar 
95292467d33SBram Moolenaar 	case DM_INTEROP:
95392467d33SBram Moolenaar 	    if (mDrawing == false)
95492467d33SBram Moolenaar 	    {
95592467d33SBram Moolenaar 		CreateDeviceResources();
95692467d33SBram Moolenaar 		mRT->BeginDraw();
95792467d33SBram Moolenaar 		mDrawing = true;
95892467d33SBram Moolenaar 	    }
95992467d33SBram Moolenaar 	    if (mInteropHDC == NULL)
96092467d33SBram Moolenaar 		hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC);
96192467d33SBram Moolenaar 	    break;
96292467d33SBram Moolenaar     }
96392467d33SBram Moolenaar     mDMode = mode;
96492467d33SBram Moolenaar     return hr;
965d7ccc4d8SBram Moolenaar }
966d7ccc4d8SBram Moolenaar 
967d7ccc4d8SBram Moolenaar     ID2D1Brush*
968d7ccc4d8SBram Moolenaar DWriteContext::SolidBrush(COLORREF color)
969d7ccc4d8SBram Moolenaar {
970d7ccc4d8SBram Moolenaar     mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
971d7ccc4d8SBram Moolenaar 		UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
972d7ccc4d8SBram Moolenaar     return mBrush;
973d7ccc4d8SBram Moolenaar }
974d7ccc4d8SBram Moolenaar 
975d7ccc4d8SBram Moolenaar     void
976d7ccc4d8SBram Moolenaar DWriteContext::DrawText(const WCHAR *text, int len,
977d7ccc4d8SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color,
97892467d33SBram Moolenaar 	UINT fuOptions, const RECT *lprc, const INT *lpDx)
979d7ccc4d8SBram Moolenaar {
980d7ccc4d8SBram Moolenaar     if (mFallbackDC)
981d7ccc4d8SBram Moolenaar     {
98292467d33SBram Moolenaar 	// Fall back to GDI rendering.
98392467d33SBram Moolenaar 	HRESULT hr = SetDrawingMode(DM_INTEROP);
98492467d33SBram Moolenaar 	if (SUCCEEDED(hr))
98592467d33SBram Moolenaar 	{
98692467d33SBram Moolenaar 	    HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT);
98792467d33SBram Moolenaar 	    HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont);
98892467d33SBram Moolenaar 	    ::SetTextColor(mInteropHDC, color);
98992467d33SBram Moolenaar 	    ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC));
99092467d33SBram Moolenaar 	    ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx);
99192467d33SBram Moolenaar 	    ::SelectObject(mInteropHDC, hOldFont);
99292467d33SBram Moolenaar 	}
993d7ccc4d8SBram Moolenaar 	return;
994d7ccc4d8SBram Moolenaar     }
995d7ccc4d8SBram Moolenaar 
996d7ccc4d8SBram Moolenaar     HRESULT hr;
997b5a7a8b5SBram Moolenaar     IDWriteTextLayout *textLayout = NULL;
998b5a7a8b5SBram Moolenaar 
99992467d33SBram Moolenaar     SetDrawingMode(DM_DIRECTX);
100092467d33SBram Moolenaar 
1001d7ccc4d8SBram Moolenaar     hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
1002d7ccc4d8SBram Moolenaar 	    FLOAT(w), FLOAT(h), &textLayout);
1003b5a7a8b5SBram Moolenaar 
1004b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
1005b5a7a8b5SBram Moolenaar     {
1006d7ccc4d8SBram Moolenaar 	DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
1007b5a7a8b5SBram Moolenaar 	textLayout->SetFontWeight(mFontWeight, textRange);
1008b5a7a8b5SBram Moolenaar 	textLayout->SetFontStyle(mFontStyle, textRange);
1009b5a7a8b5SBram Moolenaar 
1010d7ccc4d8SBram Moolenaar 	TextRenderer renderer(this);
1011d7ccc4d8SBram Moolenaar 	TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
1012*7f88b65fSBram Moolenaar 	textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y) - 0.5f);
1013b5a7a8b5SBram Moolenaar     }
1014b5a7a8b5SBram Moolenaar 
1015b5a7a8b5SBram Moolenaar     SafeRelease(&textLayout);
1016b5a7a8b5SBram Moolenaar }
1017b5a7a8b5SBram Moolenaar 
1018d7ccc4d8SBram Moolenaar     void
101992467d33SBram Moolenaar DWriteContext::FillRect(const RECT *rc, COLORREF color)
1020d7ccc4d8SBram Moolenaar {
102192467d33SBram Moolenaar     if (mDMode == DM_INTEROP)
102292467d33SBram Moolenaar     {
102392467d33SBram Moolenaar 	// GDI functions are used before this call.  Keep using GDI.
102492467d33SBram Moolenaar 	// (Switching to Direct2D causes terrible slowdown.)
102592467d33SBram Moolenaar 	HBRUSH hbr = ::CreateSolidBrush(color);
102692467d33SBram Moolenaar 	::FillRect(mInteropHDC, rc, hbr);
102792467d33SBram Moolenaar 	::DeleteObject(HGDIOBJ(hbr));
102892467d33SBram Moolenaar     }
102992467d33SBram Moolenaar     else
103092467d33SBram Moolenaar     {
103192467d33SBram Moolenaar 	SetDrawingMode(DM_DIRECTX);
1032d7ccc4d8SBram Moolenaar 	mRT->FillRectangle(
1033d7ccc4d8SBram Moolenaar 		D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
1034d7ccc4d8SBram Moolenaar 		    FLOAT(rc->right), FLOAT(rc->bottom)),
1035d7ccc4d8SBram Moolenaar 		SolidBrush(color));
1036b5a7a8b5SBram Moolenaar     }
103792467d33SBram Moolenaar }
103892467d33SBram Moolenaar 
103992467d33SBram Moolenaar     void
104092467d33SBram Moolenaar DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
104192467d33SBram Moolenaar {
104292467d33SBram Moolenaar     if (mDMode == DM_INTEROP)
104392467d33SBram Moolenaar     {
104492467d33SBram Moolenaar 	// GDI functions are used before this call.  Keep using GDI.
104592467d33SBram Moolenaar 	// (Switching to Direct2D causes terrible slowdown.)
104692467d33SBram Moolenaar 	HPEN hpen = ::CreatePen(PS_SOLID, 1, color);
104792467d33SBram Moolenaar 	HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen));
104892467d33SBram Moolenaar 	::MoveToEx(mInteropHDC, x1, y1, NULL);
104992467d33SBram Moolenaar 	::LineTo(mInteropHDC, x2, y2);
105092467d33SBram Moolenaar 	::SelectObject(mInteropHDC, old_pen);
105192467d33SBram Moolenaar 	::DeleteObject(HGDIOBJ(hpen));
105292467d33SBram Moolenaar     }
105392467d33SBram Moolenaar     else
105492467d33SBram Moolenaar     {
105592467d33SBram Moolenaar 	SetDrawingMode(DM_DIRECTX);
105692467d33SBram Moolenaar 	mRT->DrawLine(
105792467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f),
105892467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f),
105992467d33SBram Moolenaar 		SolidBrush(color));
106092467d33SBram Moolenaar     }
106192467d33SBram Moolenaar }
106292467d33SBram Moolenaar 
106392467d33SBram Moolenaar     void
106492467d33SBram Moolenaar DWriteContext::SetPixel(int x, int y, COLORREF color)
106592467d33SBram Moolenaar {
106692467d33SBram Moolenaar     if (mDMode == DM_INTEROP)
106792467d33SBram Moolenaar     {
106892467d33SBram Moolenaar 	// GDI functions are used before this call.  Keep using GDI.
106992467d33SBram Moolenaar 	// (Switching to Direct2D causes terrible slowdown.)
107092467d33SBram Moolenaar 	::SetPixel(mInteropHDC, x, y, color);
107192467d33SBram Moolenaar     }
107292467d33SBram Moolenaar     else
107392467d33SBram Moolenaar     {
107492467d33SBram Moolenaar 	SetDrawingMode(DM_DIRECTX);
107592467d33SBram Moolenaar 	// Direct2D doesn't have SetPixel API.  Use DrawLine instead.
107692467d33SBram Moolenaar 	mRT->DrawLine(
107792467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f),
107892467d33SBram Moolenaar 		D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f),
107992467d33SBram Moolenaar 		SolidBrush(color));
108092467d33SBram Moolenaar     }
108192467d33SBram Moolenaar }
1082b5a7a8b5SBram Moolenaar 
1083d7ccc4d8SBram Moolenaar     void
1084d7ccc4d8SBram Moolenaar DWriteContext::Flush()
1085b5a7a8b5SBram Moolenaar {
108692467d33SBram Moolenaar     SetDrawingMode(DM_GDI);
1087b5a7a8b5SBram Moolenaar }
1088b5a7a8b5SBram Moolenaar 
1089b5a7a8b5SBram Moolenaar     void
1090b5a7a8b5SBram Moolenaar DWriteContext::SetRenderingParams(
1091b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
1092b5a7a8b5SBram Moolenaar {
1093b5a7a8b5SBram Moolenaar     if (mDWriteFactory == NULL)
1094b5a7a8b5SBram Moolenaar 	return;
1095b5a7a8b5SBram Moolenaar 
1096b5a7a8b5SBram Moolenaar     IDWriteRenderingParams *renderingParams = NULL;
1097b5a7a8b5SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
1098b5a7a8b5SBram Moolenaar 	D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
1099b5a7a8b5SBram Moolenaar     HRESULT hr;
1100b5a7a8b5SBram Moolenaar     if (params != NULL)
1101b5a7a8b5SBram Moolenaar     {
1102b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
1103b5a7a8b5SBram Moolenaar 		params->enhancedContrast, params->clearTypeLevel,
1104b5a7a8b5SBram Moolenaar 		ToPixelGeometry(params->pixelGeometry),
1105b5a7a8b5SBram Moolenaar 		ToRenderingMode(params->renderingMode), &renderingParams);
1106b5a7a8b5SBram Moolenaar 	textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
1107b5a7a8b5SBram Moolenaar     }
1108b5a7a8b5SBram Moolenaar     else
1109b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
1110b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr) && renderingParams != NULL)
1111b5a7a8b5SBram Moolenaar     {
1112b5a7a8b5SBram Moolenaar 	SafeRelease(&mRenderingParams);
1113b5a7a8b5SBram Moolenaar 	mRenderingParams = renderingParams;
1114b5a7a8b5SBram Moolenaar 	mTextAntialiasMode = textAntialiasMode;
1115d7ccc4d8SBram Moolenaar 
1116d7ccc4d8SBram Moolenaar 	Flush();
1117d7ccc4d8SBram Moolenaar 	mRT->SetTextRenderingParams(mRenderingParams);
1118d7ccc4d8SBram Moolenaar 	mRT->SetTextAntialiasMode(mTextAntialiasMode);
1119b5a7a8b5SBram Moolenaar     }
1120b5a7a8b5SBram Moolenaar }
1121b5a7a8b5SBram Moolenaar 
1122b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
1123b5a7a8b5SBram Moolenaar DWriteContext::GetRenderingParams(
1124b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
1125b5a7a8b5SBram Moolenaar {
1126b5a7a8b5SBram Moolenaar     if (params != NULL && mRenderingParams != NULL)
1127b5a7a8b5SBram Moolenaar     {
1128b5a7a8b5SBram Moolenaar 	params->gamma = mRenderingParams->GetGamma();
1129b5a7a8b5SBram Moolenaar 	params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
1130b5a7a8b5SBram Moolenaar 	params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
1131b5a7a8b5SBram Moolenaar 	params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
1132b5a7a8b5SBram Moolenaar 	params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
1133b5a7a8b5SBram Moolenaar 	params->textAntialiasMode = mTextAntialiasMode;
1134b5a7a8b5SBram Moolenaar     }
1135b5a7a8b5SBram Moolenaar     return params;
1136b5a7a8b5SBram Moolenaar }
1137b5a7a8b5SBram Moolenaar 
1138b5a7a8b5SBram Moolenaar ////////////////////////////////////////////////////////////////////////////
1139b5a7a8b5SBram Moolenaar // PUBLIC C INTERFACES
1140b5a7a8b5SBram Moolenaar 
1141b5a7a8b5SBram Moolenaar     void
1142b5a7a8b5SBram Moolenaar DWrite_Init(void)
1143b5a7a8b5SBram Moolenaar {
1144b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1145b5a7a8b5SBram Moolenaar     // Load libraries.
1146b5a7a8b5SBram Moolenaar     hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
1147b5a7a8b5SBram Moolenaar     hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
1148b5a7a8b5SBram Moolenaar     if (hD2D1DLL == NULL || hDWriteDLL == NULL)
1149b5a7a8b5SBram Moolenaar     {
1150b5a7a8b5SBram Moolenaar 	DWrite_Final();
1151b5a7a8b5SBram Moolenaar 	return;
1152b5a7a8b5SBram Moolenaar     }
1153b5a7a8b5SBram Moolenaar     // Get address of procedures.
1154b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
1155b5a7a8b5SBram Moolenaar 	    GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
1156b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
1157b5a7a8b5SBram Moolenaar 	    "D2D1CreateFactory");
1158b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
1159b5a7a8b5SBram Moolenaar 	    "DWriteCreateFactory");
1160b5a7a8b5SBram Moolenaar #endif
1161b5a7a8b5SBram Moolenaar }
1162b5a7a8b5SBram Moolenaar 
1163b5a7a8b5SBram Moolenaar     void
1164b5a7a8b5SBram Moolenaar DWrite_Final(void)
1165b5a7a8b5SBram Moolenaar {
1166b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1167b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = NULL;
1168b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = NULL;
1169b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = NULL;
1170b5a7a8b5SBram Moolenaar     unload(hDWriteDLL);
1171b5a7a8b5SBram Moolenaar     unload(hD2D1DLL);
1172b5a7a8b5SBram Moolenaar #endif
1173b5a7a8b5SBram Moolenaar }
1174b5a7a8b5SBram Moolenaar 
1175b5a7a8b5SBram Moolenaar     DWriteContext *
1176b5a7a8b5SBram Moolenaar DWriteContext_Open(void)
1177b5a7a8b5SBram Moolenaar {
1178b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1179b5a7a8b5SBram Moolenaar     if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
1180b5a7a8b5SBram Moolenaar 	    || pDWriteCreateFactory == NULL)
1181b5a7a8b5SBram Moolenaar 	return NULL;
1182b5a7a8b5SBram Moolenaar #endif
1183b5a7a8b5SBram Moolenaar     return new DWriteContext();
1184b5a7a8b5SBram Moolenaar }
1185b5a7a8b5SBram Moolenaar 
1186b5a7a8b5SBram Moolenaar     void
118792467d33SBram Moolenaar DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
1188b5a7a8b5SBram Moolenaar {
1189d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1190d7ccc4d8SBram Moolenaar 	ctx->BindDC(hdc, rect);
1191b5a7a8b5SBram Moolenaar }
1192b5a7a8b5SBram Moolenaar 
1193b5a7a8b5SBram Moolenaar     void
1194b5a7a8b5SBram Moolenaar DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
1195b5a7a8b5SBram Moolenaar {
1196b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1197b5a7a8b5SBram Moolenaar 	ctx->SetFont(hFont);
1198b5a7a8b5SBram Moolenaar }
1199b5a7a8b5SBram Moolenaar 
1200b5a7a8b5SBram Moolenaar     void
1201b5a7a8b5SBram Moolenaar DWriteContext_DrawText(
1202b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1203b5a7a8b5SBram Moolenaar 	const WCHAR *text,
1204b5a7a8b5SBram Moolenaar 	int len,
1205b5a7a8b5SBram Moolenaar 	int x,
1206b5a7a8b5SBram Moolenaar 	int y,
1207b5a7a8b5SBram Moolenaar 	int w,
1208b5a7a8b5SBram Moolenaar 	int h,
1209b5a7a8b5SBram Moolenaar 	int cellWidth,
1210d7ccc4d8SBram Moolenaar 	COLORREF color,
1211d7ccc4d8SBram Moolenaar 	UINT fuOptions,
121292467d33SBram Moolenaar 	const RECT *lprc,
121392467d33SBram Moolenaar 	const INT *lpDx)
1214b5a7a8b5SBram Moolenaar {
1215b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1216d7ccc4d8SBram Moolenaar 	ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
1217d7ccc4d8SBram Moolenaar 		fuOptions, lprc, lpDx);
1218b5a7a8b5SBram Moolenaar }
1219b5a7a8b5SBram Moolenaar 
1220b5a7a8b5SBram Moolenaar     void
122192467d33SBram Moolenaar DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color)
1222b5a7a8b5SBram Moolenaar {
1223d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1224d7ccc4d8SBram Moolenaar 	ctx->FillRect(rc, color);
1225b5a7a8b5SBram Moolenaar }
1226d7ccc4d8SBram Moolenaar 
1227d7ccc4d8SBram Moolenaar     void
122892467d33SBram Moolenaar DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
122992467d33SBram Moolenaar 	COLORREF color)
123092467d33SBram Moolenaar {
123192467d33SBram Moolenaar     if (ctx != NULL)
123292467d33SBram Moolenaar 	ctx->DrawLine(x1, y1, x2, y2, color);
123392467d33SBram Moolenaar }
123492467d33SBram Moolenaar 
123592467d33SBram Moolenaar     void
123692467d33SBram Moolenaar DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color)
123792467d33SBram Moolenaar {
123892467d33SBram Moolenaar     if (ctx != NULL)
123992467d33SBram Moolenaar 	ctx->SetPixel(x, y, color);
124092467d33SBram Moolenaar }
124192467d33SBram Moolenaar 
124292467d33SBram Moolenaar     void
1243d7ccc4d8SBram Moolenaar DWriteContext_Flush(DWriteContext *ctx)
1244d7ccc4d8SBram Moolenaar {
1245d7ccc4d8SBram Moolenaar     if (ctx != NULL)
1246d7ccc4d8SBram Moolenaar 	ctx->Flush();
1247b5a7a8b5SBram Moolenaar }
1248b5a7a8b5SBram Moolenaar 
1249b5a7a8b5SBram Moolenaar     void
1250b5a7a8b5SBram Moolenaar DWriteContext_Close(DWriteContext *ctx)
1251b5a7a8b5SBram Moolenaar {
1252b5a7a8b5SBram Moolenaar     delete ctx;
1253b5a7a8b5SBram Moolenaar }
1254b5a7a8b5SBram Moolenaar 
1255b5a7a8b5SBram Moolenaar     void
1256b5a7a8b5SBram Moolenaar DWriteContext_SetRenderingParams(
1257b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1258b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
1259b5a7a8b5SBram Moolenaar {
1260b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1261b5a7a8b5SBram Moolenaar 	ctx->SetRenderingParams(params);
1262b5a7a8b5SBram Moolenaar }
1263b5a7a8b5SBram Moolenaar 
1264b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
1265b5a7a8b5SBram Moolenaar DWriteContext_GetRenderingParams(
1266b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
1267b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
1268b5a7a8b5SBram Moolenaar {
1269b5a7a8b5SBram Moolenaar     if (ctx != NULL)
1270b5a7a8b5SBram Moolenaar 	return ctx->GetRenderingParams(params);
1271b5a7a8b5SBram Moolenaar     else
1272b5a7a8b5SBram Moolenaar 	return NULL;
1273b5a7a8b5SBram Moolenaar }
1274