blob: 3c940a3042d624ef73ff1debf4847c6d10ab2a46 [file] [log] [blame]
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001/* vi:set ts=8 sts=4 sw=4 noet: */
2/*
3 * Author: MURAOKA Taro <koron.kaoriya@gmail.com>
4 *
5 * Contributors:
6 * - Ken Takata
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01007 * - Yasuhiro Matsumoto
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02008 *
9 * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com>
10 * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE.
11 */
12
13#define WIN32_LEAN_AND_MEAN
14
15#ifndef DYNAMIC_DIRECTX
16# if WINVER < 0x0600
17# error WINVER must be 0x0600 or above to use DirectWrite(DirectX)
18# endif
19#endif
20
21#include <windows.h>
22#include <crtdbg.h>
23#include <assert.h>
24#include <math.h>
25#include <d2d1.h>
26#include <d2d1helper.h>
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +010027
28// Disable these macros to compile with old VC and newer SDK (V8.1 or later).
29#if defined(_MSC_VER) && (_MSC_VER < 1700)
30# define _COM_Outptr_ __out
31# define _In_reads_(s)
32# define _In_reads_opt_(s)
33# define _Maybenull_
34# define _Out_writes_(s)
35# define _Out_writes_opt_(s)
36# define _Out_writes_to_(x, y)
37# define _Out_writes_to_opt_(x, y)
38# define _Outptr_
39#endif
40
Bram Moolenaar7f88b652017-12-14 13:15:19 +010041#ifdef FEAT_DIRECTX_COLOR_EMOJI
42# include <dwrite_2.h>
43#else
44# include <dwrite.h>
45#endif
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +020046
47#include "gui_dwrite.h"
48
49#ifdef __MINGW32__
50# define __maybenull SAL__maybenull
51# define __in SAL__in
52# define __out SAL__out
53#endif
54
Bram Moolenaarcc6cf9b2016-03-19 20:51:35 +010055#if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
56# define FINAL final
57#else
58# define FINAL
59#endif
60
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +020061#ifdef DYNAMIC_DIRECTX
62extern "C" HINSTANCE vimLoadLib(char *name);
63
64typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
65typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
66 REFIID, const D2D1_FACTORY_OPTIONS *, void **);
67typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
68 REFIID, IUnknown **);
69
70static HINSTANCE hD2D1DLL = NULL;
71static HINSTANCE hDWriteDLL = NULL;
72
73static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
74static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
75static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
76
77#define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName)
78#define D2D1CreateFactory (*pD2D1CreateFactory)
79#define DWriteCreateFactory (*pDWriteCreateFactory)
80
81 static void
82unload(HINSTANCE &hinst)
83{
84 if (hinst != NULL)
85 {
86 FreeLibrary(hinst);
87 hinst = NULL;
88 }
89}
90#endif // DYNAMIC_DIRECTX
91
92template <class T> inline void SafeRelease(T **ppT)
93{
94 if (*ppT)
95 {
96 (*ppT)->Release();
97 *ppT = NULL;
98 }
99}
100
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200101 static DWRITE_PIXEL_GEOMETRY
102ToPixelGeometry(int value)
103{
104 switch (value)
105 {
106 default:
107 case 0:
108 return DWRITE_PIXEL_GEOMETRY_FLAT;
109 case 1:
110 return DWRITE_PIXEL_GEOMETRY_RGB;
111 case 2:
112 return DWRITE_PIXEL_GEOMETRY_BGR;
113 }
114}
115
116 static int
117ToInt(DWRITE_PIXEL_GEOMETRY value)
118{
119 switch (value)
120 {
121 case DWRITE_PIXEL_GEOMETRY_FLAT:
122 return 0;
123 case DWRITE_PIXEL_GEOMETRY_RGB:
124 return 1;
125 case DWRITE_PIXEL_GEOMETRY_BGR:
126 return 2;
127 default:
128 return -1;
129 }
130}
131
132 static DWRITE_RENDERING_MODE
133ToRenderingMode(int value)
134{
135 switch (value)
136 {
137 default:
138 case 0:
139 return DWRITE_RENDERING_MODE_DEFAULT;
140 case 1:
141 return DWRITE_RENDERING_MODE_ALIASED;
142 case 2:
143 return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
144 case 3:
145 return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
146 case 4:
147 return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
148 case 5:
149 return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
150 case 6:
151 return DWRITE_RENDERING_MODE_OUTLINE;
152 }
153}
154
155 static D2D1_TEXT_ANTIALIAS_MODE
156ToTextAntialiasMode(int value)
157{
158 switch (value)
159 {
160 default:
161 case 0:
162 return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
163 case 1:
164 return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
165 case 2:
166 return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
167 case 3:
168 return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
169 }
170}
171
172 static int
173ToInt(DWRITE_RENDERING_MODE value)
174{
175 switch (value)
176 {
177 case DWRITE_RENDERING_MODE_DEFAULT:
178 return 0;
179 case DWRITE_RENDERING_MODE_ALIASED:
180 return 1;
181 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
182 return 2;
183 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
184 return 3;
185 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
186 return 4;
187 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
188 return 5;
189 case DWRITE_RENDERING_MODE_OUTLINE:
190 return 6;
191 default:
192 return -1;
193 }
194}
195
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100196class FontCache {
197public:
198 struct Item {
199 HFONT hFont;
200 IDWriteTextFormat* pTextFormat;
201 DWRITE_FONT_WEIGHT fontWeight;
202 DWRITE_FONT_STYLE fontStyle;
203 Item() : hFont(NULL), pTextFormat(NULL) {}
204 };
205
206private:
207 int mSize;
208 Item *mItems;
209
210public:
211 FontCache(int size = 2) :
212 mSize(size),
213 mItems(new Item[size])
214 {
215 }
216
217 ~FontCache()
218 {
219 for (int i = 0; i < mSize; ++i)
220 SafeRelease(&mItems[i].pTextFormat);
221 delete[] mItems;
222 }
223
224 bool get(HFONT hFont, Item &item)
225 {
226 int n = find(hFont);
227 if (n < 0)
228 return false;
229 item = mItems[n];
230 slide(n);
231 return true;
232 }
233
234 void put(const Item& item)
235 {
236 int n = find(item.hFont);
237 if (n < 0)
238 n = mSize - 1;
239 if (mItems[n].pTextFormat != item.pTextFormat)
240 {
241 SafeRelease(&mItems[n].pTextFormat);
242 item.pTextFormat->AddRef();
243 }
244 mItems[n] = item;
245 slide(n);
246 }
247
248private:
249 int find(HFONT hFont)
250 {
251 for (int i = 0; i < mSize; ++i)
252 {
253 if (mItems[i].hFont == hFont)
254 return i;
255 }
256 return -1;
257 }
258
259 void slide(int nextTop)
260 {
261 if (nextTop == 0)
262 return;
263 Item tmp = mItems[nextTop];
264 for (int i = nextTop - 1; i >= 0; --i)
265 mItems[i + 1] = mItems[i];
266 mItems[0] = tmp;
267 }
268};
269
Bram Moolenaar92467d32017-12-05 13:22:16 +0100270enum DrawingMode {
271 DM_GDI = 0,
272 DM_DIRECTX = 1,
273 DM_INTEROP = 2,
274};
275
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100276struct DWriteContext {
277 HDC mHDC;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100278 RECT mBindRect;
279 DrawingMode mDMode;
280 HDC mInteropHDC;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100281 bool mDrawing;
282 bool mFallbackDC;
283
284 ID2D1Factory *mD2D1Factory;
285
286 ID2D1DCRenderTarget *mRT;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100287 ID2D1GdiInteropRenderTarget *mGDIRT;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100288 ID2D1SolidColorBrush *mBrush;
289
290 IDWriteFactory *mDWriteFactory;
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100291#ifdef FEAT_DIRECTX_COLOR_EMOJI
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100292 IDWriteFactory2 *mDWriteFactory2;
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100293#endif
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100294
295 IDWriteGdiInterop *mGdiInterop;
296 IDWriteRenderingParams *mRenderingParams;
297
298 FontCache mFontCache;
299 IDWriteTextFormat *mTextFormat;
300 DWRITE_FONT_WEIGHT mFontWeight;
301 DWRITE_FONT_STYLE mFontStyle;
302
303 D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
304
305 // METHODS
306
307 DWriteContext();
308
309 virtual ~DWriteContext();
310
Bram Moolenaar92467d32017-12-05 13:22:16 +0100311 HRESULT CreateDeviceResources();
312
313 void DiscardDeviceResources();
314
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100315 HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
316 IDWriteTextFormat **ppTextFormat);
317
318 HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
319
320 void SetFont(HFONT hFont);
321
Bram Moolenaar92467d32017-12-05 13:22:16 +0100322 void BindDC(HDC hdc, const RECT *rect);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100323
Bram Moolenaar92467d32017-12-05 13:22:16 +0100324 HRESULT SetDrawingMode(DrawingMode mode);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100325
326 ID2D1Brush* SolidBrush(COLORREF color);
327
Bram Moolenaar92467d32017-12-05 13:22:16 +0100328 void DrawText(const WCHAR *text, int len,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100329 int x, int y, int w, int h, int cellWidth, COLORREF color,
Bram Moolenaar92467d32017-12-05 13:22:16 +0100330 UINT fuOptions, const RECT *lprc, const INT *lpDx);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100331
Bram Moolenaar92467d32017-12-05 13:22:16 +0100332 void FillRect(const RECT *rc, COLORREF color);
333
334 void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
335
336 void SetPixel(int x, int y, COLORREF color);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100337
338 void Flush();
339
340 void SetRenderingParams(
341 const DWriteRenderingParams *params);
342
343 DWriteRenderingParams *GetRenderingParams(
344 DWriteRenderingParams *params);
345};
346
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200347class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
348{
349private:
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100350 FLOAT &mAccum;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200351 FLOAT mDelta;
352 FLOAT *mAdjustedAdvances;
353
354public:
355 AdjustedGlyphRun(
356 const DWRITE_GLYPH_RUN *glyphRun,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100357 FLOAT cellWidth,
358 FLOAT &accum) :
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200359 DWRITE_GLYPH_RUN(*glyphRun),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100360 mAccum(accum),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200361 mDelta(0.0f),
362 mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
363 {
364 assert(cellWidth != 0.0f);
365 for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
366 {
367 FLOAT orig = glyphRun->glyphAdvances[i];
368 FLOAT adjusted = adjustToCell(orig, cellWidth);
369 mAdjustedAdvances[i] = adjusted;
370 mDelta += adjusted - orig;
371 }
372 glyphAdvances = mAdjustedAdvances;
373 }
374
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100375 ~AdjustedGlyphRun()
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200376 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100377 mAccum += mDelta;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200378 delete[] mAdjustedAdvances;
379 }
380
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200381 static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
382 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100383 int cellCount = int(floor(value / cellWidth + 0.5f));
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200384 if (cellCount < 1)
385 cellCount = 1;
386 return cellCount * cellWidth;
387 }
388};
389
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100390struct TextRendererContext {
391 // const fields.
392 COLORREF color;
393 FLOAT cellWidth;
394
395 // working fields.
396 FLOAT offsetX;
397};
398
399class TextRenderer FINAL : public IDWriteTextRenderer
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200400{
401public:
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100402 TextRenderer(
403 DWriteContext* pDWC) :
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200404 cRefCount_(0),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100405 pDWC_(pDWC)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200406 {
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200407 AddRef();
408 }
409
Bram Moolenaaredb4f2b2016-02-27 15:27:23 +0100410 // add "virtual" to avoid a compiler warning
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100411 virtual ~TextRenderer()
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200412 {
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200413 }
414
415 IFACEMETHOD(IsPixelSnappingDisabled)(
416 __maybenull void* clientDrawingContext,
417 __out BOOL* isDisabled)
418 {
419 *isDisabled = FALSE;
420 return S_OK;
421 }
422
423 IFACEMETHOD(GetCurrentTransform)(
424 __maybenull void* clientDrawingContext,
425 __out DWRITE_MATRIX* transform)
426 {
Bram Moolenaaredb4f2b2016-02-27 15:27:23 +0100427 // forward the render target's transform
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100428 pDWC_->mRT->GetTransform(
429 reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200430 return S_OK;
431 }
432
433 IFACEMETHOD(GetPixelsPerDip)(
434 __maybenull void* clientDrawingContext,
435 __out FLOAT* pixelsPerDip)
436 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100437 float dpiX, unused;
438 pDWC_->mRT->GetDpi(&dpiX, &unused);
439 *pixelsPerDip = dpiX / 96.0f;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200440 return S_OK;
441 }
442
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200443 IFACEMETHOD(DrawUnderline)(
444 __maybenull void* clientDrawingContext,
445 FLOAT baselineOriginX,
446 FLOAT baselineOriginY,
447 __in DWRITE_UNDERLINE const* underline,
448 IUnknown* clientDrawingEffect)
449 {
450 return E_NOTIMPL;
451 }
452
453 IFACEMETHOD(DrawStrikethrough)(
454 __maybenull void* clientDrawingContext,
455 FLOAT baselineOriginX,
456 FLOAT baselineOriginY,
457 __in DWRITE_STRIKETHROUGH const* strikethrough,
458 IUnknown* clientDrawingEffect)
459 {
460 return E_NOTIMPL;
461 }
462
463 IFACEMETHOD(DrawInlineObject)(
464 __maybenull void* clientDrawingContext,
465 FLOAT originX,
466 FLOAT originY,
467 IDWriteInlineObject* inlineObject,
468 BOOL isSideways,
469 BOOL isRightToLeft,
470 IUnknown* clientDrawingEffect)
471 {
472 return E_NOTIMPL;
473 }
474
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100475 IFACEMETHOD(DrawGlyphRun)(
476 __maybenull void* clientDrawingContext,
477 FLOAT baselineOriginX,
478 FLOAT baselineOriginY,
479 DWRITE_MEASURING_MODE measuringMode,
480 __in DWRITE_GLYPH_RUN const* glyphRun,
481 __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
482 IUnknown* clientDrawingEffect)
483 {
484 TextRendererContext *context =
485 reinterpret_cast<TextRendererContext*>(clientDrawingContext);
486
487 AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
488 context->offsetX);
489
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100490#ifdef FEAT_DIRECTX_COLOR_EMOJI
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100491 if (pDWC_->mDWriteFactory2 != NULL)
492 {
493 IDWriteColorGlyphRunEnumerator *enumerator = NULL;
494 HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
495 baselineOriginX + context->offsetX,
496 baselineOriginY,
497 &adjustedGlyphRun,
498 NULL,
499 DWRITE_MEASURING_MODE_GDI_NATURAL,
500 NULL,
501 0,
502 &enumerator);
503 if (SUCCEEDED(hr))
504 {
505 // Draw by IDWriteFactory2 for color emoji
506 BOOL hasRun = TRUE;
507 enumerator->MoveNext(&hasRun);
508 while (hasRun)
509 {
510 const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
511 enumerator->GetCurrentRun(&colorGlyphRun);
512
513 pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
514 pDWC_->mRT->DrawGlyphRun(
515 D2D1::Point2F(
516 colorGlyphRun->baselineOriginX,
517 colorGlyphRun->baselineOriginY),
518 &colorGlyphRun->glyphRun,
519 pDWC_->mBrush,
520 DWRITE_MEASURING_MODE_NATURAL);
521 enumerator->MoveNext(&hasRun);
522 }
523 SafeRelease(&enumerator);
524 return S_OK;
525 }
526 }
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100527#endif
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100528
529 // Draw by IDWriteFactory (without color emoji)
530 pDWC_->mRT->DrawGlyphRun(
531 D2D1::Point2F(
532 baselineOriginX + context->offsetX,
533 baselineOriginY),
534 &adjustedGlyphRun,
535 pDWC_->SolidBrush(context->color),
536 DWRITE_MEASURING_MODE_NATURAL);
537 return S_OK;
538 }
539
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200540public:
541 IFACEMETHOD_(unsigned long, AddRef) ()
542 {
543 return InterlockedIncrement(&cRefCount_);
544 }
545
546 IFACEMETHOD_(unsigned long, Release) ()
547 {
548 long newCount = InterlockedDecrement(&cRefCount_);
549
550 if (newCount == 0)
551 {
552 delete this;
553 return 0;
554 }
555 return newCount;
556 }
557
558 IFACEMETHOD(QueryInterface)(
559 IID const& riid,
560 void** ppvObject)
561 {
562 if (__uuidof(IDWriteTextRenderer) == riid)
563 {
564 *ppvObject = this;
565 }
566 else if (__uuidof(IDWritePixelSnapping) == riid)
567 {
568 *ppvObject = this;
569 }
570 else if (__uuidof(IUnknown) == riid)
571 {
572 *ppvObject = this;
573 }
574 else
575 {
576 *ppvObject = NULL;
577 return E_FAIL;
578 }
579
580 return S_OK;
581 }
582
583private:
Bram Moolenaar0106b4b2014-08-07 13:55:10 +0200584 long cRefCount_;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100585 DWriteContext* pDWC_;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200586};
587
588DWriteContext::DWriteContext() :
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100589 mHDC(NULL),
Bram Moolenaar92467d32017-12-05 13:22:16 +0100590 mBindRect(),
591 mDMode(DM_GDI),
592 mInteropHDC(NULL),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200593 mDrawing(false),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100594 mFallbackDC(false),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200595 mD2D1Factory(NULL),
596 mRT(NULL),
Bram Moolenaar92467d32017-12-05 13:22:16 +0100597 mGDIRT(NULL),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200598 mBrush(NULL),
599 mDWriteFactory(NULL),
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100600#ifdef FEAT_DIRECTX_COLOR_EMOJI
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100601 mDWriteFactory2(NULL),
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100602#endif
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200603 mGdiInterop(NULL),
604 mRenderingParams(NULL),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100605 mFontCache(8),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200606 mTextFormat(NULL),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200607 mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
608 mFontStyle(DWRITE_FONT_STYLE_NORMAL),
609 mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
610{
611 HRESULT hr;
612
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200613 hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
614 __uuidof(ID2D1Factory), NULL,
615 reinterpret_cast<void**>(&mD2D1Factory));
616 _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
617
618 if (SUCCEEDED(hr))
Bram Moolenaar92467d32017-12-05 13:22:16 +0100619 hr = CreateDeviceResources();
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200620
621 if (SUCCEEDED(hr))
622 {
623 hr = DWriteCreateFactory(
624 DWRITE_FACTORY_TYPE_SHARED,
625 __uuidof(IDWriteFactory),
626 reinterpret_cast<IUnknown**>(&mDWriteFactory));
627 _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
628 mDWriteFactory);
629 }
630
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100631#ifdef FEAT_DIRECTX_COLOR_EMOJI
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200632 if (SUCCEEDED(hr))
633 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100634 DWriteCreateFactory(
635 DWRITE_FACTORY_TYPE_SHARED,
636 __uuidof(IDWriteFactory2),
637 reinterpret_cast<IUnknown**>(&mDWriteFactory2));
638 _RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
639 }
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100640#endif
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100641
642 if (SUCCEEDED(hr))
643 {
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200644 hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
645 _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
646 }
647
648 if (SUCCEEDED(hr))
649 {
650 hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
651 _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
652 mRenderingParams);
653 }
654}
655
656DWriteContext::~DWriteContext()
657{
658 SafeRelease(&mTextFormat);
659 SafeRelease(&mRenderingParams);
660 SafeRelease(&mGdiInterop);
661 SafeRelease(&mDWriteFactory);
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100662#ifdef FEAT_DIRECTX_COLOR_EMOJI
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100663 SafeRelease(&mDWriteFactory2);
Bram Moolenaar7f88b652017-12-14 13:15:19 +0100664#endif
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200665 SafeRelease(&mBrush);
Bram Moolenaar92467d32017-12-05 13:22:16 +0100666 SafeRelease(&mGDIRT);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200667 SafeRelease(&mRT);
668 SafeRelease(&mD2D1Factory);
669}
670
671 HRESULT
Bram Moolenaar92467d32017-12-05 13:22:16 +0100672DWriteContext::CreateDeviceResources()
673{
674 HRESULT hr;
675
676 if (mRT != NULL)
677 return S_OK;
678
679 D2D1_RENDER_TARGET_PROPERTIES props = {
680 D2D1_RENDER_TARGET_TYPE_DEFAULT,
681 { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
682 0, 0,
683 D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
684 D2D1_FEATURE_LEVEL_DEFAULT
685 };
686 hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
687 _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
688
689 if (SUCCEEDED(hr))
690 {
691 // This always succeeds.
692 mRT->QueryInterface(
693 __uuidof(ID2D1GdiInteropRenderTarget),
694 reinterpret_cast<void**>(&mGDIRT));
695 _RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT);
696 }
697
698 if (SUCCEEDED(hr))
699 {
700 hr = mRT->CreateSolidColorBrush(
701 D2D1::ColorF(D2D1::ColorF::Black),
702 &mBrush);
703 _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
704 }
705
706 if (SUCCEEDED(hr))
707 {
708 if (mHDC != NULL)
709 {
710 mRT->BindDC(mHDC, &mBindRect);
711 mRT->SetTransform(D2D1::IdentityMatrix());
712 }
713 }
714
715 return hr;
716}
717
718 void
719DWriteContext::DiscardDeviceResources()
720{
721 SafeRelease(&mBrush);
722 SafeRelease(&mGDIRT);
723 SafeRelease(&mRT);
724}
725
726 HRESULT
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100727DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
728 IDWriteTextFormat **ppTextFormat)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200729{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100730 // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200731 HRESULT hr = S_OK;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100732 IDWriteTextFormat *pTextFormat = NULL;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200733
734 IDWriteFont *font = NULL;
735 IDWriteFontFamily *fontFamily = NULL;
736 IDWriteLocalizedStrings *localizedFamilyNames = NULL;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100737 float fontSize = 0;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200738
739 if (SUCCEEDED(hr))
740 {
741 hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
742 }
743
744 // Get the font family to which this font belongs.
745 if (SUCCEEDED(hr))
746 {
747 hr = font->GetFontFamily(&fontFamily);
748 }
749
750 // Get the family names. This returns an object that encapsulates one or
751 // more names with the same meaning but in different languages.
752 if (SUCCEEDED(hr))
753 {
754 hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
755 }
756
757 // Get the family name at index zero. If we were going to display the name
758 // we'd want to try to find one that matched the use locale, but for
759 // purposes of creating a text format object any language will do.
760
761 wchar_t familyName[100];
762 if (SUCCEEDED(hr))
763 {
764 hr = localizedFamilyNames->GetString(0, familyName,
765 ARRAYSIZE(familyName));
766 }
767
768 if (SUCCEEDED(hr))
769 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100770 // Use lfHeight of the LOGFONT as font size.
771 fontSize = float(logFont.lfHeight);
772
773 if (fontSize < 0)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200774 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100775 // Negative lfHeight represents the size of the em unit.
776 fontSize = -fontSize;
777 }
778 else
779 {
780 // Positive lfHeight represents the cell height (ascent +
781 // descent).
782 DWRITE_FONT_METRICS fontMetrics;
783 font->GetMetrics(&fontMetrics);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200784
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100785 // Convert the cell height (ascent + descent) from design units
786 // to ems.
787 float cellHeight = static_cast<float>(
788 fontMetrics.ascent + fontMetrics.descent)
789 / fontMetrics.designUnitsPerEm;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200790
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100791 // Divide the font size by the cell height to get the font em
792 // size.
793 fontSize /= cellHeight;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200794 }
795 }
796
797 // The text format includes a locale name. Ideally, this would be the
798 // language of the text, which may or may not be the same as the primary
799 // language of the user. However, for our purposes the user locale will do.
800 wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
801 if (SUCCEEDED(hr))
802 {
803 if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
804 hr = HRESULT_FROM_WIN32(GetLastError());
805 }
806
807 if (SUCCEEDED(hr))
808 {
809 // Create the text format object.
810 hr = mDWriteFactory->CreateTextFormat(
811 familyName,
812 NULL, // no custom font collection
813 font->GetWeight(),
814 font->GetStyle(),
815 font->GetStretch(),
816 fontSize,
817 localeName,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100818 &pTextFormat);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200819 }
820
821 if (SUCCEEDED(hr))
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100822 hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
823
824 if (SUCCEEDED(hr))
825 hr = pTextFormat->SetParagraphAlignment(
826 DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
827
828 if (SUCCEEDED(hr))
829 hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200830
831 SafeRelease(&localizedFamilyNames);
832 SafeRelease(&fontFamily);
833 SafeRelease(&font);
834
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100835 if (SUCCEEDED(hr))
836 *ppTextFormat = pTextFormat;
837 else
838 SafeRelease(&pTextFormat);
839
840 return hr;
841}
842
843 HRESULT
844DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
845{
846 HRESULT hr = S_OK;
847 IDWriteTextFormat *pTextFormat = NULL;
848
849 hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
850
851 if (SUCCEEDED(hr))
852 {
853 SafeRelease(&mTextFormat);
854 mTextFormat = pTextFormat;
855 mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
856 mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
857 : DWRITE_FONT_STYLE_NORMAL;
858 }
859
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200860 return hr;
861}
862
863 void
864DWriteContext::SetFont(HFONT hFont)
865{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100866 FontCache::Item item;
867 if (mFontCache.get(hFont, item))
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200868 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100869 if (item.pTextFormat != NULL)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200870 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100871 item.pTextFormat->AddRef();
872 SafeRelease(&mTextFormat);
873 mTextFormat = item.pTextFormat;
874 mFontWeight = item.fontWeight;
875 mFontStyle = item.fontStyle;
876 mFallbackDC = false;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200877 }
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100878 else
879 mFallbackDC = true;
880 return;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200881 }
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100882
883 HRESULT hr = E_FAIL;
884 LOGFONTW lf;
885 if (GetObjectW(hFont, sizeof(lf), &lf))
886 hr = SetFontByLOGFONT(lf);
887
888 item.hFont = hFont;
889 if (SUCCEEDED(hr))
890 {
891 item.pTextFormat = mTextFormat;
892 item.fontWeight = mFontWeight;
893 item.fontStyle = mFontStyle;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100894 mFallbackDC = false;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100895 }
Bram Moolenaar92467d32017-12-05 13:22:16 +0100896 else
897 mFallbackDC = true;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100898 mFontCache.put(item);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200899}
900
901 void
Bram Moolenaar92467d32017-12-05 13:22:16 +0100902DWriteContext::BindDC(HDC hdc, const RECT *rect)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200903{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100904 Flush();
905 mRT->BindDC(hdc, rect);
906 mRT->SetTransform(D2D1::IdentityMatrix());
907 mHDC = hdc;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100908 mBindRect = *rect;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200909}
910
Bram Moolenaar92467d32017-12-05 13:22:16 +0100911 HRESULT
912DWriteContext::SetDrawingMode(DrawingMode mode)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200913{
Bram Moolenaar92467d32017-12-05 13:22:16 +0100914 HRESULT hr = S_OK;
915
916 switch (mode)
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100917 {
Bram Moolenaar92467d32017-12-05 13:22:16 +0100918 default:
919 case DM_GDI:
920 if (mInteropHDC != NULL)
921 {
922 mGDIRT->ReleaseDC(NULL);
923 mInteropHDC = NULL;
924 }
925 if (mDrawing)
926 {
927 hr = mRT->EndDraw();
928 if (hr == D2DERR_RECREATE_TARGET)
929 {
930 hr = S_OK;
931 DiscardDeviceResources();
932 CreateDeviceResources();
933 }
934 mDrawing = false;
935 }
936 break;
937
938 case DM_DIRECTX:
939 if (mInteropHDC != NULL)
940 {
941 mGDIRT->ReleaseDC(NULL);
942 mInteropHDC = NULL;
943 }
944 else if (mDrawing == false)
945 {
946 CreateDeviceResources();
947 mRT->BeginDraw();
948 mDrawing = true;
949 }
950 break;
951
952 case DM_INTEROP:
953 if (mDrawing == false)
954 {
955 CreateDeviceResources();
956 mRT->BeginDraw();
957 mDrawing = true;
958 }
959 if (mInteropHDC == NULL)
960 hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC);
961 break;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100962 }
Bram Moolenaar92467d32017-12-05 13:22:16 +0100963 mDMode = mode;
964 return hr;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100965}
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200966
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100967 ID2D1Brush*
968DWriteContext::SolidBrush(COLORREF color)
969{
970 mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
971 UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
972 return mBrush;
973}
974
975 void
Bram Moolenaar92467d32017-12-05 13:22:16 +0100976DWriteContext::DrawText(const WCHAR *text, int len,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100977 int x, int y, int w, int h, int cellWidth, COLORREF color,
Bram Moolenaar92467d32017-12-05 13:22:16 +0100978 UINT fuOptions, const RECT *lprc, const INT *lpDx)
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100979{
980 if (mFallbackDC)
981 {
Bram Moolenaar92467d32017-12-05 13:22:16 +0100982 // Fall back to GDI rendering.
983 HRESULT hr = SetDrawingMode(DM_INTEROP);
984 if (SUCCEEDED(hr))
985 {
986 HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT);
987 HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont);
988 ::SetTextColor(mInteropHDC, color);
989 ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC));
990 ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx);
991 ::SelectObject(mInteropHDC, hOldFont);
992 }
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200993 return;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100994 }
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200995
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100996 HRESULT hr;
997 IDWriteTextLayout *textLayout = NULL;
998
Bram Moolenaar92467d32017-12-05 13:22:16 +0100999 SetDrawingMode(DM_DIRECTX);
1000
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001001 hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
1002 FLOAT(w), FLOAT(h), &textLayout);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001003
1004 if (SUCCEEDED(hr))
1005 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001006 DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
1007 textLayout->SetFontWeight(mFontWeight, textRange);
1008 textLayout->SetFontStyle(mFontStyle, textRange);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001009
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001010 TextRenderer renderer(this);
1011 TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
Bram Moolenaar7f88b652017-12-14 13:15:19 +01001012 textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y) - 0.5f);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001013 }
1014
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001015 SafeRelease(&textLayout);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001016}
1017
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001018 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001019DWriteContext::FillRect(const RECT *rc, COLORREF color)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001020{
Bram Moolenaar92467d32017-12-05 13:22:16 +01001021 if (mDMode == DM_INTEROP)
1022 {
1023 // GDI functions are used before this call. Keep using GDI.
1024 // (Switching to Direct2D causes terrible slowdown.)
1025 HBRUSH hbr = ::CreateSolidBrush(color);
1026 ::FillRect(mInteropHDC, rc, hbr);
1027 ::DeleteObject(HGDIOBJ(hbr));
1028 }
1029 else
1030 {
1031 SetDrawingMode(DM_DIRECTX);
1032 mRT->FillRectangle(
1033 D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
1034 FLOAT(rc->right), FLOAT(rc->bottom)),
1035 SolidBrush(color));
1036 }
1037}
1038
1039 void
1040DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
1041{
1042 if (mDMode == DM_INTEROP)
1043 {
1044 // GDI functions are used before this call. Keep using GDI.
1045 // (Switching to Direct2D causes terrible slowdown.)
1046 HPEN hpen = ::CreatePen(PS_SOLID, 1, color);
1047 HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen));
1048 ::MoveToEx(mInteropHDC, x1, y1, NULL);
1049 ::LineTo(mInteropHDC, x2, y2);
1050 ::SelectObject(mInteropHDC, old_pen);
1051 ::DeleteObject(HGDIOBJ(hpen));
1052 }
1053 else
1054 {
1055 SetDrawingMode(DM_DIRECTX);
1056 mRT->DrawLine(
1057 D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f),
1058 D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f),
1059 SolidBrush(color));
1060 }
1061}
1062
1063 void
1064DWriteContext::SetPixel(int x, int y, COLORREF color)
1065{
1066 if (mDMode == DM_INTEROP)
1067 {
1068 // GDI functions are used before this call. Keep using GDI.
1069 // (Switching to Direct2D causes terrible slowdown.)
1070 ::SetPixel(mInteropHDC, x, y, color);
1071 }
1072 else
1073 {
1074 SetDrawingMode(DM_DIRECTX);
1075 // Direct2D doesn't have SetPixel API. Use DrawLine instead.
1076 mRT->DrawLine(
1077 D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f),
1078 D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f),
1079 SolidBrush(color));
1080 }
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001081}
1082
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001083 void
1084DWriteContext::Flush()
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001085{
Bram Moolenaar92467d32017-12-05 13:22:16 +01001086 SetDrawingMode(DM_GDI);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001087}
1088
1089 void
1090DWriteContext::SetRenderingParams(
1091 const DWriteRenderingParams *params)
1092{
1093 if (mDWriteFactory == NULL)
1094 return;
1095
1096 IDWriteRenderingParams *renderingParams = NULL;
1097 D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
1098 D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
1099 HRESULT hr;
1100 if (params != NULL)
1101 {
1102 hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
1103 params->enhancedContrast, params->clearTypeLevel,
1104 ToPixelGeometry(params->pixelGeometry),
1105 ToRenderingMode(params->renderingMode), &renderingParams);
1106 textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
1107 }
1108 else
1109 hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
1110 if (SUCCEEDED(hr) && renderingParams != NULL)
1111 {
1112 SafeRelease(&mRenderingParams);
1113 mRenderingParams = renderingParams;
1114 mTextAntialiasMode = textAntialiasMode;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001115
1116 Flush();
1117 mRT->SetTextRenderingParams(mRenderingParams);
1118 mRT->SetTextAntialiasMode(mTextAntialiasMode);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001119 }
1120}
1121
1122 DWriteRenderingParams *
1123DWriteContext::GetRenderingParams(
1124 DWriteRenderingParams *params)
1125{
1126 if (params != NULL && mRenderingParams != NULL)
1127 {
1128 params->gamma = mRenderingParams->GetGamma();
1129 params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
1130 params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
1131 params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
1132 params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
1133 params->textAntialiasMode = mTextAntialiasMode;
1134 }
1135 return params;
1136}
1137
1138////////////////////////////////////////////////////////////////////////////
1139// PUBLIC C INTERFACES
1140
1141 void
1142DWrite_Init(void)
1143{
1144#ifdef DYNAMIC_DIRECTX
1145 // Load libraries.
1146 hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
1147 hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
1148 if (hD2D1DLL == NULL || hDWriteDLL == NULL)
1149 {
1150 DWrite_Final();
1151 return;
1152 }
1153 // Get address of procedures.
1154 pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
1155 GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
1156 pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
1157 "D2D1CreateFactory");
1158 pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
1159 "DWriteCreateFactory");
1160#endif
1161}
1162
1163 void
1164DWrite_Final(void)
1165{
1166#ifdef DYNAMIC_DIRECTX
1167 pGetUserDefaultLocaleName = NULL;
1168 pD2D1CreateFactory = NULL;
1169 pDWriteCreateFactory = NULL;
1170 unload(hDWriteDLL);
1171 unload(hD2D1DLL);
1172#endif
1173}
1174
1175 DWriteContext *
1176DWriteContext_Open(void)
1177{
1178#ifdef DYNAMIC_DIRECTX
1179 if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
1180 || pDWriteCreateFactory == NULL)
1181 return NULL;
1182#endif
1183 return new DWriteContext();
1184}
1185
1186 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001187DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001188{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001189 if (ctx != NULL)
1190 ctx->BindDC(hdc, rect);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001191}
1192
1193 void
1194DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
1195{
1196 if (ctx != NULL)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001197 ctx->SetFont(hFont);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001198}
1199
1200 void
1201DWriteContext_DrawText(
1202 DWriteContext *ctx,
Bram Moolenaar92467d32017-12-05 13:22:16 +01001203 const WCHAR *text,
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001204 int len,
1205 int x,
1206 int y,
1207 int w,
1208 int h,
1209 int cellWidth,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001210 COLORREF color,
1211 UINT fuOptions,
Bram Moolenaar92467d32017-12-05 13:22:16 +01001212 const RECT *lprc,
1213 const INT *lpDx)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001214{
1215 if (ctx != NULL)
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001216 ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
1217 fuOptions, lprc, lpDx);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001218}
1219
1220 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001221DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001222{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001223 if (ctx != NULL)
1224 ctx->FillRect(rc, color);
1225}
1226
1227 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001228DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
1229 COLORREF color)
1230{
1231 if (ctx != NULL)
1232 ctx->DrawLine(x1, y1, x2, y2, color);
1233}
1234
1235 void
1236DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color)
1237{
1238 if (ctx != NULL)
1239 ctx->SetPixel(x, y, color);
1240}
1241
1242 void
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001243DWriteContext_Flush(DWriteContext *ctx)
1244{
1245 if (ctx != NULL)
1246 ctx->Flush();
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001247}
1248
1249 void
1250DWriteContext_Close(DWriteContext *ctx)
1251{
1252 delete ctx;
1253}
1254
1255 void
1256DWriteContext_SetRenderingParams(
1257 DWriteContext *ctx,
1258 const DWriteRenderingParams *params)
1259{
1260 if (ctx != NULL)
1261 ctx->SetRenderingParams(params);
1262}
1263
1264 DWriteRenderingParams *
1265DWriteContext_GetRenderingParams(
1266 DWriteContext *ctx,
1267 DWriteRenderingParams *params)
1268{
1269 if (ctx != NULL)
1270 return ctx->GetRenderingParams(params);
1271 else
1272 return NULL;
1273}