DirectWrite support #28
2 changed files with 325 additions and 291 deletions
commit
4ce9ee6730
|
|
@ -312,10 +312,17 @@ static MwWidget MwCreateWidget_Internal(MwClass widget_class, const char* name,
|
|||
|
||||
#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) || defined(USE_DIRECTWRITE)
|
||||
if(IsFirstVisible(h)) {
|
||||
font_setup:
|
||||
h->root_font = MwFontLoad(MwTTFData, MwTTFDataSize);
|
||||
h->root_boldfont = MwFontLoad(MwBoldTTFData, MwBoldTTFDataSize);
|
||||
h->root_monofont = MwFontLoad(MwMonospaceTTFData, MwMonospaceTTFDataSize);
|
||||
h->root_boldmonofont = MwFontLoad(MwBoldMonospaceTTFData, MwBoldMonospaceTTFDataSize);
|
||||
if(!h->root_font) {
|
||||
#ifdef USE_STB_TRUETYPE
|
||||
MwFL_STBTTSetup();
|
||||
goto font_setup;
|
||||
#endif
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <Mw/Milsko.h>
|
||||
|
||||
#include <d2d1.h>
|
||||
#include <shobjidl.h>
|
||||
|
||||
#ifndef WINBOOL
|
||||
#define WINBOOL int
|
||||
|
|
@ -33,6 +34,8 @@ static struct dw {
|
|||
|
||||
HRESULT (*D2D1CreateFactory)(D2D1_FACTORY_TYPE factoryType, const IID* const riid, const D2D1_FACTORY_OPTIONS* pFactoryOptions, void** ppIFactory);
|
||||
HRESULT (*DWriteCreateFactory)(int factoryType, const IID* const iid, IUnknown** factory);
|
||||
|
||||
HMODULE kernel32_lib;
|
||||
} dw_table;
|
||||
|
||||
struct _MwFLFont {
|
||||
|
|
@ -43,14 +46,12 @@ struct _MwFLFont {
|
|||
IDWriteFactory6* write_factory;
|
||||
ID2D1Factory* d2dFactory;
|
||||
IDWriteGdiInterop* gdiInterop;
|
||||
|
||||
IDWriteFontFile* file;
|
||||
IDWriteFontFace* font_face;
|
||||
IDWriteFontSetBuilder2* font_builder;
|
||||
IDWriteFontSet* font_set;
|
||||
IDWriteFontCollection1* font_collection;
|
||||
IDWriteTextFormat* text_format;
|
||||
IDWriteTextFormat * text_layout;
|
||||
|
||||
LOGFONTW logfont;
|
||||
HFONT font;
|
||||
|
|
@ -61,15 +62,13 @@ static int unpack_ttf_data(WCHAR * temp_path_name, unsigned char* data, unsigned
|
|||
HANDLE tempFile;
|
||||
int hr;
|
||||
|
||||
hr = GetTempPath2W(MAX_PATH, temp_path_dir);
|
||||
if (hr == 0)
|
||||
{
|
||||
printf("GetTempPath2 failed for TTF, cannot use DirectWrite\n");
|
||||
hr = GetTempPathW(MAX_PATH, temp_path_dir);
|
||||
if(hr == 0) {
|
||||
printf("GetTempPathW failed for TTF, cannot use DirectWrite\n");
|
||||
return 1;
|
||||
}
|
||||
hr = GetTempFileNameW(temp_path_dir, TEXT(L"MILSKO"), 0, temp_path_name);
|
||||
if (hr == 0)
|
||||
{
|
||||
if(hr == 0) {
|
||||
printf("GetTempFileName failed for TTF, cannot use DirectWrite\n");
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -81,8 +80,7 @@ static int unpack_ttf_data(WCHAR * temp_path_name, unsigned char* data, unsigned
|
|||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (tempFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if(tempFile == INVALID_HANDLE_VALUE) {
|
||||
DWORD err = GetLastError();
|
||||
if(err == ERROR_FILE_EXISTS) {
|
||||
tempFile = CreateFileW(temp_path_name,
|
||||
|
|
@ -92,8 +90,7 @@ static int unpack_ttf_data(WCHAR * temp_path_name, unsigned char* data, unsigned
|
|||
OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (tempFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if(tempFile != INVALID_HANDLE_VALUE) {
|
||||
goto success;
|
||||
} else {
|
||||
err = GetLastError();
|
||||
|
|
@ -123,6 +120,15 @@ static void* dw_MwFontLoad(unsigned char* data, unsigned int size, int px) {
|
|||
|
||||
d2d1_options.debugLevel = D2D1_DEBUG_LEVEL_ERROR;
|
||||
|
||||
#define INTERFACE_CHECK(x, factory) \
|
||||
do { \
|
||||
x* rsrc = NULL; \
|
||||
if(!SUCCEEDED((hr = x##_QueryInterface(factory, &IID_##x, (void**)&rsrc)))) { \
|
||||
printf("Query for interface " #x " failed (%08lX). Cannot use DirectWrite.\n", hr); \
|
||||
return NULL; \
|
||||
}; \
|
||||
} while(0);
|
||||
|
||||
memset(ttf, 0, sizeof(*ttf));
|
||||
ttf->data = malloc(size);
|
||||
memcpy(ttf->data, data, size);
|
||||
|
|
@ -135,12 +141,14 @@ static void* dw_MwFontLoad(unsigned char* data, unsigned int size, int px) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
hr = dw_table.DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,&IID_IDWriteFactory, (struct IUnknown**)&ttf->write_factory);
|
||||
INTERFACE_CHECK(ID2D1Factory, ttf->d2dFactory);
|
||||
|
||||
hr = dw_table.DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (struct IUnknown**)&ttf->write_factory);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
printf("DWriteCreateFactory failed for TTF (%08lx), cannot use DirectWrite\n", hr);
|
||||
goto fail;
|
||||
}
|
||||
INTERFACE_CHECK(IDWriteFactory6, ttf->write_factory);
|
||||
|
||||
if(unpack_ttf_data(font_name, data, size) != 0) {
|
||||
goto fail;
|
||||
|
|
@ -151,18 +159,21 @@ static void* dw_MwFontLoad(unsigned char* data, unsigned int size, int px) {
|
|||
printf("CreateFontFileReference failed for TTF (%08lx), cannot use DirectWrite\n", hr);
|
||||
goto fail;
|
||||
}
|
||||
INTERFACE_CHECK(IDWriteFontFile, ttf->file);
|
||||
|
||||
hr = IDWriteFactory_CreateFontFace(ttf->write_factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ttf->file, 0, DWRITE_FONT_SIMULATIONS_NONE, &ttf->font_face);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
printf("IDWriteFactory_CreateFontFace failed for TTF (%08lx), cannot use DirectWrite\n", hr);
|
||||
goto fail;
|
||||
}
|
||||
INTERFACE_CHECK(IDWriteFontFace, ttf->font_face);
|
||||
|
||||
hr = IDWriteFactory6_CreateFontSetBuilder(ttf->write_factory, &ttf->font_builder);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
printf("IDWriteFactory6_CreateFontSetBuilder failed for TTF (%08lx), cannot use DirectWrite\n", hr);
|
||||
goto fail;
|
||||
}
|
||||
INTERFACE_CHECK(IDWriteFontSetBuilder2, ttf->font_builder);
|
||||
|
||||
hr = IDWriteFontSetBuilder2_AddFontFile(ttf->font_builder, font_name);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
|
|
@ -175,20 +186,21 @@ static void* dw_MwFontLoad(unsigned char* data, unsigned int size, int px) {
|
|||
printf("IDWriteFontSetBuilder_CreateFontSet failed for TTF (%08lx), cannot use DirectWrite\n", hr);
|
||||
goto fail;
|
||||
}
|
||||
INTERFACE_CHECK(IDWriteFontSet, ttf->font_set);
|
||||
|
||||
hr = IDWriteFactory3_CreateFontCollectionFromFontSet(ttf->write_factory, ttf->font_set, &ttf->font_collection);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
printf("IDWriteFactory3_CreateFontCollectionFromFontSet failed for TTF (%08lx), cannot use DirectWrite\n", hr);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
INTERFACE_CHECK(IDWriteFontCollection1, ttf->font_collection);
|
||||
|
||||
hr = IDWriteFactory6_GetGdiInterop(ttf->write_factory, &ttf->gdiInterop);
|
||||
if(!SUCCEEDED(hr)) {
|
||||
printf("GetGdiInterop failed for TTF (%08lx), cannot use DirectWrite\n", hr);
|
||||
goto fail;
|
||||
}
|
||||
INTERFACE_CHECK(IDWriteGdiInterop, ttf->gdiInterop);
|
||||
|
||||
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)) {
|
||||
|
|
@ -201,12 +213,11 @@ static void* dw_MwFontLoad(unsigned char* data, unsigned int size, int px) {
|
|||
|
||||
fail:
|
||||
ttf->valid = MwFALSE;
|
||||
return ttf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dw_MwTextOffset(MwFLFont ttf, const char* text);
|
||||
|
||||
|
||||
static int dw_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const char* text, MwLLColor color) {
|
||||
IDWriteTextLayout* text_layout;
|
||||
IDWriteBitmapRenderTarget* target = NULL;
|
||||
|
|
@ -335,7 +346,6 @@ static int dw_MwTextHeight(MwFLFont ttf, int count) {
|
|||
return (IDWriteTextFormat2_GetFontSize(ttf->text_format) / 72.0f) * GetDeviceCaps(GetDC(NULL), LOGPIXELSY);
|
||||
}
|
||||
|
||||
|
||||
static void dw_MwFontFree(void* handle) {
|
||||
MwFLFont ttf = handle;
|
||||
|
||||
|
|
@ -346,15 +356,13 @@ static void dw_MwFontFree(void* handle) {
|
|||
/* ---- IUnknown ---- */
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_QueryInterface(
|
||||
IDWriteTextRenderer *iface, REFIID riid, void **ppvObject)
|
||||
{
|
||||
IDWriteTextRenderer* iface, REFIID riid, void** ppvObject) {
|
||||
if(!ppvObject)
|
||||
return E_POINTER;
|
||||
|
||||
if(IsEqualGUID(riid, &IID_IUnknown) ||
|
||||
IsEqualGUID(riid, &IID_IDWritePixelSnapping) ||
|
||||
IsEqualGUID(riid, &IID_IDWriteTextRenderer))
|
||||
{
|
||||
IsEqualGUID(riid, &IID_IDWriteTextRenderer)) {
|
||||
*ppvObject = iface;
|
||||
iface->lpVtbl->AddRef(iface);
|
||||
return S_OK;
|
||||
|
|
@ -364,14 +372,12 @@ static HRESULT STDMETHODCALLTYPE CTR_QueryInterface(
|
|||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE CTR_AddRef(IDWriteTextRenderer *iface)
|
||||
{
|
||||
static ULONG STDMETHODCALLTYPE CTR_AddRef(IDWriteTextRenderer* iface) {
|
||||
CustomTextRenderer* This = (CustomTextRenderer*)iface;
|
||||
return InterlockedIncrement(&This->refCount);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE CTR_Release(IDWriteTextRenderer *iface)
|
||||
{
|
||||
static ULONG STDMETHODCALLTYPE CTR_Release(IDWriteTextRenderer* iface) {
|
||||
CustomTextRenderer* This = (CustomTextRenderer*)iface;
|
||||
LONG ref = InterlockedDecrement(&This->refCount);
|
||||
if(ref == 0)
|
||||
|
|
@ -382,9 +388,9 @@ static ULONG STDMETHODCALLTYPE CTR_Release(IDWriteTextRenderer *iface)
|
|||
/* ---- IDWritePixelSnapping (base interface, treated as "core") ---- */
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_IsPixelSnappingDisabled(
|
||||
IDWriteTextRenderer *iface, void *clientDrawingContext, BOOL *isDisabled)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext;
|
||||
IDWriteTextRenderer* iface, void* clientDrawingContext, BOOL* isDisabled) {
|
||||
(void)iface;
|
||||
(void)clientDrawingContext;
|
||||
if(!isDisabled)
|
||||
return E_POINTER;
|
||||
*isDisabled = FALSE;
|
||||
|
|
@ -392,9 +398,9 @@ static HRESULT STDMETHODCALLTYPE CTR_IsPixelSnappingDisabled(
|
|||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_GetCurrentTransform(
|
||||
IDWriteTextRenderer *iface, void *clientDrawingContext, DWRITE_MATRIX *transform)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext;
|
||||
IDWriteTextRenderer* iface, void* clientDrawingContext, DWRITE_MATRIX* transform) {
|
||||
(void)iface;
|
||||
(void)clientDrawingContext;
|
||||
if(!transform)
|
||||
return E_POINTER;
|
||||
|
||||
|
|
@ -408,9 +414,9 @@ static HRESULT STDMETHODCALLTYPE CTR_GetCurrentTransform(
|
|||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE CTR_GetPixelsPerDip(
|
||||
IDWriteTextRenderer *iface, void *clientDrawingContext, FLOAT *pixelsPerDip)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext;
|
||||
IDWriteTextRenderer* iface, void* clientDrawingContext, FLOAT* pixelsPerDip) {
|
||||
(void)iface;
|
||||
(void)clientDrawingContext;
|
||||
if(!pixelsPerDip)
|
||||
return E_POINTER;
|
||||
*pixelsPerDip = 1.0f;
|
||||
|
|
@ -425,8 +431,7 @@ static HRESULT STDMETHODCALLTYPE CTR_DrawGlyphRun(
|
|||
DWRITE_MEASURING_MODE measuringMode,
|
||||
DWRITE_GLYPH_RUN const* glyphRun,
|
||||
DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
IUnknown* clientDrawingEffect) {
|
||||
IDWriteRenderingParams* params;
|
||||
CustomTextRenderer* This = (CustomTextRenderer*)iface;
|
||||
|
||||
|
|
@ -445,10 +450,13 @@ static HRESULT STDMETHODCALLTYPE CTR_DrawUnderline(
|
|||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_UNDERLINE const* underline,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext; (void)baselineOriginX;
|
||||
(void)baselineOriginY; (void)underline; (void)clientDrawingEffect;
|
||||
IUnknown* clientDrawingEffect) {
|
||||
(void)iface;
|
||||
(void)clientDrawingContext;
|
||||
(void)baselineOriginX;
|
||||
(void)baselineOriginY;
|
||||
(void)underline;
|
||||
(void)clientDrawingEffect;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
|
@ -458,10 +466,13 @@ static HRESULT STDMETHODCALLTYPE CTR_DrawStrikethrough(
|
|||
FLOAT baselineOriginX,
|
||||
FLOAT baselineOriginY,
|
||||
DWRITE_STRIKETHROUGH const* strikethrough,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext; (void)baselineOriginX;
|
||||
(void)baselineOriginY; (void)strikethrough; (void)clientDrawingEffect;
|
||||
IUnknown* clientDrawingEffect) {
|
||||
(void)iface;
|
||||
(void)clientDrawingContext;
|
||||
(void)baselineOriginX;
|
||||
(void)baselineOriginY;
|
||||
(void)strikethrough;
|
||||
(void)clientDrawingEffect;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
|
|
@ -473,10 +484,14 @@ static HRESULT STDMETHODCALLTYPE CTR_DrawInlineObject(
|
|||
IDWriteInlineObject* inlineObject,
|
||||
BOOL isSideways,
|
||||
BOOL isRightToLeft,
|
||||
IUnknown *clientDrawingEffect)
|
||||
{
|
||||
(void)iface; (void)clientDrawingContext; (void)originX; (void)originY;
|
||||
(void)inlineObject; (void)isSideways; (void)isRightToLeft;
|
||||
IUnknown* clientDrawingEffect) {
|
||||
(void)iface;
|
||||
(void)clientDrawingContext;
|
||||
(void)originX;
|
||||
(void)originY;
|
||||
(void)inlineObject;
|
||||
(void)isSideways;
|
||||
(void)isRightToLeft;
|
||||
(void)clientDrawingEffect;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
|
@ -493,13 +508,11 @@ static IDWriteTextRendererVtbl CTR_Vtbl = {
|
|||
CTR_DrawGlyphRun,
|
||||
CTR_DrawUnderline,
|
||||
CTR_DrawStrikethrough,
|
||||
CTR_DrawInlineObject
|
||||
};
|
||||
CTR_DrawInlineObject};
|
||||
|
||||
/* ---- Constructor ---- */
|
||||
|
||||
static CustomTextRenderer *CustomTextRenderer_Create(IDWriteFactory6 * write_factory, IDWriteBitmapRenderTarget * target, MwLLColor color)
|
||||
{
|
||||
static CustomTextRenderer* CustomTextRenderer_Create(IDWriteFactory6* write_factory, IDWriteBitmapRenderTarget* target, MwLLColor color) {
|
||||
CustomTextRenderer* obj =
|
||||
(CustomTextRenderer*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
sizeof(CustomTextRenderer));
|
||||
|
|
@ -518,6 +531,10 @@ static CustomTextRenderer *CustomTextRenderer_Create(IDWriteFactory6 * write_fac
|
|||
}
|
||||
|
||||
int MWFL_DWSetup(void) {
|
||||
HRESULT hr;
|
||||
|
||||
CoInitialize(NULL);
|
||||
|
||||
/* Try and load DirectWrite. If it fails, return 1, signifying we default to bitmap drawing. */
|
||||
dw_table.d2d1_lib = LoadLibrary("D2d1.dll");
|
||||
if(!dw_table.d2d1_lib) {
|
||||
|
|
@ -530,9 +547,19 @@ int MWFL_DWSetup(void) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
#define D2D1_LOAD(x) dw_table.x = (typeof(dw_table.x))GetProcAddress(dw_table.d2d1_lib, #x); if(!dw_table.x) {printf("Can't use DirectWrite, "#x " not found."); return 1;}
|
||||
#define D2D1_LOAD(x) \
|
||||
dw_table.x = (typeof(dw_table.x))GetProcAddress(dw_table.d2d1_lib, #x); \
|
||||
if(!dw_table.x) { \
|
||||
printf("Can't use DirectWrite, " #x " not found."); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define DWRITE_LOAD(x) dw_table.x = (typeof(dw_table.x))GetProcAddress(dw_table.dwrite_lib, #x); if(!dw_table.x) {printf("Can't use DirectWrite, "#x " not found."); return 1;}
|
||||
#define DWRITE_LOAD(x) \
|
||||
dw_table.x = (typeof(dw_table.x))GetProcAddress(dw_table.dwrite_lib, #x); \
|
||||
if(!dw_table.x) { \
|
||||
printf("Can't use DirectWrite, " #x " not found."); \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
D2D1_LOAD(D2D1CreateFactory);
|
||||
DWRITE_LOAD(DWriteCreateFactory);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue