This commit is contained in:
parent
e5b37cd5ba
commit
e37e0f661f
1 changed files with 202 additions and 106 deletions
|
|
@ -17,6 +17,15 @@
|
|||
#include "dwrite.h"
|
||||
#include "dwrite_3.h"
|
||||
|
||||
typedef struct CustomTextRenderer {
|
||||
IDWriteTextRendererVtbl *lpVtbl;
|
||||
LONG refCount;
|
||||
IDWriteFactory6 * write_factory;
|
||||
IDWriteBitmapRenderTarget * target;
|
||||
|
||||
} CustomTextRenderer;
|
||||
static CustomTextRenderer *CustomTextRenderer_Create(IDWriteFactory6 * write_factory, IDWriteBitmapRenderTarget * target);
|
||||
|
||||
static struct dw {
|
||||
HMODULE d2d1_lib;
|
||||
HMODULE dwrite_lib;
|
||||
|
|
@ -31,10 +40,7 @@ struct _MwFLFont {
|
|||
MwBool valid;
|
||||
|
||||
IDWriteFactory6* write_factory;
|
||||
IDWriteTextFormat* dTextFormat;
|
||||
ID2D1Factory* d2dFactory;
|
||||
ID2D1HwndRenderTarget* rt;
|
||||
ID2D1SolidColorBrush* blackBrush;
|
||||
IDWriteGdiInterop *gdiInterop;
|
||||
|
||||
IDWriteFontFile * file;
|
||||
|
|
@ -42,6 +48,8 @@ struct _MwFLFont {
|
|||
IDWriteFontSetBuilder2 * font_builder;
|
||||
IDWriteFontSet* font_set;
|
||||
IDWriteFontCollection1* font_collection;
|
||||
IDWriteTextFormat * text_format;
|
||||
IDWriteTextFormat * text_layout;
|
||||
|
||||
LOGFONTW logfont;
|
||||
HFONT font;
|
||||
|
|
@ -175,18 +183,23 @@ static void* dw_MwFontLoad(unsigned char* data, unsigned int size, int px) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
hr = IDWriteFactory6_GetGdiInterop(ttf->write_factory, &ttf->gdiInterop);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
printf("GetGdiInterop failed for TTF (%08lx), cannot use DirectWrite\n",hr);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
IDWriteGdiInterop_ConvertFontFaceToLOGFONT(ttf->gdiInterop, ttf->font_face, &ttf->logfont);
|
||||
hr = IDWriteFactory_CreateTextFormat(ttf->write_factory, L"milsko font", (IDWriteFontCollection*)ttf->font_collection, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, px, L"en-US", &ttf->text_format);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
printf("IDWriteGdiInterop_ConvertFontFaceToLOGFONT failed for TTF (%08lx), cannot use DirectWrite\n",hr);
|
||||
printf("IDWriteFactory_CreateTextFormat failed for TTF (%08lx), cannot use DirectWrite\n",hr);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ttf->valid = MwTRUE;
|
||||
return ttf;
|
||||
|
||||
|
|
@ -195,127 +208,44 @@ fail:
|
|||
return ttf;
|
||||
}
|
||||
|
||||
static UINT32 *str_to_codepoints(const char *str, UINT codePage, UINT32 *pCount)
|
||||
{
|
||||
int wideLen;
|
||||
WCHAR *wideBuf;
|
||||
UINT32 *codePoints;
|
||||
UINT32 count;
|
||||
int i;
|
||||
|
||||
if (pCount != NULL) {
|
||||
*pCount = 0;
|
||||
}
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Size query; result includes the terminating null. */
|
||||
wideLen = MultiByteToWideChar(codePage, 0, str, -1, NULL, 0);
|
||||
if (wideLen <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wideBuf = (WCHAR *)malloc((size_t)wideLen * sizeof(WCHAR));
|
||||
if (wideBuf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (MultiByteToWideChar(codePage, 0, str, -1, wideBuf, wideLen) == 0) {
|
||||
free(wideBuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* One code point per UTF-16 unit is the worst case (no surrogate
|
||||
pairs), so wideLen is always a safe upper bound for the output. */
|
||||
codePoints = (UINT32 *)malloc((size_t)wideLen * sizeof(UINT32));
|
||||
if (codePoints == NULL) {
|
||||
free(wideBuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
i = 0;
|
||||
while (wideBuf[i] != 0) {
|
||||
WCHAR unit = wideBuf[i];
|
||||
|
||||
if (unit >= 0xD800 && unit <= 0xDBFF &&
|
||||
wideBuf[i + 1] >= 0xDC00 && wideBuf[i + 1] <= 0xDFFF) {
|
||||
/* High + low surrogate -> one supplementary-plane code point. */
|
||||
UINT32 hi = (UINT32)(unit - 0xD800);
|
||||
UINT32 lo = (UINT32)(wideBuf[i + 1] - 0xDC00);
|
||||
|
||||
codePoints[count] = 0x10000u + (hi << 10) + lo;
|
||||
count++;
|
||||
i += 2;
|
||||
} else {
|
||||
/* Ordinary BMP character (or a lone/invalid surrogate, passed
|
||||
through as-is -- GetGlyphIndices will just report .notdef
|
||||
for it). */
|
||||
codePoints[count] = (UINT32)unit;
|
||||
count++;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(wideBuf);
|
||||
|
||||
if (pCount != NULL) {
|
||||
*pCount = count;
|
||||
}
|
||||
return codePoints;
|
||||
}
|
||||
|
||||
static int dw_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color) {
|
||||
IDWriteBitmapRenderTarget *target;
|
||||
RECT rc;
|
||||
HDC memoryHDC;
|
||||
DWRITE_GLYPH_RUN glyphRun;
|
||||
DWRITE_FONT_METRICS metrics;
|
||||
LONG width, height;
|
||||
IDWriteRenderingParams * rendering_params;
|
||||
UINT32 codepoint_len;
|
||||
UINT32* codepoints;
|
||||
UINT16 *index;
|
||||
IDWriteTextLayout * text_layout;
|
||||
IDWriteBitmapRenderTarget *target = NULL;
|
||||
HRESULT hr;
|
||||
RECT rc = {0};
|
||||
HDC memoryHDC = NULL;
|
||||
DWRITE_FONT_METRICS metrics = {0};
|
||||
LONG width = 0, height = 0;
|
||||
size_t wtext_len = strlen(text) * sizeof(UINT32);
|
||||
WCHAR* wtext = malloc(wtext_len);
|
||||
CustomTextRenderer * texRenderer;
|
||||
|
||||
codepoints = str_to_codepoints(text, CP_UTF8, &codepoint_len);
|
||||
index = malloc(sizeof(UINT16) * codepoint_len);
|
||||
MultiByteToWideChar(CP_UTF8, 0, text, -1, wtext, wtext_len);
|
||||
|
||||
IDWriteFontFace_GetMetrics(ttf->font_face, &metrics);
|
||||
|
||||
GetClientRect(handle->lowlevel->gdi.hWnd, &rc);
|
||||
MapWindowPoints(handle->lowlevel->gdi.hWnd, GetParent(handle->lowlevel->gdi.hWnd), (LPPOINT)&rc, 2);
|
||||
|
||||
IDWriteFactory_CreateRenderingParams(ttf->write_factory, &rendering_params);
|
||||
|
||||
IDWriteFontFace_GetGlyphIndices(ttf->font_face, codepoints, codepoint_len, index);
|
||||
|
||||
glyphRun.fontFace = ttf->font_face;
|
||||
glyphRun.fontEmSize = (ttf->px*96.f)/72.f;
|
||||
glyphRun.glyphCount = codepoint_len;
|
||||
glyphRun.glyphIndices = index;
|
||||
|
||||
width = rc.right - rc.left;
|
||||
height = rc.bottom - rc.top;
|
||||
|
||||
hr = IDWriteFactory_CreateTextLayout(ttf->write_factory, wtext, wtext_len, ttf->text_format, width, height, &text_layout);
|
||||
|
||||
IDWriteGdiInterop_CreateBitmapRenderTarget(ttf->gdiInterop, handle->lowlevel->gdi.hDC, width, height, &target);
|
||||
|
||||
IDWriteBitmapRenderTarget_DrawGlyphRun(target, point->x, point->y, DWRITE_MEASURING_MODE_GDI_NATURAL, &glyphRun, rendering_params, RGB(color->common.red, color->common.green, color->common.blue), NULL);
|
||||
texRenderer = CustomTextRenderer_Create(ttf->write_factory, target);
|
||||
|
||||
|
||||
memoryHDC = IDWriteBitmapRenderTarget_GetMemoryDC(target);
|
||||
|
||||
BitBlt(handle->lowlevel->gdi.hDC, 0,0, width, height, memoryHDC, 0, 0, SRCCOPY | NOMIRRORBITMAP);
|
||||
IDWriteTextLayout_Draw(text_layout, target, (IDWriteTextRenderer*)texRenderer, point->x, point->y);
|
||||
|
||||
IDWriteBitmapRenderTarget_Release(target);
|
||||
|
||||
/*SelectObject(handle->lowlevel->gdi.hDC, &ttf->logfont);
|
||||
TextOut(handle->lowlevel->gdi.hDC, point->x, point->y, text, ttf->px);*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_MwTextWidth(MwFLFont ttf, const char* text) {
|
||||
int tw = 1;
|
||||
int tw = (ttf->px * strlen(text)) / 2;
|
||||
|
||||
return tw + 1;
|
||||
}
|
||||
|
|
@ -326,7 +256,7 @@ static int dw_MwTextHeight(MwFLFont ttf, int count) {
|
|||
|
||||
IDWriteFontFace_GetMetrics(ttf->font_face, &metrics);
|
||||
|
||||
height = ceil(((float)metrics.capHeight * ttf->px / metrics.designUnitsPerEm) * count);
|
||||
height = ceil(((float)metrics.capHeight * ttf->px / metrics.designUnitsPerEm) * count) * 2;
|
||||
|
||||
return height;
|
||||
}
|
||||
|
|
@ -339,6 +269,172 @@ static void dw_MwFontFree(void* handle) {
|
|||
free(ttf);
|
||||
}
|
||||
|
||||
/* ---- IUnknown ---- */
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_QueryInterface(
|
||||
IDWriteTextRenderer *iface, REFIID riid, void **ppvObject)
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_POINTER;
|
||||
|
||||
if (IsEqualGUID(riid, &IID_IUnknown) ||
|
||||
IsEqualGUID(riid, &IID_IDWritePixelSnapping) ||
|
||||
IsEqualGUID(riid, &IID_IDWriteTextRenderer))
|
||||
{
|
||||
*ppvObject = iface;
|
||||
iface->lpVtbl->AddRef(iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE CTR_AddRef(IDWriteTextRenderer *iface)
|
||||
{
|
||||
CustomTextRenderer *This = (CustomTextRenderer *)iface;
|
||||
return InterlockedIncrement(&This->refCount);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE CTR_Release(IDWriteTextRenderer *iface)
|
||||
{
|
||||
CustomTextRenderer *This = (CustomTextRenderer *)iface;
|
||||
LONG ref = InterlockedDecrement(&This->refCount);
|
||||
if (ref == 0)
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
return (ULONG)ref;
|
||||
}
|
||||
|
||||
/* ---- IDWritePixelSnapping (base interface, treated as "core") ---- */
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_IsPixelSnappingDisabled(
|
||||
IDWriteTextRenderer *iface, void *clientDrawingContext, BOOL *isDisabled)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext;
|
||||
if (!isDisabled)
|
||||
return E_POINTER;
|
||||
*isDisabled = FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_GetCurrentTransform(
|
||||
IDWriteTextRenderer *iface, void *clientDrawingContext, DWRITE_MATRIX *transform)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext;
|
||||
if (!transform)
|
||||
return E_POINTER;
|
||||
|
||||
transform->m11 = 1.0f;
|
||||
transform->m12 = 0.0f;
|
||||
transform->m21 = 0.0f;
|
||||
transform->m22 = 1.0f;
|
||||
transform->dx = 0.0f;
|
||||
transform->dy = 0.0f;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_GetPixelsPerDip(
|
||||
IDWriteTextRenderer *iface, void *clientDrawingContext, FLOAT *pixelsPerDip)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext;
|
||||
if (!pixelsPerDip)
|
||||
return E_POINTER;
|
||||
*pixelsPerDip = 1.0f;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_DrawGlyphRun(
|
||||
IDWriteTextRenderer *iface,
|
||||
void *clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_MEASURING_MODE measuringMode,
|
||||
DWRITE_GLYPH_RUN const *glyphRun,
|
||||
DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
IDWriteRenderingParams *params;
|
||||
CustomTextRenderer * This = (CustomTextRenderer*)iface;
|
||||
|
||||
IDWriteFactory6_CreateRenderingParams(This->write_factory, ¶ms);
|
||||
|
||||
return IDWriteBitmapRenderTarget_DrawGlyphRun(This->target, baselineOriginX, baselineOriginY, measuringMode, glyphRun, params, RGB(255,255,255), NULL);
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_DrawUnderline(
|
||||
IDWriteTextRenderer *iface,
|
||||
void *clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_UNDERLINE const *underline,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext; (void)baselineOriginX;
|
||||
(void)baselineOriginY; (void)underline; (void)clientDrawingEffect;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_DrawStrikethrough(
|
||||
IDWriteTextRenderer *iface,
|
||||
void *clientDrawingContext,
|
||||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_STRIKETHROUGH const *strikethrough,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext; (void)baselineOriginX;
|
||||
(void)baselineOriginY; (void)strikethrough; (void)clientDrawingEffect;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_DrawInlineObject(
|
||||
IDWriteTextRenderer *iface,
|
||||
void *clientDrawingContext,
|
||||
FLOAT originX,
|
||||
FLOAT originY,
|
||||
IDWriteInlineObject *inlineObject,
|
||||
BOOL isSideways,
|
||||
BOOL isRightToLeft,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext; (void)originX; (void)originY;
|
||||
(void)inlineObject; (void)isSideways; (void)isRightToLeft;
|
||||
(void)clientDrawingEffect;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
/* ---- Vtable instance ---- */
|
||||
|
||||
static IDWriteTextRendererVtbl CTR_Vtbl = {
|
||||
CTR_QueryInterface,
|
||||
CTR_AddRef,
|
||||
CTR_Release,
|
||||
CTR_IsPixelSnappingDisabled,
|
||||
CTR_GetCurrentTransform,
|
||||
CTR_GetPixelsPerDip,
|
||||
CTR_DrawGlyphRun,
|
||||
CTR_DrawUnderline,
|
||||
CTR_DrawStrikethrough,
|
||||
CTR_DrawInlineObject
|
||||
};
|
||||
|
||||
/* ---- Constructor ---- */
|
||||
|
||||
static CustomTextRenderer *CustomTextRenderer_Create(IDWriteFactory6 * write_factory, IDWriteBitmapRenderTarget * target)
|
||||
{
|
||||
CustomTextRenderer *obj =
|
||||
(CustomTextRenderer *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(CustomTextRenderer));
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
obj->lpVtbl = &CTR_Vtbl;
|
||||
obj->refCount = 1;
|
||||
obj->write_factory = write_factory;
|
||||
obj->target = target;
|
||||
return obj;
|
||||
}
|
||||
|
||||
int MWFL_DWSetup(void) {
|
||||
/* Try and load DirectWrite. If it fails, return 1, signifying we default to bitmap drawing. */
|
||||
dw_table.d2d1_lib = LoadLibrary("D2d1.dll");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue