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