blob: e1d19db8da72b726f498922219e03e7f1a3ef3ed [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
41#include <dwrite_2.h>
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +020042
43#include "gui_dwrite.h"
44
45#ifdef __MINGW32__
46# define __maybenull SAL__maybenull
47# define __in SAL__in
48# define __out SAL__out
49#endif
50
Bram Moolenaarcc6cf9b2016-03-19 20:51:35 +010051#if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
52# define FINAL final
53#else
54# define FINAL
55#endif
56
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +020057#ifdef DYNAMIC_DIRECTX
58extern "C" HINSTANCE vimLoadLib(char *name);
59
60typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int);
61typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE,
62 REFIID, const D2D1_FACTORY_OPTIONS *, void **);
63typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE,
64 REFIID, IUnknown **);
65
66static HINSTANCE hD2D1DLL = NULL;
67static HINSTANCE hDWriteDLL = NULL;
68
69static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL;
70static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL;
71static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL;
72
73#define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName)
74#define D2D1CreateFactory (*pD2D1CreateFactory)
75#define DWriteCreateFactory (*pDWriteCreateFactory)
76
77 static void
78unload(HINSTANCE &hinst)
79{
80 if (hinst != NULL)
81 {
82 FreeLibrary(hinst);
83 hinst = NULL;
84 }
85}
86#endif // DYNAMIC_DIRECTX
87
88template <class T> inline void SafeRelease(T **ppT)
89{
90 if (*ppT)
91 {
92 (*ppT)->Release();
93 *ppT = NULL;
94 }
95}
96
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +020097 static DWRITE_PIXEL_GEOMETRY
98ToPixelGeometry(int value)
99{
100 switch (value)
101 {
102 default:
103 case 0:
104 return DWRITE_PIXEL_GEOMETRY_FLAT;
105 case 1:
106 return DWRITE_PIXEL_GEOMETRY_RGB;
107 case 2:
108 return DWRITE_PIXEL_GEOMETRY_BGR;
109 }
110}
111
112 static int
113ToInt(DWRITE_PIXEL_GEOMETRY value)
114{
115 switch (value)
116 {
117 case DWRITE_PIXEL_GEOMETRY_FLAT:
118 return 0;
119 case DWRITE_PIXEL_GEOMETRY_RGB:
120 return 1;
121 case DWRITE_PIXEL_GEOMETRY_BGR:
122 return 2;
123 default:
124 return -1;
125 }
126}
127
128 static DWRITE_RENDERING_MODE
129ToRenderingMode(int value)
130{
131 switch (value)
132 {
133 default:
134 case 0:
135 return DWRITE_RENDERING_MODE_DEFAULT;
136 case 1:
137 return DWRITE_RENDERING_MODE_ALIASED;
138 case 2:
139 return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC;
140 case 3:
141 return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL;
142 case 4:
143 return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
144 case 5:
145 return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
146 case 6:
147 return DWRITE_RENDERING_MODE_OUTLINE;
148 }
149}
150
151 static D2D1_TEXT_ANTIALIAS_MODE
152ToTextAntialiasMode(int value)
153{
154 switch (value)
155 {
156 default:
157 case 0:
158 return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
159 case 1:
160 return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
161 case 2:
162 return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
163 case 3:
164 return D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
165 }
166}
167
168 static int
169ToInt(DWRITE_RENDERING_MODE value)
170{
171 switch (value)
172 {
173 case DWRITE_RENDERING_MODE_DEFAULT:
174 return 0;
175 case DWRITE_RENDERING_MODE_ALIASED:
176 return 1;
177 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
178 return 2;
179 case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
180 return 3;
181 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL:
182 return 4;
183 case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC:
184 return 5;
185 case DWRITE_RENDERING_MODE_OUTLINE:
186 return 6;
187 default:
188 return -1;
189 }
190}
191
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100192class FontCache {
193public:
194 struct Item {
195 HFONT hFont;
196 IDWriteTextFormat* pTextFormat;
197 DWRITE_FONT_WEIGHT fontWeight;
198 DWRITE_FONT_STYLE fontStyle;
199 Item() : hFont(NULL), pTextFormat(NULL) {}
200 };
201
202private:
203 int mSize;
204 Item *mItems;
205
206public:
207 FontCache(int size = 2) :
208 mSize(size),
209 mItems(new Item[size])
210 {
211 }
212
213 ~FontCache()
214 {
215 for (int i = 0; i < mSize; ++i)
216 SafeRelease(&mItems[i].pTextFormat);
217 delete[] mItems;
218 }
219
220 bool get(HFONT hFont, Item &item)
221 {
222 int n = find(hFont);
223 if (n < 0)
224 return false;
225 item = mItems[n];
226 slide(n);
227 return true;
228 }
229
230 void put(const Item& item)
231 {
232 int n = find(item.hFont);
233 if (n < 0)
234 n = mSize - 1;
235 if (mItems[n].pTextFormat != item.pTextFormat)
236 {
237 SafeRelease(&mItems[n].pTextFormat);
238 item.pTextFormat->AddRef();
239 }
240 mItems[n] = item;
241 slide(n);
242 }
243
244private:
245 int find(HFONT hFont)
246 {
247 for (int i = 0; i < mSize; ++i)
248 {
249 if (mItems[i].hFont == hFont)
250 return i;
251 }
252 return -1;
253 }
254
255 void slide(int nextTop)
256 {
257 if (nextTop == 0)
258 return;
259 Item tmp = mItems[nextTop];
260 for (int i = nextTop - 1; i >= 0; --i)
261 mItems[i + 1] = mItems[i];
262 mItems[0] = tmp;
263 }
264};
265
Bram Moolenaar92467d32017-12-05 13:22:16 +0100266enum DrawingMode {
267 DM_GDI = 0,
268 DM_DIRECTX = 1,
269 DM_INTEROP = 2,
270};
271
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100272struct DWriteContext {
273 HDC mHDC;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100274 RECT mBindRect;
275 DrawingMode mDMode;
276 HDC mInteropHDC;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100277 bool mDrawing;
278 bool mFallbackDC;
279
280 ID2D1Factory *mD2D1Factory;
281
282 ID2D1DCRenderTarget *mRT;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100283 ID2D1GdiInteropRenderTarget *mGDIRT;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100284 ID2D1SolidColorBrush *mBrush;
285
286 IDWriteFactory *mDWriteFactory;
287 IDWriteFactory2 *mDWriteFactory2;
288
289 IDWriteGdiInterop *mGdiInterop;
290 IDWriteRenderingParams *mRenderingParams;
291
292 FontCache mFontCache;
293 IDWriteTextFormat *mTextFormat;
294 DWRITE_FONT_WEIGHT mFontWeight;
295 DWRITE_FONT_STYLE mFontStyle;
296
297 D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode;
298
299 // METHODS
300
301 DWriteContext();
302
303 virtual ~DWriteContext();
304
Bram Moolenaar92467d32017-12-05 13:22:16 +0100305 HRESULT CreateDeviceResources();
306
307 void DiscardDeviceResources();
308
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100309 HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
310 IDWriteTextFormat **ppTextFormat);
311
312 HRESULT SetFontByLOGFONT(const LOGFONTW &logFont);
313
314 void SetFont(HFONT hFont);
315
Bram Moolenaar92467d32017-12-05 13:22:16 +0100316 void BindDC(HDC hdc, const RECT *rect);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100317
Bram Moolenaar92467d32017-12-05 13:22:16 +0100318 HRESULT SetDrawingMode(DrawingMode mode);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100319
320 ID2D1Brush* SolidBrush(COLORREF color);
321
Bram Moolenaar92467d32017-12-05 13:22:16 +0100322 void DrawText(const WCHAR *text, int len,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100323 int x, int y, int w, int h, int cellWidth, COLORREF color,
Bram Moolenaar92467d32017-12-05 13:22:16 +0100324 UINT fuOptions, const RECT *lprc, const INT *lpDx);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100325
Bram Moolenaar92467d32017-12-05 13:22:16 +0100326 void FillRect(const RECT *rc, COLORREF color);
327
328 void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
329
330 void SetPixel(int x, int y, COLORREF color);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100331
332 void Flush();
333
334 void SetRenderingParams(
335 const DWriteRenderingParams *params);
336
337 DWriteRenderingParams *GetRenderingParams(
338 DWriteRenderingParams *params);
339};
340
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200341class AdjustedGlyphRun : public DWRITE_GLYPH_RUN
342{
343private:
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100344 FLOAT &mAccum;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200345 FLOAT mDelta;
346 FLOAT *mAdjustedAdvances;
347
348public:
349 AdjustedGlyphRun(
350 const DWRITE_GLYPH_RUN *glyphRun,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100351 FLOAT cellWidth,
352 FLOAT &accum) :
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200353 DWRITE_GLYPH_RUN(*glyphRun),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100354 mAccum(accum),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200355 mDelta(0.0f),
356 mAdjustedAdvances(new FLOAT[glyphRun->glyphCount])
357 {
358 assert(cellWidth != 0.0f);
359 for (UINT32 i = 0; i < glyphRun->glyphCount; ++i)
360 {
361 FLOAT orig = glyphRun->glyphAdvances[i];
362 FLOAT adjusted = adjustToCell(orig, cellWidth);
363 mAdjustedAdvances[i] = adjusted;
364 mDelta += adjusted - orig;
365 }
366 glyphAdvances = mAdjustedAdvances;
367 }
368
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100369 ~AdjustedGlyphRun()
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200370 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100371 mAccum += mDelta;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200372 delete[] mAdjustedAdvances;
373 }
374
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200375 static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth)
376 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100377 int cellCount = int(floor(value / cellWidth + 0.5f));
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200378 if (cellCount < 1)
379 cellCount = 1;
380 return cellCount * cellWidth;
381 }
382};
383
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100384struct TextRendererContext {
385 // const fields.
386 COLORREF color;
387 FLOAT cellWidth;
388
389 // working fields.
390 FLOAT offsetX;
391};
392
393class TextRenderer FINAL : public IDWriteTextRenderer
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200394{
395public:
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100396 TextRenderer(
397 DWriteContext* pDWC) :
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200398 cRefCount_(0),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100399 pDWC_(pDWC)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200400 {
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200401 AddRef();
402 }
403
Bram Moolenaaredb4f2b2016-02-27 15:27:23 +0100404 // add "virtual" to avoid a compiler warning
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100405 virtual ~TextRenderer()
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200406 {
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200407 }
408
409 IFACEMETHOD(IsPixelSnappingDisabled)(
410 __maybenull void* clientDrawingContext,
411 __out BOOL* isDisabled)
412 {
413 *isDisabled = FALSE;
414 return S_OK;
415 }
416
417 IFACEMETHOD(GetCurrentTransform)(
418 __maybenull void* clientDrawingContext,
419 __out DWRITE_MATRIX* transform)
420 {
Bram Moolenaaredb4f2b2016-02-27 15:27:23 +0100421 // forward the render target's transform
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100422 pDWC_->mRT->GetTransform(
423 reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform));
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200424 return S_OK;
425 }
426
427 IFACEMETHOD(GetPixelsPerDip)(
428 __maybenull void* clientDrawingContext,
429 __out FLOAT* pixelsPerDip)
430 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100431 float dpiX, unused;
432 pDWC_->mRT->GetDpi(&dpiX, &unused);
433 *pixelsPerDip = dpiX / 96.0f;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200434 return S_OK;
435 }
436
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200437 IFACEMETHOD(DrawUnderline)(
438 __maybenull void* clientDrawingContext,
439 FLOAT baselineOriginX,
440 FLOAT baselineOriginY,
441 __in DWRITE_UNDERLINE const* underline,
442 IUnknown* clientDrawingEffect)
443 {
444 return E_NOTIMPL;
445 }
446
447 IFACEMETHOD(DrawStrikethrough)(
448 __maybenull void* clientDrawingContext,
449 FLOAT baselineOriginX,
450 FLOAT baselineOriginY,
451 __in DWRITE_STRIKETHROUGH const* strikethrough,
452 IUnknown* clientDrawingEffect)
453 {
454 return E_NOTIMPL;
455 }
456
457 IFACEMETHOD(DrawInlineObject)(
458 __maybenull void* clientDrawingContext,
459 FLOAT originX,
460 FLOAT originY,
461 IDWriteInlineObject* inlineObject,
462 BOOL isSideways,
463 BOOL isRightToLeft,
464 IUnknown* clientDrawingEffect)
465 {
466 return E_NOTIMPL;
467 }
468
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100469 IFACEMETHOD(DrawGlyphRun)(
470 __maybenull void* clientDrawingContext,
471 FLOAT baselineOriginX,
472 FLOAT baselineOriginY,
473 DWRITE_MEASURING_MODE measuringMode,
474 __in DWRITE_GLYPH_RUN const* glyphRun,
475 __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
476 IUnknown* clientDrawingEffect)
477 {
478 TextRendererContext *context =
479 reinterpret_cast<TextRendererContext*>(clientDrawingContext);
480
481 AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth,
482 context->offsetX);
483
484 if (pDWC_->mDWriteFactory2 != NULL)
485 {
486 IDWriteColorGlyphRunEnumerator *enumerator = NULL;
487 HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun(
488 baselineOriginX + context->offsetX,
489 baselineOriginY,
490 &adjustedGlyphRun,
491 NULL,
492 DWRITE_MEASURING_MODE_GDI_NATURAL,
493 NULL,
494 0,
495 &enumerator);
496 if (SUCCEEDED(hr))
497 {
498 // Draw by IDWriteFactory2 for color emoji
499 BOOL hasRun = TRUE;
500 enumerator->MoveNext(&hasRun);
501 while (hasRun)
502 {
503 const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun;
504 enumerator->GetCurrentRun(&colorGlyphRun);
505
506 pDWC_->mBrush->SetColor(colorGlyphRun->runColor);
507 pDWC_->mRT->DrawGlyphRun(
508 D2D1::Point2F(
509 colorGlyphRun->baselineOriginX,
510 colorGlyphRun->baselineOriginY),
511 &colorGlyphRun->glyphRun,
512 pDWC_->mBrush,
513 DWRITE_MEASURING_MODE_NATURAL);
514 enumerator->MoveNext(&hasRun);
515 }
516 SafeRelease(&enumerator);
517 return S_OK;
518 }
519 }
520
521 // Draw by IDWriteFactory (without color emoji)
522 pDWC_->mRT->DrawGlyphRun(
523 D2D1::Point2F(
524 baselineOriginX + context->offsetX,
525 baselineOriginY),
526 &adjustedGlyphRun,
527 pDWC_->SolidBrush(context->color),
528 DWRITE_MEASURING_MODE_NATURAL);
529 return S_OK;
530 }
531
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200532public:
533 IFACEMETHOD_(unsigned long, AddRef) ()
534 {
535 return InterlockedIncrement(&cRefCount_);
536 }
537
538 IFACEMETHOD_(unsigned long, Release) ()
539 {
540 long newCount = InterlockedDecrement(&cRefCount_);
541
542 if (newCount == 0)
543 {
544 delete this;
545 return 0;
546 }
547 return newCount;
548 }
549
550 IFACEMETHOD(QueryInterface)(
551 IID const& riid,
552 void** ppvObject)
553 {
554 if (__uuidof(IDWriteTextRenderer) == riid)
555 {
556 *ppvObject = this;
557 }
558 else if (__uuidof(IDWritePixelSnapping) == riid)
559 {
560 *ppvObject = this;
561 }
562 else if (__uuidof(IUnknown) == riid)
563 {
564 *ppvObject = this;
565 }
566 else
567 {
568 *ppvObject = NULL;
569 return E_FAIL;
570 }
571
572 return S_OK;
573 }
574
575private:
Bram Moolenaar0106b4b2014-08-07 13:55:10 +0200576 long cRefCount_;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100577 DWriteContext* pDWC_;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200578};
579
580DWriteContext::DWriteContext() :
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100581 mHDC(NULL),
Bram Moolenaar92467d32017-12-05 13:22:16 +0100582 mBindRect(),
583 mDMode(DM_GDI),
584 mInteropHDC(NULL),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200585 mDrawing(false),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100586 mFallbackDC(false),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200587 mD2D1Factory(NULL),
588 mRT(NULL),
Bram Moolenaar92467d32017-12-05 13:22:16 +0100589 mGDIRT(NULL),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200590 mBrush(NULL),
591 mDWriteFactory(NULL),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100592 mDWriteFactory2(NULL),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200593 mGdiInterop(NULL),
594 mRenderingParams(NULL),
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100595 mFontCache(8),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200596 mTextFormat(NULL),
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200597 mFontWeight(DWRITE_FONT_WEIGHT_NORMAL),
598 mFontStyle(DWRITE_FONT_STYLE_NORMAL),
599 mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT)
600{
601 HRESULT hr;
602
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200603 hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
604 __uuidof(ID2D1Factory), NULL,
605 reinterpret_cast<void**>(&mD2D1Factory));
606 _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
607
608 if (SUCCEEDED(hr))
Bram Moolenaar92467d32017-12-05 13:22:16 +0100609 hr = CreateDeviceResources();
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200610
611 if (SUCCEEDED(hr))
612 {
613 hr = DWriteCreateFactory(
614 DWRITE_FACTORY_TYPE_SHARED,
615 __uuidof(IDWriteFactory),
616 reinterpret_cast<IUnknown**>(&mDWriteFactory));
617 _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr,
618 mDWriteFactory);
619 }
620
621 if (SUCCEEDED(hr))
622 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100623 DWriteCreateFactory(
624 DWRITE_FACTORY_TYPE_SHARED,
625 __uuidof(IDWriteFactory2),
626 reinterpret_cast<IUnknown**>(&mDWriteFactory2));
627 _RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available");
628 }
629
630 if (SUCCEEDED(hr))
631 {
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200632 hr = mDWriteFactory->GetGdiInterop(&mGdiInterop);
633 _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop);
634 }
635
636 if (SUCCEEDED(hr))
637 {
638 hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams);
639 _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr,
640 mRenderingParams);
641 }
642}
643
644DWriteContext::~DWriteContext()
645{
646 SafeRelease(&mTextFormat);
647 SafeRelease(&mRenderingParams);
648 SafeRelease(&mGdiInterop);
649 SafeRelease(&mDWriteFactory);
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100650 SafeRelease(&mDWriteFactory2);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200651 SafeRelease(&mBrush);
Bram Moolenaar92467d32017-12-05 13:22:16 +0100652 SafeRelease(&mGDIRT);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200653 SafeRelease(&mRT);
654 SafeRelease(&mD2D1Factory);
655}
656
657 HRESULT
Bram Moolenaar92467d32017-12-05 13:22:16 +0100658DWriteContext::CreateDeviceResources()
659{
660 HRESULT hr;
661
662 if (mRT != NULL)
663 return S_OK;
664
665 D2D1_RENDER_TARGET_PROPERTIES props = {
666 D2D1_RENDER_TARGET_TYPE_DEFAULT,
667 { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE },
668 0, 0,
669 D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
670 D2D1_FEATURE_LEVEL_DEFAULT
671 };
672 hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT);
673 _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT);
674
675 if (SUCCEEDED(hr))
676 {
677 // This always succeeds.
678 mRT->QueryInterface(
679 __uuidof(ID2D1GdiInteropRenderTarget),
680 reinterpret_cast<void**>(&mGDIRT));
681 _RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT);
682 }
683
684 if (SUCCEEDED(hr))
685 {
686 hr = mRT->CreateSolidColorBrush(
687 D2D1::ColorF(D2D1::ColorF::Black),
688 &mBrush);
689 _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush);
690 }
691
692 if (SUCCEEDED(hr))
693 {
694 if (mHDC != NULL)
695 {
696 mRT->BindDC(mHDC, &mBindRect);
697 mRT->SetTransform(D2D1::IdentityMatrix());
698 }
699 }
700
701 return hr;
702}
703
704 void
705DWriteContext::DiscardDeviceResources()
706{
707 SafeRelease(&mBrush);
708 SafeRelease(&mGDIRT);
709 SafeRelease(&mRT);
710}
711
712 HRESULT
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100713DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont,
714 IDWriteTextFormat **ppTextFormat)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200715{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100716 // 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 +0200717 HRESULT hr = S_OK;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100718 IDWriteTextFormat *pTextFormat = NULL;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200719
720 IDWriteFont *font = NULL;
721 IDWriteFontFamily *fontFamily = NULL;
722 IDWriteLocalizedStrings *localizedFamilyNames = NULL;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100723 float fontSize = 0;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200724
725 if (SUCCEEDED(hr))
726 {
727 hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font);
728 }
729
730 // Get the font family to which this font belongs.
731 if (SUCCEEDED(hr))
732 {
733 hr = font->GetFontFamily(&fontFamily);
734 }
735
736 // Get the family names. This returns an object that encapsulates one or
737 // more names with the same meaning but in different languages.
738 if (SUCCEEDED(hr))
739 {
740 hr = fontFamily->GetFamilyNames(&localizedFamilyNames);
741 }
742
743 // Get the family name at index zero. If we were going to display the name
744 // we'd want to try to find one that matched the use locale, but for
745 // purposes of creating a text format object any language will do.
746
747 wchar_t familyName[100];
748 if (SUCCEEDED(hr))
749 {
750 hr = localizedFamilyNames->GetString(0, familyName,
751 ARRAYSIZE(familyName));
752 }
753
754 if (SUCCEEDED(hr))
755 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100756 // Use lfHeight of the LOGFONT as font size.
757 fontSize = float(logFont.lfHeight);
758
759 if (fontSize < 0)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200760 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100761 // Negative lfHeight represents the size of the em unit.
762 fontSize = -fontSize;
763 }
764 else
765 {
766 // Positive lfHeight represents the cell height (ascent +
767 // descent).
768 DWRITE_FONT_METRICS fontMetrics;
769 font->GetMetrics(&fontMetrics);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200770
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100771 // Convert the cell height (ascent + descent) from design units
772 // to ems.
773 float cellHeight = static_cast<float>(
774 fontMetrics.ascent + fontMetrics.descent)
775 / fontMetrics.designUnitsPerEm;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200776
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100777 // Divide the font size by the cell height to get the font em
778 // size.
779 fontSize /= cellHeight;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200780 }
781 }
782
783 // The text format includes a locale name. Ideally, this would be the
784 // language of the text, which may or may not be the same as the primary
785 // language of the user. However, for our purposes the user locale will do.
786 wchar_t localeName[LOCALE_NAME_MAX_LENGTH];
787 if (SUCCEEDED(hr))
788 {
789 if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0)
790 hr = HRESULT_FROM_WIN32(GetLastError());
791 }
792
793 if (SUCCEEDED(hr))
794 {
795 // Create the text format object.
796 hr = mDWriteFactory->CreateTextFormat(
797 familyName,
798 NULL, // no custom font collection
799 font->GetWeight(),
800 font->GetStyle(),
801 font->GetStretch(),
802 fontSize,
803 localeName,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100804 &pTextFormat);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200805 }
806
807 if (SUCCEEDED(hr))
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100808 hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
809
810 if (SUCCEEDED(hr))
811 hr = pTextFormat->SetParagraphAlignment(
812 DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
813
814 if (SUCCEEDED(hr))
815 hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200816
817 SafeRelease(&localizedFamilyNames);
818 SafeRelease(&fontFamily);
819 SafeRelease(&font);
820
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100821 if (SUCCEEDED(hr))
822 *ppTextFormat = pTextFormat;
823 else
824 SafeRelease(&pTextFormat);
825
826 return hr;
827}
828
829 HRESULT
830DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont)
831{
832 HRESULT hr = S_OK;
833 IDWriteTextFormat *pTextFormat = NULL;
834
835 hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat);
836
837 if (SUCCEEDED(hr))
838 {
839 SafeRelease(&mTextFormat);
840 mTextFormat = pTextFormat;
841 mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight);
842 mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC
843 : DWRITE_FONT_STYLE_NORMAL;
844 }
845
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200846 return hr;
847}
848
849 void
850DWriteContext::SetFont(HFONT hFont)
851{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100852 FontCache::Item item;
853 if (mFontCache.get(hFont, item))
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200854 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100855 if (item.pTextFormat != NULL)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200856 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100857 item.pTextFormat->AddRef();
858 SafeRelease(&mTextFormat);
859 mTextFormat = item.pTextFormat;
860 mFontWeight = item.fontWeight;
861 mFontStyle = item.fontStyle;
862 mFallbackDC = false;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200863 }
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100864 else
865 mFallbackDC = true;
866 return;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200867 }
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100868
869 HRESULT hr = E_FAIL;
870 LOGFONTW lf;
871 if (GetObjectW(hFont, sizeof(lf), &lf))
872 hr = SetFontByLOGFONT(lf);
873
874 item.hFont = hFont;
875 if (SUCCEEDED(hr))
876 {
877 item.pTextFormat = mTextFormat;
878 item.fontWeight = mFontWeight;
879 item.fontStyle = mFontStyle;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100880 mFallbackDC = false;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100881 }
Bram Moolenaar92467d32017-12-05 13:22:16 +0100882 else
883 mFallbackDC = true;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100884 mFontCache.put(item);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200885}
886
887 void
Bram Moolenaar92467d32017-12-05 13:22:16 +0100888DWriteContext::BindDC(HDC hdc, const RECT *rect)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200889{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100890 Flush();
891 mRT->BindDC(hdc, rect);
892 mRT->SetTransform(D2D1::IdentityMatrix());
893 mHDC = hdc;
Bram Moolenaar92467d32017-12-05 13:22:16 +0100894 mBindRect = *rect;
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200895}
896
Bram Moolenaar92467d32017-12-05 13:22:16 +0100897 HRESULT
898DWriteContext::SetDrawingMode(DrawingMode mode)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200899{
Bram Moolenaar92467d32017-12-05 13:22:16 +0100900 HRESULT hr = S_OK;
901
902 switch (mode)
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100903 {
Bram Moolenaar92467d32017-12-05 13:22:16 +0100904 default:
905 case DM_GDI:
906 if (mInteropHDC != NULL)
907 {
908 mGDIRT->ReleaseDC(NULL);
909 mInteropHDC = NULL;
910 }
911 if (mDrawing)
912 {
913 hr = mRT->EndDraw();
914 if (hr == D2DERR_RECREATE_TARGET)
915 {
916 hr = S_OK;
917 DiscardDeviceResources();
918 CreateDeviceResources();
919 }
920 mDrawing = false;
921 }
922 break;
923
924 case DM_DIRECTX:
925 if (mInteropHDC != NULL)
926 {
927 mGDIRT->ReleaseDC(NULL);
928 mInteropHDC = NULL;
929 }
930 else if (mDrawing == false)
931 {
932 CreateDeviceResources();
933 mRT->BeginDraw();
934 mDrawing = true;
935 }
936 break;
937
938 case DM_INTEROP:
939 if (mDrawing == false)
940 {
941 CreateDeviceResources();
942 mRT->BeginDraw();
943 mDrawing = true;
944 }
945 if (mInteropHDC == NULL)
946 hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC);
947 break;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100948 }
Bram Moolenaar92467d32017-12-05 13:22:16 +0100949 mDMode = mode;
950 return hr;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100951}
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200952
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100953 ID2D1Brush*
954DWriteContext::SolidBrush(COLORREF color)
955{
956 mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 |
957 UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color))));
958 return mBrush;
959}
960
961 void
Bram Moolenaar92467d32017-12-05 13:22:16 +0100962DWriteContext::DrawText(const WCHAR *text, int len,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100963 int x, int y, int w, int h, int cellWidth, COLORREF color,
Bram Moolenaar92467d32017-12-05 13:22:16 +0100964 UINT fuOptions, const RECT *lprc, const INT *lpDx)
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100965{
966 if (mFallbackDC)
967 {
Bram Moolenaar92467d32017-12-05 13:22:16 +0100968 // Fall back to GDI rendering.
969 HRESULT hr = SetDrawingMode(DM_INTEROP);
970 if (SUCCEEDED(hr))
971 {
972 HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT);
973 HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont);
974 ::SetTextColor(mInteropHDC, color);
975 ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC));
976 ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx);
977 ::SelectObject(mInteropHDC, hOldFont);
978 }
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200979 return;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100980 }
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200981
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100982 HRESULT hr;
983 IDWriteTextLayout *textLayout = NULL;
984
Bram Moolenaar92467d32017-12-05 13:22:16 +0100985 SetDrawingMode(DM_DIRECTX);
986
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100987 hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat,
988 FLOAT(w), FLOAT(h), &textLayout);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200989
990 if (SUCCEEDED(hr))
991 {
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100992 DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) };
993 textLayout->SetFontWeight(mFontWeight, textRange);
994 textLayout->SetFontStyle(mFontStyle, textRange);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200995
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +0100996 TextRenderer renderer(this);
997 TextRendererContext context = { color, FLOAT(cellWidth), 0.0f };
998 textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y));
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +0200999 }
1000
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001001 SafeRelease(&textLayout);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001002}
1003
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001004 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001005DWriteContext::FillRect(const RECT *rc, COLORREF color)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001006{
Bram Moolenaar92467d32017-12-05 13:22:16 +01001007 if (mDMode == DM_INTEROP)
1008 {
1009 // GDI functions are used before this call. Keep using GDI.
1010 // (Switching to Direct2D causes terrible slowdown.)
1011 HBRUSH hbr = ::CreateSolidBrush(color);
1012 ::FillRect(mInteropHDC, rc, hbr);
1013 ::DeleteObject(HGDIOBJ(hbr));
1014 }
1015 else
1016 {
1017 SetDrawingMode(DM_DIRECTX);
1018 mRT->FillRectangle(
1019 D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top),
1020 FLOAT(rc->right), FLOAT(rc->bottom)),
1021 SolidBrush(color));
1022 }
1023}
1024
1025 void
1026DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color)
1027{
1028 if (mDMode == DM_INTEROP)
1029 {
1030 // GDI functions are used before this call. Keep using GDI.
1031 // (Switching to Direct2D causes terrible slowdown.)
1032 HPEN hpen = ::CreatePen(PS_SOLID, 1, color);
1033 HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen));
1034 ::MoveToEx(mInteropHDC, x1, y1, NULL);
1035 ::LineTo(mInteropHDC, x2, y2);
1036 ::SelectObject(mInteropHDC, old_pen);
1037 ::DeleteObject(HGDIOBJ(hpen));
1038 }
1039 else
1040 {
1041 SetDrawingMode(DM_DIRECTX);
1042 mRT->DrawLine(
1043 D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f),
1044 D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f),
1045 SolidBrush(color));
1046 }
1047}
1048
1049 void
1050DWriteContext::SetPixel(int x, int y, COLORREF color)
1051{
1052 if (mDMode == DM_INTEROP)
1053 {
1054 // GDI functions are used before this call. Keep using GDI.
1055 // (Switching to Direct2D causes terrible slowdown.)
1056 ::SetPixel(mInteropHDC, x, y, color);
1057 }
1058 else
1059 {
1060 SetDrawingMode(DM_DIRECTX);
1061 // Direct2D doesn't have SetPixel API. Use DrawLine instead.
1062 mRT->DrawLine(
1063 D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f),
1064 D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f),
1065 SolidBrush(color));
1066 }
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001067}
1068
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001069 void
1070DWriteContext::Flush()
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001071{
Bram Moolenaar92467d32017-12-05 13:22:16 +01001072 SetDrawingMode(DM_GDI);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001073}
1074
1075 void
1076DWriteContext::SetRenderingParams(
1077 const DWriteRenderingParams *params)
1078{
1079 if (mDWriteFactory == NULL)
1080 return;
1081
1082 IDWriteRenderingParams *renderingParams = NULL;
1083 D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode =
1084 D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
1085 HRESULT hr;
1086 if (params != NULL)
1087 {
1088 hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma,
1089 params->enhancedContrast, params->clearTypeLevel,
1090 ToPixelGeometry(params->pixelGeometry),
1091 ToRenderingMode(params->renderingMode), &renderingParams);
1092 textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode);
1093 }
1094 else
1095 hr = mDWriteFactory->CreateRenderingParams(&renderingParams);
1096 if (SUCCEEDED(hr) && renderingParams != NULL)
1097 {
1098 SafeRelease(&mRenderingParams);
1099 mRenderingParams = renderingParams;
1100 mTextAntialiasMode = textAntialiasMode;
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001101
1102 Flush();
1103 mRT->SetTextRenderingParams(mRenderingParams);
1104 mRT->SetTextAntialiasMode(mTextAntialiasMode);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001105 }
1106}
1107
1108 DWriteRenderingParams *
1109DWriteContext::GetRenderingParams(
1110 DWriteRenderingParams *params)
1111{
1112 if (params != NULL && mRenderingParams != NULL)
1113 {
1114 params->gamma = mRenderingParams->GetGamma();
1115 params->enhancedContrast = mRenderingParams->GetEnhancedContrast();
1116 params->clearTypeLevel = mRenderingParams->GetClearTypeLevel();
1117 params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry());
1118 params->renderingMode = ToInt(mRenderingParams->GetRenderingMode());
1119 params->textAntialiasMode = mTextAntialiasMode;
1120 }
1121 return params;
1122}
1123
1124////////////////////////////////////////////////////////////////////////////
1125// PUBLIC C INTERFACES
1126
1127 void
1128DWrite_Init(void)
1129{
1130#ifdef DYNAMIC_DIRECTX
1131 // Load libraries.
1132 hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll"));
1133 hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll"));
1134 if (hD2D1DLL == NULL || hDWriteDLL == NULL)
1135 {
1136 DWrite_Final();
1137 return;
1138 }
1139 // Get address of procedures.
1140 pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress(
1141 GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName");
1142 pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL,
1143 "D2D1CreateFactory");
1144 pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL,
1145 "DWriteCreateFactory");
1146#endif
1147}
1148
1149 void
1150DWrite_Final(void)
1151{
1152#ifdef DYNAMIC_DIRECTX
1153 pGetUserDefaultLocaleName = NULL;
1154 pD2D1CreateFactory = NULL;
1155 pDWriteCreateFactory = NULL;
1156 unload(hDWriteDLL);
1157 unload(hD2D1DLL);
1158#endif
1159}
1160
1161 DWriteContext *
1162DWriteContext_Open(void)
1163{
1164#ifdef DYNAMIC_DIRECTX
1165 if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL
1166 || pDWriteCreateFactory == NULL)
1167 return NULL;
1168#endif
1169 return new DWriteContext();
1170}
1171
1172 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001173DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001174{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001175 if (ctx != NULL)
1176 ctx->BindDC(hdc, rect);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001177}
1178
1179 void
1180DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont)
1181{
1182 if (ctx != NULL)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001183 ctx->SetFont(hFont);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001184}
1185
1186 void
1187DWriteContext_DrawText(
1188 DWriteContext *ctx,
Bram Moolenaar92467d32017-12-05 13:22:16 +01001189 const WCHAR *text,
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001190 int len,
1191 int x,
1192 int y,
1193 int w,
1194 int h,
1195 int cellWidth,
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001196 COLORREF color,
1197 UINT fuOptions,
Bram Moolenaar92467d32017-12-05 13:22:16 +01001198 const RECT *lprc,
1199 const INT *lpDx)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001200{
1201 if (ctx != NULL)
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001202 ctx->DrawText(text, len, x, y, w, h, cellWidth, color,
1203 fuOptions, lprc, lpDx);
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001204}
1205
1206 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001207DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color)
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001208{
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001209 if (ctx != NULL)
1210 ctx->FillRect(rc, color);
1211}
1212
1213 void
Bram Moolenaar92467d32017-12-05 13:22:16 +01001214DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
1215 COLORREF color)
1216{
1217 if (ctx != NULL)
1218 ctx->DrawLine(x1, y1, x2, y2, color);
1219}
1220
1221 void
1222DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color)
1223{
1224 if (ctx != NULL)
1225 ctx->SetPixel(x, y, color);
1226}
1227
1228 void
Bram Moolenaard7ccc4d2017-11-26 14:29:32 +01001229DWriteContext_Flush(DWriteContext *ctx)
1230{
1231 if (ctx != NULL)
1232 ctx->Flush();
Bram Moolenaarb5a7a8b2014-08-06 14:52:30 +02001233}
1234
1235 void
1236DWriteContext_Close(DWriteContext *ctx)
1237{
1238 delete ctx;
1239}
1240
1241 void
1242DWriteContext_SetRenderingParams(
1243 DWriteContext *ctx,
1244 const DWriteRenderingParams *params)
1245{
1246 if (ctx != NULL)
1247 ctx->SetRenderingParams(params);
1248}
1249
1250 DWriteRenderingParams *
1251DWriteContext_GetRenderingParams(
1252 DWriteContext *ctx,
1253 DWriteRenderingParams *params)
1254{
1255 if (ctx != NULL)
1256 return ctx->GetRenderingParams(params);
1257 else
1258 return NULL;
1259}