summaryrefslogtreecommitdiff
path: root/uvim/src/gui_dwrite.cpp
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-04 12:41:27 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-04 12:41:27 +0300
commit4f2d36194b4f299aa7509d815c07121039ea833b (patch)
treef3ded014bad3a4c76ff6a22b8726ebaab68c3d13 /uvim/src/gui_dwrite.cpp
parent5b578e70c314723a3cde5c9bfc2be0bf1dadc93b (diff)
downloadProject-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.cpp1415
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;
-}