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 7d7ccc4d8SBram Moolenaar * - Yasuhiro Matsumoto 8b5a7a8b5SBram Moolenaar * 9b5a7a8b5SBram Moolenaar * Copyright (C) 2013 MURAOKA Taro <[email protected]> 10b5a7a8b5SBram Moolenaar * THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. 11b5a7a8b5SBram Moolenaar */ 12b5a7a8b5SBram Moolenaar 13b5a7a8b5SBram Moolenaar #define WIN32_LEAN_AND_MEAN 14b5a7a8b5SBram Moolenaar 15b5a7a8b5SBram Moolenaar #ifndef DYNAMIC_DIRECTX 16b5a7a8b5SBram Moolenaar # if WINVER < 0x0600 17b5a7a8b5SBram Moolenaar # error WINVER must be 0x0600 or above to use DirectWrite(DirectX) 18b5a7a8b5SBram Moolenaar # endif 19b5a7a8b5SBram Moolenaar #endif 20b5a7a8b5SBram Moolenaar 21b5a7a8b5SBram Moolenaar #include <windows.h> 22b5a7a8b5SBram Moolenaar #include <crtdbg.h> 23b5a7a8b5SBram Moolenaar #include <assert.h> 24b5a7a8b5SBram Moolenaar #include <math.h> 25b5a7a8b5SBram Moolenaar #include <d2d1.h> 26b5a7a8b5SBram Moolenaar #include <d2d1helper.h> 27d7ccc4d8SBram Moolenaar 28d7ccc4d8SBram Moolenaar // Disable these macros to compile with old VC and newer SDK (V8.1 or later). 29d7ccc4d8SBram Moolenaar #if defined(_MSC_VER) && (_MSC_VER < 1700) 30d7ccc4d8SBram Moolenaar # define _COM_Outptr_ __out 31d7ccc4d8SBram Moolenaar # define _In_reads_(s) 32d7ccc4d8SBram Moolenaar # define _In_reads_opt_(s) 33d7ccc4d8SBram Moolenaar # define _Maybenull_ 34d7ccc4d8SBram Moolenaar # define _Out_writes_(s) 35d7ccc4d8SBram Moolenaar # define _Out_writes_opt_(s) 36d7ccc4d8SBram Moolenaar # define _Out_writes_to_(x, y) 37d7ccc4d8SBram Moolenaar # define _Out_writes_to_opt_(x, y) 38d7ccc4d8SBram Moolenaar # define _Outptr_ 39d7ccc4d8SBram Moolenaar #endif 40d7ccc4d8SBram Moolenaar 41d7ccc4d8SBram Moolenaar #include <dwrite_2.h> 42b5a7a8b5SBram Moolenaar 43b5a7a8b5SBram Moolenaar #include "gui_dwrite.h" 44b5a7a8b5SBram Moolenaar 45b5a7a8b5SBram Moolenaar #ifdef __MINGW32__ 46b5a7a8b5SBram Moolenaar # define __maybenull SAL__maybenull 47b5a7a8b5SBram Moolenaar # define __in SAL__in 48b5a7a8b5SBram Moolenaar # define __out SAL__out 49b5a7a8b5SBram Moolenaar #endif 50b5a7a8b5SBram Moolenaar 51cc6cf9b9SBram Moolenaar #if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L) 52cc6cf9b9SBram Moolenaar # define FINAL final 53cc6cf9b9SBram Moolenaar #else 54cc6cf9b9SBram Moolenaar # define FINAL 55cc6cf9b9SBram Moolenaar #endif 56cc6cf9b9SBram Moolenaar 57b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX 58b5a7a8b5SBram Moolenaar extern "C" HINSTANCE vimLoadLib(char *name); 59b5a7a8b5SBram Moolenaar 60b5a7a8b5SBram Moolenaar typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int); 61b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE, 62b5a7a8b5SBram Moolenaar REFIID, const D2D1_FACTORY_OPTIONS *, void **); 63b5a7a8b5SBram Moolenaar typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE, 64b5a7a8b5SBram Moolenaar REFIID, IUnknown **); 65b5a7a8b5SBram Moolenaar 66b5a7a8b5SBram Moolenaar static HINSTANCE hD2D1DLL = NULL; 67b5a7a8b5SBram Moolenaar static HINSTANCE hDWriteDLL = NULL; 68b5a7a8b5SBram Moolenaar 69b5a7a8b5SBram Moolenaar static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL; 70b5a7a8b5SBram Moolenaar static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL; 71b5a7a8b5SBram Moolenaar static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL; 72b5a7a8b5SBram Moolenaar 73b5a7a8b5SBram Moolenaar #define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName) 74b5a7a8b5SBram Moolenaar #define D2D1CreateFactory (*pD2D1CreateFactory) 75b5a7a8b5SBram Moolenaar #define DWriteCreateFactory (*pDWriteCreateFactory) 76b5a7a8b5SBram Moolenaar 77b5a7a8b5SBram Moolenaar static void 78b5a7a8b5SBram Moolenaar unload(HINSTANCE &hinst) 79b5a7a8b5SBram Moolenaar { 80b5a7a8b5SBram Moolenaar if (hinst != NULL) 81b5a7a8b5SBram Moolenaar { 82b5a7a8b5SBram Moolenaar FreeLibrary(hinst); 83b5a7a8b5SBram Moolenaar hinst = NULL; 84b5a7a8b5SBram Moolenaar } 85b5a7a8b5SBram Moolenaar } 86b5a7a8b5SBram Moolenaar #endif // DYNAMIC_DIRECTX 87b5a7a8b5SBram Moolenaar 88b5a7a8b5SBram Moolenaar template <class T> inline void SafeRelease(T **ppT) 89b5a7a8b5SBram Moolenaar { 90b5a7a8b5SBram Moolenaar if (*ppT) 91b5a7a8b5SBram Moolenaar { 92b5a7a8b5SBram Moolenaar (*ppT)->Release(); 93b5a7a8b5SBram Moolenaar *ppT = NULL; 94b5a7a8b5SBram Moolenaar } 95b5a7a8b5SBram Moolenaar } 96b5a7a8b5SBram Moolenaar 97b5a7a8b5SBram Moolenaar static DWRITE_PIXEL_GEOMETRY 98b5a7a8b5SBram Moolenaar ToPixelGeometry(int value) 99b5a7a8b5SBram Moolenaar { 100b5a7a8b5SBram Moolenaar switch (value) 101b5a7a8b5SBram Moolenaar { 102b5a7a8b5SBram Moolenaar default: 103b5a7a8b5SBram Moolenaar case 0: 104b5a7a8b5SBram Moolenaar return DWRITE_PIXEL_GEOMETRY_FLAT; 105b5a7a8b5SBram Moolenaar case 1: 106b5a7a8b5SBram Moolenaar return DWRITE_PIXEL_GEOMETRY_RGB; 107b5a7a8b5SBram Moolenaar case 2: 108b5a7a8b5SBram Moolenaar return DWRITE_PIXEL_GEOMETRY_BGR; 109b5a7a8b5SBram Moolenaar } 110b5a7a8b5SBram Moolenaar } 111b5a7a8b5SBram Moolenaar 112b5a7a8b5SBram Moolenaar static int 113b5a7a8b5SBram Moolenaar ToInt(DWRITE_PIXEL_GEOMETRY value) 114b5a7a8b5SBram Moolenaar { 115b5a7a8b5SBram Moolenaar switch (value) 116b5a7a8b5SBram Moolenaar { 117b5a7a8b5SBram Moolenaar case DWRITE_PIXEL_GEOMETRY_FLAT: 118b5a7a8b5SBram Moolenaar return 0; 119b5a7a8b5SBram Moolenaar case DWRITE_PIXEL_GEOMETRY_RGB: 120b5a7a8b5SBram Moolenaar return 1; 121b5a7a8b5SBram Moolenaar case DWRITE_PIXEL_GEOMETRY_BGR: 122b5a7a8b5SBram Moolenaar return 2; 123b5a7a8b5SBram Moolenaar default: 124b5a7a8b5SBram Moolenaar return -1; 125b5a7a8b5SBram Moolenaar } 126b5a7a8b5SBram Moolenaar } 127b5a7a8b5SBram Moolenaar 128b5a7a8b5SBram Moolenaar static DWRITE_RENDERING_MODE 129b5a7a8b5SBram Moolenaar ToRenderingMode(int value) 130b5a7a8b5SBram Moolenaar { 131b5a7a8b5SBram Moolenaar switch (value) 132b5a7a8b5SBram Moolenaar { 133b5a7a8b5SBram Moolenaar default: 134b5a7a8b5SBram Moolenaar case 0: 135b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_DEFAULT; 136b5a7a8b5SBram Moolenaar case 1: 137b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_ALIASED; 138b5a7a8b5SBram Moolenaar case 2: 139b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; 140b5a7a8b5SBram Moolenaar case 3: 141b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL; 142b5a7a8b5SBram Moolenaar case 4: 143b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; 144b5a7a8b5SBram Moolenaar case 5: 145b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; 146b5a7a8b5SBram Moolenaar case 6: 147b5a7a8b5SBram Moolenaar return DWRITE_RENDERING_MODE_OUTLINE; 148b5a7a8b5SBram Moolenaar } 149b5a7a8b5SBram Moolenaar } 150b5a7a8b5SBram Moolenaar 151b5a7a8b5SBram Moolenaar static D2D1_TEXT_ANTIALIAS_MODE 152b5a7a8b5SBram Moolenaar ToTextAntialiasMode(int value) 153b5a7a8b5SBram Moolenaar { 154b5a7a8b5SBram Moolenaar switch (value) 155b5a7a8b5SBram Moolenaar { 156b5a7a8b5SBram Moolenaar default: 157b5a7a8b5SBram Moolenaar case 0: 158b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; 159b5a7a8b5SBram Moolenaar case 1: 160b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; 161b5a7a8b5SBram Moolenaar case 2: 162b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; 163b5a7a8b5SBram Moolenaar case 3: 164b5a7a8b5SBram Moolenaar return D2D1_TEXT_ANTIALIAS_MODE_ALIASED; 165b5a7a8b5SBram Moolenaar } 166b5a7a8b5SBram Moolenaar } 167b5a7a8b5SBram Moolenaar 168b5a7a8b5SBram Moolenaar static int 169b5a7a8b5SBram Moolenaar ToInt(DWRITE_RENDERING_MODE value) 170b5a7a8b5SBram Moolenaar { 171b5a7a8b5SBram Moolenaar switch (value) 172b5a7a8b5SBram Moolenaar { 173b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_DEFAULT: 174b5a7a8b5SBram Moolenaar return 0; 175b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_ALIASED: 176b5a7a8b5SBram Moolenaar return 1; 177b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC: 178b5a7a8b5SBram Moolenaar return 2; 179b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL: 180b5a7a8b5SBram Moolenaar return 3; 181b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL: 182b5a7a8b5SBram Moolenaar return 4; 183b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC: 184b5a7a8b5SBram Moolenaar return 5; 185b5a7a8b5SBram Moolenaar case DWRITE_RENDERING_MODE_OUTLINE: 186b5a7a8b5SBram Moolenaar return 6; 187b5a7a8b5SBram Moolenaar default: 188b5a7a8b5SBram Moolenaar return -1; 189b5a7a8b5SBram Moolenaar } 190b5a7a8b5SBram Moolenaar } 191b5a7a8b5SBram Moolenaar 192d7ccc4d8SBram Moolenaar class FontCache { 193d7ccc4d8SBram Moolenaar public: 194d7ccc4d8SBram Moolenaar struct Item { 195d7ccc4d8SBram Moolenaar HFONT hFont; 196d7ccc4d8SBram Moolenaar IDWriteTextFormat* pTextFormat; 197d7ccc4d8SBram Moolenaar DWRITE_FONT_WEIGHT fontWeight; 198d7ccc4d8SBram Moolenaar DWRITE_FONT_STYLE fontStyle; 199d7ccc4d8SBram Moolenaar Item() : hFont(NULL), pTextFormat(NULL) {} 200d7ccc4d8SBram Moolenaar }; 201d7ccc4d8SBram Moolenaar 202d7ccc4d8SBram Moolenaar private: 203d7ccc4d8SBram Moolenaar int mSize; 204d7ccc4d8SBram Moolenaar Item *mItems; 205d7ccc4d8SBram Moolenaar 206d7ccc4d8SBram Moolenaar public: 207d7ccc4d8SBram Moolenaar FontCache(int size = 2) : 208d7ccc4d8SBram Moolenaar mSize(size), 209d7ccc4d8SBram Moolenaar mItems(new Item[size]) 210d7ccc4d8SBram Moolenaar { 211d7ccc4d8SBram Moolenaar } 212d7ccc4d8SBram Moolenaar 213d7ccc4d8SBram Moolenaar ~FontCache() 214d7ccc4d8SBram Moolenaar { 215d7ccc4d8SBram Moolenaar for (int i = 0; i < mSize; ++i) 216d7ccc4d8SBram Moolenaar SafeRelease(&mItems[i].pTextFormat); 217d7ccc4d8SBram Moolenaar delete[] mItems; 218d7ccc4d8SBram Moolenaar } 219d7ccc4d8SBram Moolenaar 220d7ccc4d8SBram Moolenaar bool get(HFONT hFont, Item &item) 221d7ccc4d8SBram Moolenaar { 222d7ccc4d8SBram Moolenaar int n = find(hFont); 223d7ccc4d8SBram Moolenaar if (n < 0) 224d7ccc4d8SBram Moolenaar return false; 225d7ccc4d8SBram Moolenaar item = mItems[n]; 226d7ccc4d8SBram Moolenaar slide(n); 227d7ccc4d8SBram Moolenaar return true; 228d7ccc4d8SBram Moolenaar } 229d7ccc4d8SBram Moolenaar 230d7ccc4d8SBram Moolenaar void put(const Item& item) 231d7ccc4d8SBram Moolenaar { 232d7ccc4d8SBram Moolenaar int n = find(item.hFont); 233d7ccc4d8SBram Moolenaar if (n < 0) 234d7ccc4d8SBram Moolenaar n = mSize - 1; 235d7ccc4d8SBram Moolenaar if (mItems[n].pTextFormat != item.pTextFormat) 236d7ccc4d8SBram Moolenaar { 237d7ccc4d8SBram Moolenaar SafeRelease(&mItems[n].pTextFormat); 238d7ccc4d8SBram Moolenaar item.pTextFormat->AddRef(); 239d7ccc4d8SBram Moolenaar } 240d7ccc4d8SBram Moolenaar mItems[n] = item; 241d7ccc4d8SBram Moolenaar slide(n); 242d7ccc4d8SBram Moolenaar } 243d7ccc4d8SBram Moolenaar 244d7ccc4d8SBram Moolenaar private: 245d7ccc4d8SBram Moolenaar int find(HFONT hFont) 246d7ccc4d8SBram Moolenaar { 247d7ccc4d8SBram Moolenaar for (int i = 0; i < mSize; ++i) 248d7ccc4d8SBram Moolenaar { 249d7ccc4d8SBram Moolenaar if (mItems[i].hFont == hFont) 250d7ccc4d8SBram Moolenaar return i; 251d7ccc4d8SBram Moolenaar } 252d7ccc4d8SBram Moolenaar return -1; 253d7ccc4d8SBram Moolenaar } 254d7ccc4d8SBram Moolenaar 255d7ccc4d8SBram Moolenaar void slide(int nextTop) 256d7ccc4d8SBram Moolenaar { 257d7ccc4d8SBram Moolenaar if (nextTop == 0) 258d7ccc4d8SBram Moolenaar return; 259d7ccc4d8SBram Moolenaar Item tmp = mItems[nextTop]; 260d7ccc4d8SBram Moolenaar for (int i = nextTop - 1; i >= 0; --i) 261d7ccc4d8SBram Moolenaar mItems[i + 1] = mItems[i]; 262d7ccc4d8SBram Moolenaar mItems[0] = tmp; 263d7ccc4d8SBram Moolenaar } 264d7ccc4d8SBram Moolenaar }; 265d7ccc4d8SBram Moolenaar 266*92467d33SBram Moolenaar enum DrawingMode { 267*92467d33SBram Moolenaar DM_GDI = 0, 268*92467d33SBram Moolenaar DM_DIRECTX = 1, 269*92467d33SBram Moolenaar DM_INTEROP = 2, 270*92467d33SBram Moolenaar }; 271*92467d33SBram Moolenaar 272d7ccc4d8SBram Moolenaar struct DWriteContext { 273d7ccc4d8SBram Moolenaar HDC mHDC; 274*92467d33SBram Moolenaar RECT mBindRect; 275*92467d33SBram Moolenaar DrawingMode mDMode; 276*92467d33SBram Moolenaar HDC mInteropHDC; 277d7ccc4d8SBram Moolenaar bool mDrawing; 278d7ccc4d8SBram Moolenaar bool mFallbackDC; 279d7ccc4d8SBram Moolenaar 280d7ccc4d8SBram Moolenaar ID2D1Factory *mD2D1Factory; 281d7ccc4d8SBram Moolenaar 282d7ccc4d8SBram Moolenaar ID2D1DCRenderTarget *mRT; 283*92467d33SBram Moolenaar ID2D1GdiInteropRenderTarget *mGDIRT; 284d7ccc4d8SBram Moolenaar ID2D1SolidColorBrush *mBrush; 285d7ccc4d8SBram Moolenaar 286d7ccc4d8SBram Moolenaar IDWriteFactory *mDWriteFactory; 287d7ccc4d8SBram Moolenaar IDWriteFactory2 *mDWriteFactory2; 288d7ccc4d8SBram Moolenaar 289d7ccc4d8SBram Moolenaar IDWriteGdiInterop *mGdiInterop; 290d7ccc4d8SBram Moolenaar IDWriteRenderingParams *mRenderingParams; 291d7ccc4d8SBram Moolenaar 292d7ccc4d8SBram Moolenaar FontCache mFontCache; 293d7ccc4d8SBram Moolenaar IDWriteTextFormat *mTextFormat; 294d7ccc4d8SBram Moolenaar DWRITE_FONT_WEIGHT mFontWeight; 295d7ccc4d8SBram Moolenaar DWRITE_FONT_STYLE mFontStyle; 296d7ccc4d8SBram Moolenaar 297d7ccc4d8SBram Moolenaar D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode; 298d7ccc4d8SBram Moolenaar 299d7ccc4d8SBram Moolenaar // METHODS 300d7ccc4d8SBram Moolenaar 301d7ccc4d8SBram Moolenaar DWriteContext(); 302d7ccc4d8SBram Moolenaar 303d7ccc4d8SBram Moolenaar virtual ~DWriteContext(); 304d7ccc4d8SBram Moolenaar 305*92467d33SBram Moolenaar HRESULT CreateDeviceResources(); 306*92467d33SBram Moolenaar 307*92467d33SBram Moolenaar void DiscardDeviceResources(); 308*92467d33SBram Moolenaar 309d7ccc4d8SBram Moolenaar HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont, 310d7ccc4d8SBram Moolenaar IDWriteTextFormat **ppTextFormat); 311d7ccc4d8SBram Moolenaar 312d7ccc4d8SBram Moolenaar HRESULT SetFontByLOGFONT(const LOGFONTW &logFont); 313d7ccc4d8SBram Moolenaar 314d7ccc4d8SBram Moolenaar void SetFont(HFONT hFont); 315d7ccc4d8SBram Moolenaar 316*92467d33SBram Moolenaar void BindDC(HDC hdc, const RECT *rect); 317d7ccc4d8SBram Moolenaar 318*92467d33SBram Moolenaar HRESULT SetDrawingMode(DrawingMode mode); 319d7ccc4d8SBram Moolenaar 320d7ccc4d8SBram Moolenaar ID2D1Brush* SolidBrush(COLORREF color); 321d7ccc4d8SBram Moolenaar 322d7ccc4d8SBram Moolenaar void DrawText(const WCHAR *text, int len, 323d7ccc4d8SBram Moolenaar int x, int y, int w, int h, int cellWidth, COLORREF color, 324*92467d33SBram Moolenaar UINT fuOptions, const RECT *lprc, const INT *lpDx); 325d7ccc4d8SBram Moolenaar 326*92467d33SBram Moolenaar void FillRect(const RECT *rc, COLORREF color); 327*92467d33SBram Moolenaar 328*92467d33SBram Moolenaar void DrawLine(int x1, int y1, int x2, int y2, COLORREF color); 329*92467d33SBram Moolenaar 330*92467d33SBram Moolenaar void SetPixel(int x, int y, COLORREF color); 331d7ccc4d8SBram Moolenaar 332d7ccc4d8SBram Moolenaar void Flush(); 333d7ccc4d8SBram Moolenaar 334d7ccc4d8SBram Moolenaar void SetRenderingParams( 335d7ccc4d8SBram Moolenaar const DWriteRenderingParams *params); 336d7ccc4d8SBram Moolenaar 337d7ccc4d8SBram Moolenaar DWriteRenderingParams *GetRenderingParams( 338d7ccc4d8SBram Moolenaar DWriteRenderingParams *params); 339d7ccc4d8SBram Moolenaar }; 340d7ccc4d8SBram Moolenaar 341b5a7a8b5SBram Moolenaar class AdjustedGlyphRun : public DWRITE_GLYPH_RUN 342b5a7a8b5SBram Moolenaar { 343b5a7a8b5SBram Moolenaar private: 344d7ccc4d8SBram Moolenaar FLOAT &mAccum; 345b5a7a8b5SBram Moolenaar FLOAT mDelta; 346b5a7a8b5SBram Moolenaar FLOAT *mAdjustedAdvances; 347b5a7a8b5SBram Moolenaar 348b5a7a8b5SBram Moolenaar public: 349b5a7a8b5SBram Moolenaar AdjustedGlyphRun( 350b5a7a8b5SBram Moolenaar const DWRITE_GLYPH_RUN *glyphRun, 351d7ccc4d8SBram Moolenaar FLOAT cellWidth, 352d7ccc4d8SBram Moolenaar FLOAT &accum) : 353b5a7a8b5SBram Moolenaar DWRITE_GLYPH_RUN(*glyphRun), 354d7ccc4d8SBram Moolenaar mAccum(accum), 355b5a7a8b5SBram Moolenaar mDelta(0.0f), 356b5a7a8b5SBram Moolenaar mAdjustedAdvances(new FLOAT[glyphRun->glyphCount]) 357b5a7a8b5SBram Moolenaar { 358b5a7a8b5SBram Moolenaar assert(cellWidth != 0.0f); 359b5a7a8b5SBram Moolenaar for (UINT32 i = 0; i < glyphRun->glyphCount; ++i) 360b5a7a8b5SBram Moolenaar { 361b5a7a8b5SBram Moolenaar FLOAT orig = glyphRun->glyphAdvances[i]; 362b5a7a8b5SBram Moolenaar FLOAT adjusted = adjustToCell(orig, cellWidth); 363b5a7a8b5SBram Moolenaar mAdjustedAdvances[i] = adjusted; 364b5a7a8b5SBram Moolenaar mDelta += adjusted - orig; 365b5a7a8b5SBram Moolenaar } 366b5a7a8b5SBram Moolenaar glyphAdvances = mAdjustedAdvances; 367b5a7a8b5SBram Moolenaar } 368b5a7a8b5SBram Moolenaar 369d7ccc4d8SBram Moolenaar ~AdjustedGlyphRun() 370b5a7a8b5SBram Moolenaar { 371d7ccc4d8SBram Moolenaar mAccum += mDelta; 372b5a7a8b5SBram Moolenaar delete[] mAdjustedAdvances; 373b5a7a8b5SBram Moolenaar } 374b5a7a8b5SBram Moolenaar 375b5a7a8b5SBram Moolenaar static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth) 376b5a7a8b5SBram Moolenaar { 377d7ccc4d8SBram Moolenaar int cellCount = int(floor(value / cellWidth + 0.5f)); 378b5a7a8b5SBram Moolenaar if (cellCount < 1) 379b5a7a8b5SBram Moolenaar cellCount = 1; 380b5a7a8b5SBram Moolenaar return cellCount * cellWidth; 381b5a7a8b5SBram Moolenaar } 382b5a7a8b5SBram Moolenaar }; 383b5a7a8b5SBram Moolenaar 384d7ccc4d8SBram Moolenaar struct TextRendererContext { 385d7ccc4d8SBram Moolenaar // const fields. 386d7ccc4d8SBram Moolenaar COLORREF color; 387d7ccc4d8SBram Moolenaar FLOAT cellWidth; 388d7ccc4d8SBram Moolenaar 389d7ccc4d8SBram Moolenaar // working fields. 390d7ccc4d8SBram Moolenaar FLOAT offsetX; 391d7ccc4d8SBram Moolenaar }; 392d7ccc4d8SBram Moolenaar 393d7ccc4d8SBram Moolenaar class TextRenderer FINAL : public IDWriteTextRenderer 394b5a7a8b5SBram Moolenaar { 395b5a7a8b5SBram Moolenaar public: 396d7ccc4d8SBram Moolenaar TextRenderer( 397d7ccc4d8SBram Moolenaar DWriteContext* pDWC) : 398b5a7a8b5SBram Moolenaar cRefCount_(0), 399d7ccc4d8SBram Moolenaar pDWC_(pDWC) 400b5a7a8b5SBram Moolenaar { 401b5a7a8b5SBram Moolenaar AddRef(); 402b5a7a8b5SBram Moolenaar } 403b5a7a8b5SBram Moolenaar 404edb4f2b3SBram Moolenaar // add "virtual" to avoid a compiler warning 405d7ccc4d8SBram Moolenaar virtual ~TextRenderer() 406b5a7a8b5SBram Moolenaar { 407b5a7a8b5SBram Moolenaar } 408b5a7a8b5SBram Moolenaar 409b5a7a8b5SBram Moolenaar IFACEMETHOD(IsPixelSnappingDisabled)( 410b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext, 411b5a7a8b5SBram Moolenaar __out BOOL* isDisabled) 412b5a7a8b5SBram Moolenaar { 413b5a7a8b5SBram Moolenaar *isDisabled = FALSE; 414b5a7a8b5SBram Moolenaar return S_OK; 415b5a7a8b5SBram Moolenaar } 416b5a7a8b5SBram Moolenaar 417b5a7a8b5SBram Moolenaar IFACEMETHOD(GetCurrentTransform)( 418b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext, 419b5a7a8b5SBram Moolenaar __out DWRITE_MATRIX* transform) 420b5a7a8b5SBram Moolenaar { 421b5a7a8b5SBram Moolenaar // forward the render target's transform 422d7ccc4d8SBram Moolenaar pDWC_->mRT->GetTransform( 423d7ccc4d8SBram Moolenaar reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform)); 424b5a7a8b5SBram Moolenaar return S_OK; 425b5a7a8b5SBram Moolenaar } 426b5a7a8b5SBram Moolenaar 427b5a7a8b5SBram Moolenaar IFACEMETHOD(GetPixelsPerDip)( 428b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext, 429b5a7a8b5SBram Moolenaar __out FLOAT* pixelsPerDip) 430b5a7a8b5SBram Moolenaar { 431d7ccc4d8SBram Moolenaar float dpiX, unused; 432d7ccc4d8SBram Moolenaar pDWC_->mRT->GetDpi(&dpiX, &unused); 433d7ccc4d8SBram Moolenaar *pixelsPerDip = dpiX / 96.0f; 434b5a7a8b5SBram Moolenaar return S_OK; 435b5a7a8b5SBram Moolenaar } 436b5a7a8b5SBram Moolenaar 437b5a7a8b5SBram Moolenaar IFACEMETHOD(DrawUnderline)( 438b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext, 439b5a7a8b5SBram Moolenaar FLOAT baselineOriginX, 440b5a7a8b5SBram Moolenaar FLOAT baselineOriginY, 441b5a7a8b5SBram Moolenaar __in DWRITE_UNDERLINE const* underline, 442b5a7a8b5SBram Moolenaar IUnknown* clientDrawingEffect) 443b5a7a8b5SBram Moolenaar { 444b5a7a8b5SBram Moolenaar return E_NOTIMPL; 445b5a7a8b5SBram Moolenaar } 446b5a7a8b5SBram Moolenaar 447b5a7a8b5SBram Moolenaar IFACEMETHOD(DrawStrikethrough)( 448b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext, 449b5a7a8b5SBram Moolenaar FLOAT baselineOriginX, 450b5a7a8b5SBram Moolenaar FLOAT baselineOriginY, 451b5a7a8b5SBram Moolenaar __in DWRITE_STRIKETHROUGH const* strikethrough, 452b5a7a8b5SBram Moolenaar IUnknown* clientDrawingEffect) 453b5a7a8b5SBram Moolenaar { 454b5a7a8b5SBram Moolenaar return E_NOTIMPL; 455b5a7a8b5SBram Moolenaar } 456b5a7a8b5SBram Moolenaar 457b5a7a8b5SBram Moolenaar IFACEMETHOD(DrawInlineObject)( 458b5a7a8b5SBram Moolenaar __maybenull void* clientDrawingContext, 459b5a7a8b5SBram Moolenaar FLOAT originX, 460b5a7a8b5SBram Moolenaar FLOAT originY, 461b5a7a8b5SBram Moolenaar IDWriteInlineObject* inlineObject, 462b5a7a8b5SBram Moolenaar BOOL isSideways, 463b5a7a8b5SBram Moolenaar BOOL isRightToLeft, 464b5a7a8b5SBram Moolenaar IUnknown* clientDrawingEffect) 465b5a7a8b5SBram Moolenaar { 466b5a7a8b5SBram Moolenaar return E_NOTIMPL; 467b5a7a8b5SBram Moolenaar } 468b5a7a8b5SBram Moolenaar 469d7ccc4d8SBram Moolenaar IFACEMETHOD(DrawGlyphRun)( 470d7ccc4d8SBram Moolenaar __maybenull void* clientDrawingContext, 471d7ccc4d8SBram Moolenaar FLOAT baselineOriginX, 472d7ccc4d8SBram Moolenaar FLOAT baselineOriginY, 473d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE measuringMode, 474d7ccc4d8SBram Moolenaar __in DWRITE_GLYPH_RUN const* glyphRun, 475d7ccc4d8SBram Moolenaar __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, 476d7ccc4d8SBram Moolenaar IUnknown* clientDrawingEffect) 477d7ccc4d8SBram Moolenaar { 478d7ccc4d8SBram Moolenaar TextRendererContext *context = 479d7ccc4d8SBram Moolenaar reinterpret_cast<TextRendererContext*>(clientDrawingContext); 480d7ccc4d8SBram Moolenaar 481d7ccc4d8SBram Moolenaar AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth, 482d7ccc4d8SBram Moolenaar context->offsetX); 483d7ccc4d8SBram Moolenaar 484d7ccc4d8SBram Moolenaar if (pDWC_->mDWriteFactory2 != NULL) 485d7ccc4d8SBram Moolenaar { 486d7ccc4d8SBram Moolenaar IDWriteColorGlyphRunEnumerator *enumerator = NULL; 487d7ccc4d8SBram Moolenaar HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun( 488d7ccc4d8SBram Moolenaar baselineOriginX + context->offsetX, 489d7ccc4d8SBram Moolenaar baselineOriginY, 490d7ccc4d8SBram Moolenaar &adjustedGlyphRun, 491d7ccc4d8SBram Moolenaar NULL, 492d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE_GDI_NATURAL, 493d7ccc4d8SBram Moolenaar NULL, 494d7ccc4d8SBram Moolenaar 0, 495d7ccc4d8SBram Moolenaar &enumerator); 496d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr)) 497d7ccc4d8SBram Moolenaar { 498d7ccc4d8SBram Moolenaar // Draw by IDWriteFactory2 for color emoji 499d7ccc4d8SBram Moolenaar BOOL hasRun = TRUE; 500d7ccc4d8SBram Moolenaar enumerator->MoveNext(&hasRun); 501d7ccc4d8SBram Moolenaar while (hasRun) 502d7ccc4d8SBram Moolenaar { 503d7ccc4d8SBram Moolenaar const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun; 504d7ccc4d8SBram Moolenaar enumerator->GetCurrentRun(&colorGlyphRun); 505d7ccc4d8SBram Moolenaar 506d7ccc4d8SBram Moolenaar pDWC_->mBrush->SetColor(colorGlyphRun->runColor); 507d7ccc4d8SBram Moolenaar pDWC_->mRT->DrawGlyphRun( 508d7ccc4d8SBram Moolenaar D2D1::Point2F( 509d7ccc4d8SBram Moolenaar colorGlyphRun->baselineOriginX, 510d7ccc4d8SBram Moolenaar colorGlyphRun->baselineOriginY), 511d7ccc4d8SBram Moolenaar &colorGlyphRun->glyphRun, 512d7ccc4d8SBram Moolenaar pDWC_->mBrush, 513d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE_NATURAL); 514d7ccc4d8SBram Moolenaar enumerator->MoveNext(&hasRun); 515d7ccc4d8SBram Moolenaar } 516d7ccc4d8SBram Moolenaar SafeRelease(&enumerator); 517d7ccc4d8SBram Moolenaar return S_OK; 518d7ccc4d8SBram Moolenaar } 519d7ccc4d8SBram Moolenaar } 520d7ccc4d8SBram Moolenaar 521d7ccc4d8SBram Moolenaar // Draw by IDWriteFactory (without color emoji) 522d7ccc4d8SBram Moolenaar pDWC_->mRT->DrawGlyphRun( 523d7ccc4d8SBram Moolenaar D2D1::Point2F( 524d7ccc4d8SBram Moolenaar baselineOriginX + context->offsetX, 525d7ccc4d8SBram Moolenaar baselineOriginY), 526d7ccc4d8SBram Moolenaar &adjustedGlyphRun, 527d7ccc4d8SBram Moolenaar pDWC_->SolidBrush(context->color), 528d7ccc4d8SBram Moolenaar DWRITE_MEASURING_MODE_NATURAL); 529d7ccc4d8SBram Moolenaar return S_OK; 530d7ccc4d8SBram Moolenaar } 531d7ccc4d8SBram Moolenaar 532b5a7a8b5SBram Moolenaar public: 533b5a7a8b5SBram Moolenaar IFACEMETHOD_(unsigned long, AddRef) () 534b5a7a8b5SBram Moolenaar { 535b5a7a8b5SBram Moolenaar return InterlockedIncrement(&cRefCount_); 536b5a7a8b5SBram Moolenaar } 537b5a7a8b5SBram Moolenaar 538b5a7a8b5SBram Moolenaar IFACEMETHOD_(unsigned long, Release) () 539b5a7a8b5SBram Moolenaar { 540b5a7a8b5SBram Moolenaar long newCount = InterlockedDecrement(&cRefCount_); 541b5a7a8b5SBram Moolenaar 542b5a7a8b5SBram Moolenaar if (newCount == 0) 543b5a7a8b5SBram Moolenaar { 544b5a7a8b5SBram Moolenaar delete this; 545b5a7a8b5SBram Moolenaar return 0; 546b5a7a8b5SBram Moolenaar } 547b5a7a8b5SBram Moolenaar return newCount; 548b5a7a8b5SBram Moolenaar } 549b5a7a8b5SBram Moolenaar 550b5a7a8b5SBram Moolenaar IFACEMETHOD(QueryInterface)( 551b5a7a8b5SBram Moolenaar IID const& riid, 552b5a7a8b5SBram Moolenaar void** ppvObject) 553b5a7a8b5SBram Moolenaar { 554b5a7a8b5SBram Moolenaar if (__uuidof(IDWriteTextRenderer) == riid) 555b5a7a8b5SBram Moolenaar { 556b5a7a8b5SBram Moolenaar *ppvObject = this; 557b5a7a8b5SBram Moolenaar } 558b5a7a8b5SBram Moolenaar else if (__uuidof(IDWritePixelSnapping) == riid) 559b5a7a8b5SBram Moolenaar { 560b5a7a8b5SBram Moolenaar *ppvObject = this; 561b5a7a8b5SBram Moolenaar } 562b5a7a8b5SBram Moolenaar else if (__uuidof(IUnknown) == riid) 563b5a7a8b5SBram Moolenaar { 564b5a7a8b5SBram Moolenaar *ppvObject = this; 565b5a7a8b5SBram Moolenaar } 566b5a7a8b5SBram Moolenaar else 567b5a7a8b5SBram Moolenaar { 568b5a7a8b5SBram Moolenaar *ppvObject = NULL; 569b5a7a8b5SBram Moolenaar return E_FAIL; 570b5a7a8b5SBram Moolenaar } 571b5a7a8b5SBram Moolenaar 572b5a7a8b5SBram Moolenaar return S_OK; 573b5a7a8b5SBram Moolenaar } 574b5a7a8b5SBram Moolenaar 575b5a7a8b5SBram Moolenaar private: 5760106b4b8SBram Moolenaar long cRefCount_; 577d7ccc4d8SBram Moolenaar DWriteContext* pDWC_; 578b5a7a8b5SBram Moolenaar }; 579b5a7a8b5SBram Moolenaar 580b5a7a8b5SBram Moolenaar DWriteContext::DWriteContext() : 581d7ccc4d8SBram Moolenaar mHDC(NULL), 582*92467d33SBram Moolenaar mBindRect(), 583*92467d33SBram Moolenaar mDMode(DM_GDI), 584*92467d33SBram Moolenaar mInteropHDC(NULL), 585b5a7a8b5SBram Moolenaar mDrawing(false), 586d7ccc4d8SBram Moolenaar mFallbackDC(false), 587b5a7a8b5SBram Moolenaar mD2D1Factory(NULL), 588b5a7a8b5SBram Moolenaar mRT(NULL), 589*92467d33SBram Moolenaar mGDIRT(NULL), 590b5a7a8b5SBram Moolenaar mBrush(NULL), 591b5a7a8b5SBram Moolenaar mDWriteFactory(NULL), 592d7ccc4d8SBram Moolenaar mDWriteFactory2(NULL), 593b5a7a8b5SBram Moolenaar mGdiInterop(NULL), 594b5a7a8b5SBram Moolenaar mRenderingParams(NULL), 595d7ccc4d8SBram Moolenaar mFontCache(8), 596b5a7a8b5SBram Moolenaar mTextFormat(NULL), 597b5a7a8b5SBram Moolenaar mFontWeight(DWRITE_FONT_WEIGHT_NORMAL), 598b5a7a8b5SBram Moolenaar mFontStyle(DWRITE_FONT_STYLE_NORMAL), 599b5a7a8b5SBram Moolenaar mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT) 600b5a7a8b5SBram Moolenaar { 601b5a7a8b5SBram Moolenaar HRESULT hr; 602b5a7a8b5SBram Moolenaar 603b5a7a8b5SBram Moolenaar hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, 604b5a7a8b5SBram Moolenaar __uuidof(ID2D1Factory), NULL, 605b5a7a8b5SBram Moolenaar reinterpret_cast<void**>(&mD2D1Factory)); 606b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory); 607b5a7a8b5SBram Moolenaar 608b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 609*92467d33SBram Moolenaar hr = CreateDeviceResources(); 610b5a7a8b5SBram Moolenaar 611b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 612b5a7a8b5SBram Moolenaar { 613b5a7a8b5SBram Moolenaar hr = DWriteCreateFactory( 614b5a7a8b5SBram Moolenaar DWRITE_FACTORY_TYPE_SHARED, 615b5a7a8b5SBram Moolenaar __uuidof(IDWriteFactory), 616b5a7a8b5SBram Moolenaar reinterpret_cast<IUnknown**>(&mDWriteFactory)); 617b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr, 618b5a7a8b5SBram Moolenaar mDWriteFactory); 619b5a7a8b5SBram Moolenaar } 620b5a7a8b5SBram Moolenaar 621b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 622b5a7a8b5SBram Moolenaar { 623d7ccc4d8SBram Moolenaar DWriteCreateFactory( 624d7ccc4d8SBram Moolenaar DWRITE_FACTORY_TYPE_SHARED, 625d7ccc4d8SBram Moolenaar __uuidof(IDWriteFactory2), 626d7ccc4d8SBram Moolenaar reinterpret_cast<IUnknown**>(&mDWriteFactory2)); 627d7ccc4d8SBram Moolenaar _RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available"); 628d7ccc4d8SBram Moolenaar } 629d7ccc4d8SBram Moolenaar 630d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr)) 631d7ccc4d8SBram Moolenaar { 632b5a7a8b5SBram Moolenaar hr = mDWriteFactory->GetGdiInterop(&mGdiInterop); 633b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop); 634b5a7a8b5SBram Moolenaar } 635b5a7a8b5SBram Moolenaar 636b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 637b5a7a8b5SBram Moolenaar { 638b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams); 639b5a7a8b5SBram Moolenaar _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr, 640b5a7a8b5SBram Moolenaar mRenderingParams); 641b5a7a8b5SBram Moolenaar } 642b5a7a8b5SBram Moolenaar } 643b5a7a8b5SBram Moolenaar 644b5a7a8b5SBram Moolenaar DWriteContext::~DWriteContext() 645b5a7a8b5SBram Moolenaar { 646b5a7a8b5SBram Moolenaar SafeRelease(&mTextFormat); 647b5a7a8b5SBram Moolenaar SafeRelease(&mRenderingParams); 648b5a7a8b5SBram Moolenaar SafeRelease(&mGdiInterop); 649b5a7a8b5SBram Moolenaar SafeRelease(&mDWriteFactory); 650d7ccc4d8SBram Moolenaar SafeRelease(&mDWriteFactory2); 651b5a7a8b5SBram Moolenaar SafeRelease(&mBrush); 652*92467d33SBram Moolenaar SafeRelease(&mGDIRT); 653b5a7a8b5SBram Moolenaar SafeRelease(&mRT); 654b5a7a8b5SBram Moolenaar SafeRelease(&mD2D1Factory); 655b5a7a8b5SBram Moolenaar } 656b5a7a8b5SBram Moolenaar 657b5a7a8b5SBram Moolenaar HRESULT 658*92467d33SBram Moolenaar DWriteContext::CreateDeviceResources() 659*92467d33SBram Moolenaar { 660*92467d33SBram Moolenaar HRESULT hr; 661*92467d33SBram Moolenaar 662*92467d33SBram Moolenaar if (mRT != NULL) 663*92467d33SBram Moolenaar return S_OK; 664*92467d33SBram Moolenaar 665*92467d33SBram Moolenaar D2D1_RENDER_TARGET_PROPERTIES props = { 666*92467d33SBram Moolenaar D2D1_RENDER_TARGET_TYPE_DEFAULT, 667*92467d33SBram Moolenaar { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE }, 668*92467d33SBram Moolenaar 0, 0, 669*92467d33SBram Moolenaar D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, 670*92467d33SBram Moolenaar D2D1_FEATURE_LEVEL_DEFAULT 671*92467d33SBram Moolenaar }; 672*92467d33SBram Moolenaar hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT); 673*92467d33SBram Moolenaar _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT); 674*92467d33SBram Moolenaar 675*92467d33SBram Moolenaar if (SUCCEEDED(hr)) 676*92467d33SBram Moolenaar { 677*92467d33SBram Moolenaar // This always succeeds. 678*92467d33SBram Moolenaar mRT->QueryInterface( 679*92467d33SBram Moolenaar __uuidof(ID2D1GdiInteropRenderTarget), 680*92467d33SBram Moolenaar reinterpret_cast<void**>(&mGDIRT)); 681*92467d33SBram Moolenaar _RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT); 682*92467d33SBram Moolenaar } 683*92467d33SBram Moolenaar 684*92467d33SBram Moolenaar if (SUCCEEDED(hr)) 685*92467d33SBram Moolenaar { 686*92467d33SBram Moolenaar hr = mRT->CreateSolidColorBrush( 687*92467d33SBram Moolenaar D2D1::ColorF(D2D1::ColorF::Black), 688*92467d33SBram Moolenaar &mBrush); 689*92467d33SBram Moolenaar _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush); 690*92467d33SBram Moolenaar } 691*92467d33SBram Moolenaar 692*92467d33SBram Moolenaar if (SUCCEEDED(hr)) 693*92467d33SBram Moolenaar { 694*92467d33SBram Moolenaar if (mHDC != NULL) 695*92467d33SBram Moolenaar { 696*92467d33SBram Moolenaar mRT->BindDC(mHDC, &mBindRect); 697*92467d33SBram Moolenaar mRT->SetTransform(D2D1::IdentityMatrix()); 698*92467d33SBram Moolenaar } 699*92467d33SBram Moolenaar } 700*92467d33SBram Moolenaar 701*92467d33SBram Moolenaar return hr; 702*92467d33SBram Moolenaar } 703*92467d33SBram Moolenaar 704*92467d33SBram Moolenaar void 705*92467d33SBram Moolenaar DWriteContext::DiscardDeviceResources() 706*92467d33SBram Moolenaar { 707*92467d33SBram Moolenaar SafeRelease(&mBrush); 708*92467d33SBram Moolenaar SafeRelease(&mGDIRT); 709*92467d33SBram Moolenaar SafeRelease(&mRT); 710*92467d33SBram Moolenaar } 711*92467d33SBram Moolenaar 712*92467d33SBram Moolenaar HRESULT 713d7ccc4d8SBram Moolenaar DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont, 714d7ccc4d8SBram Moolenaar IDWriteTextFormat **ppTextFormat) 715b5a7a8b5SBram Moolenaar { 716d7ccc4d8SBram Moolenaar // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp 717b5a7a8b5SBram Moolenaar HRESULT hr = S_OK; 718d7ccc4d8SBram Moolenaar IDWriteTextFormat *pTextFormat = NULL; 719b5a7a8b5SBram Moolenaar 720b5a7a8b5SBram Moolenaar IDWriteFont *font = NULL; 721b5a7a8b5SBram Moolenaar IDWriteFontFamily *fontFamily = NULL; 722b5a7a8b5SBram Moolenaar IDWriteLocalizedStrings *localizedFamilyNames = NULL; 723d7ccc4d8SBram Moolenaar float fontSize = 0; 724b5a7a8b5SBram Moolenaar 725b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 726b5a7a8b5SBram Moolenaar { 727b5a7a8b5SBram Moolenaar hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font); 728b5a7a8b5SBram Moolenaar } 729b5a7a8b5SBram Moolenaar 730b5a7a8b5SBram Moolenaar // Get the font family to which this font belongs. 731b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 732b5a7a8b5SBram Moolenaar { 733b5a7a8b5SBram Moolenaar hr = font->GetFontFamily(&fontFamily); 734b5a7a8b5SBram Moolenaar } 735b5a7a8b5SBram Moolenaar 736b5a7a8b5SBram Moolenaar // Get the family names. This returns an object that encapsulates one or 737b5a7a8b5SBram Moolenaar // more names with the same meaning but in different languages. 738b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 739b5a7a8b5SBram Moolenaar { 740b5a7a8b5SBram Moolenaar hr = fontFamily->GetFamilyNames(&localizedFamilyNames); 741b5a7a8b5SBram Moolenaar } 742b5a7a8b5SBram Moolenaar 743b5a7a8b5SBram Moolenaar // Get the family name at index zero. If we were going to display the name 744b5a7a8b5SBram Moolenaar // we'd want to try to find one that matched the use locale, but for 745b5a7a8b5SBram Moolenaar // purposes of creating a text format object any language will do. 746b5a7a8b5SBram Moolenaar 747b5a7a8b5SBram Moolenaar wchar_t familyName[100]; 748b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 749b5a7a8b5SBram Moolenaar { 750b5a7a8b5SBram Moolenaar hr = localizedFamilyNames->GetString(0, familyName, 751b5a7a8b5SBram Moolenaar ARRAYSIZE(familyName)); 752b5a7a8b5SBram Moolenaar } 753b5a7a8b5SBram Moolenaar 754b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 755b5a7a8b5SBram Moolenaar { 756d7ccc4d8SBram Moolenaar // Use lfHeight of the LOGFONT as font size. 757d7ccc4d8SBram Moolenaar fontSize = float(logFont.lfHeight); 758d7ccc4d8SBram Moolenaar 759b5a7a8b5SBram Moolenaar if (fontSize < 0) 760b5a7a8b5SBram Moolenaar { 761b5a7a8b5SBram Moolenaar // Negative lfHeight represents the size of the em unit. 762b5a7a8b5SBram Moolenaar fontSize = -fontSize; 763b5a7a8b5SBram Moolenaar } 764b5a7a8b5SBram Moolenaar else 765b5a7a8b5SBram Moolenaar { 766b5a7a8b5SBram Moolenaar // Positive lfHeight represents the cell height (ascent + 767b5a7a8b5SBram Moolenaar // descent). 768b5a7a8b5SBram Moolenaar DWRITE_FONT_METRICS fontMetrics; 769b5a7a8b5SBram Moolenaar font->GetMetrics(&fontMetrics); 770b5a7a8b5SBram Moolenaar 771b5a7a8b5SBram Moolenaar // Convert the cell height (ascent + descent) from design units 772b5a7a8b5SBram Moolenaar // to ems. 773b5a7a8b5SBram Moolenaar float cellHeight = static_cast<float>( 774b5a7a8b5SBram Moolenaar fontMetrics.ascent + fontMetrics.descent) 775b5a7a8b5SBram Moolenaar / fontMetrics.designUnitsPerEm; 776b5a7a8b5SBram Moolenaar 777b5a7a8b5SBram Moolenaar // Divide the font size by the cell height to get the font em 778b5a7a8b5SBram Moolenaar // size. 779b5a7a8b5SBram Moolenaar fontSize /= cellHeight; 780b5a7a8b5SBram Moolenaar } 781b5a7a8b5SBram Moolenaar } 782b5a7a8b5SBram Moolenaar 783b5a7a8b5SBram Moolenaar // The text format includes a locale name. Ideally, this would be the 784b5a7a8b5SBram Moolenaar // language of the text, which may or may not be the same as the primary 785b5a7a8b5SBram Moolenaar // language of the user. However, for our purposes the user locale will do. 786b5a7a8b5SBram Moolenaar wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; 787b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 788b5a7a8b5SBram Moolenaar { 789b5a7a8b5SBram Moolenaar if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0) 790b5a7a8b5SBram Moolenaar hr = HRESULT_FROM_WIN32(GetLastError()); 791b5a7a8b5SBram Moolenaar } 792b5a7a8b5SBram Moolenaar 793b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 794b5a7a8b5SBram Moolenaar { 795b5a7a8b5SBram Moolenaar // Create the text format object. 796b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateTextFormat( 797b5a7a8b5SBram Moolenaar familyName, 798b5a7a8b5SBram Moolenaar NULL, // no custom font collection 799b5a7a8b5SBram Moolenaar font->GetWeight(), 800b5a7a8b5SBram Moolenaar font->GetStyle(), 801b5a7a8b5SBram Moolenaar font->GetStretch(), 802b5a7a8b5SBram Moolenaar fontSize, 803b5a7a8b5SBram Moolenaar localeName, 804d7ccc4d8SBram Moolenaar &pTextFormat); 805b5a7a8b5SBram Moolenaar } 806b5a7a8b5SBram Moolenaar 807b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 808d7ccc4d8SBram Moolenaar hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); 809d7ccc4d8SBram Moolenaar 810d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr)) 811d7ccc4d8SBram Moolenaar hr = pTextFormat->SetParagraphAlignment( 812d7ccc4d8SBram Moolenaar DWRITE_PARAGRAPH_ALIGNMENT_CENTER); 813d7ccc4d8SBram Moolenaar 814d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr)) 815d7ccc4d8SBram Moolenaar hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); 816b5a7a8b5SBram Moolenaar 817b5a7a8b5SBram Moolenaar SafeRelease(&localizedFamilyNames); 818b5a7a8b5SBram Moolenaar SafeRelease(&fontFamily); 819b5a7a8b5SBram Moolenaar SafeRelease(&font); 820b5a7a8b5SBram Moolenaar 821d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr)) 822d7ccc4d8SBram Moolenaar *ppTextFormat = pTextFormat; 823d7ccc4d8SBram Moolenaar else 824d7ccc4d8SBram Moolenaar SafeRelease(&pTextFormat); 825d7ccc4d8SBram Moolenaar 826d7ccc4d8SBram Moolenaar return hr; 827d7ccc4d8SBram Moolenaar } 828d7ccc4d8SBram Moolenaar 829d7ccc4d8SBram Moolenaar HRESULT 830d7ccc4d8SBram Moolenaar DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont) 831d7ccc4d8SBram Moolenaar { 832d7ccc4d8SBram Moolenaar HRESULT hr = S_OK; 833d7ccc4d8SBram Moolenaar IDWriteTextFormat *pTextFormat = NULL; 834d7ccc4d8SBram Moolenaar 835d7ccc4d8SBram Moolenaar hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat); 836d7ccc4d8SBram Moolenaar 837d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr)) 838d7ccc4d8SBram Moolenaar { 839d7ccc4d8SBram Moolenaar SafeRelease(&mTextFormat); 840d7ccc4d8SBram Moolenaar mTextFormat = pTextFormat; 841d7ccc4d8SBram Moolenaar mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight); 842d7ccc4d8SBram Moolenaar mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC 843d7ccc4d8SBram Moolenaar : DWRITE_FONT_STYLE_NORMAL; 844d7ccc4d8SBram Moolenaar } 845d7ccc4d8SBram Moolenaar 846b5a7a8b5SBram Moolenaar return hr; 847b5a7a8b5SBram Moolenaar } 848b5a7a8b5SBram Moolenaar 849b5a7a8b5SBram Moolenaar void 850b5a7a8b5SBram Moolenaar DWriteContext::SetFont(HFONT hFont) 851b5a7a8b5SBram Moolenaar { 852d7ccc4d8SBram Moolenaar FontCache::Item item; 853d7ccc4d8SBram Moolenaar if (mFontCache.get(hFont, item)) 854b5a7a8b5SBram Moolenaar { 855d7ccc4d8SBram Moolenaar if (item.pTextFormat != NULL) 856d7ccc4d8SBram Moolenaar { 857d7ccc4d8SBram Moolenaar item.pTextFormat->AddRef(); 858d7ccc4d8SBram Moolenaar SafeRelease(&mTextFormat); 859d7ccc4d8SBram Moolenaar mTextFormat = item.pTextFormat; 860d7ccc4d8SBram Moolenaar mFontWeight = item.fontWeight; 861d7ccc4d8SBram Moolenaar mFontStyle = item.fontStyle; 862d7ccc4d8SBram Moolenaar mFallbackDC = false; 863d7ccc4d8SBram Moolenaar } 864d7ccc4d8SBram Moolenaar else 865d7ccc4d8SBram Moolenaar mFallbackDC = true; 866d7ccc4d8SBram Moolenaar return; 867d7ccc4d8SBram Moolenaar } 868d7ccc4d8SBram Moolenaar 869d7ccc4d8SBram Moolenaar HRESULT hr = E_FAIL; 870b5a7a8b5SBram Moolenaar LOGFONTW lf; 871b5a7a8b5SBram Moolenaar if (GetObjectW(hFont, sizeof(lf), &lf)) 872d7ccc4d8SBram Moolenaar hr = SetFontByLOGFONT(lf); 873d7ccc4d8SBram Moolenaar 874d7ccc4d8SBram Moolenaar item.hFont = hFont; 875d7ccc4d8SBram Moolenaar if (SUCCEEDED(hr)) 876b5a7a8b5SBram Moolenaar { 877d7ccc4d8SBram Moolenaar item.pTextFormat = mTextFormat; 878d7ccc4d8SBram Moolenaar item.fontWeight = mFontWeight; 879d7ccc4d8SBram Moolenaar item.fontStyle = mFontStyle; 880*92467d33SBram Moolenaar mFallbackDC = false; 881b5a7a8b5SBram Moolenaar } 882*92467d33SBram Moolenaar else 883*92467d33SBram Moolenaar mFallbackDC = true; 884d7ccc4d8SBram Moolenaar mFontCache.put(item); 885b5a7a8b5SBram Moolenaar } 886b5a7a8b5SBram Moolenaar 887b5a7a8b5SBram Moolenaar void 888*92467d33SBram Moolenaar DWriteContext::BindDC(HDC hdc, const RECT *rect) 889b5a7a8b5SBram Moolenaar { 890d7ccc4d8SBram Moolenaar Flush(); 891d7ccc4d8SBram Moolenaar mRT->BindDC(hdc, rect); 892d7ccc4d8SBram Moolenaar mRT->SetTransform(D2D1::IdentityMatrix()); 893d7ccc4d8SBram Moolenaar mHDC = hdc; 894*92467d33SBram Moolenaar mBindRect = *rect; 895b5a7a8b5SBram Moolenaar } 896b5a7a8b5SBram Moolenaar 897*92467d33SBram Moolenaar HRESULT 898*92467d33SBram Moolenaar DWriteContext::SetDrawingMode(DrawingMode mode) 899b5a7a8b5SBram Moolenaar { 900*92467d33SBram Moolenaar HRESULT hr = S_OK; 901*92467d33SBram Moolenaar 902*92467d33SBram Moolenaar switch (mode) 903b5a7a8b5SBram Moolenaar { 904*92467d33SBram Moolenaar default: 905*92467d33SBram Moolenaar case DM_GDI: 906*92467d33SBram Moolenaar if (mInteropHDC != NULL) 907*92467d33SBram Moolenaar { 908*92467d33SBram Moolenaar mGDIRT->ReleaseDC(NULL); 909*92467d33SBram Moolenaar mInteropHDC = NULL; 910*92467d33SBram Moolenaar } 911*92467d33SBram Moolenaar if (mDrawing) 912*92467d33SBram Moolenaar { 913*92467d33SBram Moolenaar hr = mRT->EndDraw(); 914*92467d33SBram Moolenaar if (hr == D2DERR_RECREATE_TARGET) 915*92467d33SBram Moolenaar { 916*92467d33SBram Moolenaar hr = S_OK; 917*92467d33SBram Moolenaar DiscardDeviceResources(); 918*92467d33SBram Moolenaar CreateDeviceResources(); 919*92467d33SBram Moolenaar } 920*92467d33SBram Moolenaar mDrawing = false; 921*92467d33SBram Moolenaar } 922*92467d33SBram Moolenaar break; 923*92467d33SBram Moolenaar 924*92467d33SBram Moolenaar case DM_DIRECTX: 925*92467d33SBram Moolenaar if (mInteropHDC != NULL) 926*92467d33SBram Moolenaar { 927*92467d33SBram Moolenaar mGDIRT->ReleaseDC(NULL); 928*92467d33SBram Moolenaar mInteropHDC = NULL; 929*92467d33SBram Moolenaar } 930*92467d33SBram Moolenaar else if (mDrawing == false) 931*92467d33SBram Moolenaar { 932*92467d33SBram Moolenaar CreateDeviceResources(); 933d7ccc4d8SBram Moolenaar mRT->BeginDraw(); 934d7ccc4d8SBram Moolenaar mDrawing = true; 935d7ccc4d8SBram Moolenaar } 936*92467d33SBram Moolenaar break; 937*92467d33SBram Moolenaar 938*92467d33SBram Moolenaar case DM_INTEROP: 939*92467d33SBram Moolenaar if (mDrawing == false) 940*92467d33SBram Moolenaar { 941*92467d33SBram Moolenaar CreateDeviceResources(); 942*92467d33SBram Moolenaar mRT->BeginDraw(); 943*92467d33SBram Moolenaar mDrawing = true; 944*92467d33SBram Moolenaar } 945*92467d33SBram Moolenaar if (mInteropHDC == NULL) 946*92467d33SBram Moolenaar hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC); 947*92467d33SBram Moolenaar break; 948*92467d33SBram Moolenaar } 949*92467d33SBram Moolenaar mDMode = mode; 950*92467d33SBram Moolenaar return hr; 951d7ccc4d8SBram Moolenaar } 952d7ccc4d8SBram Moolenaar 953d7ccc4d8SBram Moolenaar ID2D1Brush* 954d7ccc4d8SBram Moolenaar DWriteContext::SolidBrush(COLORREF color) 955d7ccc4d8SBram Moolenaar { 956d7ccc4d8SBram Moolenaar mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 | 957d7ccc4d8SBram Moolenaar UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color)))); 958d7ccc4d8SBram Moolenaar return mBrush; 959d7ccc4d8SBram Moolenaar } 960d7ccc4d8SBram Moolenaar 961d7ccc4d8SBram Moolenaar void 962d7ccc4d8SBram Moolenaar DWriteContext::DrawText(const WCHAR *text, int len, 963d7ccc4d8SBram Moolenaar int x, int y, int w, int h, int cellWidth, COLORREF color, 964*92467d33SBram Moolenaar UINT fuOptions, const RECT *lprc, const INT *lpDx) 965d7ccc4d8SBram Moolenaar { 966d7ccc4d8SBram Moolenaar if (mFallbackDC) 967d7ccc4d8SBram Moolenaar { 968*92467d33SBram Moolenaar // Fall back to GDI rendering. 969*92467d33SBram Moolenaar HRESULT hr = SetDrawingMode(DM_INTEROP); 970*92467d33SBram Moolenaar if (SUCCEEDED(hr)) 971*92467d33SBram Moolenaar { 972*92467d33SBram Moolenaar HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT); 973*92467d33SBram Moolenaar HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont); 974*92467d33SBram Moolenaar ::SetTextColor(mInteropHDC, color); 975*92467d33SBram Moolenaar ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC)); 976*92467d33SBram Moolenaar ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx); 977*92467d33SBram Moolenaar ::SelectObject(mInteropHDC, hOldFont); 978*92467d33SBram Moolenaar } 979d7ccc4d8SBram Moolenaar return; 980d7ccc4d8SBram Moolenaar } 981d7ccc4d8SBram Moolenaar 982d7ccc4d8SBram Moolenaar HRESULT hr; 983b5a7a8b5SBram Moolenaar IDWriteTextLayout *textLayout = NULL; 984b5a7a8b5SBram Moolenaar 985*92467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX); 986*92467d33SBram Moolenaar 987d7ccc4d8SBram Moolenaar hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat, 988d7ccc4d8SBram Moolenaar FLOAT(w), FLOAT(h), &textLayout); 989b5a7a8b5SBram Moolenaar 990b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr)) 991b5a7a8b5SBram Moolenaar { 992d7ccc4d8SBram Moolenaar DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) }; 993b5a7a8b5SBram Moolenaar textLayout->SetFontWeight(mFontWeight, textRange); 994b5a7a8b5SBram Moolenaar textLayout->SetFontStyle(mFontStyle, textRange); 995b5a7a8b5SBram Moolenaar 996d7ccc4d8SBram Moolenaar TextRenderer renderer(this); 997d7ccc4d8SBram Moolenaar TextRendererContext context = { color, FLOAT(cellWidth), 0.0f }; 998d7ccc4d8SBram Moolenaar textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y)); 999b5a7a8b5SBram Moolenaar } 1000b5a7a8b5SBram Moolenaar 1001b5a7a8b5SBram Moolenaar SafeRelease(&textLayout); 1002b5a7a8b5SBram Moolenaar } 1003b5a7a8b5SBram Moolenaar 1004d7ccc4d8SBram Moolenaar void 1005*92467d33SBram Moolenaar DWriteContext::FillRect(const RECT *rc, COLORREF color) 1006d7ccc4d8SBram Moolenaar { 1007*92467d33SBram Moolenaar if (mDMode == DM_INTEROP) 1008*92467d33SBram Moolenaar { 1009*92467d33SBram Moolenaar // GDI functions are used before this call. Keep using GDI. 1010*92467d33SBram Moolenaar // (Switching to Direct2D causes terrible slowdown.) 1011*92467d33SBram Moolenaar HBRUSH hbr = ::CreateSolidBrush(color); 1012*92467d33SBram Moolenaar ::FillRect(mInteropHDC, rc, hbr); 1013*92467d33SBram Moolenaar ::DeleteObject(HGDIOBJ(hbr)); 1014*92467d33SBram Moolenaar } 1015*92467d33SBram Moolenaar else 1016*92467d33SBram Moolenaar { 1017*92467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX); 1018d7ccc4d8SBram Moolenaar mRT->FillRectangle( 1019d7ccc4d8SBram Moolenaar D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top), 1020d7ccc4d8SBram Moolenaar FLOAT(rc->right), FLOAT(rc->bottom)), 1021d7ccc4d8SBram Moolenaar SolidBrush(color)); 1022b5a7a8b5SBram Moolenaar } 1023*92467d33SBram Moolenaar } 1024*92467d33SBram Moolenaar 1025*92467d33SBram Moolenaar void 1026*92467d33SBram Moolenaar DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color) 1027*92467d33SBram Moolenaar { 1028*92467d33SBram Moolenaar if (mDMode == DM_INTEROP) 1029*92467d33SBram Moolenaar { 1030*92467d33SBram Moolenaar // GDI functions are used before this call. Keep using GDI. 1031*92467d33SBram Moolenaar // (Switching to Direct2D causes terrible slowdown.) 1032*92467d33SBram Moolenaar HPEN hpen = ::CreatePen(PS_SOLID, 1, color); 1033*92467d33SBram Moolenaar HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen)); 1034*92467d33SBram Moolenaar ::MoveToEx(mInteropHDC, x1, y1, NULL); 1035*92467d33SBram Moolenaar ::LineTo(mInteropHDC, x2, y2); 1036*92467d33SBram Moolenaar ::SelectObject(mInteropHDC, old_pen); 1037*92467d33SBram Moolenaar ::DeleteObject(HGDIOBJ(hpen)); 1038*92467d33SBram Moolenaar } 1039*92467d33SBram Moolenaar else 1040*92467d33SBram Moolenaar { 1041*92467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX); 1042*92467d33SBram Moolenaar mRT->DrawLine( 1043*92467d33SBram Moolenaar D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f), 1044*92467d33SBram Moolenaar D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f), 1045*92467d33SBram Moolenaar SolidBrush(color)); 1046*92467d33SBram Moolenaar } 1047*92467d33SBram Moolenaar } 1048*92467d33SBram Moolenaar 1049*92467d33SBram Moolenaar void 1050*92467d33SBram Moolenaar DWriteContext::SetPixel(int x, int y, COLORREF color) 1051*92467d33SBram Moolenaar { 1052*92467d33SBram Moolenaar if (mDMode == DM_INTEROP) 1053*92467d33SBram Moolenaar { 1054*92467d33SBram Moolenaar // GDI functions are used before this call. Keep using GDI. 1055*92467d33SBram Moolenaar // (Switching to Direct2D causes terrible slowdown.) 1056*92467d33SBram Moolenaar ::SetPixel(mInteropHDC, x, y, color); 1057*92467d33SBram Moolenaar } 1058*92467d33SBram Moolenaar else 1059*92467d33SBram Moolenaar { 1060*92467d33SBram Moolenaar SetDrawingMode(DM_DIRECTX); 1061*92467d33SBram Moolenaar // Direct2D doesn't have SetPixel API. Use DrawLine instead. 1062*92467d33SBram Moolenaar mRT->DrawLine( 1063*92467d33SBram Moolenaar D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f), 1064*92467d33SBram Moolenaar D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f), 1065*92467d33SBram Moolenaar SolidBrush(color)); 1066*92467d33SBram Moolenaar } 1067*92467d33SBram Moolenaar } 1068b5a7a8b5SBram Moolenaar 1069d7ccc4d8SBram Moolenaar void 1070d7ccc4d8SBram Moolenaar DWriteContext::Flush() 1071b5a7a8b5SBram Moolenaar { 1072*92467d33SBram Moolenaar SetDrawingMode(DM_GDI); 1073b5a7a8b5SBram Moolenaar } 1074b5a7a8b5SBram Moolenaar 1075b5a7a8b5SBram Moolenaar void 1076b5a7a8b5SBram Moolenaar DWriteContext::SetRenderingParams( 1077b5a7a8b5SBram Moolenaar const DWriteRenderingParams *params) 1078b5a7a8b5SBram Moolenaar { 1079b5a7a8b5SBram Moolenaar if (mDWriteFactory == NULL) 1080b5a7a8b5SBram Moolenaar return; 1081b5a7a8b5SBram Moolenaar 1082b5a7a8b5SBram Moolenaar IDWriteRenderingParams *renderingParams = NULL; 1083b5a7a8b5SBram Moolenaar D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode = 1084b5a7a8b5SBram Moolenaar D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; 1085b5a7a8b5SBram Moolenaar HRESULT hr; 1086b5a7a8b5SBram Moolenaar if (params != NULL) 1087b5a7a8b5SBram Moolenaar { 1088b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma, 1089b5a7a8b5SBram Moolenaar params->enhancedContrast, params->clearTypeLevel, 1090b5a7a8b5SBram Moolenaar ToPixelGeometry(params->pixelGeometry), 1091b5a7a8b5SBram Moolenaar ToRenderingMode(params->renderingMode), &renderingParams); 1092b5a7a8b5SBram Moolenaar textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode); 1093b5a7a8b5SBram Moolenaar } 1094b5a7a8b5SBram Moolenaar else 1095b5a7a8b5SBram Moolenaar hr = mDWriteFactory->CreateRenderingParams(&renderingParams); 1096b5a7a8b5SBram Moolenaar if (SUCCEEDED(hr) && renderingParams != NULL) 1097b5a7a8b5SBram Moolenaar { 1098b5a7a8b5SBram Moolenaar SafeRelease(&mRenderingParams); 1099b5a7a8b5SBram Moolenaar mRenderingParams = renderingParams; 1100b5a7a8b5SBram Moolenaar mTextAntialiasMode = textAntialiasMode; 1101d7ccc4d8SBram Moolenaar 1102d7ccc4d8SBram Moolenaar Flush(); 1103d7ccc4d8SBram Moolenaar mRT->SetTextRenderingParams(mRenderingParams); 1104d7ccc4d8SBram Moolenaar mRT->SetTextAntialiasMode(mTextAntialiasMode); 1105b5a7a8b5SBram Moolenaar } 1106b5a7a8b5SBram Moolenaar } 1107b5a7a8b5SBram Moolenaar 1108b5a7a8b5SBram Moolenaar DWriteRenderingParams * 1109b5a7a8b5SBram Moolenaar DWriteContext::GetRenderingParams( 1110b5a7a8b5SBram Moolenaar DWriteRenderingParams *params) 1111b5a7a8b5SBram Moolenaar { 1112b5a7a8b5SBram Moolenaar if (params != NULL && mRenderingParams != NULL) 1113b5a7a8b5SBram Moolenaar { 1114b5a7a8b5SBram Moolenaar params->gamma = mRenderingParams->GetGamma(); 1115b5a7a8b5SBram Moolenaar params->enhancedContrast = mRenderingParams->GetEnhancedContrast(); 1116b5a7a8b5SBram Moolenaar params->clearTypeLevel = mRenderingParams->GetClearTypeLevel(); 1117b5a7a8b5SBram Moolenaar params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry()); 1118b5a7a8b5SBram Moolenaar params->renderingMode = ToInt(mRenderingParams->GetRenderingMode()); 1119b5a7a8b5SBram Moolenaar params->textAntialiasMode = mTextAntialiasMode; 1120b5a7a8b5SBram Moolenaar } 1121b5a7a8b5SBram Moolenaar return params; 1122b5a7a8b5SBram Moolenaar } 1123b5a7a8b5SBram Moolenaar 1124b5a7a8b5SBram Moolenaar //////////////////////////////////////////////////////////////////////////// 1125b5a7a8b5SBram Moolenaar // PUBLIC C INTERFACES 1126b5a7a8b5SBram Moolenaar 1127b5a7a8b5SBram Moolenaar void 1128b5a7a8b5SBram Moolenaar DWrite_Init(void) 1129b5a7a8b5SBram Moolenaar { 1130b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX 1131b5a7a8b5SBram Moolenaar // Load libraries. 1132b5a7a8b5SBram Moolenaar hD2D1DLL = vimLoadLib(const_cast<char*>("d2d1.dll")); 1133b5a7a8b5SBram Moolenaar hDWriteDLL = vimLoadLib(const_cast<char*>("dwrite.dll")); 1134b5a7a8b5SBram Moolenaar if (hD2D1DLL == NULL || hDWriteDLL == NULL) 1135b5a7a8b5SBram Moolenaar { 1136b5a7a8b5SBram Moolenaar DWrite_Final(); 1137b5a7a8b5SBram Moolenaar return; 1138b5a7a8b5SBram Moolenaar } 1139b5a7a8b5SBram Moolenaar // Get address of procedures. 1140b5a7a8b5SBram Moolenaar pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress( 1141b5a7a8b5SBram Moolenaar GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName"); 1142b5a7a8b5SBram Moolenaar pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL, 1143b5a7a8b5SBram Moolenaar "D2D1CreateFactory"); 1144b5a7a8b5SBram Moolenaar pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL, 1145b5a7a8b5SBram Moolenaar "DWriteCreateFactory"); 1146b5a7a8b5SBram Moolenaar #endif 1147b5a7a8b5SBram Moolenaar } 1148b5a7a8b5SBram Moolenaar 1149b5a7a8b5SBram Moolenaar void 1150b5a7a8b5SBram Moolenaar DWrite_Final(void) 1151b5a7a8b5SBram Moolenaar { 1152b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX 1153b5a7a8b5SBram Moolenaar pGetUserDefaultLocaleName = NULL; 1154b5a7a8b5SBram Moolenaar pD2D1CreateFactory = NULL; 1155b5a7a8b5SBram Moolenaar pDWriteCreateFactory = NULL; 1156b5a7a8b5SBram Moolenaar unload(hDWriteDLL); 1157b5a7a8b5SBram Moolenaar unload(hD2D1DLL); 1158b5a7a8b5SBram Moolenaar #endif 1159b5a7a8b5SBram Moolenaar } 1160b5a7a8b5SBram Moolenaar 1161b5a7a8b5SBram Moolenaar DWriteContext * 1162b5a7a8b5SBram Moolenaar DWriteContext_Open(void) 1163b5a7a8b5SBram Moolenaar { 1164b5a7a8b5SBram Moolenaar #ifdef DYNAMIC_DIRECTX 1165b5a7a8b5SBram Moolenaar if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL 1166b5a7a8b5SBram Moolenaar || pDWriteCreateFactory == NULL) 1167b5a7a8b5SBram Moolenaar return NULL; 1168b5a7a8b5SBram Moolenaar #endif 1169b5a7a8b5SBram Moolenaar return new DWriteContext(); 1170b5a7a8b5SBram Moolenaar } 1171b5a7a8b5SBram Moolenaar 1172b5a7a8b5SBram Moolenaar void 1173*92467d33SBram Moolenaar DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect) 1174b5a7a8b5SBram Moolenaar { 1175d7ccc4d8SBram Moolenaar if (ctx != NULL) 1176d7ccc4d8SBram Moolenaar ctx->BindDC(hdc, rect); 1177b5a7a8b5SBram Moolenaar } 1178b5a7a8b5SBram Moolenaar 1179b5a7a8b5SBram Moolenaar void 1180b5a7a8b5SBram Moolenaar DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont) 1181b5a7a8b5SBram Moolenaar { 1182b5a7a8b5SBram Moolenaar if (ctx != NULL) 1183b5a7a8b5SBram Moolenaar ctx->SetFont(hFont); 1184b5a7a8b5SBram Moolenaar } 1185b5a7a8b5SBram Moolenaar 1186b5a7a8b5SBram Moolenaar void 1187b5a7a8b5SBram Moolenaar DWriteContext_DrawText( 1188b5a7a8b5SBram Moolenaar DWriteContext *ctx, 1189b5a7a8b5SBram Moolenaar const WCHAR *text, 1190b5a7a8b5SBram Moolenaar int len, 1191b5a7a8b5SBram Moolenaar int x, 1192b5a7a8b5SBram Moolenaar int y, 1193b5a7a8b5SBram Moolenaar int w, 1194b5a7a8b5SBram Moolenaar int h, 1195b5a7a8b5SBram Moolenaar int cellWidth, 1196d7ccc4d8SBram Moolenaar COLORREF color, 1197d7ccc4d8SBram Moolenaar UINT fuOptions, 1198*92467d33SBram Moolenaar const RECT *lprc, 1199*92467d33SBram Moolenaar const INT *lpDx) 1200b5a7a8b5SBram Moolenaar { 1201b5a7a8b5SBram Moolenaar if (ctx != NULL) 1202d7ccc4d8SBram Moolenaar ctx->DrawText(text, len, x, y, w, h, cellWidth, color, 1203d7ccc4d8SBram Moolenaar fuOptions, lprc, lpDx); 1204b5a7a8b5SBram Moolenaar } 1205b5a7a8b5SBram Moolenaar 1206b5a7a8b5SBram Moolenaar void 1207*92467d33SBram Moolenaar DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color) 1208b5a7a8b5SBram Moolenaar { 1209d7ccc4d8SBram Moolenaar if (ctx != NULL) 1210d7ccc4d8SBram Moolenaar ctx->FillRect(rc, color); 1211b5a7a8b5SBram Moolenaar } 1212d7ccc4d8SBram Moolenaar 1213d7ccc4d8SBram Moolenaar void 1214*92467d33SBram Moolenaar DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2, 1215*92467d33SBram Moolenaar COLORREF color) 1216*92467d33SBram Moolenaar { 1217*92467d33SBram Moolenaar if (ctx != NULL) 1218*92467d33SBram Moolenaar ctx->DrawLine(x1, y1, x2, y2, color); 1219*92467d33SBram Moolenaar } 1220*92467d33SBram Moolenaar 1221*92467d33SBram Moolenaar void 1222*92467d33SBram Moolenaar DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color) 1223*92467d33SBram Moolenaar { 1224*92467d33SBram Moolenaar if (ctx != NULL) 1225*92467d33SBram Moolenaar ctx->SetPixel(x, y, color); 1226*92467d33SBram Moolenaar } 1227*92467d33SBram Moolenaar 1228*92467d33SBram Moolenaar void 1229d7ccc4d8SBram Moolenaar DWriteContext_Flush(DWriteContext *ctx) 1230d7ccc4d8SBram Moolenaar { 1231d7ccc4d8SBram Moolenaar if (ctx != NULL) 1232d7ccc4d8SBram Moolenaar ctx->Flush(); 1233b5a7a8b5SBram Moolenaar } 1234b5a7a8b5SBram Moolenaar 1235b5a7a8b5SBram Moolenaar void 1236b5a7a8b5SBram Moolenaar DWriteContext_Close(DWriteContext *ctx) 1237b5a7a8b5SBram Moolenaar { 1238b5a7a8b5SBram Moolenaar delete ctx; 1239b5a7a8b5SBram Moolenaar } 1240b5a7a8b5SBram Moolenaar 1241b5a7a8b5SBram Moolenaar void 1242b5a7a8b5SBram Moolenaar DWriteContext_SetRenderingParams( 1243b5a7a8b5SBram Moolenaar DWriteContext *ctx, 1244b5a7a8b5SBram Moolenaar const DWriteRenderingParams *params) 1245b5a7a8b5SBram Moolenaar { 1246b5a7a8b5SBram Moolenaar if (ctx != NULL) 1247b5a7a8b5SBram Moolenaar ctx->SetRenderingParams(params); 1248b5a7a8b5SBram Moolenaar } 1249b5a7a8b5SBram Moolenaar 1250b5a7a8b5SBram Moolenaar DWriteRenderingParams * 1251b5a7a8b5SBram Moolenaar DWriteContext_GetRenderingParams( 1252b5a7a8b5SBram Moolenaar DWriteContext *ctx, 1253b5a7a8b5SBram Moolenaar DWriteRenderingParams *params) 1254b5a7a8b5SBram Moolenaar { 1255b5a7a8b5SBram Moolenaar if (ctx != NULL) 1256b5a7a8b5SBram Moolenaar return ctx->GetRenderingParams(params); 1257b5a7a8b5SBram Moolenaar else 1258b5a7a8b5SBram Moolenaar return NULL; 1259b5a7a8b5SBram Moolenaar } 1260