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