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