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