Mercurial > vim
annotate src/gui_dwrite.cpp @ 12834:5b61a133b547
Added tag v8.0.1293 for changeset db9ffed7e1fc09ee0266beda34a94def6a8c6c06
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 12 Nov 2017 18:15:05 +0100 |
parents | 0af716a4f5d2 |
children | 2ebc3df65ca2 |
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 | |
8641
0af716a4f5d2
commit https://github.com/vim/vim/commit/cc6cf9b9f9045a7d8b5923ea0c556e9a4c2567d3
Christian Brabandt <cb@256bit.org>
parents:
8271
diff
changeset
|
36 #if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L) |
0af716a4f5d2
commit https://github.com/vim/vim/commit/cc6cf9b9f9045a7d8b5923ea0c556e9a4c2567d3
Christian Brabandt <cb@256bit.org>
parents:
8271
diff
changeset
|
37 # define FINAL final |
0af716a4f5d2
commit https://github.com/vim/vim/commit/cc6cf9b9f9045a7d8b5923ea0c556e9a4c2567d3
Christian Brabandt <cb@256bit.org>
parents:
8271
diff
changeset
|
38 #else |
0af716a4f5d2
commit https://github.com/vim/vim/commit/cc6cf9b9f9045a7d8b5923ea0c556e9a4c2567d3
Christian Brabandt <cb@256bit.org>
parents:
8271
diff
changeset
|
39 # define FINAL |
0af716a4f5d2
commit https://github.com/vim/vim/commit/cc6cf9b9f9045a7d8b5923ea0c556e9a4c2567d3
Christian Brabandt <cb@256bit.org>
parents:
8271
diff
changeset
|
40 #endif |
0af716a4f5d2
commit https://github.com/vim/vim/commit/cc6cf9b9f9045a7d8b5923ea0c556e9a4c2567d3
Christian Brabandt <cb@256bit.org>
parents:
8271
diff
changeset
|
41 |
6110 | 42 #ifdef DYNAMIC_DIRECTX |
43 extern "C" HINSTANCE vimLoadLib(char *name); | |
44 | |
45 typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int); | |
46 typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE, | |
47 REFIID, const D2D1_FACTORY_OPTIONS *, void **); | |
48 typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE, | |
49 REFIID, IUnknown **); | |
50 | |
51 static HINSTANCE hD2D1DLL = NULL; | |
52 static HINSTANCE hDWriteDLL = NULL; | |
53 | |
54 static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL; | |
55 static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL; | |
56 static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL; | |
57 | |
58 #define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName) | |
59 #define D2D1CreateFactory (*pD2D1CreateFactory) | |
60 #define DWriteCreateFactory (*pDWriteCreateFactory) | |
61 | |
62 static void | |
63 unload(HINSTANCE &hinst) | |
64 { | |
65 if (hinst != NULL) | |
66 { | |
67 FreeLibrary(hinst); | |
68 hinst = NULL; | |
69 } | |
70 } | |
71 #endif // DYNAMIC_DIRECTX | |
72 | |
73 template <class T> inline void SafeRelease(T **ppT) | |
74 { | |
75 if (*ppT) | |
76 { | |
77 (*ppT)->Release(); | |
78 *ppT = NULL; | |
79 } | |
80 } | |
81 | |
82 struct 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 | |
93 ToPixelGeometry(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 | |
108 ToInt(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 | |
124 ToRenderingMode(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 | |
147 ToTextAntialiasMode(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 | |
164 ToInt(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 | |
187 class AdjustedGlyphRun : public DWRITE_GLYPH_RUN | |
188 { | |
189 private: | |
190 FLOAT mDelta; | |
191 FLOAT *mAdjustedAdvances; | |
192 | |
193 public: | |
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 | |
8641
0af716a4f5d2
commit https://github.com/vim/vim/commit/cc6cf9b9f9045a7d8b5923ea0c556e9a4c2567d3
Christian Brabandt <cb@256bit.org>
parents:
8271
diff
changeset
|
231 class GdiTextRenderer FINAL : public IDWriteTextRenderer |
6110 | 232 { |
233 public: | |
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 | |
8271
770774e66011
commit https://github.com/vim/vim/commit/edb4f2b3601b0abd47091606269c0ac3244a805b
Christian Brabandt <cb@256bit.org>
parents:
7547
diff
changeset
|
246 // 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
|
247 virtual ~GdiTextRenderer() |
6110 | 248 { |
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 { | |
8271
770774e66011
commit https://github.com/vim/vim/commit/edb4f2b3601b0abd47091606269c0ac3244a805b
Christian Brabandt <cb@256bit.org>
parents:
7547
diff
changeset
|
265 // forward the render target's transform |
6110 | 266 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 | |
343 public: | |
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 | |
386 private: | |
6120 | 387 long cRefCount_; |
6110 | 388 IDWriteBitmapRenderTarget* pRenderTarget_; |
389 IDWriteRenderingParams* pRenderingParams_; | |
390 }; | |
391 | |
392 struct 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 | |
439 DWriteContext::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 | |
512 DWriteContext::~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 | |
524 DWriteContext::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 | |
633 DWriteContext::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 | |
647 DWriteContext::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 | |
666 DWriteContext::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 { | |
7547
567e027a3ea1
commit https://github.com/vim/vim/commit/5fa4d448fb717874b6619bcda62e42190702997c
Christian Brabandt <cb@256bit.org>
parents:
6120
diff
changeset
|
696 DWRITE_TEXT_RANGE textRange = { 0, (UINT32)len }; |
6110 | 697 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 | |
723 DWriteContext::PixelsToDipsX(int x) | |
724 { | |
725 return x / mDpiScaleX; | |
726 } | |
727 | |
728 float | |
729 DWriteContext::PixelsToDipsY(int y) | |
730 { | |
731 return y / mDpiScaleY; | |
732 } | |
733 | |
734 void | |
735 DWriteContext::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 * | |
764 DWriteContext::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 | |
783 DWrite_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 | |
805 DWrite_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 * | |
817 DWriteContext_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 | |
828 DWriteContext_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 | |
839 DWriteContext_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 | |
849 DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont) | |
850 { | |
851 if (ctx != NULL) | |
852 { | |
853 ctx->SetFont(hFont); | |
854 } | |
855 } | |
856 | |
857 void | |
858 DWriteContext_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 | |
875 DWriteContext_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 | |
885 DWriteContext_Close(DWriteContext *ctx) | |
886 { | |
887 delete ctx; | |
888 } | |
889 | |
890 void | |
891 DWriteContext_SetRenderingParams( | |
892 DWriteContext *ctx, | |
893 const DWriteRenderingParams *params) | |
894 { | |
895 if (ctx != NULL) | |
896 ctx->SetRenderingParams(params); | |
897 } | |
898 | |
899 DWriteRenderingParams * | |
900 DWriteContext_GetRenderingParams( | |
901 DWriteContext *ctx, | |
902 DWriteRenderingParams *params) | |
903 { | |
904 if (ctx != NULL) | |
905 return ctx->GetRenderingParams(params); | |
906 else | |
907 return NULL; | |
908 } |