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