Mercurial > vim
annotate src/gui_dwrite.cpp @ 8581:fd454847836d v7.4.1580
commit https://github.com/vim/vim/commit/7a5c46a9df7ef01a4f6a620861c35400d5ad28d9
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Mar 16 20:41:21 2016 +0100
patch 7.4.1580
Problem: Crash when using function reference. (Luchr)
Solution: Set initial refcount. (Ken Takata, closes https://github.com/vim/vim/issues/690)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Wed, 16 Mar 2016 20:45:05 +0100 |
parents | 770774e66011 |
children | 0af716a4f5d2 |
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 | |
8271
770774e66011
commit https://github.com/vim/vim/commit/edb4f2b3601b0abd47091606269c0ac3244a805b
Christian Brabandt <cb@256bit.org>
parents:
7547
diff
changeset
|
240 // add "virtual" to avoid a compiler warning |
770774e66011
commit https://github.com/vim/vim/commit/edb4f2b3601b0abd47091606269c0ac3244a805b
Christian Brabandt <cb@256bit.org>
parents:
7547
diff
changeset
|
241 virtual ~GdiTextRenderer() |
6110 | 242 { |
243 SafeRelease(&pRenderTarget_); | |
244 SafeRelease(&pRenderingParams_); | |
245 } | |
246 | |
247 IFACEMETHOD(IsPixelSnappingDisabled)( | |
248 __maybenull void* clientDrawingContext, | |
249 __out BOOL* isDisabled) | |
250 { | |
251 *isDisabled = FALSE; | |
252 return S_OK; | |
253 } | |
254 | |
255 IFACEMETHOD(GetCurrentTransform)( | |
256 __maybenull void* clientDrawingContext, | |
257 __out DWRITE_MATRIX* transform) | |
258 { | |
8271
770774e66011
commit https://github.com/vim/vim/commit/edb4f2b3601b0abd47091606269c0ac3244a805b
Christian Brabandt <cb@256bit.org>
parents:
7547
diff
changeset
|
259 // forward the render target's transform |
6110 | 260 pRenderTarget_->GetCurrentTransform(transform); |
261 return S_OK; | |
262 } | |
263 | |
264 IFACEMETHOD(GetPixelsPerDip)( | |
265 __maybenull void* clientDrawingContext, | |
266 __out FLOAT* pixelsPerDip) | |
267 { | |
268 *pixelsPerDip = pRenderTarget_->GetPixelsPerDip(); | |
269 return S_OK; | |
270 } | |
271 | |
272 IFACEMETHOD(DrawGlyphRun)( | |
273 __maybenull void* clientDrawingContext, | |
274 FLOAT baselineOriginX, | |
275 FLOAT baselineOriginY, | |
276 DWRITE_MEASURING_MODE measuringMode, | |
277 __in DWRITE_GLYPH_RUN const* glyphRun, | |
278 __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, | |
279 IUnknown* clientDrawingEffect) | |
280 { | |
281 HRESULT hr = S_OK; | |
282 | |
283 GdiTextRendererContext *context = | |
284 reinterpret_cast<GdiTextRendererContext*>(clientDrawingContext); | |
285 | |
286 AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth); | |
287 | |
288 // Pass on the drawing call to the render target to do the real work. | |
289 RECT dirtyRect = {0}; | |
290 | |
291 hr = pRenderTarget_->DrawGlyphRun( | |
292 baselineOriginX + context->offsetX, | |
293 baselineOriginY, | |
294 measuringMode, | |
295 &adjustedGlyphRun, | |
296 pRenderingParams_, | |
297 context->color, | |
298 &dirtyRect); | |
299 | |
300 context->offsetX += adjustedGlyphRun.getDelta(); | |
301 | |
302 return hr; | |
303 } | |
304 | |
305 IFACEMETHOD(DrawUnderline)( | |
306 __maybenull void* clientDrawingContext, | |
307 FLOAT baselineOriginX, | |
308 FLOAT baselineOriginY, | |
309 __in DWRITE_UNDERLINE const* underline, | |
310 IUnknown* clientDrawingEffect) | |
311 { | |
312 return E_NOTIMPL; | |
313 } | |
314 | |
315 IFACEMETHOD(DrawStrikethrough)( | |
316 __maybenull void* clientDrawingContext, | |
317 FLOAT baselineOriginX, | |
318 FLOAT baselineOriginY, | |
319 __in DWRITE_STRIKETHROUGH const* strikethrough, | |
320 IUnknown* clientDrawingEffect) | |
321 { | |
322 return E_NOTIMPL; | |
323 } | |
324 | |
325 IFACEMETHOD(DrawInlineObject)( | |
326 __maybenull void* clientDrawingContext, | |
327 FLOAT originX, | |
328 FLOAT originY, | |
329 IDWriteInlineObject* inlineObject, | |
330 BOOL isSideways, | |
331 BOOL isRightToLeft, | |
332 IUnknown* clientDrawingEffect) | |
333 { | |
334 return E_NOTIMPL; | |
335 } | |
336 | |
337 public: | |
338 IFACEMETHOD_(unsigned long, AddRef) () | |
339 { | |
340 return InterlockedIncrement(&cRefCount_); | |
341 } | |
342 | |
343 IFACEMETHOD_(unsigned long, Release) () | |
344 { | |
345 long newCount = InterlockedDecrement(&cRefCount_); | |
346 | |
347 if (newCount == 0) | |
348 { | |
349 delete this; | |
350 return 0; | |
351 } | |
352 return newCount; | |
353 } | |
354 | |
355 IFACEMETHOD(QueryInterface)( | |
356 IID const& riid, | |
357 void** ppvObject) | |
358 { | |
359 if (__uuidof(IDWriteTextRenderer) == riid) | |
360 { | |
361 *ppvObject = this; | |
362 } | |
363 else if (__uuidof(IDWritePixelSnapping) == riid) | |
364 { | |
365 *ppvObject = this; | |
366 } | |
367 else if (__uuidof(IUnknown) == riid) | |
368 { | |
369 *ppvObject = this; | |
370 } | |
371 else | |
372 { | |
373 *ppvObject = NULL; | |
374 return E_FAIL; | |
375 } | |
376 | |
377 return S_OK; | |
378 } | |
379 | |
380 private: | |
6120 | 381 long cRefCount_; |
6110 | 382 IDWriteBitmapRenderTarget* pRenderTarget_; |
383 IDWriteRenderingParams* pRenderingParams_; | |
384 }; | |
385 | |
386 struct DWriteContext { | |
387 FLOAT mDpiScaleX; | |
388 FLOAT mDpiScaleY; | |
389 bool mDrawing; | |
390 | |
391 ID2D1Factory *mD2D1Factory; | |
392 | |
393 ID2D1DCRenderTarget *mRT; | |
394 ID2D1SolidColorBrush *mBrush; | |
395 | |
396 IDWriteFactory *mDWriteFactory; | |
397 IDWriteGdiInterop *mGdiInterop; | |
398 IDWriteRenderingParams *mRenderingParams; | |
399 IDWriteTextFormat *mTextFormat; | |
400 | |
401 HFONT mLastHFont; | |
402 DWRITE_FONT_WEIGHT mFontWeight; | |
403 DWRITE_FONT_STYLE mFontStyle; | |
404 | |
405 D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode; | |
406 | |
407 // METHODS | |
408 | |
409 DWriteContext(); | |
410 | |
411 virtual ~DWriteContext(); | |
412 | |
413 HRESULT SetLOGFONT(const LOGFONTW &logFont, float fontSize); | |
414 | |
415 void SetFont(HFONT hFont); | |
416 | |
417 void SetFont(const LOGFONTW &logFont); | |
418 | |
419 void DrawText(HDC hdc, const WCHAR* text, int len, | |
420 int x, int y, int w, int h, int cellWidth, COLORREF color); | |
421 | |
422 float PixelsToDipsX(int x); | |
423 | |
424 float PixelsToDipsY(int y); | |
425 | |
426 void SetRenderingParams( | |
427 const DWriteRenderingParams *params); | |
428 | |
429 DWriteRenderingParams *GetRenderingParams( | |
430 DWriteRenderingParams *params); | |
431 }; | |
432 | |
433 DWriteContext::DWriteContext() : | |
434 mDpiScaleX(1.f), | |
435 mDpiScaleY(1.f), | |
436 mDrawing(false), | |
437 mD2D1Factory(NULL), | |
438 mRT(NULL), | |
439 mBrush(NULL), | |
440 mDWriteFactory(NULL), | |
441 mGdiInterop(NULL), | |
442 mRenderingParams(NULL), | |
443 mTextFormat(NULL), | |
444 mLastHFont(NULL), | |
445 mFontWeight(DWRITE_FONT_WEIGHT_NORMAL), | |
446 mFontStyle(DWRITE_FONT_STYLE_NORMAL), | |
447 mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT) | |
448 { | |
449 HRESULT hr; | |
450 | |
451 HDC screen = ::GetDC(0); | |
452 mDpiScaleX = ::GetDeviceCaps(screen, LOGPIXELSX) / 96.0f; | |
453 mDpiScaleY = ::GetDeviceCaps(screen, LOGPIXELSY) / 96.0f; | |
454 ::ReleaseDC(0, screen); | |
455 | |
456 hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, | |
457 __uuidof(ID2D1Factory), NULL, | |
458 reinterpret_cast<void**>(&mD2D1Factory)); | |
459 _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory); | |
460 | |
461 if (SUCCEEDED(hr)) | |
462 { | |
463 D2D1_RENDER_TARGET_PROPERTIES props = { | |
464 D2D1_RENDER_TARGET_TYPE_DEFAULT, | |
465 { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE }, | |
466 0, 0, | |
467 D2D1_RENDER_TARGET_USAGE_NONE, | |
468 D2D1_FEATURE_LEVEL_DEFAULT | |
469 }; | |
470 hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT); | |
471 _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT); | |
472 } | |
473 | |
474 if (SUCCEEDED(hr)) | |
475 { | |
476 hr = mRT->CreateSolidColorBrush( | |
477 D2D1::ColorF(D2D1::ColorF::Black), | |
478 &mBrush); | |
479 _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush); | |
480 } | |
481 | |
482 if (SUCCEEDED(hr)) | |
483 { | |
484 hr = DWriteCreateFactory( | |
485 DWRITE_FACTORY_TYPE_SHARED, | |
486 __uuidof(IDWriteFactory), | |
487 reinterpret_cast<IUnknown**>(&mDWriteFactory)); | |
488 _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr, | |
489 mDWriteFactory); | |
490 } | |
491 | |
492 if (SUCCEEDED(hr)) | |
493 { | |
494 hr = mDWriteFactory->GetGdiInterop(&mGdiInterop); | |
495 _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop); | |
496 } | |
497 | |
498 if (SUCCEEDED(hr)) | |
499 { | |
500 hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams); | |
501 _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr, | |
502 mRenderingParams); | |
503 } | |
504 } | |
505 | |
506 DWriteContext::~DWriteContext() | |
507 { | |
508 SafeRelease(&mTextFormat); | |
509 SafeRelease(&mRenderingParams); | |
510 SafeRelease(&mGdiInterop); | |
511 SafeRelease(&mDWriteFactory); | |
512 SafeRelease(&mBrush); | |
513 SafeRelease(&mRT); | |
514 SafeRelease(&mD2D1Factory); | |
515 } | |
516 | |
517 HRESULT | |
518 DWriteContext::SetLOGFONT(const LOGFONTW &logFont, float fontSize) | |
519 { | |
520 // Most of this function is copy from: http://msdn.microsoft.com/en-us/library/windows/desktop/dd941783(v=vs.85).aspx | |
521 HRESULT hr = S_OK; | |
522 | |
523 IDWriteFont *font = NULL; | |
524 IDWriteFontFamily *fontFamily = NULL; | |
525 IDWriteLocalizedStrings *localizedFamilyNames = NULL; | |
526 | |
527 if (SUCCEEDED(hr)) | |
528 { | |
529 hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font); | |
530 } | |
531 | |
532 // Get the font family to which this font belongs. | |
533 if (SUCCEEDED(hr)) | |
534 { | |
535 hr = font->GetFontFamily(&fontFamily); | |
536 } | |
537 | |
538 // Get the family names. This returns an object that encapsulates one or | |
539 // more names with the same meaning but in different languages. | |
540 if (SUCCEEDED(hr)) | |
541 { | |
542 hr = fontFamily->GetFamilyNames(&localizedFamilyNames); | |
543 } | |
544 | |
545 // Get the family name at index zero. If we were going to display the name | |
546 // we'd want to try to find one that matched the use locale, but for | |
547 // purposes of creating a text format object any language will do. | |
548 | |
549 wchar_t familyName[100]; | |
550 if (SUCCEEDED(hr)) | |
551 { | |
552 hr = localizedFamilyNames->GetString(0, familyName, | |
553 ARRAYSIZE(familyName)); | |
554 } | |
555 | |
556 if (SUCCEEDED(hr)) | |
557 { | |
558 // If no font size was passed in use the lfHeight of the LOGFONT. | |
559 if (fontSize == 0) | |
560 { | |
561 // Convert from pixels to DIPs. | |
562 fontSize = PixelsToDipsY(logFont.lfHeight); | |
563 if (fontSize < 0) | |
564 { | |
565 // Negative lfHeight represents the size of the em unit. | |
566 fontSize = -fontSize; | |
567 } | |
568 else | |
569 { | |
570 // Positive lfHeight represents the cell height (ascent + | |
571 // descent). | |
572 DWRITE_FONT_METRICS fontMetrics; | |
573 font->GetMetrics(&fontMetrics); | |
574 | |
575 // Convert the cell height (ascent + descent) from design units | |
576 // to ems. | |
577 float cellHeight = static_cast<float>( | |
578 fontMetrics.ascent + fontMetrics.descent) | |
579 / fontMetrics.designUnitsPerEm; | |
580 | |
581 // Divide the font size by the cell height to get the font em | |
582 // size. | |
583 fontSize /= cellHeight; | |
584 } | |
585 } | |
586 } | |
587 | |
588 // The text format includes a locale name. Ideally, this would be the | |
589 // language of the text, which may or may not be the same as the primary | |
590 // language of the user. However, for our purposes the user locale will do. | |
591 wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; | |
592 if (SUCCEEDED(hr)) | |
593 { | |
594 if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0) | |
595 hr = HRESULT_FROM_WIN32(GetLastError()); | |
596 } | |
597 | |
598 if (SUCCEEDED(hr)) | |
599 { | |
600 // Create the text format object. | |
601 hr = mDWriteFactory->CreateTextFormat( | |
602 familyName, | |
603 NULL, // no custom font collection | |
604 font->GetWeight(), | |
605 font->GetStyle(), | |
606 font->GetStretch(), | |
607 fontSize, | |
608 localeName, | |
609 &mTextFormat); | |
610 } | |
611 | |
612 if (SUCCEEDED(hr)) | |
613 { | |
614 mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight); | |
615 mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC | |
616 : DWRITE_FONT_STYLE_NORMAL; | |
617 } | |
618 | |
619 SafeRelease(&localizedFamilyNames); | |
620 SafeRelease(&fontFamily); | |
621 SafeRelease(&font); | |
622 | |
623 return hr; | |
624 } | |
625 | |
626 void | |
627 DWriteContext::SetFont(HFONT hFont) | |
628 { | |
629 if (mLastHFont != hFont) | |
630 { | |
631 LOGFONTW lf; | |
632 if (GetObjectW(hFont, sizeof(lf), &lf)) | |
633 { | |
634 SetFont(lf); | |
635 mLastHFont = hFont; | |
636 } | |
637 } | |
638 } | |
639 | |
640 void | |
641 DWriteContext::SetFont(const LOGFONTW &logFont) | |
642 { | |
643 SafeRelease(&mTextFormat); | |
644 mLastHFont = NULL; | |
645 | |
646 HRESULT hr = SetLOGFONT(logFont, 0.f); | |
647 | |
648 if (SUCCEEDED(hr)) | |
649 hr = mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); | |
650 | |
651 if (SUCCEEDED(hr)) | |
652 hr = mTextFormat->SetParagraphAlignment( | |
653 DWRITE_PARAGRAPH_ALIGNMENT_CENTER); | |
654 | |
655 if (SUCCEEDED(hr)) | |
656 hr = mTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); | |
657 } | |
658 | |
659 void | |
660 DWriteContext::DrawText(HDC hdc, const WCHAR* text, int len, | |
661 int x, int y, int w, int h, int cellWidth, COLORREF color) | |
662 { | |
663 HRESULT hr = S_OK; | |
664 IDWriteBitmapRenderTarget *bmpRT = NULL; | |
665 | |
666 // Skip when any fonts are not set. | |
667 if (mTextFormat == NULL) | |
668 return; | |
669 | |
670 // Check possibility of zero divided error. | |
671 if (cellWidth == 0 || mDpiScaleX == 0.0f || mDpiScaleY == 0.0f) | |
672 return; | |
673 | |
674 if (SUCCEEDED(hr)) | |
675 hr = mGdiInterop->CreateBitmapRenderTarget(hdc, w, h, &bmpRT); | |
676 | |
677 if (SUCCEEDED(hr)) | |
678 { | |
679 IDWriteTextLayout *textLayout = NULL; | |
680 | |
681 HDC memdc = bmpRT->GetMemoryDC(); | |
682 BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY); | |
683 | |
684 hr = mDWriteFactory->CreateGdiCompatibleTextLayout( | |
685 text, len, mTextFormat, PixelsToDipsX(w), | |
686 PixelsToDipsY(h), mDpiScaleX, NULL, TRUE, &textLayout); | |
687 | |
688 if (SUCCEEDED(hr)) | |
689 { | |
7547
567e027a3ea1
commit https://github.com/vim/vim/commit/5fa4d448fb717874b6619bcda62e42190702997c
Christian Brabandt <cb@256bit.org>
parents:
6120
diff
changeset
|
690 DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len }; |
6110 | 691 textLayout->SetFontWeight(mFontWeight, textRange); |
692 textLayout->SetFontStyle(mFontStyle, textRange); | |
693 } | |
694 | |
695 if (SUCCEEDED(hr)) | |
696 { | |
697 GdiTextRenderer *renderer = new GdiTextRenderer(bmpRT, | |
698 mRenderingParams); | |
699 GdiTextRendererContext data = { | |
700 color, | |
701 PixelsToDipsX(cellWidth), | |
702 0.0f | |
703 }; | |
704 textLayout->Draw(&data, renderer, 0, 0); | |
705 SafeRelease(&renderer); | |
706 } | |
707 | |
708 BitBlt(hdc, x, y, w, h, memdc, 0, 0, SRCCOPY); | |
709 | |
710 SafeRelease(&textLayout); | |
711 } | |
712 | |
713 SafeRelease(&bmpRT); | |
714 } | |
715 | |
716 float | |
717 DWriteContext::PixelsToDipsX(int x) | |
718 { | |
719 return x / mDpiScaleX; | |
720 } | |
721 | |
722 float | |
723 DWriteContext::PixelsToDipsY(int y) | |
724 { | |
725 return y / mDpiScaleY; | |
726 } | |
727 | |
728 void | |
729 DWriteContext::SetRenderingParams( | |
730 const DWriteRenderingParams *params) | |
731 { | |
732 if (mDWriteFactory == NULL) | |
733 return; | |
734 | |
735 IDWriteRenderingParams *renderingParams = NULL; | |
736 D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode = | |
737 D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; | |
738 HRESULT hr; | |
739 if (params != NULL) | |
740 { | |
741 hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma, | |
742 params->enhancedContrast, params->clearTypeLevel, | |
743 ToPixelGeometry(params->pixelGeometry), | |
744 ToRenderingMode(params->renderingMode), &renderingParams); | |
745 textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode); | |
746 } | |
747 else | |
748 hr = mDWriteFactory->CreateRenderingParams(&renderingParams); | |
749 if (SUCCEEDED(hr) && renderingParams != NULL) | |
750 { | |
751 SafeRelease(&mRenderingParams); | |
752 mRenderingParams = renderingParams; | |
753 mTextAntialiasMode = textAntialiasMode; | |
754 } | |
755 } | |
756 | |
757 DWriteRenderingParams * | |
758 DWriteContext::GetRenderingParams( | |
759 DWriteRenderingParams *params) | |
760 { | |
761 if (params != NULL && mRenderingParams != NULL) | |
762 { | |
763 params->gamma = mRenderingParams->GetGamma(); | |
764 params->enhancedContrast = mRenderingParams->GetEnhancedContrast(); | |
765 params->clearTypeLevel = mRenderingParams->GetClearTypeLevel(); | |
766 params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry()); | |
767 params->renderingMode = ToInt(mRenderingParams->GetRenderingMode()); | |
768 params->textAntialiasMode = mTextAntialiasMode; | |
769 } | |
770 return params; | |
771 } | |
772 | |
773 //////////////////////////////////////////////////////////////////////////// | |
774 // PUBLIC C INTERFACES | |
775 | |
776 void | |
777 DWrite_Init(void) | |
778 { | |
779 #ifdef DYNAMIC_DIRECTX | |
780 // Load libraries. | |
781 hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll")); | |
782 hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll")); | |
783 if (hD2D1DLL == NULL || hDWriteDLL == NULL) | |
784 { | |
785 DWrite_Final(); | |
786 return; | |
787 } | |
788 // Get address of procedures. | |
789 pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress( | |
790 GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName"); | |
791 pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL, | |
792 "D2D1CreateFactory"); | |
793 pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL, | |
794 "DWriteCreateFactory"); | |
795 #endif | |
796 } | |
797 | |
798 void | |
799 DWrite_Final(void) | |
800 { | |
801 #ifdef DYNAMIC_DIRECTX | |
802 pGetUserDefaultLocaleName = NULL; | |
803 pD2D1CreateFactory = NULL; | |
804 pDWriteCreateFactory = NULL; | |
805 unload(hDWriteDLL); | |
806 unload(hD2D1DLL); | |
807 #endif | |
808 } | |
809 | |
810 DWriteContext * | |
811 DWriteContext_Open(void) | |
812 { | |
813 #ifdef DYNAMIC_DIRECTX | |
814 if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL | |
815 || pDWriteCreateFactory == NULL) | |
816 return NULL; | |
817 #endif | |
818 return new DWriteContext(); | |
819 } | |
820 | |
821 void | |
822 DWriteContext_BeginDraw(DWriteContext *ctx) | |
823 { | |
824 if (ctx != NULL && ctx->mRT != NULL) | |
825 { | |
826 ctx->mRT->BeginDraw(); | |
827 ctx->mRT->SetTransform(D2D1::IdentityMatrix()); | |
828 ctx->mDrawing = true; | |
829 } | |
830 } | |
831 | |
832 void | |
833 DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, RECT *rect) | |
834 { | |
835 if (ctx != NULL && ctx->mRT != NULL) | |
836 { | |
837 ctx->mRT->BindDC(hdc, rect); | |
838 ctx->mRT->SetTextAntialiasMode(ctx->mTextAntialiasMode); | |
839 } | |
840 } | |
841 | |
842 void | |
843 DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont) | |
844 { | |
845 if (ctx != NULL) | |
846 { | |
847 ctx->SetFont(hFont); | |
848 } | |
849 } | |
850 | |
851 void | |
852 DWriteContext_DrawText( | |
853 DWriteContext *ctx, | |
854 HDC hdc, | |
855 const WCHAR* text, | |
856 int len, | |
857 int x, | |
858 int y, | |
859 int w, | |
860 int h, | |
861 int cellWidth, | |
862 COLORREF color) | |
863 { | |
864 if (ctx != NULL) | |
865 ctx->DrawText(hdc, text, len, x, y, w, h, cellWidth, color); | |
866 } | |
867 | |
868 void | |
869 DWriteContext_EndDraw(DWriteContext *ctx) | |
870 { | |
871 if (ctx != NULL && ctx->mRT != NULL) | |
872 { | |
873 ctx->mRT->EndDraw(); | |
874 ctx->mDrawing = false; | |
875 } | |
876 } | |
877 | |
878 void | |
879 DWriteContext_Close(DWriteContext *ctx) | |
880 { | |
881 delete ctx; | |
882 } | |
883 | |
884 void | |
885 DWriteContext_SetRenderingParams( | |
886 DWriteContext *ctx, | |
887 const DWriteRenderingParams *params) | |
888 { | |
889 if (ctx != NULL) | |
890 ctx->SetRenderingParams(params); | |
891 } | |
892 | |
893 DWriteRenderingParams * | |
894 DWriteContext_GetRenderingParams( | |
895 DWriteContext *ctx, | |
896 DWriteRenderingParams *params) | |
897 { | |
898 if (ctx != NULL) | |
899 return ctx->GetRenderingParams(params); | |
900 else | |
901 return NULL; | |
902 } |