diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-04 12:41:27 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-04 12:41:27 +0300 |
| commit | 4f2d36194b4f299aa7509d815c07121039ea833b (patch) | |
| tree | f3ded014bad3a4c76ff6a22b8726ebaab68c3d13 /uvim/src/gui_dwrite.cpp | |
| parent | 5b578e70c314723a3cde5c9bfc2be0bf1dadc93b (diff) | |
| download | Project-Tick-4f2d36194b4f299aa7509d815c07121039ea833b.tar.gz Project-Tick-4f2d36194b4f299aa7509d815c07121039ea833b.zip | |
NOISSUE change uvim folder name to mnv
Signed-off-by: Mehmet Samet Duman <yongdohyun@projecttick.org>
Diffstat (limited to 'uvim/src/gui_dwrite.cpp')
| -rw-r--r-- | uvim/src/gui_dwrite.cpp | 1415 |
1 files changed, 0 insertions, 1415 deletions
diff --git a/uvim/src/gui_dwrite.cpp b/uvim/src/gui_dwrite.cpp deleted file mode 100644 index 7135365813..0000000000 --- a/uvim/src/gui_dwrite.cpp +++ /dev/null @@ -1,1415 +0,0 @@ -/* vi:set ts=8 sts=4 sw=4 noet: */ -/* - * Author: MURAOKA Taro <koron.kaoriya@gmail.com> - * - * Contributors: - * - Ken Takata - * - Yasuhiro Matsumoto - * - * Copyright (C) 2013 MURAOKA Taro <koron.kaoriya@gmail.com> - * THIS FILE IS DISTRIBUTED UNDER THE MNV LICENSE. - */ - -#define WIN32_LEAN_AND_MEAN - -#ifndef DYNAMIC_DIRECTX -# if WINVER < 0x0600 -# error WINVER must be 0x0600 or above to use DirectWrite(DirectX) -# endif -#endif - -#include <windows.h> -#include <crtdbg.h> -#include <assert.h> -#include <math.h> -#include <d2d1.h> -#include <d2d1helper.h> - -// Disable these macros to compile with old VC and newer SDK (V8.1 or later). -#if defined(_MSC_VER) && (_MSC_VER < 1700) -# define _COM_Outptr_ __out -# define _In_reads_(s) -# define _In_reads_opt_(s) -# define _Maybenull_ -# define _Out_writes_(s) -# define _Out_writes_opt_(s) -# define _Out_writes_to_(x, y) -# define _Out_writes_to_opt_(x, y) -# define _Outptr_ -#endif - -#ifdef FEAT_DIRECTX_COLOR_EMOJI -# include <dwrite_2.h> -#else -# include <dwrite.h> -#endif - -#include "gui_dwrite.h" - -#ifdef __MINGW32__ -# define __maybenull SAL__maybenull -# define __in SAL__in -# define __out SAL__out -#endif - -#ifdef __MINGW32__ -# define UNUSED __attribute__((unused)) -#else -# define UNUSED -#endif - -#if (defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L) -# define FINAL final -#else -# define FINAL -#endif - -#ifdef DYNAMIC_DIRECTX -extern "C" HINSTANCE mnvLoadLib(const char *name); - -typedef int (WINAPI *PGETUSERDEFAULTLOCALENAME)(LPWSTR, int); -typedef HRESULT (WINAPI *PD2D1CREATEFACTORY)(D2D1_FACTORY_TYPE, - REFIID, const D2D1_FACTORY_OPTIONS *, void **); -typedef HRESULT (WINAPI *PDWRITECREATEFACTORY)(DWRITE_FACTORY_TYPE, - REFIID, IUnknown **); - -static HINSTANCE hD2D1DLL = NULL; -static HINSTANCE hDWriteDLL = NULL; - -static PGETUSERDEFAULTLOCALENAME pGetUserDefaultLocaleName = NULL; -static PD2D1CREATEFACTORY pD2D1CreateFactory = NULL; -static PDWRITECREATEFACTORY pDWriteCreateFactory = NULL; - -#define GetUserDefaultLocaleName (*pGetUserDefaultLocaleName) -#define D2D1CreateFactory (*pD2D1CreateFactory) -#define DWriteCreateFactory (*pDWriteCreateFactory) - - static void -unload(HINSTANCE &hinst) -{ - if (hinst != NULL) - { - FreeLibrary(hinst); - hinst = NULL; - } -} -#endif // DYNAMIC_DIRECTX - -template <class T> inline void SafeRelease(T **ppT) -{ - if (*ppT) - { - (*ppT)->Release(); - *ppT = NULL; - } -} - - static DWRITE_PIXEL_GEOMETRY -ToPixelGeometry(int value) -{ - switch (value) - { - default: - case 0: - return DWRITE_PIXEL_GEOMETRY_FLAT; - case 1: - return DWRITE_PIXEL_GEOMETRY_RGB; - case 2: - return DWRITE_PIXEL_GEOMETRY_BGR; - } -} - - static int -ToInt(DWRITE_PIXEL_GEOMETRY value) -{ - switch (value) - { - case DWRITE_PIXEL_GEOMETRY_FLAT: - return 0; - case DWRITE_PIXEL_GEOMETRY_RGB: - return 1; - case DWRITE_PIXEL_GEOMETRY_BGR: - return 2; - default: - return -1; - } -} - - static DWRITE_RENDERING_MODE -ToRenderingMode(int value) -{ - switch (value) - { - default: - case 0: - return DWRITE_RENDERING_MODE_DEFAULT; - case 1: - return DWRITE_RENDERING_MODE_ALIASED; - case 2: - return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; - case 3: - return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL; - case 4: - return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; - case 5: - return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; - case 6: - return DWRITE_RENDERING_MODE_OUTLINE; - } -} - - static D2D1_TEXT_ANTIALIAS_MODE -ToTextAntialiasMode(int value) -{ - switch (value) - { - default: - case 0: - return D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; - case 1: - return D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; - case 2: - return D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; - case 3: - return D2D1_TEXT_ANTIALIAS_MODE_ALIASED; - } -} - - static int -ToInt(DWRITE_RENDERING_MODE value) -{ - switch (value) - { - case DWRITE_RENDERING_MODE_DEFAULT: - return 0; - case DWRITE_RENDERING_MODE_ALIASED: - return 1; - case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC: - return 2; - case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL: - return 3; - case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL: - return 4; - case DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC: - return 5; - case DWRITE_RENDERING_MODE_OUTLINE: - return 6; - default: - return -1; - } -} - -class FontCache { -public: - struct Item { - HFONT hFont; - IDWriteTextFormat* pTextFormat; - DWRITE_FONT_WEIGHT fontWeight; - DWRITE_FONT_STYLE fontStyle; - FLOAT fontAscent; - Item() : hFont(NULL), pTextFormat(NULL), fontAscent(0.0f) {} - }; - -private: - int mSize; - Item *mItems; - -public: - FontCache(int size = 2) : - mSize(size), - mItems(new Item[size]) - { - } - - ~FontCache() - { - for (int i = 0; i < mSize; ++i) - SafeRelease(&mItems[i].pTextFormat); - delete[] mItems; - } - - bool get(HFONT hFont, Item &item) - { - int n = find(hFont); - if (n < 0) - return false; - item = mItems[n]; - slide(n); - return true; - } - - void put(const Item& item) - { - int n = find(item.hFont); - if (n < 0) - n = mSize - 1; - if (mItems[n].pTextFormat != item.pTextFormat) - { - SafeRelease(&mItems[n].pTextFormat); - if (item.pTextFormat != NULL) - item.pTextFormat->AddRef(); - } - mItems[n] = item; - slide(n); - } - -private: - int find(HFONT hFont) - { - for (int i = 0; i < mSize; ++i) - { - if (mItems[i].hFont == hFont) - return i; - } - return -1; - } - - void slide(int nextTop) - { - if (nextTop == 0) - return; - Item tmp = mItems[nextTop]; - for (int i = nextTop - 1; i >= 0; --i) - mItems[i + 1] = mItems[i]; - mItems[0] = tmp; - } -}; - -enum DrawingMode { - DM_GDI = 0, - DM_DIRECTX = 1, - DM_INTEROP = 2, -}; - -struct DWriteContext { - HDC mHDC; - RECT mBindRect; - DrawingMode mDMode; - HDC mInteropHDC; - bool mDrawing; - bool mFallbackDC; - - ID2D1Factory *mD2D1Factory; - - ID2D1DCRenderTarget *mRT; - ID2D1GdiInteropRenderTarget *mGDIRT; - ID2D1SolidColorBrush *mBrush; - ID2D1Bitmap *mBitmap; - - IDWriteFactory *mDWriteFactory; -#ifdef FEAT_DIRECTX_COLOR_EMOJI - IDWriteFactory2 *mDWriteFactory2; -#endif - - IDWriteGdiInterop *mGdiInterop; - IDWriteRenderingParams *mRenderingParams; - - FontCache mFontCache; - IDWriteTextFormat *mTextFormat; - DWRITE_FONT_WEIGHT mFontWeight; - DWRITE_FONT_STYLE mFontStyle; - FLOAT mFontSize; // Font size in pixels (em height) - FLOAT mFontAscent; // Font ascent in pixels - - D2D1_TEXT_ANTIALIAS_MODE mTextAntialiasMode; - - // METHODS - - DWriteContext(); - - virtual ~DWriteContext(); - - HRESULT CreateDeviceResources(); - - void DiscardDeviceResources(); - - HRESULT CreateTextFormatFromLOGFONT(const LOGFONTW &logFont, - IDWriteTextFormat **ppTextFormat, FLOAT *pFontAscent); - - HRESULT SetFontByLOGFONT(const LOGFONTW &logFont); - - void SetFont(HFONT hFont); - - void Rebind(); - - void BindDC(HDC hdc, const RECT *rect); - - HRESULT SetDrawingMode(DrawingMode mode); - - ID2D1Brush* SolidBrush(COLORREF color); - - void DrawText(const WCHAR *text, int len, - int x, int y, int w, int h, int cellWidth, COLORREF color, - UINT fuOptions, const RECT *lprc, const INT *lpDx); - - void FillRect(const RECT *rc, COLORREF color); - - void DrawLine(int x1, int y1, int x2, int y2, COLORREF color); - - void SetPixel(int x, int y, COLORREF color); - - void Scroll(int x, int y, const RECT *rc); - - void Flush(); - - void SetRenderingParams( - const DWriteRenderingParams *params); - - DWriteRenderingParams *GetRenderingParams( - DWriteRenderingParams *params); -}; - -class AdjustedGlyphRun : public DWRITE_GLYPH_RUN -{ -private: - FLOAT &mAccum; - FLOAT mDelta; - FLOAT *mAdjustedAdvances; - -public: - AdjustedGlyphRun( - const DWRITE_GLYPH_RUN *glyphRun, - FLOAT cellWidth, - FLOAT &accum, - const INT *lpDx, - int *glyphIndex, - int cchText) : - DWRITE_GLYPH_RUN(*glyphRun), - mAccum(accum), - mDelta(0.0f), - mAdjustedAdvances(new FLOAT[glyphRun->glyphCount]) - { - assert(cellWidth != 0.0f); - for (UINT32 i = 0; i < glyphRun->glyphCount; ++i) - { - FLOAT orig = glyphRun->glyphAdvances[i]; - FLOAT adjusted; - - if (*glyphIndex < cchText) - { - adjusted = FLOAT(lpDx[*glyphIndex]); - (*glyphIndex)++; - } - else - { - adjusted = adjustToCell(orig, cellWidth); - } - - mAdjustedAdvances[i] = adjusted; - mDelta += adjusted - orig; - } - glyphAdvances = mAdjustedAdvances; - } - - ~AdjustedGlyphRun() - { - mAccum += mDelta; - delete[] mAdjustedAdvances; - } - - static FLOAT adjustToCell(FLOAT value, FLOAT cellWidth) - { - int cellCount = int(floor(value / cellWidth + 0.5f)); - if (cellCount < 1) - cellCount = 1; - return cellCount * cellWidth; - } -}; - -struct TextRendererContext { - // const fields. - COLORREF color; - FLOAT cellWidth; - const INT *lpDx; - int cchText; - FLOAT baselineY; // Fixed baseline Y coordinate - - // working fields. - FLOAT offsetX; - int glyphIndex; -}; - -class TextRenderer FINAL : public IDWriteTextRenderer -{ -public: - TextRenderer( - DWriteContext* pDWC) : - cRefCount_(0), - pDWC_(pDWC) - { - AddRef(); - } - - // add "virtual" to avoid a compiler warning - virtual ~TextRenderer() - { - } - - IFACEMETHOD(IsPixelSnappingDisabled)( - __maybenull void* clientDrawingContext UNUSED, - __out BOOL* isDisabled) - { - *isDisabled = FALSE; - return S_OK; - } - - IFACEMETHOD(GetCurrentTransform)( - __maybenull void* clientDrawingContext UNUSED, - __out DWRITE_MATRIX* transform) - { - // forward the render target's transform - pDWC_->mRT->GetTransform( - reinterpret_cast<D2D1_MATRIX_3X2_F*>(transform)); - return S_OK; - } - - IFACEMETHOD(GetPixelsPerDip)( - __maybenull void* clientDrawingContext UNUSED, - __out FLOAT* pixelsPerDip) - { - float dpiX, unused; - pDWC_->mRT->GetDpi(&dpiX, &unused); - *pixelsPerDip = dpiX / 96.0f; - return S_OK; - } - - IFACEMETHOD(DrawUnderline)( - __maybenull void* clientDrawingContext UNUSED, - FLOAT baselineOriginX UNUSED, - FLOAT baselineOriginY UNUSED, - __in DWRITE_UNDERLINE const* underline UNUSED, - IUnknown* clientDrawingEffect UNUSED) - { - return E_NOTIMPL; - } - - IFACEMETHOD(DrawStrikethrough)( - __maybenull void* clientDrawingContext UNUSED, - FLOAT baselineOriginX UNUSED, - FLOAT baselineOriginY UNUSED, - __in DWRITE_STRIKETHROUGH const* strikethrough UNUSED, - IUnknown* clientDrawingEffect UNUSED) - { - return E_NOTIMPL; - } - - IFACEMETHOD(DrawInlineObject)( - __maybenull void* clientDrawingContext UNUSED, - FLOAT originX UNUSED, - FLOAT originY UNUSED, - IDWriteInlineObject* inlineObject UNUSED, - BOOL isSideways UNUSED, - BOOL isRightToLeft UNUSED, - IUnknown* clientDrawingEffect UNUSED) - { - return E_NOTIMPL; - } - - IFACEMETHOD(DrawGlyphRun)( - __maybenull void* clientDrawingContext, - FLOAT baselineOriginX, - FLOAT baselineOriginY, - DWRITE_MEASURING_MODE measuringMode UNUSED, - __in DWRITE_GLYPH_RUN const* glyphRun, - __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription UNUSED, - IUnknown* clientDrawingEffect UNUSED) - { - TextRendererContext *context = - reinterpret_cast<TextRendererContext*>(clientDrawingContext); - - // Use fixed baseline Y from context instead of DirectWrite's - // baselineOriginY to prevent vertical shifts when font fallback - // occurs (e.g., for CJK characters). - FLOAT fixedBaselineY = context->baselineY; - - AdjustedGlyphRun adjustedGlyphRun(glyphRun, context->cellWidth, - context->offsetX, context->lpDx, &context->glyphIndex, - context->cchText); - -#ifdef FEAT_DIRECTX_COLOR_EMOJI - if (pDWC_->mDWriteFactory2 != NULL) - { - IDWriteColorGlyphRunEnumerator *enumerator = NULL; - HRESULT hr = pDWC_->mDWriteFactory2->TranslateColorGlyphRun( - baselineOriginX + context->offsetX, - baselineOriginY, - &adjustedGlyphRun, - NULL, - DWRITE_MEASURING_MODE_GDI_NATURAL, - NULL, - 0, - &enumerator); - if (SUCCEEDED(hr)) - { - // Draw by IDWriteFactory2 for color emoji - BOOL hasRun = TRUE; - enumerator->MoveNext(&hasRun); - while (hasRun) - { - const DWRITE_COLOR_GLYPH_RUN* colorGlyphRun; - enumerator->GetCurrentRun(&colorGlyphRun); - - pDWC_->mBrush->SetColor(colorGlyphRun->runColor); - pDWC_->mRT->DrawGlyphRun( - D2D1::Point2F( - colorGlyphRun->baselineOriginX, - fixedBaselineY), - &colorGlyphRun->glyphRun, - pDWC_->mBrush, - DWRITE_MEASURING_MODE_NATURAL); - enumerator->MoveNext(&hasRun); - } - SafeRelease(&enumerator); - return S_OK; - } - } -#endif - - // Draw by IDWriteFactory (without color emoji) - pDWC_->mRT->DrawGlyphRun( - D2D1::Point2F( - baselineOriginX + context->offsetX, - fixedBaselineY), - &adjustedGlyphRun, - pDWC_->SolidBrush(context->color), - DWRITE_MEASURING_MODE_NATURAL); - return S_OK; - } - -public: - IFACEMETHOD_(unsigned long, AddRef) () - { - return InterlockedIncrement(&cRefCount_); - } - - IFACEMETHOD_(unsigned long, Release) () - { - long newCount = InterlockedDecrement(&cRefCount_); - - if (newCount == 0) - { - delete this; - return 0; - } - return newCount; - } - - IFACEMETHOD(QueryInterface)( - IID const& riid, - void** ppvObject) - { - if (__uuidof(IDWriteTextRenderer) == riid) - { - *ppvObject = this; - } - else if (__uuidof(IDWritePixelSnapping) == riid) - { - *ppvObject = this; - } - else if (__uuidof(IUnknown) == riid) - { - *ppvObject = this; - } - else - { - *ppvObject = NULL; - return E_FAIL; - } - - return S_OK; - } - -private: - long cRefCount_; - DWriteContext* pDWC_; -}; - -DWriteContext::DWriteContext() : - mHDC(NULL), - mBindRect(), - mDMode(DM_GDI), - mInteropHDC(NULL), - mDrawing(false), - mFallbackDC(false), - mD2D1Factory(NULL), - mRT(NULL), - mGDIRT(NULL), - mBrush(NULL), - mBitmap(NULL), - mDWriteFactory(NULL), -#ifdef FEAT_DIRECTX_COLOR_EMOJI - mDWriteFactory2(NULL), -#endif - mGdiInterop(NULL), - mRenderingParams(NULL), - mFontCache(8), - mTextFormat(NULL), - mFontWeight(DWRITE_FONT_WEIGHT_NORMAL), - mFontStyle(DWRITE_FONT_STYLE_NORMAL), - mFontSize(0.0f), - mFontAscent(0.0f), - mTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_DEFAULT) -{ - HRESULT hr; - - hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, - __uuidof(ID2D1Factory), NULL, - reinterpret_cast<void**>(&mD2D1Factory)); - _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory); - - if (SUCCEEDED(hr)) - { - hr = DWriteCreateFactory( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast<IUnknown**>(&mDWriteFactory)); - _RPT2(_CRT_WARN, "DWriteCreateFactory: hr=%p p=%p\n", hr, - mDWriteFactory); - } - -#ifdef FEAT_DIRECTX_COLOR_EMOJI - if (SUCCEEDED(hr)) - { - DWriteCreateFactory( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory2), - reinterpret_cast<IUnknown**>(&mDWriteFactory2)); - _RPT1(_CRT_WARN, "IDWriteFactory2: %s\n", SUCCEEDED(hr) ? "available" : "not available"); - } -#endif - - if (SUCCEEDED(hr)) - { - hr = mDWriteFactory->GetGdiInterop(&mGdiInterop); - _RPT2(_CRT_WARN, "GetGdiInterop: hr=%p p=%p\n", hr, mGdiInterop); - } - - if (SUCCEEDED(hr)) - { - hr = mDWriteFactory->CreateRenderingParams(&mRenderingParams); - _RPT2(_CRT_WARN, "CreateRenderingParams: hr=%p p=%p\n", hr, - mRenderingParams); - } -} - -DWriteContext::~DWriteContext() -{ - SafeRelease(&mTextFormat); - SafeRelease(&mRenderingParams); - SafeRelease(&mGdiInterop); - SafeRelease(&mDWriteFactory); -#ifdef FEAT_DIRECTX_COLOR_EMOJI - SafeRelease(&mDWriteFactory2); -#endif - SafeRelease(&mBitmap); - SafeRelease(&mBrush); - SafeRelease(&mGDIRT); - SafeRelease(&mRT); - SafeRelease(&mD2D1Factory); -} - - HRESULT -DWriteContext::CreateDeviceResources() -{ - HRESULT hr; - - if (mRT != NULL) - return S_OK; - - D2D1_RENDER_TARGET_PROPERTIES props = { - D2D1_RENDER_TARGET_TYPE_DEFAULT, - { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE }, - 0, 0, - D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE, - D2D1_FEATURE_LEVEL_DEFAULT - }; - hr = mD2D1Factory->CreateDCRenderTarget(&props, &mRT); - _RPT2(_CRT_WARN, "CreateDCRenderTarget: hr=%p p=%p\n", hr, mRT); - - if (SUCCEEDED(hr)) - { - // This always succeeds. - mRT->QueryInterface( - __uuidof(ID2D1GdiInteropRenderTarget), - reinterpret_cast<void**>(&mGDIRT)); - _RPT1(_CRT_WARN, "GdiInteropRenderTarget: p=%p\n", mGDIRT); - } - - if (SUCCEEDED(hr)) - { - hr = mRT->CreateSolidColorBrush( - D2D1::ColorF(D2D1::ColorF::Black), - &mBrush); - _RPT2(_CRT_WARN, "CreateSolidColorBrush: hr=%p p=%p\n", hr, mBrush); - } - - if (SUCCEEDED(hr)) - Rebind(); - - return hr; -} - - void -DWriteContext::DiscardDeviceResources() -{ - SafeRelease(&mBitmap); - SafeRelease(&mBrush); - SafeRelease(&mGDIRT); - SafeRelease(&mRT); -} - - HRESULT -DWriteContext::CreateTextFormatFromLOGFONT(const LOGFONTW &logFont, - IDWriteTextFormat **ppTextFormat, FLOAT *pFontAscent) -{ - // Most of this function is copied from: https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/RenderTest/TextHelpers.cpp - HRESULT hr = S_OK; - IDWriteTextFormat *pTextFormat = NULL; - - IDWriteFont *font = NULL; - IDWriteFontFamily *fontFamily = NULL; - IDWriteLocalizedStrings *localizedFamilyNames = NULL; - float fontSize = 0; - DWRITE_FONT_METRICS fontMetrics = {}; - - if (SUCCEEDED(hr)) - { - hr = mGdiInterop->CreateFontFromLOGFONT(&logFont, &font); - } - - // Get the font family to which this font belongs. - if (SUCCEEDED(hr)) - { - hr = font->GetFontFamily(&fontFamily); - } - - // Get the family names. This returns an object that encapsulates one or - // more names with the same meaning but in different languages. - if (SUCCEEDED(hr)) - { - hr = fontFamily->GetFamilyNames(&localizedFamilyNames); - } - - // Get the family name at index zero. If we were going to display the name - // we'd want to try to find one that matched the use locale, but for - // purposes of creating a text format object any language will do. - - wchar_t familyName[100]; - if (SUCCEEDED(hr)) - { - hr = localizedFamilyNames->GetString(0, familyName, - ARRAYSIZE(familyName)); - } - - if (SUCCEEDED(hr)) - { - // Use lfHeight of the LOGFONT as font size. - fontSize = float(logFont.lfHeight); - - font->GetMetrics(&fontMetrics); - - // Convert lfHeight to DirectWrite font size - if (fontSize < 0) - { - // Negative lfHeight represents the font's em height in pixels - fontSize = -fontSize; - } - else if (fontSize > 0) - { - // Positive lfHeight represents the font's cell height (ascent + descent) - // Convert to em height - fontSize = fontSize * float(fontMetrics.designUnitsPerEm) - / float(fontMetrics.ascent + fontMetrics.descent + fontMetrics.lineGap); - } - } - - // The text format includes a locale name. Ideally, this would be the - // language of the text, which may or may not be the same as the primary - // language of the user. However, for our purposes the user locale will do. - wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; - if (SUCCEEDED(hr)) - { - if (GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH) == 0) - hr = HRESULT_FROM_WIN32(GetLastError()); - } - - if (SUCCEEDED(hr)) - { - // Create the text format object. - hr = mDWriteFactory->CreateTextFormat( - familyName, - NULL, // no custom font collection - font->GetWeight(), - font->GetStyle(), - font->GetStretch(), - fontSize, - localeName, - &pTextFormat); - } - - if (SUCCEEDED(hr)) - hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - - if (SUCCEEDED(hr)) - hr = pTextFormat->SetParagraphAlignment( - DWRITE_PARAGRAPH_ALIGNMENT_FAR); - - if (SUCCEEDED(hr)) - hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); - - SafeRelease(&localizedFamilyNames); - SafeRelease(&fontFamily); - SafeRelease(&font); - - if (SUCCEEDED(hr)) - { - *ppTextFormat = pTextFormat; - if (pFontAscent != NULL && fontMetrics.designUnitsPerEm != 0) - { - // Calculate ascent ratio (0.0 to 1.0) relative to total font height - FLOAT totalHeight = float(fontMetrics.ascent + fontMetrics.descent); - if (totalHeight != 0.0f) - *pFontAscent = float(fontMetrics.ascent) / totalHeight; - else - *pFontAscent = 0.83f; // fallback - } - } - else - SafeRelease(&pTextFormat); - - return hr; -} - - HRESULT -DWriteContext::SetFontByLOGFONT(const LOGFONTW &logFont) -{ - HRESULT hr = S_OK; - IDWriteTextFormat *pTextFormat = NULL; - FLOAT fontAscent = 0.0f; - - hr = CreateTextFormatFromLOGFONT(logFont, &pTextFormat, &fontAscent); - - if (SUCCEEDED(hr)) - { - SafeRelease(&mTextFormat); - mTextFormat = pTextFormat; - mFontWeight = static_cast<DWRITE_FONT_WEIGHT>(logFont.lfWeight); - mFontStyle = logFont.lfItalic ? DWRITE_FONT_STYLE_ITALIC - : DWRITE_FONT_STYLE_NORMAL; - mFontAscent = fontAscent; - } - - return hr; -} - - void -DWriteContext::SetFont(HFONT hFont) -{ - FontCache::Item item; - if (mFontCache.get(hFont, item)) - { - if (item.pTextFormat != NULL) - { - item.pTextFormat->AddRef(); - SafeRelease(&mTextFormat); - mTextFormat = item.pTextFormat; - mFontWeight = item.fontWeight; - mFontStyle = item.fontStyle; - mFontAscent = item.fontAscent; - mFallbackDC = false; - } - else - mFallbackDC = true; - return; - } - - HRESULT hr = E_FAIL; - LOGFONTW lf; - if (GetObjectW(hFont, sizeof(lf), &lf)) - hr = SetFontByLOGFONT(lf); - - item.hFont = hFont; - if (SUCCEEDED(hr)) - { - item.pTextFormat = mTextFormat; - item.fontWeight = mFontWeight; - item.fontStyle = mFontStyle; - item.fontAscent = mFontAscent; - mFallbackDC = false; - } - else - mFallbackDC = true; - mFontCache.put(item); -} - - void -DWriteContext::Rebind() -{ - SafeRelease(&mBitmap); - - mRT->BindDC(mHDC, &mBindRect); - mRT->SetTransform(D2D1::IdentityMatrix()); - - D2D1_BITMAP_PROPERTIES props = { - {DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE}, - 96.0f, 96.0f - }; - mRT->CreateBitmap( - D2D1::SizeU(mBindRect.right - mBindRect.left, - mBindRect.bottom - mBindRect.top), - props, &mBitmap); -} - - void -DWriteContext::BindDC(HDC hdc, const RECT *rect) -{ - mHDC = hdc; - mBindRect = *rect; - - if (mRT == NULL) - CreateDeviceResources(); - else - { - Flush(); - Rebind(); - } -} - -extern "C" void redraw_later_clear(void); - - HRESULT -DWriteContext::SetDrawingMode(DrawingMode mode) -{ - HRESULT hr = S_OK; - - switch (mode) - { - default: - case DM_GDI: - if (mInteropHDC != NULL) - { - mGDIRT->ReleaseDC(NULL); - mInteropHDC = NULL; - } - if (mDrawing) - { - hr = mRT->EndDraw(); - if (hr == (HRESULT)D2DERR_RECREATE_TARGET) - { - hr = S_OK; - DiscardDeviceResources(); - CreateDeviceResources(); - redraw_later_clear(); - } - mDrawing = false; - } - break; - - case DM_DIRECTX: - if (mInteropHDC != NULL) - { - mGDIRT->ReleaseDC(NULL); - mInteropHDC = NULL; - } - else if (mDrawing == false) - { - CreateDeviceResources(); - mRT->BeginDraw(); - mDrawing = true; - } - break; - - case DM_INTEROP: - if (mDrawing == false) - { - CreateDeviceResources(); - mRT->BeginDraw(); - mDrawing = true; - } - if (mInteropHDC == NULL) - hr = mGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &mInteropHDC); - break; - } - mDMode = mode; - return hr; -} - - ID2D1Brush* -DWriteContext::SolidBrush(COLORREF color) -{ - mBrush->SetColor(D2D1::ColorF(UINT32(GetRValue(color)) << 16 | - UINT32(GetGValue(color)) << 8 | UINT32(GetBValue(color)))); - return mBrush; -} - - void -DWriteContext::DrawText(const WCHAR *text, int len, - int x, int y, int w, int h, int cellWidth, COLORREF color, - UINT fuOptions, const RECT *lprc, const INT *lpDx) -{ - if (mFallbackDC) - { - // Fall back to GDI rendering. - HRESULT hr = SetDrawingMode(DM_INTEROP); - if (SUCCEEDED(hr)) - { - HGDIOBJ hFont = ::GetCurrentObject(mHDC, OBJ_FONT); - HGDIOBJ hOldFont = ::SelectObject(mInteropHDC, hFont); - ::SetTextColor(mInteropHDC, color); - ::SetBkMode(mInteropHDC, ::GetBkMode(mHDC)); - ::ExtTextOutW(mInteropHDC, x, y, fuOptions, lprc, text, len, lpDx); - ::SelectObject(mInteropHDC, hOldFont); - } - return; - } - - HRESULT hr; - IDWriteTextLayout *textLayout = NULL; - - SetDrawingMode(DM_DIRECTX); - - // Apply clipping if ETO_CLIPPED is specified - if ((fuOptions & ETO_CLIPPED) && lprc != NULL) - { - mRT->PushAxisAlignedClip( - D2D1::RectF(FLOAT(lprc->left), FLOAT(lprc->top), - FLOAT(lprc->right), FLOAT(lprc->bottom)), - D2D1_ANTIALIAS_MODE_ALIASED); - } - - hr = mDWriteFactory->CreateTextLayout(text, len, mTextFormat, - FLOAT(w), FLOAT(h), &textLayout); - - if (SUCCEEDED(hr)) - { - DWRITE_TEXT_RANGE textRange = { 0, UINT32(len) }; - textLayout->SetFontWeight(mFontWeight, textRange); - textLayout->SetFontStyle(mFontStyle, textRange); - - // Calculate baseline using font ascent from font metrics. - // Do NOT use GetLineMetrics() because it returns different values - // depending on text content (e.g., when CJK characters trigger - // font fallback, the metrics change). - // Use the pre-calculated font ascent for all text to prevent - // vertical shifts during redraw. - FLOAT baselineY = roundf(FLOAT(y) + FLOAT(h) * mFontAscent + 0.5); - - TextRenderer renderer(this); - TextRendererContext context = { color, FLOAT(cellWidth), lpDx, len, - baselineY, 0.0f, 0 }; - - textLayout->Draw(&context, &renderer, FLOAT(x), FLOAT(y)); - } - - SafeRelease(&textLayout); - - if ((fuOptions & ETO_CLIPPED) && lprc != NULL) - mRT->PopAxisAlignedClip(); -} - - void -DWriteContext::FillRect(const RECT *rc, COLORREF color) -{ - if (mDMode == DM_INTEROP) - { - // GDI functions are used before this call. Keep using GDI. - // (Switching to Direct2D causes terrible slowdown.) - HBRUSH hbr = ::CreateSolidBrush(color); - ::FillRect(mInteropHDC, rc, hbr); - ::DeleteObject(HGDIOBJ(hbr)); - } - else - { - SetDrawingMode(DM_DIRECTX); - mRT->FillRectangle( - D2D1::RectF(FLOAT(rc->left), FLOAT(rc->top), - FLOAT(rc->right), FLOAT(rc->bottom)), - SolidBrush(color)); - } -} - - void -DWriteContext::DrawLine(int x1, int y1, int x2, int y2, COLORREF color) -{ - if (mDMode == DM_INTEROP) - { - // GDI functions are used before this call. Keep using GDI. - // (Switching to Direct2D causes terrible slowdown.) - HPEN hpen = ::CreatePen(PS_SOLID, 1, color); - HGDIOBJ old_pen = ::SelectObject(mInteropHDC, HGDIOBJ(hpen)); - ::MoveToEx(mInteropHDC, x1, y1, NULL); - ::LineTo(mInteropHDC, x2, y2); - ::SelectObject(mInteropHDC, old_pen); - ::DeleteObject(HGDIOBJ(hpen)); - } - else - { - SetDrawingMode(DM_DIRECTX); - mRT->DrawLine( - D2D1::Point2F(FLOAT(x1), FLOAT(y1) + 0.5f), - D2D1::Point2F(FLOAT(x2), FLOAT(y2) + 0.5f), - SolidBrush(color)); - } -} - - void -DWriteContext::SetPixel(int x, int y, COLORREF color) -{ - if (mDMode == DM_INTEROP) - { - // GDI functions are used before this call. Keep using GDI. - // (Switching to Direct2D causes terrible slowdown.) - ::SetPixel(mInteropHDC, x, y, color); - } - else - { - SetDrawingMode(DM_DIRECTX); - // Direct2D doesn't have SetPixel API. Use DrawLine instead. - mRT->DrawLine( - D2D1::Point2F(FLOAT(x), FLOAT(y) + 0.5f), - D2D1::Point2F(FLOAT(x+1), FLOAT(y) + 0.5f), - SolidBrush(color)); - } -} - - void -DWriteContext::Scroll(int x, int y, const RECT *rc) -{ - SetDrawingMode(DM_DIRECTX); - mRT->Flush(); - - D2D1_RECT_U srcRect; - D2D1_POINT_2U destPoint; - if (x >= 0) - { - srcRect.left = rc->left; - srcRect.right = rc->right - x; - destPoint.x = rc->left + x; - } - else - { - srcRect.left = rc->left - x; - srcRect.right = rc->right; - destPoint.x = rc->left; - } - if (y >= 0) - { - srcRect.top = rc->top; - srcRect.bottom = rc->bottom - y; - destPoint.y = rc->top + y; - } - else - { - srcRect.top = rc->top - y; - srcRect.bottom = rc->bottom; - destPoint.y = rc->top; - } - mBitmap->CopyFromRenderTarget(&destPoint, mRT, &srcRect); - - D2D1_RECT_F destRect = { - FLOAT(destPoint.x), FLOAT(destPoint.y), - FLOAT(destPoint.x + srcRect.right - srcRect.left), - FLOAT(destPoint.y + srcRect.bottom - srcRect.top) - }; - mRT->DrawBitmap(mBitmap, destRect, 1.0F, - D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, destRect); -} - - void -DWriteContext::Flush() -{ - SetDrawingMode(DM_GDI); -} - - void -DWriteContext::SetRenderingParams( - const DWriteRenderingParams *params) -{ - if (mDWriteFactory == NULL) - return; - - IDWriteRenderingParams *renderingParams = NULL; - D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode = - D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; - HRESULT hr; - if (params != NULL) - { - hr = mDWriteFactory->CreateCustomRenderingParams(params->gamma, - params->enhancedContrast, params->clearTypeLevel, - ToPixelGeometry(params->pixelGeometry), - ToRenderingMode(params->renderingMode), &renderingParams); - textAntialiasMode = ToTextAntialiasMode(params->textAntialiasMode); - } - else - hr = mDWriteFactory->CreateRenderingParams(&renderingParams); - if (SUCCEEDED(hr) && renderingParams != NULL) - { - SafeRelease(&mRenderingParams); - mRenderingParams = renderingParams; - mTextAntialiasMode = textAntialiasMode; - - Flush(); - mRT->SetTextRenderingParams(mRenderingParams); - mRT->SetTextAntialiasMode(mTextAntialiasMode); - } -} - - DWriteRenderingParams * -DWriteContext::GetRenderingParams( - DWriteRenderingParams *params) -{ - if (params != NULL && mRenderingParams != NULL) - { - params->gamma = mRenderingParams->GetGamma(); - params->enhancedContrast = mRenderingParams->GetEnhancedContrast(); - params->clearTypeLevel = mRenderingParams->GetClearTypeLevel(); - params->pixelGeometry = ToInt(mRenderingParams->GetPixelGeometry()); - params->renderingMode = ToInt(mRenderingParams->GetRenderingMode()); - params->textAntialiasMode = mTextAntialiasMode; - } - return params; -} - -//////////////////////////////////////////////////////////////////////////// -// PUBLIC C INTERFACES - - void -DWrite_Init(void) -{ -#ifdef DYNAMIC_DIRECTX - // Load libraries. - hD2D1DLL = mnvLoadLib("d2d1.dll"); - hDWriteDLL = mnvLoadLib("dwrite.dll"); - if (hD2D1DLL == NULL || hDWriteDLL == NULL) - { - DWrite_Final(); - return; - } - // Get address of procedures. - pGetUserDefaultLocaleName = (PGETUSERDEFAULTLOCALENAME)GetProcAddress( - GetModuleHandle("kernel32.dll"), "GetUserDefaultLocaleName"); - pD2D1CreateFactory = (PD2D1CREATEFACTORY)GetProcAddress(hD2D1DLL, - "D2D1CreateFactory"); - pDWriteCreateFactory = (PDWRITECREATEFACTORY)GetProcAddress(hDWriteDLL, - "DWriteCreateFactory"); -#endif -} - - void -DWrite_Final(void) -{ -#ifdef DYNAMIC_DIRECTX - pGetUserDefaultLocaleName = NULL; - pD2D1CreateFactory = NULL; - pDWriteCreateFactory = NULL; - unload(hDWriteDLL); - unload(hD2D1DLL); -#endif -} - - DWriteContext * -DWriteContext_Open(void) -{ -#ifdef DYNAMIC_DIRECTX - if (pGetUserDefaultLocaleName == NULL || pD2D1CreateFactory == NULL - || pDWriteCreateFactory == NULL) - return NULL; -#endif - return new DWriteContext(); -} - - void -DWriteContext_BindDC(DWriteContext *ctx, HDC hdc, const RECT *rect) -{ - if (ctx != NULL) - ctx->BindDC(hdc, rect); -} - - void -DWriteContext_SetFont(DWriteContext *ctx, HFONT hFont) -{ - if (ctx != NULL) - ctx->SetFont(hFont); -} - - void -DWriteContext_DrawText( - DWriteContext *ctx, - const WCHAR *text, - int len, - int x, - int y, - int w, - int h, - int cellWidth, - COLORREF color, - UINT fuOptions, - const RECT *lprc, - const INT *lpDx) -{ - if (ctx != NULL) - ctx->DrawText(text, len, x, y, w, h, cellWidth, color, - fuOptions, lprc, lpDx); -} - - void -DWriteContext_FillRect(DWriteContext *ctx, const RECT *rc, COLORREF color) -{ - if (ctx != NULL) - ctx->FillRect(rc, color); -} - - void -DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2, - COLORREF color) -{ - if (ctx != NULL) - ctx->DrawLine(x1, y1, x2, y2, color); -} - - void -DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color) -{ - if (ctx != NULL) - ctx->SetPixel(x, y, color); -} - - void -DWriteContext_Scroll(DWriteContext *ctx, int x, int y, const RECT *rc) -{ - if (ctx != NULL) - ctx->Scroll(x, y, rc); -} - - void -DWriteContext_Flush(DWriteContext *ctx) -{ - if (ctx != NULL) - ctx->Flush(); -} - - void -DWriteContext_Close(DWriteContext *ctx) -{ - delete ctx; -} - - void -DWriteContext_SetRenderingParams( - DWriteContext *ctx, - const DWriteRenderingParams *params) -{ - if (ctx != NULL) - ctx->SetRenderingParams(params); -} - - DWriteRenderingParams * -DWriteContext_GetRenderingParams( - DWriteContext *ctx, - DWriteRenderingParams *params) -{ - if (ctx != NULL) - return ctx->GetRenderingParams(params); - else - return NULL; -} |
