1b5a7a8b5SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet: */
2b5a7a8b5SBram Moolenaar /*
3b5a7a8b5SBram Moolenaar * Author: MURAOKA Taro <[email protected]>
4b5a7a8b5SBram Moolenaar *
5b5a7a8b5SBram Moolenaar * Contributors:
6b5a7a8b5SBram Moolenaar * - Ken Takata
7d7ccc4d8SBram Moolenaar * - Yasuhiro Matsumoto
8b5a7a8b5SBram Moolenaar *
9b5a7a8b5SBram Moolenaar * Copyright (C) 2013 MURAOKA Taro <[email protected]>
10b5a7a8b5SBram Moolenaar * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
11b5a7a8b5SBram Moolenaar */
12b5a7a8b5SBram Moolenaar
13b5a7a8b5SBram Moolenaar #define WIN32_LEAN_AND_MEAN
14b5a7a8b5SBram Moolenaar
15b5a7a8b5SBram Moolenaar #ifndef DYNAMIC_DIRECTX
16b5a7a8b5SBram Moolenaar # if WINVER < 0x0600
17b5a7a8b5SBram Moolenaar # error WINVER must be 0x0600 or above to use DirectWrite(DirectX)
18b5a7a8b5SBram Moolenaar # endif
19b5a7a8b5SBram Moolenaar #endif
20b5a7a8b5SBram Moolenaar
21b5a7a8b5SBram Moolenaar #include <windows.h>
22b5a7a8b5SBram Moolenaar #include <crtdbg.h>
23b5a7a8b5SBram Moolenaar #include <assert.h>
24b5a7a8b5SBram Moolenaar #include <math.h>
25b5a7a8b5SBram Moolenaar #include <d2d1.h>
26b5a7a8b5SBram Moolenaar #include <d2d1helper.h>
27d7ccc4d8SBram Moolenaar
28d7ccc4d8SBram Moolenaar // Disable these macros to compile with old VC and newer SDK (V8.1 or later).
29d7ccc4d8SBram Moolenaar #if defined(_MSC_VER) && (_MSC_VER < 1700)
30d7ccc4d8SBram Moolenaar # define _COM_Outptr_ __out
31d7ccc4d8SBram Moolenaar # define _In_reads_(s)
32d7ccc4d8SBram Moolenaar # define _In_reads_opt_(s)
33d7ccc4d8SBram Moolenaar # define _Maybenull_
34d7ccc4d8SBram Moolenaar # define _Out_writes_(s)
35d7ccc4d8SBram Moolenaar # define _Out_writes_opt_(s)
36d7ccc4d8SBram Moolenaar # define _Out_writes_to_(x, y)
37d7ccc4d8SBram Moolenaar # define _Out_writes_to_opt_(x, y)
38d7ccc4d8SBram Moolenaar # define _Outptr_
39d7ccc4d8SBram Moolenaar #endif
40d7ccc4d8SBram Moolenaar
417f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
42d7ccc4d8SBram Moolenaar # include <dwrite_2.h>
437f88b65fSBram Moolenaar #else
447f88b65fSBram Moolenaar # include <dwrite.h>
457f88b65fSBram Moolenaar #endif
46b5a7a8b5SBram Moolenaar
47b5a7a8b5SBram Moolenaar #include "gui_dwrite.h"
48b5a7a8b5SBram Moolenaar
49b5a7a8b5SBram Moolenaar #ifdef __MINGW32__
50b5a7a8b5SBram Moolenaar # define __maybenull SAL__maybenull
51b5a7a8b5SBram Moolenaar # define __in SAL__in
52b5a7a8b5SBram Moolenaar # define __out SAL__out
53b5a7a8b5SBram Moolenaar #endif
54b5a7a8b5SBram Moolenaar
55cc6cf9b9SBram Moolenaar #if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
56cc6cf9b9SBram Moolenaar # define FINAL final
57cc6cf9b9SBram Moolenaar #else
58cc6cf9b9SBram Moolenaar # define FINAL
59cc6cf9b9SBram Moolenaar #endif
60cc6cf9b9SBram Moolenaar
61b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
62b5a7a8b5SBram Moolenaar extern "C" HINSTANCE vimLoadLib(char *name);
63b5a7a8b5SBram Moolenaar
64b5a7a8b5SBram Moolenaar typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
65b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
66b5a7a8b5SBram Moolenaar REFIID, const D2D1_FACTORY_OPTIONS *, void **);
67b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
68b5a7a8b5SBram Moolenaar REFIID, IUnknown **);
69b5a7a8b5SBram Moolenaar
70b5a7a8b5SBram Moolenaar static HINSTANCE hD2D1DLL = NULL;
71b5a7a8b5SBram Moolenaar static HINSTANCE hDWriteDLL = NULL;
72b5a7a8b5SBram Moolenaar
73b5a7a8b5SBram Moolenaar static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
74b5a7a8b5SBram Moolenaar static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
75b5a7a8b5SBram Moolenaar static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
76b5a7a8b5SBram Moolenaar
77b5a7a8b5SBram Moolenaar #define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName)
78b5a7a8b5SBram Moolenaar #define D2D1CreateFactory (*pD2D1CreateFactory)
79b5a7a8b5SBram Moolenaar #define DWriteCreateFactory (*pDWriteCreateFactory)
80b5a7a8b5SBram Moolenaar
81b5a7a8b5SBram Moolenaar static void
unload(HINSTANCE & hinst)82b5a7a8b5SBram Moolenaar unload(HINSTANCE &hinst)
83b5a7a8b5SBram Moolenaar {
84b5a7a8b5SBram Moolenaar if (hinst != NULL)
85b5a7a8b5SBram Moolenaar {
86b5a7a8b5SBram Moolenaar FreeLibrary(hinst);
87b5a7a8b5SBram Moolenaar hinst = NULL;
88b5a7a8b5SBram Moolenaar }
89b5a7a8b5SBram Moolenaar }
90b5a7a8b5SBram Moolenaar #endif // DYNAMIC_DIRECTX
91b5a7a8b5SBram Moolenaar
SafeRelease(T ** ppT)92b5a7a8b5SBram Moolenaar template <class T> inline void SafeRelease(T **ppT)
93b5a7a8b5SBram Moolenaar {
94b5a7a8b5SBram Moolenaar if (*ppT)
95b5a7a8b5SBram Moolenaar {
96b5a7a8b5SBram Moolenaar (*ppT)->Release();
97b5a7a8b5SBram Moolenaar *ppT = NULL;
98b5a7a8b5SBram Moolenaar }
99b5a7a8b5SBram Moolenaar }
100b5a7a8b5SBram Moolenaar
101b5a7a8b5SBram Moolenaar static DWRITE_PIXEL_GEOMETRY
ToPixelGeometry(int value)102b5a7a8b5SBram Moolenaar ToPixelGeometry(int value)
103b5a7a8b5SBram Moolenaar {
104b5a7a8b5SBram Moolenaar switch (value)
105b5a7a8b5SBram Moolenaar {
106b5a7a8b5SBram Moolenaar default:
107b5a7a8b5SBram Moolenaar case 0:
108b5a7a8b5SBram Moolenaar return DWRITE_PIXEL_GEOMETRY_FLAT;
109b5a7a8b5SBram Moolenaar case 1:
110b5a7a8b5SBram Moolenaar return DWRITE_PIXEL_GEOMETRY_RGB;
111b5a7a8b5SBram Moolenaar case 2:
112b5a7a8b5SBram Moolenaar return DWRITE_PIXEL_GEOMETRY_BGR;
113b5a7a8b5SBram Moolenaar }
114b5a7a8b5SBram Moolenaar }
115b5a7a8b5SBram Moolenaar
116b5a7a8b5SBram Moolenaar static int
ToInt(DWRITE_PIXEL_GEOMETRY value)117b5a7a8b5SBram Moolenaar ToInt(DWRITE_PIXEL_GEOMETRY value)
118b5a7a8b5SBram Moolenaar {
119b5a7a8b5SBram Moolenaar switch (value)
120b5a7a8b5SBram Moolenaar {
121b5a7a8b5SBram Moolenaar case DWRITE_PIXEL_GEOMETRY_FLAT:
122b5a7a8b5SBram Moolenaar return 0;
123b5a7a8b5SBram Moolenaar case DWRITE_PIXEL_GEOMETRY_RGB:
124b5a7a8b5SBram Moolenaar return 1;
125b5a7a8b5SBram Moolenaar case DWRITE_PIXEL_GEOMETRY_BGR:
126b5a7a8b5SBram Moolenaar return 2;
127b5a7a8b5SBram Moolenaar default:
128b5a7a8b5SBram Moolenaar return -1;
129b5a7a8b5SBram Moolenaar }
130b5a7a8b5SBram Moolenaar }
131b5a7a8b5SBram Moolenaar
132b5a7a8b5SBram Moolenaar static DWRITE_RENDERING_MODE
ToRenderingMode(int value)133b5a7a8b5SBram Moolenaar ToRenderingMode(int value)
134b5a7a8b5SBram Moolenaar {
135b5a7a8b5SBram Moolenaar switch (value)
136b5a7a8b5SBram Moolenaar {
137b5a7a8b5SBram Moolenaar default:
138b5a7a8b5SBram Moolenaar case 0:
139b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_DEFAULT;
140b5a7a8b5SBram Moolenaar case 1:
141b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_ALIASED;
142b5a7a8b5SBram Moolenaar case 2:
143b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
144b5a7a8b5SBram Moolenaar case 3:
145b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
146b5a7a8b5SBram Moolenaar case 4:
147b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
148b5a7a8b5SBram Moolenaar case 5:
149b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
150b5a7a8b5SBram Moolenaar case 6:
151b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_OUTLINE;
152b5a7a8b5SBram Moolenaar }
153b5a7a8b5SBram Moolenaar }
154b5a7a8b5SBram Moolenaar
155b5a7a8b5SBram Moolenaar static D2D1_TEXT_ANTIALIAS_MODE
ToTextAntialiasMode(int value)156b5a7a8b5SBram Moolenaar ToTextAntialiasMode(int value)
157b5a7a8b5SBram Moolenaar {
158b5a7a8b5SBram Moolenaar switch (value)
159b5a7a8b5SBram Moolenaar {
160b5a7a8b5SBram Moolenaar default:
161b5a7a8b5SBram Moolenaar case 0:
162b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
163b5a7a8b5SBram Moolenaar case 1:
164b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
165b5a7a8b5SBram Moolenaar case 2:
166b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
167b5a7a8b5SBram Moolenaar case 3:
168b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
169b5a7a8b5SBram Moolenaar }
170b5a7a8b5SBram Moolenaar }
171b5a7a8b5SBram Moolenaar
172b5a7a8b5SBram Moolenaar static int
ToInt(DWRITE_RENDERING_MODE value)173b5a7a8b5SBram Moolenaar ToInt(DWRITE_RENDERING_MODE value)
174b5a7a8b5SBram Moolenaar {
175b5a7a8b5SBram Moolenaar switch (value)
176b5a7a8b5SBram Moolenaar {
177b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_DEFAULT:
178b5a7a8b5SBram Moolenaar return 0;
179b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_ALIASED:
180b5a7a8b5SBram Moolenaar return 1;
181b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
182b5a7a8b5SBram Moolenaar return 2;
183b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
184b5a7a8b5SBram Moolenaar return 3;
185b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
186b5a7a8b5SBram Moolenaar return 4;
187b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
188b5a7a8b5SBram Moolenaar return 5;
189b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_OUTLINE:
190b5a7a8b5SBram Moolenaar return 6;
191b5a7a8b5SBram Moolenaar default:
192b5a7a8b5SBram Moolenaar return -1;
193b5a7a8b5SBram Moolenaar }
194b5a7a8b5SBram Moolenaar }
195b5a7a8b5SBram Moolenaar
196d7ccc4d8SBram Moolenaar class FontCache {
197d7ccc4d8SBram Moolenaar public:
198d7ccc4d8SBram Moolenaar struct Item {
199d7ccc4d8SBram Moolenaar HFONT hFont;
200d7ccc4d8SBram Moolenaar IDWriteTextFormat* pTextFormat;
201d7ccc4d8SBram Moolenaar DWRITE_FONT_WEIGHT fontWeight;
202d7ccc4d8SBram Moolenaar DWRITE_FONT_STYLE fontStyle;
ItemFontCache::Item203d7ccc4d8SBram Moolenaar Item() : hFont(NULL), pTextFormat(NULL) {}
204d7ccc4d8SBram Moolenaar };
205d7ccc4d8SBram Moolenaar
206d7ccc4d8SBram Moolenaar private:
207d7ccc4d8SBram Moolenaar int mSize;
208d7ccc4d8SBram Moolenaar Item *mItems;
209d7ccc4d8SBram Moolenaar
210d7ccc4d8SBram Moolenaar public:
FontCache(int size=2)211d7ccc4d8SBram Moolenaar FontCache(int size = 2) :
212d7ccc4d8SBram Moolenaar mSize(size),
213d7ccc4d8SBram Moolenaar mItems(new Item[size])
214d7ccc4d8SBram Moolenaar {
215d7ccc4d8SBram Moolenaar }
216d7ccc4d8SBram Moolenaar
~FontCache()217d7ccc4d8SBram Moolenaar ~FontCache()
218d7ccc4d8SBram Moolenaar {
219d7ccc4d8SBram Moolenaar for (int i = 0; i < mSize; ++i)
220d7ccc4d8SBram Moolenaar SafeRelease(&mItems[i].pTextFormat);
221d7ccc4d8SBram Moolenaar delete[] mItems;
222d7ccc4d8SBram Moolenaar }
223d7ccc4d8SBram Moolenaar
get(HFONT hFont,Item & item)224d7ccc4d8SBram Moolenaar bool get(HFONT hFont, Item &item)
225d7ccc4d8SBram Moolenaar {
226d7ccc4d8SBram Moolenaar int n = find(hFont);
227d7ccc4d8SBram Moolenaar if (n < 0)
228d7ccc4d8SBram Moolenaar return false;
229d7ccc4d8SBram Moolenaar item = mItems[n];
230d7ccc4d8SBram Moolenaar slide(n);
231d7ccc4d8SBram Moolenaar return true;
232d7ccc4d8SBram Moolenaar }
233d7ccc4d8SBram Moolenaar
put(const Item & item)234d7ccc4d8SBram Moolenaar void put(const Item& item)
235d7ccc4d8SBram Moolenaar {
236d7ccc4d8SBram Moolenaar int n = find(item.hFont);
237d7ccc4d8SBram Moolenaar if (n < 0)
238d7ccc4d8SBram Moolenaar n = mSize - 1;
239d7ccc4d8SBram Moolenaar if (mItems[n].pTextFormat != item.pTextFormat)
240d7ccc4d8SBram Moolenaar {
241d7ccc4d8SBram Moolenaar SafeRelease(&mItems[n].pTextFormat);
242*1b3e0727SBram Moolenaar if (item.pTextFormat != NULL)
243d7ccc4d8SBram Moolenaar item.pTextFormat->AddRef();
244d7ccc4d8SBram Moolenaar }
245d7ccc4d8SBram Moolenaar mItems[n] = item;
246d7ccc4d8SBram Moolenaar slide(n);
247d7ccc4d8SBram Moolenaar }
248d7ccc4d8SBram Moolenaar
249d7ccc4d8SBram Moolenaar private:
find(HFONT hFont)250d7ccc4d8SBram Moolenaar int find(HFONT hFont)
251d7ccc4d8SBram Moolenaar {
252d7ccc4d8SBram Moolenaar for (int i = 0; i < mSize; ++i)
253d7ccc4d8SBram Moolenaar {
254d7ccc4d8SBram Moolenaar if (mItems[i].hFont == hFont)
255d7ccc4d8SBram Moolenaar return i;
256d7ccc4d8SBram Moolenaar }
257d7ccc4d8SBram Moolenaar return -1;
258d7ccc4d8SBram Moolenaar }
259d7ccc4d8SBram Moolenaar
slide(int nextTop)260d7ccc4d8SBram Moolenaar void slide(int nextTop)
261d7ccc4d8SBram Moolenaar {
262d7ccc4d8SBram Moolenaar if (nextTop == 0)
263d7ccc4d8SBram Moolenaar return;
264d7ccc4d8SBram Moolenaar Item tmp = mItems[nextTop];
265d7ccc4d8SBram Moolenaar for (int i = nextTop - 1; i >= 0; --i)
266d7ccc4d8SBram Moolenaar mItems[i + 1] = mItems[i];
267d7ccc4d8SBram Moolenaar mItems[0] = tmp;
268d7ccc4d8SBram Moolenaar }
269d7ccc4d8SBram Moolenaar };
270d7ccc4d8SBram Moolenaar
27192467d33SBram Moolenaar enum DrawingMode {
27292467d33SBram Moolenaar DM_GDI = 0,
27392467d33SBram Moolenaar DM_DIRECTX = 1,
27492467d33SBram Moolenaar DM_INTEROP = 2,
27592467d33SBram Moolenaar };
27692467d33SBram Moolenaar
277d7ccc4d8SBram Moolenaar struct DWriteContext {
278d7ccc4d8SBram Moolenaar HDC mHDC;
27992467d33SBram Moolenaar RECT mBindRect;
28092467d33SBram Moolenaar DrawingMode mDMode;
28192467d33SBram Moolenaar HDC mInteropHDC;
282d7ccc4d8SBram Moolenaar bool mDrawing;
283d7ccc4d8SBram Moolenaar bool mFallbackDC;
284d7ccc4d8SBram Moolenaar
285d7ccc4d8SBram Moolenaar ID2D1Factory *mD2D1Factory;
286d7ccc4d8SBram Moolenaar
287d7ccc4d8SBram Moolenaar ID2D1DCRenderTarget *mRT;
28892467d33SBram Moolenaar ID2D1GdiInteropRenderTarget *mGDIRT;
289d7ccc4d8SBram Moolenaar ID2D1SolidColorBrush *mBrush;
290a338adcfSBram Moolenaar ID2D1Bitmap *mBitmap;
291d7ccc4d8SBram Moolenaar
292d7ccc4d8SBram Moolenaar IDWriteFactory *mDWriteFactory;
2937f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
294d7ccc4d8SBram Moolenaar IDWriteFactory2 *mDWriteFactory2;
2957f88b65fSBram Moolenaar #endif
296d7ccc4d8SBram Moolenaar
297d7ccc4d8SBram Moolenaar IDWriteGdiInterop *mGdiInterop;
298d7ccc4d8SBram Moolenaar IDWriteRenderingParams *mRenderingParams;
299d7ccc4d8SBram Moolenaar
300d7ccc4d8SBram Moolenaar FontCache mFontCache;
301d7ccc4d8SBram Moolenaar IDWriteTextFormat *mTextFormat;
302d7ccc4d8SBram Moolenaar DWRITE_FONT_WEIGHT mFontWeight;
303d7ccc4d8SBram Moolenaar DWRITE_FONT_STYLE mFontStyle;
304d7ccc4d8SBram Moolenaar
305d7ccc4d8SBram Moolenaar D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
306d7ccc4d8SBram Moolenaar
307d7ccc4d8SBram Moolenaar // METHODS
308d7ccc4d8SBram Moolenaar
309d7ccc4d8SBram Moolenaar DWriteContext();
310d7ccc4d8SBram Moolenaar
311d7ccc4d8SBram Moolenaar virtual ~DWriteContext();
312d7ccc4d8SBram Moolenaar
31392467d33SBram Moolenaar HRESULT CreateDeviceResources();
31492467d33SBram Moolenaar
31592467d33SBram Moolenaar void DiscardDeviceResources();
31692467d33SBram Moolenaar
317d7ccc4d8SBram Moolenaar HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
318d7ccc4d8SBram Moolenaar IDWriteTextFormat **ppTextFormat);
319d7ccc4d8SBram Moolenaar
320d7ccc4d8SBram Moolenaar HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
321d7ccc4d8SBram Moolenaar
322d7ccc4d8SBram Moolenaar void SetFont(HFONT hFont);
323d7ccc4d8SBram Moolenaar
324a338adcfSBram Moolenaar void Rebind();
325a338adcfSBram Moolenaar
32692467d33SBram Moolenaar void BindDC(HDC hdc, const RECT *rect);
327d7ccc4d8SBram Moolenaar
32892467d33SBram Moolenaar HRESULT SetDrawingMode(DrawingMode mode);
329d7ccc4d8SBram Moolenaar
330d7ccc4d8SBram Moolenaar ID2D1Brush* SolidBrush(COLORREF color);
331d7ccc4d8SBram Moolenaar
332d7ccc4d8SBram Moolenaar void DrawText(const WCHAR *text, int len,
333d7ccc4d8SBram Moolenaar int x, int y, int w, int h, int cellWidth, COLORREF color,
33492467d33SBram Moolenaar UINT fuOptions, const RECT *lprc, const INT *lpDx);
335d7ccc4d8SBram Moolenaar
33692467d33SBram Moolenaar void FillRect(const RECT *rc, COLORREF color);
33792467d33SBram Moolenaar
33892467d33SBram Moolenaar void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
33992467d33SBram Moolenaar
34092467d33SBram Moolenaar void SetPixel(int x, int y, COLORREF color);
341d7ccc4d8SBram Moolenaar
342a338adcfSBram Moolenaar void Scroll(int x, int y, const RECT *rc);
343a338adcfSBram Moolenaar
344d7ccc4d8SBram Moolenaar void Flush();
345d7ccc4d8SBram Moolenaar
346d7ccc4d8SBram Moolenaar void SetRenderingParams(
347d7ccc4d8SBram Moolenaar const DWriteRenderingParams *params);
348d7ccc4d8SBram Moolenaar
349d7ccc4d8SBram Moolenaar DWriteRenderingParams *GetRenderingParams(
350d7ccc4d8SBram Moolenaar DWriteRenderingParams *params);
351d7ccc4d8SBram Moolenaar };
352d7ccc4d8SBram Moolenaar
353b5a7a8b5SBram Moolenaar class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
354b5a7a8b5SBram Moolenaar {
355b5a7a8b5SBram Moolenaar private:
356d7ccc4d8SBram Moolenaar FLOAT &mAccum;
357b5a7a8b5SBram Moolenaar FLOAT mDelta;
358b5a7a8b5SBram Moolenaar FLOAT *mAdjustedAdvances;
359b5a7a8b5SBram Moolenaar
360b5a7a8b5SBram Moolenaar public:
AdjustedGlyphRun(const DWRITE_GLYPH_RUN * glyphRun,FLOAT cellWidth,FLOAT & accum)361b5a7a8b5SBram Moolenaar AdjustedGlyphRun(
362b5a7a8b5SBram Moolenaar const DWRITE_GLYPH_RUN *glyphRun,
363d7ccc4d8SBram Moolenaar FLOAT cellWidth,
364d7ccc4d8SBram Moolenaar FLOAT &accum) :
365b5a7a8b5SBram Moolenaar DWRITE_GLYPH_RUN(*glyphRun),
366d7ccc4d8SBram Moolenaar mAccum(accum),
367b5a7a8b5SBram Moolenaar mDelta(0.0f),
368b5a7a8b5SBram Moolenaar mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
369b5a7a8b5SBram Moolenaar {
370b5a7a8b5SBram Moolenaar assert(cellWidth != 0.0f);
371b5a7a8b5SBram Moolenaar for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
372b5a7a8b5SBram Moolenaar {
373b5a7a8b5SBram Moolenaar FLOAT orig = glyphRun->glyphAdvances[i];
374b5a7a8b5SBram Moolenaar FLOAT adjusted = adjustToCell(orig, cellWidth);
375b5a7a8b5SBram Moolenaar mAdjustedAdvances[i] = adjusted;
376b5a7a8b5SBram Moolenaar mDelta += adjusted - orig;
377b5a7a8b5SBram Moolenaar }
378b5a7a8b5SBram Moolenaar glyphAdvances = mAdjustedAdvances;
379b5a7a8b5SBram Moolenaar }
380b5a7a8b5SBram Moolenaar
~AdjustedGlyphRun()381d7ccc4d8SBram Moolenaar ~AdjustedGlyphRun()
382b5a7a8b5SBram Moolenaar {
383d7ccc4d8SBram Moolenaar mAccum += mDelta;
384b5a7a8b5SBram Moolenaar delete[] mAdjustedAdvances;
385b5a7a8b5SBram Moolenaar }
386b5a7a8b5SBram Moolenaar
adjustToCell(FLOAT value,FLOAT cellWidth)387b5a7a8b5SBram Moolenaar static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
388b5a7a8b5SBram Moolenaar {
389d7ccc4d8SBram Moolenaar int cellCount = int(floor(value / cellWidth + 0.5f));
390b5a7a8b5SBram Moolenaar if (cellCount < 1)
391b5a7a8b5SBram Moolenaar cellCount = 1;
392b5a7a8b5SBram Moolenaar return cellCount * cellWidth;
393b5a7a8b5SBram Moolenaar }
394b5a7a8b5SBram Moolenaar };
395b5a7a8b5SBram Moolenaar
396d7ccc4d8SBram Moolenaar struct TextRendererContext {
397d7ccc4d8SBram Moolenaar // const fields.
398d7ccc4d8SBram Moolenaar COLORREF color;
399d7ccc4d8SBram Moolenaar FLOAT cellWidth;
400d7ccc4d8SBram Moolenaar
401d7ccc4d8SBram Moolenaar // working fields.
402d7ccc4d8SBram Moolenaar FLOAT offsetX;
403d7ccc4d8SBram Moolenaar };
404d7ccc4d8SBram Moolenaar
405d7ccc4d8SBram Moolenaar class TextRenderer FINAL : public IDWriteTextRenderer
406b5a7a8b5SBram Moolenaar {
407b5a7a8b5SBram Moolenaar public:
TextRenderer(DWriteContext * pDWC)408d7ccc4d8SBram Moolenaar TextRenderer(
409d7ccc4d8SBram Moolenaar DWriteContext* pDWC) :
410b5a7a8b5SBram Moolenaar cRefCount_(0),
411d7ccc4d8SBram Moolenaar pDWC_(pDWC)
412b5a7a8b5SBram Moolenaar {
413b5a7a8b5SBram Moolenaar AddRef();
414b5a7a8b5SBram Moolenaar }
415b5a7a8b5SBram Moolenaar
416edb4f2b3SBram Moolenaar // add "virtual" to avoid a compiler warning
~TextRenderer()417d7ccc4d8SBram Moolenaar virtual ~TextRenderer()
418b5a7a8b5SBram Moolenaar {
419b5a7a8b5SBram Moolenaar }
420b5a7a8b5SBram Moolenaar
IFACEMETHOD(IsPixelSnappingDisabled)421b5a7a8b5SBram Moolenaar IFACEMETHOD(IsPixelSnappingDisabled)(
422b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext,
423b5a7a8b5SBram Moolenaar __out BOOL* isDisabled)
424b5a7a8b5SBram Moolenaar {
425b5a7a8b5SBram Moolenaar *isDisabled = FALSE;
426b5a7a8b5SBram Moolenaar return S_OK;
427b5a7a8b5SBram Moolenaar }
428b5a7a8b5SBram Moolenaar
IFACEMETHOD(GetCurrentTransform)429b5a7a8b5SBram Moolenaar IFACEMETHOD(GetCurrentTransform)(
430b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext,
431b5a7a8b5SBram Moolenaar __out DWRITE_MATRIX* transform)
432b5a7a8b5SBram Moolenaar {
433b5a7a8b5SBram Moolenaar // forward the render target's transform
434d7ccc4d8SBram Moolenaar pDWC_->mRT->GetTransform(
435d7ccc4d8SBram Moolenaar reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
436b5a7a8b5SBram Moolenaar return S_OK;
437b5a7a8b5SBram Moolenaar }
438b5a7a8b5SBram Moolenaar
IFACEMETHOD(GetPixelsPerDip)439b5a7a8b5SBram Moolenaar IFACEMETHOD(GetPixelsPerDip)(
440b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext,
441b5a7a8b5SBram Moolenaar __out FLOAT* pixelsPerDip)
442b5a7a8b5SBram Moolenaar {
443d7ccc4d8SBram Moolenaar float dpiX, unused;
444d7ccc4d8SBram Moolenaar pDWC_->mRT->GetDpi(&dpiX, &unused);
445d7ccc4d8SBram Moolenaar *pixelsPerDip = dpiX / 96.0f;
446b5a7a8b5SBram Moolenaar return S_OK;
447b5a7a8b5SBram Moolenaar }
448b5a7a8b5SBram Moolenaar
IFACEMETHOD(DrawUnderline)449b5a7a8b5SBram Moolenaar IFACEMETHOD(DrawUnderline)(
450b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext,
451b5a7a8b5SBram Moolenaar FLOAT baselineOriginX,
452b5a7a8b5SBram Moolenaar FLOAT baselineOriginY,
453b5a7a8b5SBram Moolenaar __in DWRITE_UNDERLINE const* underline,
454b5a7a8b5SBram Moolenaar IUnknown* clientDrawingEffect)
455b5a7a8b5SBram Moolenaar {
456b5a7a8b5SBram Moolenaar return E_NOTIMPL;
457b5a7a8b5SBram Moolenaar }
458b5a7a8b5SBram Moolenaar
IFACEMETHOD(DrawStrikethrough)459b5a7a8b5SBram Moolenaar IFACEMETHOD(DrawStrikethrough)(
460b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext,
461b5a7a8b5SBram Moolenaar FLOAT baselineOriginX,
462b5a7a8b5SBram Moolenaar FLOAT baselineOriginY,
463b5a7a8b5SBram Moolenaar __in DWRITE_STRIKETHROUGH const* strikethrough,
464b5a7a8b5SBram Moolenaar IUnknown* clientDrawingEffect)
465b5a7a8b5SBram Moolenaar {
466b5a7a8b5SBram Moolenaar return E_NOTIMPL;
467b5a7a8b5SBram Moolenaar }
468b5a7a8b5SBram Moolenaar
IFACEMETHOD(DrawInlineObject)469b5a7a8b5SBram Moolenaar IFACEMETHOD(DrawInlineObject)(
470b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext,
471b5a7a8b5SBram Moolenaar FLOAT originX,
472b5a7a8b5SBram Moolenaar FLOAT originY,
473b5a7a8b5SBram Moolenaar IDWriteInlineObject* inlineObject,
474b5a7a8b5SBram Moolenaar BOOL isSideways,
475b5a7a8b5SBram Moolenaar BOOL isRightToLeft,
476b5a7a8b5SBram Moolenaar IUnknown* clientDrawingEffect)
477b5a7a8b5SBram Moolenaar {
478b5a7a8b5SBram Moolenaar return E_NOTIMPL;
479b5a7a8b5SBram Moolenaar }
480b5a7a8b5SBram Moolenaar
IFACEMETHOD(DrawGlyphRun)481d7ccc4d8SBram Moolenaar IFACEMETHOD(DrawGlyphRun)(
482d7ccc4d8SBram Moolenaar __maybenull void* clientDrawingContext,
483d7ccc4d8SBram Moolenaar FLOAT baselineOriginX,
484d7ccc4d8SBram Moolenaar FLOAT baselineOriginY,
485d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE measuringMode,
486d7ccc4d8SBram Moolenaar __in DWRITE_GLYPH_RUN const* glyphRun,
487d7ccc4d8SBram Moolenaar __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
488d7ccc4d8SBram Moolenaar IUnknown* clientDrawingEffect)
489d7ccc4d8SBram Moolenaar {
490d7ccc4d8SBram Moolenaar TextRendererContext *context =
491d7ccc4d8SBram Moolenaar reinterpret_cast<TextRendererContext*>(clientDrawingContext);
492d7ccc4d8SBram Moolenaar
493d7ccc4d8SBram Moolenaar AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
494d7ccc4d8SBram Moolenaar context->offsetX);
495d7ccc4d8SBram Moolenaar
4967f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
497d7ccc4d8SBram Moolenaar if (pDWC_->mDWriteFactory2 != NULL)
498d7ccc4d8SBram Moolenaar {
499d7ccc4d8SBram Moolenaar IDWriteColorGlyphRunEnumerator *enumerator = NULL;
500d7ccc4d8SBram Moolenaar HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
501d7ccc4d8SBram Moolenaar baselineOriginX + context->offsetX,
502d7ccc4d8SBram Moolenaar baselineOriginY,
503d7ccc4d8SBram Moolenaar &adjustedGlyphRun,
504d7ccc4d8SBram Moolenaar NULL,
505d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE_GDI_NATURAL,
506d7ccc4d8SBram Moolenaar NULL,
507d7ccc4d8SBram Moolenaar 0,
508d7ccc4d8SBram Moolenaar &enumerator);
509d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr))
510d7ccc4d8SBram Moolenaar {
511d7ccc4d8SBram Moolenaar // Draw by IDWriteFactory2 for color emoji
512d7ccc4d8SBram Moolenaar BOOL hasRun = TRUE;
513d7ccc4d8SBram Moolenaar enumerator->MoveNext(&hasRun);
514d7ccc4d8SBram Moolenaar while (hasRun)
515d7ccc4d8SBram Moolenaar {
516d7ccc4d8SBram Moolenaar const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
517d7ccc4d8SBram Moolenaar enumerator->GetCurrentRun(&colorGlyphRun);
518d7ccc4d8SBram Moolenaar
519d7ccc4d8SBram Moolenaar pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
520d7ccc4d8SBram Moolenaar pDWC_->mRT->DrawGlyphRun(
521d7ccc4d8SBram Moolenaar D2D1::Point2F(
522d7ccc4d8SBram Moolenaar colorGlyphRun->baselineOriginX,
523d7ccc4d8SBram Moolenaar colorGlyphRun->baselineOriginY),
524d7ccc4d8SBram Moolenaar &colorGlyphRun->glyphRun,
525d7ccc4d8SBram Moolenaar pDWC_->mBrush,
526d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE_NATURAL);
527d7ccc4d8SBram Moolenaar enumerator->MoveNext(&hasRun);
528d7ccc4d8SBram Moolenaar }
529d7ccc4d8SBram Moolenaar SafeRelease(&enumerator);
530d7ccc4d8SBram Moolenaar return S_OK;
531d7ccc4d8SBram Moolenaar }
532d7ccc4d8SBram Moolenaar }
5337f88b65fSBram Moolenaar #endif
534d7ccc4d8SBram Moolenaar
535d7ccc4d8SBram Moolenaar // Draw by IDWriteFactory (without color emoji)
536d7ccc4d8SBram Moolenaar pDWC_->mRT->DrawGlyphRun(
537d7ccc4d8SBram Moolenaar D2D1::Point2F(
538d7ccc4d8SBram Moolenaar baselineOriginX + context->offsetX,
539d7ccc4d8SBram Moolenaar baselineOriginY),
540d7ccc4d8SBram Moolenaar &adjustedGlyphRun,
541d7ccc4d8SBram Moolenaar pDWC_->SolidBrush(context->color),
542d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE_NATURAL);
543d7ccc4d8SBram Moolenaar return S_OK;
544d7ccc4d8SBram Moolenaar }
545d7ccc4d8SBram Moolenaar
546b5a7a8b5SBram Moolenaar public:
IFACEMETHOD_(unsigned long,AddRef)547b5a7a8b5SBram Moolenaar IFACEMETHOD_(unsigned long, AddRef) ()
548b5a7a8b5SBram Moolenaar {
549b5a7a8b5SBram Moolenaar return InterlockedIncrement(&cRefCount_);
550b5a7a8b5SBram Moolenaar }
551b5a7a8b5SBram Moolenaar
IFACEMETHOD_(unsigned long,Release)552b5a7a8b5SBram Moolenaar IFACEMETHOD_(unsigned long, Release) ()
553b5a7a8b5SBram Moolenaar {
554b5a7a8b5SBram Moolenaar long newCount = InterlockedDecrement(&cRefCount_);
555b5a7a8b5SBram Moolenaar
556b5a7a8b5SBram Moolenaar if (newCount == 0)
557b5a7a8b5SBram Moolenaar {
558b5a7a8b5SBram Moolenaar delete this;
559b5a7a8b5SBram Moolenaar return 0;
560b5a7a8b5SBram Moolenaar }
561b5a7a8b5SBram Moolenaar return newCount;
562b5a7a8b5SBram Moolenaar }
563b5a7a8b5SBram Moolenaar
IFACEMETHOD(QueryInterface)564b5a7a8b5SBram Moolenaar IFACEMETHOD(QueryInterface)(
565b5a7a8b5SBram Moolenaar IID const& riid,
566b5a7a8b5SBram Moolenaar void** ppvObject)
567b5a7a8b5SBram Moolenaar {
568b5a7a8b5SBram Moolenaar if (__uuidof(IDWriteTextRenderer) == riid)
569b5a7a8b5SBram Moolenaar {
570b5a7a8b5SBram Moolenaar *ppvObject = this;
571b5a7a8b5SBram Moolenaar }
572b5a7a8b5SBram Moolenaar else if (__uuidof(IDWritePixelSnapping) == riid)
573b5a7a8b5SBram Moolenaar {
574b5a7a8b5SBram Moolenaar *ppvObject = this;
575b5a7a8b5SBram Moolenaar }
576b5a7a8b5SBram Moolenaar else if (__uuidof(IUnknown) == riid)
577b5a7a8b5SBram Moolenaar {
578b5a7a8b5SBram Moolenaar *ppvObject = this;
579b5a7a8b5SBram Moolenaar }
580b5a7a8b5SBram Moolenaar else
581b5a7a8b5SBram Moolenaar {
582b5a7a8b5SBram Moolenaar *ppvObject = NULL;
583b5a7a8b5SBram Moolenaar return E_FAIL;
584b5a7a8b5SBram Moolenaar }
585b5a7a8b5SBram Moolenaar
586b5a7a8b5SBram Moolenaar return S_OK;
587b5a7a8b5SBram Moolenaar }
588b5a7a8b5SBram Moolenaar
589b5a7a8b5SBram Moolenaar private:
5900106b4b8SBram Moolenaar long cRefCount_;
591d7ccc4d8SBram Moolenaar DWriteContext* pDWC_;
592b5a7a8b5SBram Moolenaar };
593b5a7a8b5SBram Moolenaar
DWriteContext()594b5a7a8b5SBram Moolenaar DWriteContext::DWriteContext() :
595d7ccc4d8SBram Moolenaar mHDC(NULL),
59692467d33SBram Moolenaar mBindRect(),
59792467d33SBram Moolenaar mDMode(DM_GDI),
59892467d33SBram Moolenaar mInteropHDC(NULL),
599b5a7a8b5SBram Moolenaar mDrawing(false),
600d7ccc4d8SBram Moolenaar mFallbackDC(false),
601b5a7a8b5SBram Moolenaar mD2D1Factory(NULL),
602b5a7a8b5SBram Moolenaar mRT(NULL),
60392467d33SBram Moolenaar mGDIRT(NULL),
604b5a7a8b5SBram Moolenaar mBrush(NULL),
605a338adcfSBram Moolenaar mBitmap(NULL),
606b5a7a8b5SBram Moolenaar mDWriteFactory(NULL),
6077f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
608d7ccc4d8SBram Moolenaar mDWriteFactory2(NULL),
6097f88b65fSBram Moolenaar #endif
610b5a7a8b5SBram Moolenaar mGdiInterop(NULL),
611b5a7a8b5SBram Moolenaar mRenderingParams(NULL),
612d7ccc4d8SBram Moolenaar mFontCache(8),
613b5a7a8b5SBram Moolenaar mTextFormat(NULL),
614b5a7a8b5SBram Moolenaar mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
615b5a7a8b5SBram Moolenaar mFontStyle(DWRITE_FONT_STYLE_NORMAL),
616b5a7a8b5SBram Moolenaar mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
617b5a7a8b5SBram Moolenaar {
618b5a7a8b5SBram Moolenaar HRESULT hr;
619b5a7a8b5SBram Moolenaar
620b5a7a8b5SBram Moolenaar hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
621b5a7a8b5SBram Moolenaar __uuidof(ID2D1Factory), NULL,
622b5a7a8b5SBram Moolenaar reinterpret_cast<void**>(&mD2D1Factory));
623b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
624b5a7a8b5SBram Moolenaar
625b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
626b5a7a8b5SBram Moolenaar {
627b5a7a8b5SBram Moolenaar hr = DWriteCreateFactory(
628b5a7a8b5SBram Moolenaar DWRITE_FACTORY_TYPE_SHARED,
629b5a7a8b5SBram Moolenaar __uuidof(IDWriteFactory),
630b5a7a8b5SBram Moolenaar reinterpret_cast<IUnknown**>(&mDWriteFactory));
631b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
632b5a7a8b5SBram Moolenaar mDWriteFactory);
633b5a7a8b5SBram Moolenaar }
634b5a7a8b5SBram Moolenaar
6357f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
636b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
637b5a7a8b5SBram Moolenaar {
638d7ccc4d8SBram Moolenaar DWriteCreateFactory(
639d7ccc4d8SBram Moolenaar DWRITE_FACTORY_TYPE_SHARED,
640d7ccc4d8SBram Moolenaar __uuidof(IDWriteFactory2),
641d7ccc4d8SBram Moolenaar reinterpret_cast<IUnknown**>(&mDWriteFactory2));
642d7ccc4d8SBram Moolenaar _RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
643d7ccc4d8SBram Moolenaar }
6447f88b65fSBram Moolenaar #endif
645d7ccc4d8SBram Moolenaar
646d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr))
647d7ccc4d8SBram Moolenaar {
648b5a7a8b5SBram Moolenaar hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
649b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
650b5a7a8b5SBram Moolenaar }
651b5a7a8b5SBram Moolenaar
652b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
653b5a7a8b5SBram Moolenaar {
654b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
655b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
656b5a7a8b5SBram Moolenaar mRenderingParams);
657b5a7a8b5SBram Moolenaar }
658b5a7a8b5SBram Moolenaar }
659b5a7a8b5SBram Moolenaar
~DWriteContext()660b5a7a8b5SBram Moolenaar DWriteContext::~DWriteContext()
661b5a7a8b5SBram Moolenaar {
662b5a7a8b5SBram Moolenaar SafeRelease(&mTextFormat);
663b5a7a8b5SBram Moolenaar SafeRelease(&mRenderingParams);
664b5a7a8b5SBram Moolenaar SafeRelease(&mGdiInterop);
665b5a7a8b5SBram Moolenaar SafeRelease(&mDWriteFactory);
6667f88b65fSBram Moolenaar #ifdef FEAT_DIRECTX_COLOR_EMOJI
667d7ccc4d8SBram Moolenaar SafeRelease(&mDWriteFactory2);
6687f88b65fSBram Moolenaar #endif
669a338adcfSBram Moolenaar SafeRelease(&mBitmap);
670b5a7a8b5SBram Moolenaar SafeRelease(&mBrush);
67192467d33SBram Moolenaar SafeRelease(&mGDIRT);
672b5a7a8b5SBram Moolenaar SafeRelease(&mRT);
673b5a7a8b5SBram Moolenaar SafeRelease(&mD2D1Factory);
674b5a7a8b5SBram Moolenaar }
675b5a7a8b5SBram Moolenaar
676b5a7a8b5SBram Moolenaar HRESULT
CreateDeviceResources()67792467d33SBram Moolenaar DWriteContext::CreateDeviceResources()
67892467d33SBram Moolenaar {
67992467d33SBram Moolenaar HRESULT hr;
68092467d33SBram Moolenaar
68192467d33SBram Moolenaar if (mRT != NULL)
68292467d33SBram Moolenaar return S_OK;
68392467d33SBram Moolenaar
68492467d33SBram Moolenaar D2D1_RENDER_TARGET_PROPERTIES props = {
68592467d33SBram Moolenaar D2D1_RENDER_TARGET_TYPE_DEFAULT,
68692467d33SBram Moolenaar { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
68792467d33SBram Moolenaar 0, 0,
68892467d33SBram Moolenaar D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
68992467d33SBram Moolenaar D2D1_FEATURE_LEVEL_DEFAULT
69092467d33SBram Moolenaar };
69192467d33SBram Moolenaar hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
69292467d33SBram Moolenaar _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
69392467d33SBram Moolenaar
69492467d33SBram Moolenaar if (SUCCEEDED(hr))
69592467d33SBram Moolenaar {
69692467d33SBram Moolenaar // This always succeeds.
69792467d33SBram Moolenaar mRT->QueryInterface(
69892467d33SBram Moolenaar __uuidof(ID2D1GdiInteropRenderTarget),
69992467d33SBram Moolenaar reinterpret_cast<void**>(&mGDIRT));
70092467d33SBram Moolenaar _RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT);
70192467d33SBram Moolenaar }
70292467d33SBram Moolenaar
70392467d33SBram Moolenaar if (SUCCEEDED(hr))
70492467d33SBram Moolenaar {
70592467d33SBram Moolenaar hr = mRT->CreateSolidColorBrush(
70692467d33SBram Moolenaar D2D1::ColorF(D2D1::ColorF::Black),
70792467d33SBram Moolenaar &mBrush);
70892467d33SBram Moolenaar _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
70992467d33SBram Moolenaar }
71092467d33SBram Moolenaar
71192467d33SBram Moolenaar if (SUCCEEDED(hr))
712a338adcfSBram Moolenaar Rebind();
71392467d33SBram Moolenaar
71492467d33SBram Moolenaar return hr;
71592467d33SBram Moolenaar }
71692467d33SBram Moolenaar
71792467d33SBram Moolenaar void
DiscardDeviceResources()71892467d33SBram Moolenaar DWriteContext::DiscardDeviceResources()
71992467d33SBram Moolenaar {
720a338adcfSBram Moolenaar SafeRelease(&mBitmap);
72192467d33SBram Moolenaar SafeRelease(&mBrush);
72292467d33SBram Moolenaar SafeRelease(&mGDIRT);
72392467d33SBram Moolenaar SafeRelease(&mRT);
72492467d33SBram Moolenaar }
72592467d33SBram Moolenaar
72692467d33SBram Moolenaar HRESULT
CreateTextFormatFromLOGFONT(const LOGFONTW & logFont,IDWriteTextFormat ** ppTextFormat)727d7ccc4d8SBram Moolenaar DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
728d7ccc4d8SBram Moolenaar IDWriteTextFormat **ppTextFormat)
729b5a7a8b5SBram Moolenaar {
730d7ccc4d8SBram Moolenaar // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
731b5a7a8b5SBram Moolenaar HRESULT hr = S_OK;
732d7ccc4d8SBram Moolenaar IDWriteTextFormat *pTextFormat = NULL;
733b5a7a8b5SBram Moolenaar
734b5a7a8b5SBram Moolenaar IDWriteFont *font = NULL;
735b5a7a8b5SBram Moolenaar IDWriteFontFamily *fontFamily = NULL;
736b5a7a8b5SBram Moolenaar IDWriteLocalizedStrings *localizedFamilyNames = NULL;
737d7ccc4d8SBram Moolenaar float fontSize = 0;
738b5a7a8b5SBram Moolenaar
739b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
740b5a7a8b5SBram Moolenaar {
741b5a7a8b5SBram Moolenaar hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
742b5a7a8b5SBram Moolenaar }
743b5a7a8b5SBram Moolenaar
744b5a7a8b5SBram Moolenaar // Get the font family to which this font belongs.
745b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
746b5a7a8b5SBram Moolenaar {
747b5a7a8b5SBram Moolenaar hr = font->GetFontFamily(&fontFamily);
748b5a7a8b5SBram Moolenaar }
749b5a7a8b5SBram Moolenaar
750b5a7a8b5SBram Moolenaar // Get the family names. This returns an object that encapsulates one or
751b5a7a8b5SBram Moolenaar // more names with the same meaning but in different languages.
752b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
753b5a7a8b5SBram Moolenaar {
754b5a7a8b5SBram Moolenaar hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
755b5a7a8b5SBram Moolenaar }
756b5a7a8b5SBram Moolenaar
757b5a7a8b5SBram Moolenaar // Get the family name at index zero. If we were going to display the name
758b5a7a8b5SBram Moolenaar // we'd want to try to find one that matched the use locale, but for
759b5a7a8b5SBram Moolenaar // purposes of creating a text format object any language will do.
760b5a7a8b5SBram Moolenaar
761b5a7a8b5SBram Moolenaar wchar_t familyName[100];
762b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
763b5a7a8b5SBram Moolenaar {
764b5a7a8b5SBram Moolenaar hr = localizedFamilyNames->GetString(0, familyName,
765b5a7a8b5SBram Moolenaar ARRAYSIZE(familyName));
766b5a7a8b5SBram Moolenaar }
767b5a7a8b5SBram Moolenaar
768b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
769b5a7a8b5SBram Moolenaar {
770d7ccc4d8SBram Moolenaar // Use lfHeight of the LOGFONT as font size.
771d7ccc4d8SBram Moolenaar fontSize = float(logFont.lfHeight);
772d7ccc4d8SBram Moolenaar
773b5a7a8b5SBram Moolenaar if (fontSize < 0)
774b5a7a8b5SBram Moolenaar {
775b5a7a8b5SBram Moolenaar // Negative lfHeight represents the size of the em unit.
776b5a7a8b5SBram Moolenaar fontSize = -fontSize;
777b5a7a8b5SBram Moolenaar }
778b5a7a8b5SBram Moolenaar else
779b5a7a8b5SBram Moolenaar {
780b5a7a8b5SBram Moolenaar // Positive lfHeight represents the cell height (ascent +
781b5a7a8b5SBram Moolenaar // descent).
782b5a7a8b5SBram Moolenaar DWRITE_FONT_METRICS fontMetrics;
783b5a7a8b5SBram Moolenaar font->GetMetrics(&fontMetrics);
784b5a7a8b5SBram Moolenaar
785b5a7a8b5SBram Moolenaar // Convert the cell height (ascent + descent) from design units
786b5a7a8b5SBram Moolenaar // to ems.
787b5a7a8b5SBram Moolenaar float cellHeight = static_cast<float>(
788b5a7a8b5SBram Moolenaar fontMetrics.ascent + fontMetrics.descent)
789b5a7a8b5SBram Moolenaar / fontMetrics.designUnitsPerEm;
790b5a7a8b5SBram Moolenaar
791b5a7a8b5SBram Moolenaar // Divide the font size by the cell height to get the font em
792b5a7a8b5SBram Moolenaar // size.
793b5a7a8b5SBram Moolenaar fontSize /= cellHeight;
794b5a7a8b5SBram Moolenaar }
795b5a7a8b5SBram Moolenaar }
796b5a7a8b5SBram Moolenaar
797b5a7a8b5SBram Moolenaar // The text format includes a locale name. Ideally, this would be the
798b5a7a8b5SBram Moolenaar // language of the text, which may or may not be the same as the primary
799b5a7a8b5SBram Moolenaar // language of the user. However, for our purposes the user locale will do.
800b5a7a8b5SBram Moolenaar wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
801b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
802b5a7a8b5SBram Moolenaar {
803b5a7a8b5SBram Moolenaar if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
804b5a7a8b5SBram Moolenaar hr = HRESULT_FROM_WIN32(GetLastError());
805b5a7a8b5SBram Moolenaar }
806b5a7a8b5SBram Moolenaar
807b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
808b5a7a8b5SBram Moolenaar {
809b5a7a8b5SBram Moolenaar // Create the text format object.
810b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateTextFormat(
811b5a7a8b5SBram Moolenaar familyName,
812b5a7a8b5SBram Moolenaar NULL, // no custom font collection
813b5a7a8b5SBram Moolenaar font->GetWeight(),
814b5a7a8b5SBram Moolenaar font->GetStyle(),
815b5a7a8b5SBram Moolenaar font->GetStretch(),
816b5a7a8b5SBram Moolenaar fontSize,
817b5a7a8b5SBram Moolenaar localeName,
818d7ccc4d8SBram Moolenaar &pTextFormat);
819b5a7a8b5SBram Moolenaar }
820b5a7a8b5SBram Moolenaar
821b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
822d7ccc4d8SBram Moolenaar hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
823d7ccc4d8SBram Moolenaar
824d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr))
825d7ccc4d8SBram Moolenaar hr = pTextFormat->SetParagraphAlignment(
8261f271efbSBram Moolenaar DWRITE_PARAGRAPH_ALIGNMENT_FAR);
827d7ccc4d8SBram Moolenaar
828d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr))
829d7ccc4d8SBram Moolenaar hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
830b5a7a8b5SBram Moolenaar
831b5a7a8b5SBram Moolenaar SafeRelease(&localizedFamilyNames);
832b5a7a8b5SBram Moolenaar SafeRelease(&fontFamily);
833b5a7a8b5SBram Moolenaar SafeRelease(&font);
834b5a7a8b5SBram Moolenaar
835d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr))
836d7ccc4d8SBram Moolenaar *ppTextFormat = pTextFormat;
837d7ccc4d8SBram Moolenaar else
838d7ccc4d8SBram Moolenaar SafeRelease(&pTextFormat);
839d7ccc4d8SBram Moolenaar
840d7ccc4d8SBram Moolenaar return hr;
841d7ccc4d8SBram Moolenaar }
842d7ccc4d8SBram Moolenaar
843d7ccc4d8SBram Moolenaar HRESULT
SetFontByLOGFONT(const LOGFONTW & logFont)844d7ccc4d8SBram Moolenaar DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
845d7ccc4d8SBram Moolenaar {
846d7ccc4d8SBram Moolenaar HRESULT hr = S_OK;
847d7ccc4d8SBram Moolenaar IDWriteTextFormat *pTextFormat = NULL;
848d7ccc4d8SBram Moolenaar
849d7ccc4d8SBram Moolenaar hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
850d7ccc4d8SBram Moolenaar
851d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr))
852d7ccc4d8SBram Moolenaar {
853d7ccc4d8SBram Moolenaar SafeRelease(&mTextFormat);
854d7ccc4d8SBram Moolenaar mTextFormat = pTextFormat;
855d7ccc4d8SBram Moolenaar mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
856d7ccc4d8SBram Moolenaar mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
857d7ccc4d8SBram Moolenaar : DWRITE_FONT_STYLE_NORMAL;
858d7ccc4d8SBram Moolenaar }
859d7ccc4d8SBram Moolenaar
860b5a7a8b5SBram Moolenaar return hr;
861b5a7a8b5SBram Moolenaar }
862b5a7a8b5SBram Moolenaar
863b5a7a8b5SBram Moolenaar void
SetFont(HFONT hFont)864b5a7a8b5SBram Moolenaar DWriteContext::SetFont(HFONT hFont)
865b5a7a8b5SBram Moolenaar {
866d7ccc4d8SBram Moolenaar FontCache::Item item;
867d7ccc4d8SBram Moolenaar if (mFontCache.get(hFont, item))
868b5a7a8b5SBram Moolenaar {
869d7ccc4d8SBram Moolenaar if (item.pTextFormat != NULL)
870d7ccc4d8SBram Moolenaar {
871d7ccc4d8SBram Moolenaar item.pTextFormat->AddRef();
872d7ccc4d8SBram Moolenaar SafeRelease(&mTextFormat);
873d7ccc4d8SBram Moolenaar mTextFormat = item.pTextFormat;
874d7ccc4d8SBram Moolenaar mFontWeight = item.fontWeight;
875d7ccc4d8SBram Moolenaar mFontStyle = item.fontStyle;
876d7ccc4d8SBram Moolenaar mFallbackDC = false;
877d7ccc4d8SBram Moolenaar }
878d7ccc4d8SBram Moolenaar else
879d7ccc4d8SBram Moolenaar mFallbackDC = true;
880d7ccc4d8SBram Moolenaar return;
881d7ccc4d8SBram Moolenaar }
882d7ccc4d8SBram Moolenaar
883d7ccc4d8SBram Moolenaar HRESULT hr = E_FAIL;
884b5a7a8b5SBram Moolenaar LOGFONTW lf;
885b5a7a8b5SBram Moolenaar if (GetObjectW(hFont, sizeof(lf), &lf))
886d7ccc4d8SBram Moolenaar hr = SetFontByLOGFONT(lf);
887d7ccc4d8SBram Moolenaar
888d7ccc4d8SBram Moolenaar item.hFont = hFont;
889d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr))
890b5a7a8b5SBram Moolenaar {
891d7ccc4d8SBram Moolenaar item.pTextFormat = mTextFormat;
892d7ccc4d8SBram Moolenaar item.fontWeight = mFontWeight;
893d7ccc4d8SBram Moolenaar item.fontStyle = mFontStyle;
89492467d33SBram Moolenaar mFallbackDC = false;
895b5a7a8b5SBram Moolenaar }
89692467d33SBram Moolenaar else
89792467d33SBram Moolenaar mFallbackDC = true;
898d7ccc4d8SBram Moolenaar mFontCache.put(item);
899b5a7a8b5SBram Moolenaar }
900b5a7a8b5SBram Moolenaar
901b5a7a8b5SBram Moolenaar void
Rebind()902a338adcfSBram Moolenaar DWriteContext::Rebind()
903a338adcfSBram Moolenaar {
904a338adcfSBram Moolenaar SafeRelease(&mBitmap);
905a338adcfSBram Moolenaar
906a338adcfSBram Moolenaar mRT->BindDC(mHDC, &mBindRect);
907a338adcfSBram Moolenaar mRT->SetTransform(D2D1::IdentityMatrix());
908a338adcfSBram Moolenaar
909a338adcfSBram Moolenaar D2D1_BITMAP_PROPERTIES props = {
910a338adcfSBram Moolenaar {DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE},
911a338adcfSBram Moolenaar 96.0f, 96.0f
912a338adcfSBram Moolenaar };
913a338adcfSBram Moolenaar mRT->CreateBitmap(
914a338adcfSBram Moolenaar D2D1::SizeU(mBindRect.right - mBindRect.left,
915a338adcfSBram Moolenaar mBindRect.bottom - mBindRect.top),
916a338adcfSBram Moolenaar props, &mBitmap);
917a338adcfSBram Moolenaar }
918a338adcfSBram Moolenaar
919a338adcfSBram Moolenaar void
BindDC(HDC hdc,const RECT * rect)92092467d33SBram Moolenaar DWriteContext::BindDC(HDC hdc, const RECT *rect)
921b5a7a8b5SBram Moolenaar {
922d7ccc4d8SBram Moolenaar mHDC = hdc;
92392467d33SBram Moolenaar mBindRect = *rect;
924a338adcfSBram Moolenaar
925a338adcfSBram Moolenaar if (mRT == NULL)
926a338adcfSBram Moolenaar CreateDeviceResources();
927a338adcfSBram Moolenaar else
928a338adcfSBram Moolenaar {
929a338adcfSBram Moolenaar Flush();
930a338adcfSBram Moolenaar Rebind();
931a338adcfSBram Moolenaar }
932b5a7a8b5SBram Moolenaar }
933b5a7a8b5SBram Moolenaar
9343dd174abSBram Moolenaar extern "C" void redraw_later_clear(void);
9353dd174abSBram Moolenaar
93692467d33SBram Moolenaar HRESULT
SetDrawingMode(DrawingMode mode)93792467d33SBram Moolenaar DWriteContext::SetDrawingMode(DrawingMode mode)
938b5a7a8b5SBram Moolenaar {
93992467d33SBram Moolenaar HRESULT hr = S_OK;
94092467d33SBram Moolenaar
94192467d33SBram Moolenaar switch (mode)
942b5a7a8b5SBram Moolenaar {
94392467d33SBram Moolenaar default:
94492467d33SBram Moolenaar case DM_GDI:
94592467d33SBram Moolenaar if (mInteropHDC != NULL)
94692467d33SBram Moolenaar {
94792467d33SBram Moolenaar mGDIRT->ReleaseDC(NULL);
94892467d33SBram Moolenaar mInteropHDC = NULL;
94992467d33SBram Moolenaar }
95092467d33SBram Moolenaar if (mDrawing)
95192467d33SBram Moolenaar {
95292467d33SBram Moolenaar hr = mRT->EndDraw();
953f653a6bcSBram Moolenaar if (hr == (HRESULT)D2DERR_RECREATE_TARGET)
95492467d33SBram Moolenaar {
95592467d33SBram Moolenaar hr = S_OK;
95692467d33SBram Moolenaar DiscardDeviceResources();
95792467d33SBram Moolenaar CreateDeviceResources();
9583dd174abSBram Moolenaar redraw_later_clear();
95992467d33SBram Moolenaar }
96092467d33SBram Moolenaar mDrawing = false;
96192467d33SBram Moolenaar }
96292467d33SBram Moolenaar break;
96392467d33SBram Moolenaar
96492467d33SBram Moolenaar case DM_DIRECTX:
96592467d33SBram Moolenaar if (mInteropHDC != NULL)
96692467d33SBram Moolenaar {
96792467d33SBram Moolenaar mGDIRT->ReleaseDC(NULL);
96892467d33SBram Moolenaar mInteropHDC = NULL;
96992467d33SBram Moolenaar }
97092467d33SBram Moolenaar else if (mDrawing == false)
97192467d33SBram Moolenaar {
97292467d33SBram Moolenaar CreateDeviceResources();
973d7ccc4d8SBram Moolenaar mRT->BeginDraw();
974d7ccc4d8SBram Moolenaar mDrawing = true;
975d7ccc4d8SBram Moolenaar }
97692467d33SBram Moolenaar break;
97792467d33SBram Moolenaar
97892467d33SBram Moolenaar case DM_INTEROP:
97992467d33SBram Moolenaar if (mDrawing == false)
98092467d33SBram Moolenaar {
98192467d33SBram Moolenaar CreateDeviceResources();
98292467d33SBram Moolenaar mRT->BeginDraw();
98392467d33SBram Moolenaar mDrawing = true;
98492467d33SBram Moolenaar }
98592467d33SBram Moolenaar if (mInteropHDC == NULL)
98692467d33SBram Moolenaar hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC);
98792467d33SBram Moolenaar break;
98892467d33SBram Moolenaar }
98992467d33SBram Moolenaar mDMode = mode;
99092467d33SBram Moolenaar return hr;
991d7ccc4d8SBram Moolenaar }
992d7ccc4d8SBram Moolenaar
993d7ccc4d8SBram Moolenaar ID2D1Brush*
SolidBrush(COLORREF color)994d7ccc4d8SBram Moolenaar DWriteContext::SolidBrush(COLORREF color)
995d7ccc4d8SBram Moolenaar {
996d7ccc4d8SBram Moolenaar mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
997d7ccc4d8SBram Moolenaar UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
998d7ccc4d8SBram Moolenaar return mBrush;
999d7ccc4d8SBram Moolenaar }
1000d7ccc4d8SBram Moolenaar
1001d7ccc4d8SBram Moolenaar void
DrawText(const WCHAR * text,int len,int x,int y,int w,int h,int cellWidth,COLORREF color,UINT fuOptions,const RECT * lprc,const INT * lpDx)1002d7ccc4d8SBram Moolenaar DWriteContext::DrawText(const WCHAR *text, int len,
1003d7ccc4d8SBram Moolenaar int x, int y, int w, int h, int cellWidth, COLORREF color,
100492467d33SBram Moolenaar UINT fuOptions, const RECT *lprc, const INT *lpDx)
1005d7ccc4d8SBram Moolenaar {
1006d7ccc4d8SBram Moolenaar if (mFallbackDC)
1007d7ccc4d8SBram Moolenaar {
100892467d33SBram Moolenaar // Fall back to GDI rendering.
100992467d33SBram Moolenaar HRESULT hr = SetDrawingMode(DM_INTEROP);
101092467d33SBram Moolenaar if (SUCCEEDED(hr))
101192467d33SBram Moolenaar {
101292467d33SBram Moolenaar HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT);
101392467d33SBram Moolenaar HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont);
101492467d33SBram Moolenaar ::SetTextColor(mInteropHDC, color);
101592467d33SBram Moolenaar ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC));
101692467d33SBram Moolenaar ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx);
101792467d33SBram Moolenaar ::SelectObject(mInteropHDC, hOldFont);
101892467d33SBram Moolenaar }
1019d7ccc4d8SBram Moolenaar return;
1020d7ccc4d8SBram Moolenaar }
1021d7ccc4d8SBram Moolenaar
1022d7ccc4d8SBram Moolenaar HRESULT hr;
1023b5a7a8b5SBram Moolenaar IDWriteTextLayout *textLayout = NULL;
1024b5a7a8b5SBram Moolenaar
102592467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX);
102692467d33SBram Moolenaar
1027d7ccc4d8SBram Moolenaar hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
1028d7ccc4d8SBram Moolenaar FLOAT(w), FLOAT(h), &textLayout);
1029b5a7a8b5SBram Moolenaar
1030b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr))
1031b5a7a8b5SBram Moolenaar {
1032d7ccc4d8SBram Moolenaar DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
1033b5a7a8b5SBram Moolenaar textLayout->SetFontWeight(mFontWeight, textRange);
1034b5a7a8b5SBram Moolenaar textLayout->SetFontStyle(mFontStyle, textRange);
1035b5a7a8b5SBram Moolenaar
1036d7ccc4d8SBram Moolenaar TextRenderer renderer(this);
1037d7ccc4d8SBram Moolenaar TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
103860ebd524SBram Moolenaar textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
1039b5a7a8b5SBram Moolenaar }
1040b5a7a8b5SBram Moolenaar
1041b5a7a8b5SBram Moolenaar SafeRelease(&textLayout);
1042b5a7a8b5SBram Moolenaar }
1043b5a7a8b5SBram Moolenaar
1044d7ccc4d8SBram Moolenaar void
FillRect(const RECT * rc,COLORREF color)104592467d33SBram Moolenaar DWriteContext::FillRect(const RECT *rc, COLORREF color)
1046d7ccc4d8SBram Moolenaar {
104792467d33SBram Moolenaar if (mDMode == DM_INTEROP)
104892467d33SBram Moolenaar {
104992467d33SBram Moolenaar // GDI functions are used before this call. Keep using GDI.
105092467d33SBram Moolenaar // (Switching to Direct2D causes terrible slowdown.)
105192467d33SBram Moolenaar HBRUSH hbr = ::CreateSolidBrush(color);
105292467d33SBram Moolenaar ::FillRect(mInteropHDC, rc, hbr);
105392467d33SBram Moolenaar ::DeleteObject(HGDIOBJ(hbr));
105492467d33SBram Moolenaar }
105592467d33SBram Moolenaar else
105692467d33SBram Moolenaar {
105792467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX);
1058d7ccc4d8SBram Moolenaar mRT->FillRectangle(
1059d7ccc4d8SBram Moolenaar D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
1060d7ccc4d8SBram Moolenaar FLOAT(rc->right), FLOAT(rc->bottom)),
1061d7ccc4d8SBram Moolenaar SolidBrush(color));
1062b5a7a8b5SBram Moolenaar }
106392467d33SBram Moolenaar }
106492467d33SBram Moolenaar
106592467d33SBram Moolenaar void
DrawLine(int x1,int y1,int x2,int y2,COLORREF color)106692467d33SBram Moolenaar DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
106792467d33SBram Moolenaar {
106892467d33SBram Moolenaar if (mDMode == DM_INTEROP)
106992467d33SBram Moolenaar {
107092467d33SBram Moolenaar // GDI functions are used before this call. Keep using GDI.
107192467d33SBram Moolenaar // (Switching to Direct2D causes terrible slowdown.)
107292467d33SBram Moolenaar HPEN hpen = ::CreatePen(PS_SOLID, 1, color);
107392467d33SBram Moolenaar HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen));
107492467d33SBram Moolenaar ::MoveToEx(mInteropHDC, x1, y1, NULL);
107592467d33SBram Moolenaar ::LineTo(mInteropHDC, x2, y2);
107692467d33SBram Moolenaar ::SelectObject(mInteropHDC, old_pen);
107792467d33SBram Moolenaar ::DeleteObject(HGDIOBJ(hpen));
107892467d33SBram Moolenaar }
107992467d33SBram Moolenaar else
108092467d33SBram Moolenaar {
108192467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX);
108292467d33SBram Moolenaar mRT->DrawLine(
108392467d33SBram Moolenaar D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f),
108492467d33SBram Moolenaar D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f),
108592467d33SBram Moolenaar SolidBrush(color));
108692467d33SBram Moolenaar }
108792467d33SBram Moolenaar }
108892467d33SBram Moolenaar
108992467d33SBram Moolenaar void
SetPixel(int x,int y,COLORREF color)109092467d33SBram Moolenaar DWriteContext::SetPixel(int x, int y, COLORREF color)
109192467d33SBram Moolenaar {
109292467d33SBram Moolenaar if (mDMode == DM_INTEROP)
109392467d33SBram Moolenaar {
109492467d33SBram Moolenaar // GDI functions are used before this call. Keep using GDI.
109592467d33SBram Moolenaar // (Switching to Direct2D causes terrible slowdown.)
109692467d33SBram Moolenaar ::SetPixel(mInteropHDC, x, y, color);
109792467d33SBram Moolenaar }
109892467d33SBram Moolenaar else
109992467d33SBram Moolenaar {
110092467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX);
110192467d33SBram Moolenaar // Direct2D doesn't have SetPixel API. Use DrawLine instead.
110292467d33SBram Moolenaar mRT->DrawLine(
110392467d33SBram Moolenaar D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f),
110492467d33SBram Moolenaar D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f),
110592467d33SBram Moolenaar SolidBrush(color));
110692467d33SBram Moolenaar }
110792467d33SBram Moolenaar }
1108b5a7a8b5SBram Moolenaar
1109d7ccc4d8SBram Moolenaar void
Scroll(int x,int y,const RECT * rc)1110a338adcfSBram Moolenaar DWriteContext::Scroll(int x, int y, const RECT *rc)
1111a338adcfSBram Moolenaar {
1112a338adcfSBram Moolenaar SetDrawingMode(DM_DIRECTX);
1113a338adcfSBram Moolenaar mRT->Flush();
1114a338adcfSBram Moolenaar
1115a338adcfSBram Moolenaar D2D1_RECT_U srcRect;
1116a338adcfSBram Moolenaar D2D1_POINT_2U destPoint;
1117a338adcfSBram Moolenaar if (x >= 0)
1118a338adcfSBram Moolenaar {
1119a338adcfSBram Moolenaar srcRect.left = rc->left;
1120a338adcfSBram Moolenaar srcRect.right = rc->right - x;
1121a338adcfSBram Moolenaar destPoint.x = rc->left + x;
1122a338adcfSBram Moolenaar }
1123a338adcfSBram Moolenaar else
1124a338adcfSBram Moolenaar {
1125a338adcfSBram Moolenaar srcRect.left = rc->left - x;
1126a338adcfSBram Moolenaar srcRect.right = rc->right;
1127a338adcfSBram Moolenaar destPoint.x = rc->left;
1128a338adcfSBram Moolenaar }
1129a338adcfSBram Moolenaar if (y >= 0)
1130a338adcfSBram Moolenaar {
1131a338adcfSBram Moolenaar srcRect.top = rc->top;
1132a338adcfSBram Moolenaar srcRect.bottom = rc->bottom - y;
1133a338adcfSBram Moolenaar destPoint.y = rc->top + y;
1134a338adcfSBram Moolenaar }
1135a338adcfSBram Moolenaar else
1136a338adcfSBram Moolenaar {
1137a338adcfSBram Moolenaar srcRect.top = rc->top - y;
1138a338adcfSBram Moolenaar srcRect.bottom = rc->bottom;
1139a338adcfSBram Moolenaar destPoint.y = rc->top;
1140a338adcfSBram Moolenaar }
1141a338adcfSBram Moolenaar mBitmap->CopyFromRenderTarget(&destPoint, mRT, &srcRect);
1142a338adcfSBram Moolenaar
1143a338adcfSBram Moolenaar D2D1_RECT_F destRect = {
1144a338adcfSBram Moolenaar FLOAT(destPoint.x), FLOAT(destPoint.y),
1145a338adcfSBram Moolenaar FLOAT(destPoint.x + srcRect.right - srcRect.left),
1146a338adcfSBram Moolenaar FLOAT(destPoint.y + srcRect.bottom - srcRect.top)
1147a338adcfSBram Moolenaar };
1148a338adcfSBram Moolenaar mRT->DrawBitmap(mBitmap, destRect, 1.0F,
1149a338adcfSBram Moolenaar D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, destRect);
1150a338adcfSBram Moolenaar }
1151a338adcfSBram Moolenaar
1152a338adcfSBram Moolenaar void
Flush()1153d7ccc4d8SBram Moolenaar DWriteContext::Flush()
1154b5a7a8b5SBram Moolenaar {
115592467d33SBram Moolenaar SetDrawingMode(DM_GDI);
1156b5a7a8b5SBram Moolenaar }
1157b5a7a8b5SBram Moolenaar
1158b5a7a8b5SBram Moolenaar void
SetRenderingParams(const DWriteRenderingParams * params)1159b5a7a8b5SBram Moolenaar DWriteContext::SetRenderingParams(
1160b5a7a8b5SBram Moolenaar const DWriteRenderingParams *params)
1161b5a7a8b5SBram Moolenaar {
1162b5a7a8b5SBram Moolenaar if (mDWriteFactory == NULL)
1163b5a7a8b5SBram Moolenaar return;
1164b5a7a8b5SBram Moolenaar
1165b5a7a8b5SBram Moolenaar IDWriteRenderingParams *renderingParams = NULL;
1166b5a7a8b5SBram Moolenaar D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
1167b5a7a8b5SBram Moolenaar D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
1168b5a7a8b5SBram Moolenaar HRESULT hr;
1169b5a7a8b5SBram Moolenaar if (params != NULL)
1170b5a7a8b5SBram Moolenaar {
1171b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
1172b5a7a8b5SBram Moolenaar params->enhancedContrast, params->clearTypeLevel,
1173b5a7a8b5SBram Moolenaar ToPixelGeometry(params->pixelGeometry),
1174b5a7a8b5SBram Moolenaar ToRenderingMode(params->renderingMode), &renderingParams);
1175b5a7a8b5SBram Moolenaar textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
1176b5a7a8b5SBram Moolenaar }
1177b5a7a8b5SBram Moolenaar else
1178b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
1179b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr) && renderingParams != NULL)
1180b5a7a8b5SBram Moolenaar {
1181b5a7a8b5SBram Moolenaar SafeRelease(&mRenderingParams);
1182b5a7a8b5SBram Moolenaar mRenderingParams = renderingParams;
1183b5a7a8b5SBram Moolenaar mTextAntialiasMode = textAntialiasMode;
1184d7ccc4d8SBram Moolenaar
1185d7ccc4d8SBram Moolenaar Flush();
1186d7ccc4d8SBram Moolenaar mRT->SetTextRenderingParams(mRenderingParams);
1187d7ccc4d8SBram Moolenaar mRT->SetTextAntialiasMode(mTextAntialiasMode);
1188b5a7a8b5SBram Moolenaar }
1189b5a7a8b5SBram Moolenaar }
1190b5a7a8b5SBram Moolenaar
1191b5a7a8b5SBram Moolenaar DWriteRenderingParams *
GetRenderingParams(DWriteRenderingParams * params)1192b5a7a8b5SBram Moolenaar DWriteContext::GetRenderingParams(
1193b5a7a8b5SBram Moolenaar DWriteRenderingParams *params)
1194b5a7a8b5SBram Moolenaar {
1195b5a7a8b5SBram Moolenaar if (params != NULL && mRenderingParams != NULL)
1196b5a7a8b5SBram Moolenaar {
1197b5a7a8b5SBram Moolenaar params->gamma = mRenderingParams->GetGamma();
1198b5a7a8b5SBram Moolenaar params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
1199b5a7a8b5SBram Moolenaar params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
1200b5a7a8b5SBram Moolenaar params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
1201b5a7a8b5SBram Moolenaar params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
1202b5a7a8b5SBram Moolenaar params->textAntialiasMode = mTextAntialiasMode;
1203b5a7a8b5SBram Moolenaar }
1204b5a7a8b5SBram Moolenaar return params;
1205b5a7a8b5SBram Moolenaar }
1206b5a7a8b5SBram Moolenaar
1207b5a7a8b5SBram Moolenaar ////////////////////////////////////////////////////////////////////////////
1208b5a7a8b5SBram Moolenaar // PUBLIC C INTERFACES
1209b5a7a8b5SBram Moolenaar
1210b5a7a8b5SBram Moolenaar void
DWrite_Init(void)1211b5a7a8b5SBram Moolenaar DWrite_Init(void)
1212b5a7a8b5SBram Moolenaar {
1213b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1214b5a7a8b5SBram Moolenaar // Load libraries.
1215b5a7a8b5SBram Moolenaar hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
1216b5a7a8b5SBram Moolenaar hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
1217b5a7a8b5SBram Moolenaar if (hD2D1DLL == NULL || hDWriteDLL == NULL)
1218b5a7a8b5SBram Moolenaar {
1219b5a7a8b5SBram Moolenaar DWrite_Final();
1220b5a7a8b5SBram Moolenaar return;
1221b5a7a8b5SBram Moolenaar }
1222b5a7a8b5SBram Moolenaar // Get address of procedures.
1223b5a7a8b5SBram Moolenaar pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
1224b5a7a8b5SBram Moolenaar GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
1225b5a7a8b5SBram Moolenaar pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
1226b5a7a8b5SBram Moolenaar "D2D1CreateFactory");
1227b5a7a8b5SBram Moolenaar pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
1228b5a7a8b5SBram Moolenaar "DWriteCreateFactory");
1229b5a7a8b5SBram Moolenaar #endif
1230b5a7a8b5SBram Moolenaar }
1231b5a7a8b5SBram Moolenaar
1232b5a7a8b5SBram Moolenaar void
DWrite_Final(void)1233b5a7a8b5SBram Moolenaar DWrite_Final(void)
1234b5a7a8b5SBram Moolenaar {
1235b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1236b5a7a8b5SBram Moolenaar pGetUserDefaultLocaleName = NULL;
1237b5a7a8b5SBram Moolenaar pD2D1CreateFactory = NULL;
1238b5a7a8b5SBram Moolenaar pDWriteCreateFactory = NULL;
1239b5a7a8b5SBram Moolenaar unload(hDWriteDLL);
1240b5a7a8b5SBram Moolenaar unload(hD2D1DLL);
1241b5a7a8b5SBram Moolenaar #endif
1242b5a7a8b5SBram Moolenaar }
1243b5a7a8b5SBram Moolenaar
1244b5a7a8b5SBram Moolenaar DWriteContext *
DWriteContext_Open(void)1245b5a7a8b5SBram Moolenaar DWriteContext_Open(void)
1246b5a7a8b5SBram Moolenaar {
1247b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX
1248b5a7a8b5SBram Moolenaar if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
1249b5a7a8b5SBram Moolenaar || pDWriteCreateFactory == NULL)
1250b5a7a8b5SBram Moolenaar return NULL;
1251b5a7a8b5SBram Moolenaar #endif
1252b5a7a8b5SBram Moolenaar return new DWriteContext();
1253b5a7a8b5SBram Moolenaar }
1254b5a7a8b5SBram Moolenaar
1255b5a7a8b5SBram Moolenaar void
DWriteContext_BindDC(DWriteContext * ctx,HDC hdc,const RECT * rect)125692467d33SBram Moolenaar DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
1257b5a7a8b5SBram Moolenaar {
1258d7ccc4d8SBram Moolenaar if (ctx != NULL)
1259d7ccc4d8SBram Moolenaar ctx->BindDC(hdc, rect);
1260b5a7a8b5SBram Moolenaar }
1261b5a7a8b5SBram Moolenaar
1262b5a7a8b5SBram Moolenaar void
DWriteContext_SetFont(DWriteContext * ctx,HFONT hFont)1263b5a7a8b5SBram Moolenaar DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
1264b5a7a8b5SBram Moolenaar {
1265b5a7a8b5SBram Moolenaar if (ctx != NULL)
1266b5a7a8b5SBram Moolenaar ctx->SetFont(hFont);
1267b5a7a8b5SBram Moolenaar }
1268b5a7a8b5SBram Moolenaar
1269b5a7a8b5SBram Moolenaar void
DWriteContext_DrawText(DWriteContext * ctx,const WCHAR * text,int len,int x,int y,int w,int h,int cellWidth,COLORREF color,UINT fuOptions,const RECT * lprc,const INT * lpDx)1270b5a7a8b5SBram Moolenaar DWriteContext_DrawText(
1271b5a7a8b5SBram Moolenaar DWriteContext *ctx,
1272b5a7a8b5SBram Moolenaar const WCHAR *text,
1273b5a7a8b5SBram Moolenaar int len,
1274b5a7a8b5SBram Moolenaar int x,
1275b5a7a8b5SBram Moolenaar int y,
1276b5a7a8b5SBram Moolenaar int w,
1277b5a7a8b5SBram Moolenaar int h,
1278b5a7a8b5SBram Moolenaar int cellWidth,
1279d7ccc4d8SBram Moolenaar COLORREF color,
1280d7ccc4d8SBram Moolenaar UINT fuOptions,
128192467d33SBram Moolenaar const RECT *lprc,
128292467d33SBram Moolenaar const INT *lpDx)
1283b5a7a8b5SBram Moolenaar {
1284b5a7a8b5SBram Moolenaar if (ctx != NULL)
1285d7ccc4d8SBram Moolenaar ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
1286d7ccc4d8SBram Moolenaar fuOptions, lprc, lpDx);
1287b5a7a8b5SBram Moolenaar }
1288b5a7a8b5SBram Moolenaar
1289b5a7a8b5SBram Moolenaar void
DWriteContext_FillRect(DWriteContext * ctx,const RECT * rc,COLORREF color)129092467d33SBram Moolenaar DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color)
1291b5a7a8b5SBram Moolenaar {
1292d7ccc4d8SBram Moolenaar if (ctx != NULL)
1293d7ccc4d8SBram Moolenaar ctx->FillRect(rc, color);
1294b5a7a8b5SBram Moolenaar }
1295d7ccc4d8SBram Moolenaar
1296d7ccc4d8SBram Moolenaar void
DWriteContext_DrawLine(DWriteContext * ctx,int x1,int y1,int x2,int y2,COLORREF color)129792467d33SBram Moolenaar DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
129892467d33SBram Moolenaar COLORREF color)
129992467d33SBram Moolenaar {
130092467d33SBram Moolenaar if (ctx != NULL)
130192467d33SBram Moolenaar ctx->DrawLine(x1, y1, x2, y2, color);
130292467d33SBram Moolenaar }
130392467d33SBram Moolenaar
130492467d33SBram Moolenaar void
DWriteContext_SetPixel(DWriteContext * ctx,int x,int y,COLORREF color)130592467d33SBram Moolenaar DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color)
130692467d33SBram Moolenaar {
130792467d33SBram Moolenaar if (ctx != NULL)
130892467d33SBram Moolenaar ctx->SetPixel(x, y, color);
130992467d33SBram Moolenaar }
131092467d33SBram Moolenaar
131192467d33SBram Moolenaar void
DWriteContext_Scroll(DWriteContext * ctx,int x,int y,const RECT * rc)1312a338adcfSBram Moolenaar DWriteContext_Scroll(DWriteContext *ctx, int x, int y, const RECT *rc)
1313a338adcfSBram Moolenaar {
1314a338adcfSBram Moolenaar if (ctx != NULL)
1315a338adcfSBram Moolenaar ctx->Scroll(x, y, rc);
1316a338adcfSBram Moolenaar }
1317a338adcfSBram Moolenaar
1318a338adcfSBram Moolenaar void
DWriteContext_Flush(DWriteContext * ctx)1319d7ccc4d8SBram Moolenaar DWriteContext_Flush(DWriteContext *ctx)
1320d7ccc4d8SBram Moolenaar {
1321d7ccc4d8SBram Moolenaar if (ctx != NULL)
1322d7ccc4d8SBram Moolenaar ctx->Flush();
1323b5a7a8b5SBram Moolenaar }
1324b5a7a8b5SBram Moolenaar
1325b5a7a8b5SBram Moolenaar void
DWriteContext_Close(DWriteContext * ctx)1326b5a7a8b5SBram Moolenaar DWriteContext_Close(DWriteContext *ctx)
1327b5a7a8b5SBram Moolenaar {
1328b5a7a8b5SBram Moolenaar delete ctx;
1329b5a7a8b5SBram Moolenaar }
1330b5a7a8b5SBram Moolenaar
1331b5a7a8b5SBram Moolenaar void
DWriteContext_SetRenderingParams(DWriteContext * ctx,const DWriteRenderingParams * params)1332b5a7a8b5SBram Moolenaar DWriteContext_SetRenderingParams(
1333b5a7a8b5SBram Moolenaar DWriteContext *ctx,
1334b5a7a8b5SBram Moolenaar const DWriteRenderingParams *params)
1335b5a7a8b5SBram Moolenaar {
1336b5a7a8b5SBram Moolenaar if (ctx != NULL)
1337b5a7a8b5SBram Moolenaar ctx->SetRenderingParams(params);
1338b5a7a8b5SBram Moolenaar }
1339b5a7a8b5SBram Moolenaar
1340b5a7a8b5SBram Moolenaar DWriteRenderingParams *
DWriteContext_GetRenderingParams(DWriteContext * ctx,DWriteRenderingParams * params)1341b5a7a8b5SBram Moolenaar DWriteContext_GetRenderingParams(
1342b5a7a8b5SBram Moolenaar DWriteContext *ctx,
1343b5a7a8b5SBram Moolenaar DWriteRenderingParams *params)
1344b5a7a8b5SBram Moolenaar {
1345b5a7a8b5SBram Moolenaar if (ctx != NULL)
1346b5a7a8b5SBram Moolenaar return ctx->GetRenderingParams(params);
1347b5a7a8b5SBram Moolenaar else
1348b5a7a8b5SBram Moolenaar return NULL;
1349b5a7a8b5SBram Moolenaar }
1350