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