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.h"
|
||||||
#include "dwrite_3.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 {
|
static struct dw {
|
||||||
HMODULE d2d1_lib;
|
HMODULE d2d1_lib;
|
||||||
HMODULE dwrite_lib;
|
HMODULE dwrite_lib;
|
||||||
|
|
@ -31,10 +40,7 @@ struct _MwFLFont {
|
||||||
MwBool valid;
|
MwBool valid;
|
||||||
|
|
||||||
IDWriteFactory6* write_factory;
|
IDWriteFactory6* write_factory;
|
||||||
IDWriteTextFormat* dTextFormat;
|
|
||||||
ID2D1Factory* d2dFactory;
|
ID2D1Factory* d2dFactory;
|
||||||
ID2D1HwndRenderTarget* rt;
|
|
||||||
ID2D1SolidColorBrush* blackBrush;
|
|
||||||
IDWriteGdiInterop *gdiInterop;
|
IDWriteGdiInterop *gdiInterop;
|
||||||
|
|
||||||
IDWriteFontFile * file;
|
IDWriteFontFile * file;
|
||||||
|
|
@ -42,6 +48,8 @@ struct _MwFLFont {
|
||||||
IDWriteFontSetBuilder2 * font_builder;
|
IDWriteFontSetBuilder2 * font_builder;
|
||||||
IDWriteFontSet* font_set;
|
IDWriteFontSet* font_set;
|
||||||
IDWriteFontCollection1* font_collection;
|
IDWriteFontCollection1* font_collection;
|
||||||
|
IDWriteTextFormat * text_format;
|
||||||
|
IDWriteTextFormat * text_layout;
|
||||||
|
|
||||||
LOGFONTW logfont;
|
LOGFONTW logfont;
|
||||||
HFONT font;
|
HFONT font;
|
||||||
|
|
@ -175,18 +183,23 @@ static void* dw_MwFontLoad(unsigned char* data, unsigned int size, int px) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
hr = IDWriteFactory6_GetGdiInterop(ttf->write_factory, &ttf->gdiInterop);
|
hr = IDWriteFactory6_GetGdiInterop(ttf->write_factory, &ttf->gdiInterop);
|
||||||
if(!SUCCEEDED(hr)) {
|
if(!SUCCEEDED(hr)) {
|
||||||
printf("GetGdiInterop failed for TTF (%08lx), cannot use DirectWrite\n",hr);
|
printf("GetGdiInterop failed for TTF (%08lx), cannot use DirectWrite\n",hr);
|
||||||
goto fail;
|
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)) {
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ttf->valid = MwTRUE;
|
ttf->valid = MwTRUE;
|
||||||
return ttf;
|
return ttf;
|
||||||
|
|
||||||
|
|
@ -195,127 +208,44 @@ fail:
|
||||||
return ttf;
|
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) {
|
static int dw_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color) {
|
||||||
IDWriteBitmapRenderTarget *target;
|
IDWriteTextLayout * text_layout;
|
||||||
RECT rc;
|
IDWriteBitmapRenderTarget *target = NULL;
|
||||||
HDC memoryHDC;
|
HRESULT hr;
|
||||||
DWRITE_GLYPH_RUN glyphRun;
|
RECT rc = {0};
|
||||||
DWRITE_FONT_METRICS metrics;
|
HDC memoryHDC = NULL;
|
||||||
LONG width, height;
|
DWRITE_FONT_METRICS metrics = {0};
|
||||||
IDWriteRenderingParams * rendering_params;
|
LONG width = 0, height = 0;
|
||||||
UINT32 codepoint_len;
|
size_t wtext_len = strlen(text) * sizeof(UINT32);
|
||||||
UINT32* codepoints;
|
WCHAR* wtext = malloc(wtext_len);
|
||||||
UINT16 *index;
|
CustomTextRenderer * texRenderer;
|
||||||
|
|
||||||
codepoints = str_to_codepoints(text, CP_UTF8, &codepoint_len);
|
MultiByteToWideChar(CP_UTF8, 0, text, -1, wtext, wtext_len);
|
||||||
index = malloc(sizeof(UINT16) * codepoint_len);
|
|
||||||
|
|
||||||
IDWriteFontFace_GetMetrics(ttf->font_face, &metrics);
|
IDWriteFontFace_GetMetrics(ttf->font_face, &metrics);
|
||||||
|
|
||||||
GetClientRect(handle->lowlevel->gdi.hWnd, &rc);
|
GetClientRect(handle->lowlevel->gdi.hWnd, &rc);
|
||||||
MapWindowPoints(handle->lowlevel->gdi.hWnd, GetParent(handle->lowlevel->gdi.hWnd), (LPPOINT)&rc, 2);
|
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;
|
width = rc.right - rc.left;
|
||||||
height = rc.bottom - rc.top;
|
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);
|
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);
|
||||||
|
|
||||||
|
IDWriteTextLayout_Draw(text_layout, target, (IDWriteTextRenderer*)texRenderer, point->x, point->y);
|
||||||
memoryHDC = IDWriteBitmapRenderTarget_GetMemoryDC(target);
|
|
||||||
|
|
||||||
BitBlt(handle->lowlevel->gdi.hDC, 0,0, width, height, memoryHDC, 0, 0, SRCCOPY | NOMIRRORBITMAP);
|
|
||||||
|
|
||||||
IDWriteBitmapRenderTarget_Release(target);
|
IDWriteBitmapRenderTarget_Release(target);
|
||||||
|
|
||||||
/*SelectObject(handle->lowlevel->gdi.hDC, &ttf->logfont);
|
|
||||||
TextOut(handle->lowlevel->gdi.hDC, point->x, point->y, text, ttf->px);*/
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_MwTextWidth(MwFLFont ttf, const char* text) {
|
static int dw_MwTextWidth(MwFLFont ttf, const char* text) {
|
||||||
int tw = 1;
|
int tw = (ttf->px * strlen(text)) / 2;
|
||||||
|
|
||||||
return tw + 1;
|
return tw + 1;
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +256,7 @@ static int dw_MwTextHeight(MwFLFont ttf, int count) {
|
||||||
|
|
||||||
IDWriteFontFace_GetMetrics(ttf->font_face, &metrics);
|
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;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
@ -339,6 +269,172 @@ static void dw_MwFontFree(void* handle) {
|
||||||
free(ttf);
|
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) {
|
int MWFL_DWSetup(void) {
|
||||||
/* Try and load DirectWrite. If it fails, return 1, signifying we default to bitmap drawing. */
|
/* Try and load DirectWrite. If it fails, return 1, signifying we default to bitmap drawing. */
|
||||||
dw_table.d2d1_lib = LoadLibrary("D2d1.dll");
|
dw_table.d2d1_lib = LoadLibrary("D2d1.dll");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue