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