xref: /vim-8.2.3635/src/gui_dwrite.cpp (revision cc6cf9b9)
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
7b5a7a8b5SBram Moolenaar  *
8b5a7a8b5SBram Moolenaar  * Copyright (C) 2013 MURAOKA Taro <[email protected]>
9b5a7a8b5SBram Moolenaar  * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
10b5a7a8b5SBram Moolenaar  */
11b5a7a8b5SBram Moolenaar 
12b5a7a8b5SBram Moolenaar #define WIN32_LEAN_AND_MEAN
13b5a7a8b5SBram Moolenaar 
14b5a7a8b5SBram Moolenaar #ifndef DYNAMIC_DIRECTX
15b5a7a8b5SBram Moolenaar # if WINVER < 0x0600
16b5a7a8b5SBram Moolenaar #  error WINVER must be 0x0600 or above to use DirectWrite(DirectX)
17b5a7a8b5SBram Moolenaar # endif
18b5a7a8b5SBram Moolenaar #endif
19b5a7a8b5SBram Moolenaar 
20b5a7a8b5SBram Moolenaar #include <windows.h>
21b5a7a8b5SBram Moolenaar #include <crtdbg.h>
22b5a7a8b5SBram Moolenaar #include <assert.h>
23b5a7a8b5SBram Moolenaar #include <math.h>
24b5a7a8b5SBram Moolenaar #include <d2d1.h>
25b5a7a8b5SBram Moolenaar #include <d2d1helper.h>
26b5a7a8b5SBram Moolenaar #include <dwrite.h>
27b5a7a8b5SBram Moolenaar 
28b5a7a8b5SBram Moolenaar #include "gui_dwrite.h"
29b5a7a8b5SBram Moolenaar 
30b5a7a8b5SBram Moolenaar #ifdef __MINGW32__
31b5a7a8b5SBram Moolenaar # define __maybenull	SAL__maybenull
32b5a7a8b5SBram Moolenaar # define __in		SAL__in
33b5a7a8b5SBram Moolenaar # define __out		SAL__out
34b5a7a8b5SBram Moolenaar #endif
35b5a7a8b5SBram Moolenaar 
36*cc6cf9b9SBram Moolenaar #if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
37*cc6cf9b9SBram Moolenaar # define FINAL final
38*cc6cf9b9SBram Moolenaar #else
39*cc6cf9b9SBram Moolenaar # define FINAL
40*cc6cf9b9SBram Moolenaar #endif
41*cc6cf9b9SBram Moolenaar 
42b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
43b5a7a8b5SBram Moolenaar extern "C" HINSTANCE vimLoadLib(char *name);
44b5a7a8b5SBram Moolenaar 
45b5a7a8b5SBram Moolenaar typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
46b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
47b5a7a8b5SBram Moolenaar 	REFIID, const D2D1_FACTORY_OPTIONS *, void **);
48b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
49b5a7a8b5SBram Moolenaar 	REFIID, IUnknown **);
50b5a7a8b5SBram Moolenaar 
51b5a7a8b5SBram Moolenaar static HINSTANCE hD2D1DLL = NULL;
52b5a7a8b5SBram Moolenaar static HINSTANCE hDWriteDLL = NULL;
53b5a7a8b5SBram Moolenaar 
54b5a7a8b5SBram Moolenaar static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
55b5a7a8b5SBram Moolenaar static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
56b5a7a8b5SBram Moolenaar static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
57b5a7a8b5SBram Moolenaar 
58b5a7a8b5SBram Moolenaar #define GetUserDefaultLocaleName	(*pGetUserDefaultLocaleName)
59b5a7a8b5SBram Moolenaar #define D2D1CreateFactory		(*pD2D1CreateFactory)
60b5a7a8b5SBram Moolenaar #define DWriteCreateFactory		(*pDWriteCreateFactory)
61b5a7a8b5SBram Moolenaar 
62b5a7a8b5SBram Moolenaar     static void
63b5a7a8b5SBram Moolenaar unload(HINSTANCE &hinst)
64b5a7a8b5SBram Moolenaar {
65b5a7a8b5SBram Moolenaar     if (hinst != NULL)
66b5a7a8b5SBram Moolenaar     {
67b5a7a8b5SBram Moolenaar 	FreeLibrary(hinst);
68b5a7a8b5SBram Moolenaar 	hinst = NULL;
69b5a7a8b5SBram Moolenaar     }
70b5a7a8b5SBram Moolenaar }
71b5a7a8b5SBram Moolenaar #endif // DYNAMIC_DIRECTX
72b5a7a8b5SBram Moolenaar 
73b5a7a8b5SBram Moolenaar template <class T> inline void SafeRelease(T **ppT)
74b5a7a8b5SBram Moolenaar {
75b5a7a8b5SBram Moolenaar     if (*ppT)
76b5a7a8b5SBram Moolenaar     {
77b5a7a8b5SBram Moolenaar 	(*ppT)->Release();
78b5a7a8b5SBram Moolenaar 	*ppT = NULL;
79b5a7a8b5SBram Moolenaar     }
80b5a7a8b5SBram Moolenaar }
81b5a7a8b5SBram Moolenaar 
82b5a7a8b5SBram Moolenaar struct GdiTextRendererContext
83b5a7a8b5SBram Moolenaar {
84b5a7a8b5SBram Moolenaar     // const fields.
85b5a7a8b5SBram Moolenaar     COLORREF color;
86b5a7a8b5SBram Moolenaar     FLOAT cellWidth;
87b5a7a8b5SBram Moolenaar 
88b5a7a8b5SBram Moolenaar     // working fields.
89b5a7a8b5SBram Moolenaar     FLOAT offsetX;
90b5a7a8b5SBram Moolenaar };
91b5a7a8b5SBram Moolenaar 
92b5a7a8b5SBram Moolenaar     static DWRITE_PIXEL_GEOMETRY
93b5a7a8b5SBram Moolenaar ToPixelGeometry(int value)
94b5a7a8b5SBram Moolenaar {
95b5a7a8b5SBram Moolenaar     switch (value)
96b5a7a8b5SBram Moolenaar     {
97b5a7a8b5SBram Moolenaar 	default:
98b5a7a8b5SBram Moolenaar 	case 0:
99b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_FLAT;
100b5a7a8b5SBram Moolenaar 	case 1:
101b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_RGB;
102b5a7a8b5SBram Moolenaar 	case 2:
103b5a7a8b5SBram Moolenaar 	    return DWRITE_PIXEL_GEOMETRY_BGR;
104b5a7a8b5SBram Moolenaar     }
105b5a7a8b5SBram Moolenaar }
106b5a7a8b5SBram Moolenaar 
107b5a7a8b5SBram Moolenaar     static int
108b5a7a8b5SBram Moolenaar ToInt(DWRITE_PIXEL_GEOMETRY value)
109b5a7a8b5SBram Moolenaar {
110b5a7a8b5SBram Moolenaar     switch (value)
111b5a7a8b5SBram Moolenaar     {
112b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_FLAT:
113b5a7a8b5SBram Moolenaar 	    return 0;
114b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_RGB:
115b5a7a8b5SBram Moolenaar 	    return 1;
116b5a7a8b5SBram Moolenaar 	case DWRITE_PIXEL_GEOMETRY_BGR:
117b5a7a8b5SBram Moolenaar 	    return 2;
118b5a7a8b5SBram Moolenaar 	default:
119b5a7a8b5SBram Moolenaar 	    return -1;
120b5a7a8b5SBram Moolenaar     }
121b5a7a8b5SBram Moolenaar }
122b5a7a8b5SBram Moolenaar 
123b5a7a8b5SBram Moolenaar     static DWRITE_RENDERING_MODE
124b5a7a8b5SBram Moolenaar ToRenderingMode(int value)
125b5a7a8b5SBram Moolenaar {
126b5a7a8b5SBram Moolenaar     switch (value)
127b5a7a8b5SBram Moolenaar     {
128b5a7a8b5SBram Moolenaar 	default:
129b5a7a8b5SBram Moolenaar 	case 0:
130b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_DEFAULT;
131b5a7a8b5SBram Moolenaar 	case 1:
132b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_ALIASED;
133b5a7a8b5SBram Moolenaar 	case 2:
134b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
135b5a7a8b5SBram Moolenaar 	case 3:
136b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
137b5a7a8b5SBram Moolenaar 	case 4:
138b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
139b5a7a8b5SBram Moolenaar 	case 5:
140b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
141b5a7a8b5SBram Moolenaar 	case 6:
142b5a7a8b5SBram Moolenaar 	    return DWRITE_RENDERING_MODE_OUTLINE;
143b5a7a8b5SBram Moolenaar     }
144b5a7a8b5SBram Moolenaar }
145b5a7a8b5SBram Moolenaar 
146b5a7a8b5SBram Moolenaar     static D2D1_TEXT_ANTIALIAS_MODE
147b5a7a8b5SBram Moolenaar ToTextAntialiasMode(int value)
148b5a7a8b5SBram Moolenaar {
149b5a7a8b5SBram Moolenaar     switch (value)
150b5a7a8b5SBram Moolenaar     {
151b5a7a8b5SBram Moolenaar 	default:
152b5a7a8b5SBram Moolenaar 	case 0:
153b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
154b5a7a8b5SBram Moolenaar 	case 1:
155b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
156b5a7a8b5SBram Moolenaar 	case 2:
157b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
158b5a7a8b5SBram Moolenaar 	case 3:
159b5a7a8b5SBram Moolenaar 	    return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
160b5a7a8b5SBram Moolenaar     }
161b5a7a8b5SBram Moolenaar }
162b5a7a8b5SBram Moolenaar 
163b5a7a8b5SBram Moolenaar     static int
164b5a7a8b5SBram Moolenaar ToInt(DWRITE_RENDERING_MODE value)
165b5a7a8b5SBram Moolenaar {
166b5a7a8b5SBram Moolenaar     switch (value)
167b5a7a8b5SBram Moolenaar     {
168b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_DEFAULT:
169b5a7a8b5SBram Moolenaar 	    return 0;
170b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_ALIASED:
171b5a7a8b5SBram Moolenaar 	    return 1;
172b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
173b5a7a8b5SBram Moolenaar 	    return 2;
174b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
175b5a7a8b5SBram Moolenaar 	    return 3;
176b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
177b5a7a8b5SBram Moolenaar 	    return 4;
178b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
179b5a7a8b5SBram Moolenaar 	    return 5;
180b5a7a8b5SBram Moolenaar 	case DWRITE_RENDERING_MODE_OUTLINE:
181b5a7a8b5SBram Moolenaar 	    return 6;
182b5a7a8b5SBram Moolenaar 	default:
183b5a7a8b5SBram Moolenaar 	    return -1;
184b5a7a8b5SBram Moolenaar     }
185b5a7a8b5SBram Moolenaar }
186b5a7a8b5SBram Moolenaar 
187b5a7a8b5SBram Moolenaar class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
188b5a7a8b5SBram Moolenaar {
189b5a7a8b5SBram Moolenaar private:
190b5a7a8b5SBram Moolenaar     FLOAT mDelta;
191b5a7a8b5SBram Moolenaar     FLOAT *mAdjustedAdvances;
192b5a7a8b5SBram Moolenaar 
193b5a7a8b5SBram Moolenaar public:
194b5a7a8b5SBram Moolenaar     AdjustedGlyphRun(
195b5a7a8b5SBram Moolenaar 	    const DWRITE_GLYPH_RUN *glyphRun,
196b5a7a8b5SBram Moolenaar 	    FLOAT cellWidth) :
197b5a7a8b5SBram Moolenaar 	DWRITE_GLYPH_RUN(*glyphRun),
198b5a7a8b5SBram Moolenaar 	mDelta(0.0f),
199b5a7a8b5SBram Moolenaar 	mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
200b5a7a8b5SBram Moolenaar     {
201b5a7a8b5SBram Moolenaar 	assert(cellWidth != 0.0f);
202b5a7a8b5SBram Moolenaar 	for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
203b5a7a8b5SBram Moolenaar 	{
204b5a7a8b5SBram Moolenaar 	    FLOAT orig = glyphRun->glyphAdvances[i];
205b5a7a8b5SBram Moolenaar 	    FLOAT adjusted = adjustToCell(orig, cellWidth);
206b5a7a8b5SBram Moolenaar 	    mAdjustedAdvances[i] = adjusted;
207b5a7a8b5SBram Moolenaar 	    mDelta += adjusted - orig;
208b5a7a8b5SBram Moolenaar 	}
209b5a7a8b5SBram Moolenaar 	glyphAdvances = mAdjustedAdvances;
210b5a7a8b5SBram Moolenaar     }
211b5a7a8b5SBram Moolenaar 
212b5a7a8b5SBram Moolenaar     ~AdjustedGlyphRun(void)
213b5a7a8b5SBram Moolenaar     {
214b5a7a8b5SBram Moolenaar 	delete[] mAdjustedAdvances;
215b5a7a8b5SBram Moolenaar     }
216b5a7a8b5SBram Moolenaar 
217b5a7a8b5SBram Moolenaar     FLOAT getDelta(void) const
218b5a7a8b5SBram Moolenaar     {
219b5a7a8b5SBram Moolenaar 	return mDelta;
220b5a7a8b5SBram Moolenaar     }
221b5a7a8b5SBram Moolenaar 
222b5a7a8b5SBram Moolenaar     static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
223b5a7a8b5SBram Moolenaar     {
224b5a7a8b5SBram Moolenaar 	int cellCount = (int)floor(value / cellWidth + 0.5f);
225b5a7a8b5SBram Moolenaar 	if (cellCount < 1)
226b5a7a8b5SBram Moolenaar 	    cellCount = 1;
227b5a7a8b5SBram Moolenaar 	return cellCount * cellWidth;
228b5a7a8b5SBram Moolenaar     }
229b5a7a8b5SBram Moolenaar };
230b5a7a8b5SBram Moolenaar 
231*cc6cf9b9SBram Moolenaar class GdiTextRenderer FINAL : public IDWriteTextRenderer
232b5a7a8b5SBram Moolenaar {
233b5a7a8b5SBram Moolenaar public:
234b5a7a8b5SBram Moolenaar     GdiTextRenderer(
235b5a7a8b5SBram Moolenaar 	    IDWriteBitmapRenderTarget* bitmapRenderTarget,
236b5a7a8b5SBram Moolenaar 	    IDWriteRenderingParams* renderingParams) :
237b5a7a8b5SBram Moolenaar 	cRefCount_(0),
238b5a7a8b5SBram Moolenaar 	pRenderTarget_(bitmapRenderTarget),
239b5a7a8b5SBram Moolenaar 	pRenderingParams_(renderingParams)
240b5a7a8b5SBram Moolenaar     {
241b5a7a8b5SBram Moolenaar 	pRenderTarget_->AddRef();
242b5a7a8b5SBram Moolenaar 	pRenderingParams_->AddRef();
243b5a7a8b5SBram Moolenaar 	AddRef();
244b5a7a8b5SBram Moolenaar     }
245b5a7a8b5SBram Moolenaar 
246edb4f2b3SBram Moolenaar     // add "virtual" to avoid a compiler warning
247edb4f2b3SBram Moolenaar     virtual ~GdiTextRenderer()
248b5a7a8b5SBram Moolenaar     {
249b5a7a8b5SBram Moolenaar 	SafeRelease(&pRenderTarget_);
250b5a7a8b5SBram Moolenaar 	SafeRelease(&pRenderingParams_);
251b5a7a8b5SBram Moolenaar     }
252b5a7a8b5SBram Moolenaar 
253b5a7a8b5SBram Moolenaar     IFACEMETHOD(IsPixelSnappingDisabled)(
254b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
255b5a7a8b5SBram Moolenaar 	__out BOOL* isDisabled)
256b5a7a8b5SBram Moolenaar     {
257b5a7a8b5SBram Moolenaar 	*isDisabled = FALSE;
258b5a7a8b5SBram Moolenaar 	return S_OK;
259b5a7a8b5SBram Moolenaar     }
260b5a7a8b5SBram Moolenaar 
261b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetCurrentTransform)(
262b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
263b5a7a8b5SBram Moolenaar 	__out DWRITE_MATRIX* transform)
264b5a7a8b5SBram Moolenaar     {
265b5a7a8b5SBram Moolenaar 	// forward the render target's transform
266b5a7a8b5SBram Moolenaar 	pRenderTarget_->GetCurrentTransform(transform);
267b5a7a8b5SBram Moolenaar 	return S_OK;
268b5a7a8b5SBram Moolenaar     }
269b5a7a8b5SBram Moolenaar 
270b5a7a8b5SBram Moolenaar     IFACEMETHOD(GetPixelsPerDip)(
271b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
272b5a7a8b5SBram Moolenaar 	__out FLOAT* pixelsPerDip)
273b5a7a8b5SBram Moolenaar     {
274b5a7a8b5SBram Moolenaar 	*pixelsPerDip = pRenderTarget_->GetPixelsPerDip();
275b5a7a8b5SBram Moolenaar 	return S_OK;
276b5a7a8b5SBram Moolenaar     }
277b5a7a8b5SBram Moolenaar 
278b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawGlyphRun)(
279b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
280b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
281b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
282b5a7a8b5SBram Moolenaar 	DWRITE_MEASURING_MODE measuringMode,
283b5a7a8b5SBram Moolenaar 	__in DWRITE_GLYPH_RUN const* glyphRun,
284b5a7a8b5SBram Moolenaar 	__in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
285b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
286b5a7a8b5SBram Moolenaar     {
287b5a7a8b5SBram Moolenaar 	HRESULT hr = S_OK;
288b5a7a8b5SBram Moolenaar 
289b5a7a8b5SBram Moolenaar 	GdiTextRendererContext *context =
290b5a7a8b5SBram Moolenaar 	    reinterpret_cast<GdiTextRendererContext*>(clientDrawingContext);
291b5a7a8b5SBram Moolenaar 
292b5a7a8b5SBram Moolenaar 	AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth);
293b5a7a8b5SBram Moolenaar 
294b5a7a8b5SBram Moolenaar 	// Pass on the drawing call to the render target to do the real work.
295b5a7a8b5SBram Moolenaar 	RECT dirtyRect = {0};
296b5a7a8b5SBram Moolenaar 
297b5a7a8b5SBram Moolenaar 	hr = pRenderTarget_->DrawGlyphRun(
298b5a7a8b5SBram Moolenaar 		baselineOriginX + context->offsetX,
299b5a7a8b5SBram Moolenaar 		baselineOriginY,
300b5a7a8b5SBram Moolenaar 		measuringMode,
301b5a7a8b5SBram Moolenaar 		&adjustedGlyphRun,
302b5a7a8b5SBram Moolenaar 		pRenderingParams_,
303b5a7a8b5SBram Moolenaar 		context->color,
304b5a7a8b5SBram Moolenaar 		&dirtyRect);
305b5a7a8b5SBram Moolenaar 
306b5a7a8b5SBram Moolenaar 	context->offsetX += adjustedGlyphRun.getDelta();
307b5a7a8b5SBram Moolenaar 
308b5a7a8b5SBram Moolenaar 	return hr;
309b5a7a8b5SBram Moolenaar     }
310b5a7a8b5SBram Moolenaar 
311b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawUnderline)(
312b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
313b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
314b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
315b5a7a8b5SBram Moolenaar 	__in DWRITE_UNDERLINE const* underline,
316b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
317b5a7a8b5SBram Moolenaar     {
318b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
319b5a7a8b5SBram Moolenaar     }
320b5a7a8b5SBram Moolenaar 
321b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawStrikethrough)(
322b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
323b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginX,
324b5a7a8b5SBram Moolenaar 	FLOAT baselineOriginY,
325b5a7a8b5SBram Moolenaar 	__in DWRITE_STRIKETHROUGH const* strikethrough,
326b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
327b5a7a8b5SBram Moolenaar     {
328b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
329b5a7a8b5SBram Moolenaar     }
330b5a7a8b5SBram Moolenaar 
331b5a7a8b5SBram Moolenaar     IFACEMETHOD(DrawInlineObject)(
332b5a7a8b5SBram Moolenaar 	__maybenull void* clientDrawingContext,
333b5a7a8b5SBram Moolenaar 	FLOAT originX,
334b5a7a8b5SBram Moolenaar 	FLOAT originY,
335b5a7a8b5SBram Moolenaar 	IDWriteInlineObject* inlineObject,
336b5a7a8b5SBram Moolenaar 	BOOL isSideways,
337b5a7a8b5SBram Moolenaar 	BOOL isRightToLeft,
338b5a7a8b5SBram Moolenaar 	IUnknown* clientDrawingEffect)
339b5a7a8b5SBram Moolenaar     {
340b5a7a8b5SBram Moolenaar 	return E_NOTIMPL;
341b5a7a8b5SBram Moolenaar     }
342b5a7a8b5SBram Moolenaar 
343b5a7a8b5SBram Moolenaar public:
344b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, AddRef) ()
345b5a7a8b5SBram Moolenaar     {
346b5a7a8b5SBram Moolenaar 	return InterlockedIncrement(&cRefCount_);
347b5a7a8b5SBram Moolenaar     }
348b5a7a8b5SBram Moolenaar 
349b5a7a8b5SBram Moolenaar     IFACEMETHOD_(unsigned long, Release) ()
350b5a7a8b5SBram Moolenaar     {
351b5a7a8b5SBram Moolenaar 	long newCount = InterlockedDecrement(&cRefCount_);
352b5a7a8b5SBram Moolenaar 
353b5a7a8b5SBram Moolenaar 	if (newCount == 0)
354b5a7a8b5SBram Moolenaar 	{
355b5a7a8b5SBram Moolenaar 	    delete this;
356b5a7a8b5SBram Moolenaar 	    return 0;
357b5a7a8b5SBram Moolenaar 	}
358b5a7a8b5SBram Moolenaar 	return newCount;
359b5a7a8b5SBram Moolenaar     }
360b5a7a8b5SBram Moolenaar 
361b5a7a8b5SBram Moolenaar     IFACEMETHOD(QueryInterface)(
362b5a7a8b5SBram Moolenaar 	IID const& riid,
363b5a7a8b5SBram Moolenaar 	void** ppvObject)
364b5a7a8b5SBram Moolenaar     {
365b5a7a8b5SBram Moolenaar 	if (__uuidof(IDWriteTextRenderer) == riid)
366b5a7a8b5SBram Moolenaar 	{
367b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
368b5a7a8b5SBram Moolenaar 	}
369b5a7a8b5SBram Moolenaar 	else if (__uuidof(IDWritePixelSnapping) == riid)
370b5a7a8b5SBram Moolenaar 	{
371b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
372b5a7a8b5SBram Moolenaar 	}
373b5a7a8b5SBram Moolenaar 	else if (__uuidof(IUnknown) == riid)
374b5a7a8b5SBram Moolenaar 	{
375b5a7a8b5SBram Moolenaar 	    *ppvObject = this;
376b5a7a8b5SBram Moolenaar 	}
377b5a7a8b5SBram Moolenaar 	else
378b5a7a8b5SBram Moolenaar 	{
379b5a7a8b5SBram Moolenaar 	    *ppvObject = NULL;
380b5a7a8b5SBram Moolenaar 	    return E_FAIL;
381b5a7a8b5SBram Moolenaar 	}
382b5a7a8b5SBram Moolenaar 
383b5a7a8b5SBram Moolenaar 	return S_OK;
384b5a7a8b5SBram Moolenaar     }
385b5a7a8b5SBram Moolenaar 
386b5a7a8b5SBram Moolenaar private:
3870106b4b8SBram Moolenaar     long cRefCount_;
388b5a7a8b5SBram Moolenaar     IDWriteBitmapRenderTarget* pRenderTarget_;
389b5a7a8b5SBram Moolenaar     IDWriteRenderingParams* pRenderingParams_;
390b5a7a8b5SBram Moolenaar };
391b5a7a8b5SBram Moolenaar 
392b5a7a8b5SBram Moolenaar struct DWriteContext {
393b5a7a8b5SBram Moolenaar     FLOAT mDpiScaleX;
394b5a7a8b5SBram Moolenaar     FLOAT mDpiScaleY;
395b5a7a8b5SBram Moolenaar     bool mDrawing;
396b5a7a8b5SBram Moolenaar 
397b5a7a8b5SBram Moolenaar     ID2D1Factory *mD2D1Factory;
398b5a7a8b5SBram Moolenaar 
399b5a7a8b5SBram Moolenaar     ID2D1DCRenderTarget *mRT;
400b5a7a8b5SBram Moolenaar     ID2D1SolidColorBrush *mBrush;
401b5a7a8b5SBram Moolenaar 
402b5a7a8b5SBram Moolenaar     IDWriteFactory *mDWriteFactory;
403b5a7a8b5SBram Moolenaar     IDWriteGdiInterop *mGdiInterop;
404b5a7a8b5SBram Moolenaar     IDWriteRenderingParams *mRenderingParams;
405b5a7a8b5SBram Moolenaar     IDWriteTextFormat *mTextFormat;
406b5a7a8b5SBram Moolenaar 
407b5a7a8b5SBram Moolenaar     HFONT mLastHFont;
408b5a7a8b5SBram Moolenaar     DWRITE_FONT_WEIGHT mFontWeight;
409b5a7a8b5SBram Moolenaar     DWRITE_FONT_STYLE mFontStyle;
410b5a7a8b5SBram Moolenaar 
411b5a7a8b5SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
412b5a7a8b5SBram Moolenaar 
413b5a7a8b5SBram Moolenaar     // METHODS
414b5a7a8b5SBram Moolenaar 
415b5a7a8b5SBram Moolenaar     DWriteContext();
416b5a7a8b5SBram Moolenaar 
417b5a7a8b5SBram Moolenaar     virtual ~DWriteContext();
418b5a7a8b5SBram Moolenaar 
419b5a7a8b5SBram Moolenaar     HRESULT SetLOGFONT(const LOGFONTW &logFont, float fontSize);
420b5a7a8b5SBram Moolenaar 
421b5a7a8b5SBram Moolenaar     void SetFont(HFONT hFont);
422b5a7a8b5SBram Moolenaar 
423b5a7a8b5SBram Moolenaar     void SetFont(const LOGFONTW &logFont);
424b5a7a8b5SBram Moolenaar 
425b5a7a8b5SBram Moolenaar     void DrawText(HDC hdc, const WCHAR* text, int len,
426b5a7a8b5SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color);
427b5a7a8b5SBram Moolenaar 
428b5a7a8b5SBram Moolenaar     float PixelsToDipsX(int x);
429b5a7a8b5SBram Moolenaar 
430b5a7a8b5SBram Moolenaar     float PixelsToDipsY(int y);
431b5a7a8b5SBram Moolenaar 
432b5a7a8b5SBram Moolenaar     void SetRenderingParams(
433b5a7a8b5SBram Moolenaar 	    const DWriteRenderingParams *params);
434b5a7a8b5SBram Moolenaar 
435b5a7a8b5SBram Moolenaar     DWriteRenderingParams *GetRenderingParams(
436b5a7a8b5SBram Moolenaar 	    DWriteRenderingParams *params);
437b5a7a8b5SBram Moolenaar };
438b5a7a8b5SBram Moolenaar 
439b5a7a8b5SBram Moolenaar DWriteContext::DWriteContext() :
440b5a7a8b5SBram Moolenaar     mDpiScaleX(1.f),
441b5a7a8b5SBram Moolenaar     mDpiScaleY(1.f),
442b5a7a8b5SBram Moolenaar     mDrawing(false),
443b5a7a8b5SBram Moolenaar     mD2D1Factory(NULL),
444b5a7a8b5SBram Moolenaar     mRT(NULL),
445b5a7a8b5SBram Moolenaar     mBrush(NULL),
446b5a7a8b5SBram Moolenaar     mDWriteFactory(NULL),
447b5a7a8b5SBram Moolenaar     mGdiInterop(NULL),
448b5a7a8b5SBram Moolenaar     mRenderingParams(NULL),
449b5a7a8b5SBram Moolenaar     mTextFormat(NULL),
450b5a7a8b5SBram Moolenaar     mLastHFont(NULL),
451b5a7a8b5SBram Moolenaar     mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
452b5a7a8b5SBram Moolenaar     mFontStyle(DWRITE_FONT_STYLE_NORMAL),
453b5a7a8b5SBram Moolenaar     mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
454b5a7a8b5SBram Moolenaar {
455b5a7a8b5SBram Moolenaar     HRESULT hr;
456b5a7a8b5SBram Moolenaar 
457b5a7a8b5SBram Moolenaar     HDC screen = ::GetDC(0);
458b5a7a8b5SBram Moolenaar     mDpiScaleX = ::GetDeviceCaps(screen, LOGPIXELSX) / 96.0f;
459b5a7a8b5SBram Moolenaar     mDpiScaleY = ::GetDeviceCaps(screen, LOGPIXELSY) / 96.0f;
460b5a7a8b5SBram Moolenaar     ::ReleaseDC(0, screen);
461b5a7a8b5SBram Moolenaar 
462b5a7a8b5SBram Moolenaar     hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
463b5a7a8b5SBram Moolenaar 	    __uuidof(ID2D1Factory), NULL,
464b5a7a8b5SBram Moolenaar 	    reinterpret_cast<void**>(&mD2D1Factory));
465b5a7a8b5SBram Moolenaar     _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
466b5a7a8b5SBram Moolenaar 
467b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
468b5a7a8b5SBram Moolenaar     {
469b5a7a8b5SBram Moolenaar 	D2D1_RENDER_TARGET_PROPERTIES props = {
470b5a7a8b5SBram Moolenaar 	    D2D1_RENDER_TARGET_TYPE_DEFAULT,
471b5a7a8b5SBram Moolenaar 	    { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
472b5a7a8b5SBram Moolenaar 	    0, 0,
473b5a7a8b5SBram Moolenaar 	    D2D1_RENDER_TARGET_USAGE_NONE,
474b5a7a8b5SBram Moolenaar 	    D2D1_FEATURE_LEVEL_DEFAULT
475b5a7a8b5SBram Moolenaar 	};
476b5a7a8b5SBram Moolenaar 	hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
477b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
478b5a7a8b5SBram Moolenaar     }
479b5a7a8b5SBram Moolenaar 
480b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
481b5a7a8b5SBram Moolenaar     {
482b5a7a8b5SBram Moolenaar 	hr = mRT->CreateSolidColorBrush(
483b5a7a8b5SBram Moolenaar 		D2D1::ColorF(D2D1::ColorF::Black),
484b5a7a8b5SBram Moolenaar 		&mBrush);
485b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
486b5a7a8b5SBram Moolenaar     }
487b5a7a8b5SBram Moolenaar 
488b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
489b5a7a8b5SBram Moolenaar     {
490b5a7a8b5SBram Moolenaar 	hr = DWriteCreateFactory(
491b5a7a8b5SBram Moolenaar 		DWRITE_FACTORY_TYPE_SHARED,
492b5a7a8b5SBram Moolenaar 		__uuidof(IDWriteFactory),
493b5a7a8b5SBram Moolenaar 		reinterpret_cast<IUnknown**>(&mDWriteFactory));
494b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
495b5a7a8b5SBram Moolenaar 		mDWriteFactory);
496b5a7a8b5SBram Moolenaar     }
497b5a7a8b5SBram Moolenaar 
498b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
499b5a7a8b5SBram Moolenaar     {
500b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
501b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
502b5a7a8b5SBram Moolenaar     }
503b5a7a8b5SBram Moolenaar 
504b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
505b5a7a8b5SBram Moolenaar     {
506b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
507b5a7a8b5SBram Moolenaar 	_RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
508b5a7a8b5SBram Moolenaar 		mRenderingParams);
509b5a7a8b5SBram Moolenaar     }
510b5a7a8b5SBram Moolenaar }
511b5a7a8b5SBram Moolenaar 
512b5a7a8b5SBram Moolenaar DWriteContext::~DWriteContext()
513b5a7a8b5SBram Moolenaar {
514b5a7a8b5SBram Moolenaar     SafeRelease(&mTextFormat);
515b5a7a8b5SBram Moolenaar     SafeRelease(&mRenderingParams);
516b5a7a8b5SBram Moolenaar     SafeRelease(&mGdiInterop);
517b5a7a8b5SBram Moolenaar     SafeRelease(&mDWriteFactory);
518b5a7a8b5SBram Moolenaar     SafeRelease(&mBrush);
519b5a7a8b5SBram Moolenaar     SafeRelease(&mRT);
520b5a7a8b5SBram Moolenaar     SafeRelease(&mD2D1Factory);
521b5a7a8b5SBram Moolenaar }
522b5a7a8b5SBram Moolenaar 
523b5a7a8b5SBram Moolenaar     HRESULT
524b5a7a8b5SBram Moolenaar DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize)
525b5a7a8b5SBram Moolenaar {
526b5a7a8b5SBram Moolenaar     // Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx
527b5a7a8b5SBram Moolenaar     HRESULT hr = S_OK;
528b5a7a8b5SBram Moolenaar 
529b5a7a8b5SBram Moolenaar     IDWriteFont *font = NULL;
530b5a7a8b5SBram Moolenaar     IDWriteFontFamily *fontFamily = NULL;
531b5a7a8b5SBram Moolenaar     IDWriteLocalizedStrings *localizedFamilyNames = NULL;
532b5a7a8b5SBram Moolenaar 
533b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
534b5a7a8b5SBram Moolenaar     {
535b5a7a8b5SBram Moolenaar 	hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
536b5a7a8b5SBram Moolenaar     }
537b5a7a8b5SBram Moolenaar 
538b5a7a8b5SBram Moolenaar     // Get the font family to which this font belongs.
539b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
540b5a7a8b5SBram Moolenaar     {
541b5a7a8b5SBram Moolenaar 	hr = font->GetFontFamily(&fontFamily);
542b5a7a8b5SBram Moolenaar     }
543b5a7a8b5SBram Moolenaar 
544b5a7a8b5SBram Moolenaar     // Get the family names. This returns an object that encapsulates one or
545b5a7a8b5SBram Moolenaar     // more names with the same meaning but in different languages.
546b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
547b5a7a8b5SBram Moolenaar     {
548b5a7a8b5SBram Moolenaar 	hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
549b5a7a8b5SBram Moolenaar     }
550b5a7a8b5SBram Moolenaar 
551b5a7a8b5SBram Moolenaar     // Get the family name at index zero. If we were going to display the name
552b5a7a8b5SBram Moolenaar     // we'd want to try to find one that matched the use locale, but for
553b5a7a8b5SBram Moolenaar     // purposes of creating a text format object any language will do.
554b5a7a8b5SBram Moolenaar 
555b5a7a8b5SBram Moolenaar     wchar_t familyName[100];
556b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
557b5a7a8b5SBram Moolenaar     {
558b5a7a8b5SBram Moolenaar 	hr = localizedFamilyNames->GetString(0, familyName,
559b5a7a8b5SBram Moolenaar 		ARRAYSIZE(familyName));
560b5a7a8b5SBram Moolenaar     }
561b5a7a8b5SBram Moolenaar 
562b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
563b5a7a8b5SBram Moolenaar     {
564b5a7a8b5SBram Moolenaar 	// If no font size was passed in use the lfHeight of the LOGFONT.
565b5a7a8b5SBram Moolenaar 	if (fontSize == 0)
566b5a7a8b5SBram Moolenaar 	{
567b5a7a8b5SBram Moolenaar 	    // Convert from pixels to DIPs.
568b5a7a8b5SBram Moolenaar 	    fontSize = PixelsToDipsY(logFont.lfHeight);
569b5a7a8b5SBram Moolenaar 	    if (fontSize < 0)
570b5a7a8b5SBram Moolenaar 	    {
571b5a7a8b5SBram Moolenaar 		// Negative lfHeight represents the size of the em unit.
572b5a7a8b5SBram Moolenaar 		fontSize = -fontSize;
573b5a7a8b5SBram Moolenaar 	    }
574b5a7a8b5SBram Moolenaar 	    else
575b5a7a8b5SBram Moolenaar 	    {
576b5a7a8b5SBram Moolenaar 		// Positive lfHeight represents the cell height (ascent +
577b5a7a8b5SBram Moolenaar 		// descent).
578b5a7a8b5SBram Moolenaar 		DWRITE_FONT_METRICS fontMetrics;
579b5a7a8b5SBram Moolenaar 		font->GetMetrics(&fontMetrics);
580b5a7a8b5SBram Moolenaar 
581b5a7a8b5SBram Moolenaar 		// Convert the cell height (ascent + descent) from design units
582b5a7a8b5SBram Moolenaar 		// to ems.
583b5a7a8b5SBram Moolenaar 		float cellHeight = static_cast<float>(
584b5a7a8b5SBram Moolenaar 			fontMetrics.ascent + fontMetrics.descent)
585b5a7a8b5SBram Moolenaar 					       / fontMetrics.designUnitsPerEm;
586b5a7a8b5SBram Moolenaar 
587b5a7a8b5SBram Moolenaar 		// Divide the font size by the cell height to get the font em
588b5a7a8b5SBram Moolenaar 		// size.
589b5a7a8b5SBram Moolenaar 		fontSize /= cellHeight;
590b5a7a8b5SBram Moolenaar 	    }
591b5a7a8b5SBram Moolenaar 	}
592b5a7a8b5SBram Moolenaar     }
593b5a7a8b5SBram Moolenaar 
594b5a7a8b5SBram Moolenaar     // The text format includes a locale name. Ideally, this would be the
595b5a7a8b5SBram Moolenaar     // language of the text, which may or may not be the same as the primary
596b5a7a8b5SBram Moolenaar     // language of the user. However, for our purposes the user locale will do.
597b5a7a8b5SBram Moolenaar     wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
598b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
599b5a7a8b5SBram Moolenaar     {
600b5a7a8b5SBram Moolenaar 	if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
601b5a7a8b5SBram Moolenaar 	    hr = HRESULT_FROM_WIN32(GetLastError());
602b5a7a8b5SBram Moolenaar     }
603b5a7a8b5SBram Moolenaar 
604b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
605b5a7a8b5SBram Moolenaar     {
606b5a7a8b5SBram Moolenaar 	// Create the text format object.
607b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateTextFormat(
608b5a7a8b5SBram Moolenaar 		familyName,
609b5a7a8b5SBram Moolenaar 		NULL, // no custom font collection
610b5a7a8b5SBram Moolenaar 		font->GetWeight(),
611b5a7a8b5SBram Moolenaar 		font->GetStyle(),
612b5a7a8b5SBram Moolenaar 		font->GetStretch(),
613b5a7a8b5SBram Moolenaar 		fontSize,
614b5a7a8b5SBram Moolenaar 		localeName,
615b5a7a8b5SBram Moolenaar 		&mTextFormat);
616b5a7a8b5SBram Moolenaar     }
617b5a7a8b5SBram Moolenaar 
618b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
619b5a7a8b5SBram Moolenaar     {
620b5a7a8b5SBram Moolenaar 	mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
621b5a7a8b5SBram Moolenaar 	mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
622b5a7a8b5SBram Moolenaar 	    : DWRITE_FONT_STYLE_NORMAL;
623b5a7a8b5SBram Moolenaar     }
624b5a7a8b5SBram Moolenaar 
625b5a7a8b5SBram Moolenaar     SafeRelease(&localizedFamilyNames);
626b5a7a8b5SBram Moolenaar     SafeRelease(&fontFamily);
627b5a7a8b5SBram Moolenaar     SafeRelease(&font);
628b5a7a8b5SBram Moolenaar 
629b5a7a8b5SBram Moolenaar     return hr;
630b5a7a8b5SBram Moolenaar }
631b5a7a8b5SBram Moolenaar 
632b5a7a8b5SBram Moolenaar     void
633b5a7a8b5SBram Moolenaar DWriteContext::SetFont(HFONT hFont)
634b5a7a8b5SBram Moolenaar {
635b5a7a8b5SBram Moolenaar     if (mLastHFont != hFont)
636b5a7a8b5SBram Moolenaar     {
637b5a7a8b5SBram Moolenaar 	LOGFONTW lf;
638b5a7a8b5SBram Moolenaar 	if (GetObjectW(hFont, sizeof(lf), &lf))
639b5a7a8b5SBram Moolenaar 	{
640b5a7a8b5SBram Moolenaar 	    SetFont(lf);
641b5a7a8b5SBram Moolenaar 	    mLastHFont = hFont;
642b5a7a8b5SBram Moolenaar 	}
643b5a7a8b5SBram Moolenaar     }
644b5a7a8b5SBram Moolenaar }
645b5a7a8b5SBram Moolenaar 
646b5a7a8b5SBram Moolenaar     void
647b5a7a8b5SBram Moolenaar DWriteContext::SetFont(const LOGFONTW &logFont)
648b5a7a8b5SBram Moolenaar {
649b5a7a8b5SBram Moolenaar     SafeRelease(&mTextFormat);
650b5a7a8b5SBram Moolenaar     mLastHFont = NULL;
651b5a7a8b5SBram Moolenaar 
652b5a7a8b5SBram Moolenaar     HRESULT hr = SetLOGFONT(logFont, 0.f);
653b5a7a8b5SBram Moolenaar 
654b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
655b5a7a8b5SBram Moolenaar 	hr = mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
656b5a7a8b5SBram Moolenaar 
657b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
658b5a7a8b5SBram Moolenaar 	hr = mTextFormat->SetParagraphAlignment(
659b5a7a8b5SBram Moolenaar 		DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
660b5a7a8b5SBram Moolenaar 
661b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
662b5a7a8b5SBram Moolenaar 	hr = mTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
663b5a7a8b5SBram Moolenaar }
664b5a7a8b5SBram Moolenaar 
665b5a7a8b5SBram Moolenaar     void
666b5a7a8b5SBram Moolenaar DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len,
667b5a7a8b5SBram Moolenaar 	int x, int y, int w, int h, int cellWidth, COLORREF color)
668b5a7a8b5SBram Moolenaar {
669b5a7a8b5SBram Moolenaar     HRESULT hr = S_OK;
670b5a7a8b5SBram Moolenaar     IDWriteBitmapRenderTarget *bmpRT = NULL;
671b5a7a8b5SBram Moolenaar 
672b5a7a8b5SBram Moolenaar     // Skip when any fonts are not set.
673b5a7a8b5SBram Moolenaar     if (mTextFormat == NULL)
674b5a7a8b5SBram Moolenaar 	return;
675b5a7a8b5SBram Moolenaar 
676b5a7a8b5SBram Moolenaar     // Check possibility of zero divided error.
677b5a7a8b5SBram Moolenaar     if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f)
678b5a7a8b5SBram Moolenaar 	return;
679b5a7a8b5SBram Moolenaar 
680b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
681b5a7a8b5SBram Moolenaar 	hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT);
682b5a7a8b5SBram Moolenaar 
683b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr))
684b5a7a8b5SBram Moolenaar     {
685b5a7a8b5SBram Moolenaar 	IDWriteTextLayout *textLayout = NULL;
686b5a7a8b5SBram Moolenaar 
687b5a7a8b5SBram Moolenaar 	HDC memdc = bmpRT->GetMemoryDC();
688b5a7a8b5SBram Moolenaar 	BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY);
689b5a7a8b5SBram Moolenaar 
690b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateGdiCompatibleTextLayout(
691b5a7a8b5SBram Moolenaar 		text, len, mTextFormat, PixelsToDipsX(w),
692b5a7a8b5SBram Moolenaar 		PixelsToDipsY(h), mDpiScaleX, NULL, TRUE, &textLayout);
693b5a7a8b5SBram Moolenaar 
694b5a7a8b5SBram Moolenaar 	if (SUCCEEDED(hr))
695b5a7a8b5SBram Moolenaar 	{
6965fa4d448SBram Moolenaar 	    DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len };
697b5a7a8b5SBram Moolenaar 	    textLayout->SetFontWeight(mFontWeight, textRange);
698b5a7a8b5SBram Moolenaar 	    textLayout->SetFontStyle(mFontStyle, textRange);
699b5a7a8b5SBram Moolenaar 	}
700b5a7a8b5SBram Moolenaar 
701b5a7a8b5SBram Moolenaar 	if (SUCCEEDED(hr))
702b5a7a8b5SBram Moolenaar 	{
703b5a7a8b5SBram Moolenaar 	    GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT,
704b5a7a8b5SBram Moolenaar 		    mRenderingParams);
705b5a7a8b5SBram Moolenaar 	    GdiTextRendererContext data = {
706b5a7a8b5SBram Moolenaar 		color,
707b5a7a8b5SBram Moolenaar 		PixelsToDipsX(cellWidth),
708b5a7a8b5SBram Moolenaar 		0.0f
709b5a7a8b5SBram Moolenaar 	    };
710b5a7a8b5SBram Moolenaar 	    textLayout->Draw(&data, renderer, 0, 0);
711b5a7a8b5SBram Moolenaar 	    SafeRelease(&renderer);
712b5a7a8b5SBram Moolenaar 	}
713b5a7a8b5SBram Moolenaar 
714b5a7a8b5SBram Moolenaar 	BitBlt(hdc, x, y, w, h, memdc, 0, 0, SRCCOPY);
715b5a7a8b5SBram Moolenaar 
716b5a7a8b5SBram Moolenaar 	SafeRelease(&textLayout);
717b5a7a8b5SBram Moolenaar     }
718b5a7a8b5SBram Moolenaar 
719b5a7a8b5SBram Moolenaar     SafeRelease(&bmpRT);
720b5a7a8b5SBram Moolenaar }
721b5a7a8b5SBram Moolenaar 
722b5a7a8b5SBram Moolenaar     float
723b5a7a8b5SBram Moolenaar DWriteContext::PixelsToDipsX(int x)
724b5a7a8b5SBram Moolenaar {
725b5a7a8b5SBram Moolenaar     return x / mDpiScaleX;
726b5a7a8b5SBram Moolenaar }
727b5a7a8b5SBram Moolenaar 
728b5a7a8b5SBram Moolenaar     float
729b5a7a8b5SBram Moolenaar DWriteContext::PixelsToDipsY(int y)
730b5a7a8b5SBram Moolenaar {
731b5a7a8b5SBram Moolenaar     return y / mDpiScaleY;
732b5a7a8b5SBram Moolenaar }
733b5a7a8b5SBram Moolenaar 
734b5a7a8b5SBram Moolenaar     void
735b5a7a8b5SBram Moolenaar DWriteContext::SetRenderingParams(
736b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
737b5a7a8b5SBram Moolenaar {
738b5a7a8b5SBram Moolenaar     if (mDWriteFactory == NULL)
739b5a7a8b5SBram Moolenaar 	return;
740b5a7a8b5SBram Moolenaar 
741b5a7a8b5SBram Moolenaar     IDWriteRenderingParams *renderingParams = NULL;
742b5a7a8b5SBram Moolenaar     D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
743b5a7a8b5SBram Moolenaar 	D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
744b5a7a8b5SBram Moolenaar     HRESULT hr;
745b5a7a8b5SBram Moolenaar     if (params != NULL)
746b5a7a8b5SBram Moolenaar     {
747b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
748b5a7a8b5SBram Moolenaar 		params->enhancedContrast, params->clearTypeLevel,
749b5a7a8b5SBram Moolenaar 		ToPixelGeometry(params->pixelGeometry),
750b5a7a8b5SBram Moolenaar 		ToRenderingMode(params->renderingMode), &renderingParams);
751b5a7a8b5SBram Moolenaar 	textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
752b5a7a8b5SBram Moolenaar     }
753b5a7a8b5SBram Moolenaar     else
754b5a7a8b5SBram Moolenaar 	hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
755b5a7a8b5SBram Moolenaar     if (SUCCEEDED(hr) && renderingParams != NULL)
756b5a7a8b5SBram Moolenaar     {
757b5a7a8b5SBram Moolenaar 	SafeRelease(&mRenderingParams);
758b5a7a8b5SBram Moolenaar 	mRenderingParams = renderingParams;
759b5a7a8b5SBram Moolenaar 	mTextAntialiasMode = textAntialiasMode;
760b5a7a8b5SBram Moolenaar     }
761b5a7a8b5SBram Moolenaar }
762b5a7a8b5SBram Moolenaar 
763b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
764b5a7a8b5SBram Moolenaar DWriteContext::GetRenderingParams(
765b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
766b5a7a8b5SBram Moolenaar {
767b5a7a8b5SBram Moolenaar     if (params != NULL && mRenderingParams != NULL)
768b5a7a8b5SBram Moolenaar     {
769b5a7a8b5SBram Moolenaar 	params->gamma = mRenderingParams->GetGamma();
770b5a7a8b5SBram Moolenaar 	params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
771b5a7a8b5SBram Moolenaar 	params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
772b5a7a8b5SBram Moolenaar 	params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
773b5a7a8b5SBram Moolenaar 	params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
774b5a7a8b5SBram Moolenaar 	params->textAntialiasMode = mTextAntialiasMode;
775b5a7a8b5SBram Moolenaar     }
776b5a7a8b5SBram Moolenaar     return params;
777b5a7a8b5SBram Moolenaar }
778b5a7a8b5SBram Moolenaar 
779b5a7a8b5SBram Moolenaar ////////////////////////////////////////////////////////////////////////////
780b5a7a8b5SBram Moolenaar // PUBLIC C INTERFACES
781b5a7a8b5SBram Moolenaar 
782b5a7a8b5SBram Moolenaar     void
783b5a7a8b5SBram Moolenaar DWrite_Init(void)
784b5a7a8b5SBram Moolenaar {
785b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
786b5a7a8b5SBram Moolenaar     // Load libraries.
787b5a7a8b5SBram Moolenaar     hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
788b5a7a8b5SBram Moolenaar     hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
789b5a7a8b5SBram Moolenaar     if (hD2D1DLL == NULL || hDWriteDLL == NULL)
790b5a7a8b5SBram Moolenaar     {
791b5a7a8b5SBram Moolenaar 	DWrite_Final();
792b5a7a8b5SBram Moolenaar 	return;
793b5a7a8b5SBram Moolenaar     }
794b5a7a8b5SBram Moolenaar     // Get address of procedures.
795b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
796b5a7a8b5SBram Moolenaar 	    GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
797b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
798b5a7a8b5SBram Moolenaar 	    "D2D1CreateFactory");
799b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
800b5a7a8b5SBram Moolenaar 	    "DWriteCreateFactory");
801b5a7a8b5SBram Moolenaar #endif
802b5a7a8b5SBram Moolenaar }
803b5a7a8b5SBram Moolenaar 
804b5a7a8b5SBram Moolenaar     void
805b5a7a8b5SBram Moolenaar DWrite_Final(void)
806b5a7a8b5SBram Moolenaar {
807b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
808b5a7a8b5SBram Moolenaar     pGetUserDefaultLocaleName = NULL;
809b5a7a8b5SBram Moolenaar     pD2D1CreateFactory = NULL;
810b5a7a8b5SBram Moolenaar     pDWriteCreateFactory = NULL;
811b5a7a8b5SBram Moolenaar     unload(hDWriteDLL);
812b5a7a8b5SBram Moolenaar     unload(hD2D1DLL);
813b5a7a8b5SBram Moolenaar #endif
814b5a7a8b5SBram Moolenaar }
815b5a7a8b5SBram Moolenaar 
816b5a7a8b5SBram Moolenaar     DWriteContext *
817b5a7a8b5SBram Moolenaar DWriteContext_Open(void)
818b5a7a8b5SBram Moolenaar {
819b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
820b5a7a8b5SBram Moolenaar     if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
821b5a7a8b5SBram Moolenaar 	    || pDWriteCreateFactory == NULL)
822b5a7a8b5SBram Moolenaar 	return NULL;
823b5a7a8b5SBram Moolenaar #endif
824b5a7a8b5SBram Moolenaar     return new DWriteContext();
825b5a7a8b5SBram Moolenaar }
826b5a7a8b5SBram Moolenaar 
827b5a7a8b5SBram Moolenaar     void
828b5a7a8b5SBram Moolenaar DWriteContext_BeginDraw(DWriteContext *ctx)
829b5a7a8b5SBram Moolenaar {
830b5a7a8b5SBram Moolenaar     if (ctx != NULL && ctx->mRT != NULL)
831b5a7a8b5SBram Moolenaar     {
832b5a7a8b5SBram Moolenaar 	ctx->mRT->BeginDraw();
833b5a7a8b5SBram Moolenaar 	ctx->mRT->SetTransform(D2D1::IdentityMatrix());
834b5a7a8b5SBram Moolenaar 	ctx->mDrawing = true;
835b5a7a8b5SBram Moolenaar     }
836b5a7a8b5SBram Moolenaar }
837b5a7a8b5SBram Moolenaar 
838b5a7a8b5SBram Moolenaar     void
839b5a7a8b5SBram Moolenaar DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect)
840b5a7a8b5SBram Moolenaar {
841b5a7a8b5SBram Moolenaar     if (ctx != NULL && ctx->mRT != NULL)
842b5a7a8b5SBram Moolenaar     {
843b5a7a8b5SBram Moolenaar 	ctx->mRT->BindDC(hdc, rect);
844b5a7a8b5SBram Moolenaar 	ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode);
845b5a7a8b5SBram Moolenaar     }
846b5a7a8b5SBram Moolenaar }
847b5a7a8b5SBram Moolenaar 
848b5a7a8b5SBram Moolenaar     void
849b5a7a8b5SBram Moolenaar DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
850b5a7a8b5SBram Moolenaar {
851b5a7a8b5SBram Moolenaar     if (ctx != NULL)
852b5a7a8b5SBram Moolenaar     {
853b5a7a8b5SBram Moolenaar 	ctx->SetFont(hFont);
854b5a7a8b5SBram Moolenaar     }
855b5a7a8b5SBram Moolenaar }
856b5a7a8b5SBram Moolenaar 
857b5a7a8b5SBram Moolenaar     void
858b5a7a8b5SBram Moolenaar DWriteContext_DrawText(
859b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
860b5a7a8b5SBram Moolenaar 	HDC hdc,
861b5a7a8b5SBram Moolenaar 	const WCHAR* text,
862b5a7a8b5SBram Moolenaar 	int len,
863b5a7a8b5SBram Moolenaar 	int x,
864b5a7a8b5SBram Moolenaar 	int y,
865b5a7a8b5SBram Moolenaar 	int w,
866b5a7a8b5SBram Moolenaar 	int h,
867b5a7a8b5SBram Moolenaar 	int cellWidth,
868b5a7a8b5SBram Moolenaar 	COLORREF color)
869b5a7a8b5SBram Moolenaar {
870b5a7a8b5SBram Moolenaar     if (ctx != NULL)
871b5a7a8b5SBram Moolenaar 	ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color);
872b5a7a8b5SBram Moolenaar }
873b5a7a8b5SBram Moolenaar 
874b5a7a8b5SBram Moolenaar     void
875b5a7a8b5SBram Moolenaar DWriteContext_EndDraw(DWriteContext *ctx)
876b5a7a8b5SBram Moolenaar {
877b5a7a8b5SBram Moolenaar     if (ctx != NULL && ctx->mRT != NULL)
878b5a7a8b5SBram Moolenaar     {
879b5a7a8b5SBram Moolenaar 	ctx->mRT->EndDraw();
880b5a7a8b5SBram Moolenaar 	ctx->mDrawing = false;
881b5a7a8b5SBram Moolenaar     }
882b5a7a8b5SBram Moolenaar }
883b5a7a8b5SBram Moolenaar 
884b5a7a8b5SBram Moolenaar     void
885b5a7a8b5SBram Moolenaar DWriteContext_Close(DWriteContext *ctx)
886b5a7a8b5SBram Moolenaar {
887b5a7a8b5SBram Moolenaar     delete ctx;
888b5a7a8b5SBram Moolenaar }
889b5a7a8b5SBram Moolenaar 
890b5a7a8b5SBram Moolenaar     void
891b5a7a8b5SBram Moolenaar DWriteContext_SetRenderingParams(
892b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
893b5a7a8b5SBram Moolenaar 	const DWriteRenderingParams *params)
894b5a7a8b5SBram Moolenaar {
895b5a7a8b5SBram Moolenaar     if (ctx != NULL)
896b5a7a8b5SBram Moolenaar 	ctx->SetRenderingParams(params);
897b5a7a8b5SBram Moolenaar }
898b5a7a8b5SBram Moolenaar 
899b5a7a8b5SBram Moolenaar     DWriteRenderingParams *
900b5a7a8b5SBram Moolenaar DWriteContext_GetRenderingParams(
901b5a7a8b5SBram Moolenaar 	DWriteContext *ctx,
902b5a7a8b5SBram Moolenaar 	DWriteRenderingParams *params)
903b5a7a8b5SBram Moolenaar {
904b5a7a8b5SBram Moolenaar     if (ctx != NULL)
905b5a7a8b5SBram Moolenaar 	return ctx->GetRenderingParams(params);
906b5a7a8b5SBram Moolenaar     else
907b5a7a8b5SBram Moolenaar 	return NULL;
908b5a7a8b5SBram Moolenaar }
909