From 29fd129671bb66a2e54717ca666b6ccd7f7ee941 Mon Sep 17 00:00:00 2001 From: feliwir Date: Tue, 19 May 2015 11:46:37 +0200 Subject: directwrite: add initial fontselect implementation Incomplete, leaks memory, but capable of rendering something. --- libass/ass.h | 1 + libass/ass_directwrite.cpp | 248 +++++++++++++++++++++++++++++++++++++++++++++ libass/ass_directwrite.h | 35 +++++++ libass/ass_fontselect.c | 22 ++++ libass/ass_utils.h | 2 +- 5 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 libass/ass_directwrite.cpp create mode 100644 libass/ass_directwrite.h (limited to 'libass') diff --git a/libass/ass.h b/libass/ass.h index 1fb2234..5fd11a6 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -190,6 +190,7 @@ typedef enum { ASS_FONTPROVIDER_AUTODETECT = 1, ASS_FONTPROVIDER_CORETEXT, ASS_FONTPROVIDER_FONTCONFIG, + ASS_FONTPROVIDER_DIRECTWRITE, } ASS_DefaultFontProvider; /** diff --git a/libass/ass_directwrite.cpp b/libass/ass_directwrite.cpp new file mode 100644 index 0000000..abf7e67 --- /dev/null +++ b/libass/ass_directwrite.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2015 Stephan Vedder + * + * This file is part of libass. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#ifdef CONFIG_DIRECTWRITE + +#include + +extern "C" +{ +#include "ass_directwrite.h" +#include "ass_utils.h" +} + +static size_t get_data(void * priv, unsigned char* buf, size_t offset, size_t length) +{ + HRESULT hr = S_OK; + IDWriteFontFace* face = NULL; + IDWriteFont* font = (IDWriteFont*)priv; + IDWriteFontFile* files = NULL; + IDWriteFontFileStream* stream = NULL; + IDWriteFontFileLoader* loader = NULL; + UINT32 n_files = 0; + UINT64 fileSize; + const void* fileBuf = NULL; + + hr = font->CreateFontFace(&face); + const void* refKey = NULL; + UINT32 keySize = 0; + void* fragContext = NULL; + + if (FAILED(hr) || !face) + return 0; + + hr = face->GetFiles(&n_files, NULL); + if (FAILED(hr)) + return 0; + + hr = face->GetFiles(&n_files, &files); + if (FAILED(hr) || !files) + return 0; + + hr = files[0].GetReferenceKey(&refKey, &keySize); + if (FAILED(hr)) + return 0; + + hr = files[0].GetLoader(&loader); + if (FAILED(hr) || !loader) + return 0; + + hr = loader->CreateStreamFromKey(refKey,keySize,&stream); + if (FAILED(hr) || !stream) + return 0; + + if (buf == NULL) + { + hr = stream->GetFileSize(&fileSize); + if (FAILED(hr)) + return 0; + + return fileSize; + } + + hr = stream->ReadFileFragment(&fileBuf, offset, length, &fragContext); + if (FAILED(hr) || !fileBuf) + return 0; + + memcpy(buf, fileBuf, length); + + stream->ReleaseFileFragment(fragContext); + + return length; +} + +static int check_glyph(void *priv, uint32_t code) +{ + //TODO: use IDWriteFont::HasCharacter method + //see: https://msdn.microsoft.com/en-us/library/windows/desktop/dd371165(v=vs.85).aspx + HRESULT hr = S_OK; + BOOL exists = FALSE; + + ((IDWriteFont*)priv)->HasCharacter(code, &exists); + + if (FAILED(hr)) + return FALSE; + + return exists; +} + +static void destroy(void* priv) +{ + ((IDWriteFactory*)priv)->Release(); +} + +static void scan_fonts(IDWriteFactory *factory, ASS_FontProvider *provider) +{ + HRESULT hr = S_OK; + IDWriteFontCollection* fontCollection = NULL; + IDWriteFont* font = NULL; + DWRITE_FONT_METRICS metrics; + DWRITE_FONT_STYLE style; + ASS_FontProviderMetaData meta = ASS_FontProviderMetaData(); + hr = factory->GetSystemFontCollection(&fontCollection,FALSE); + wchar_t localeName[LOCALE_NAME_MAX_LENGTH]; + int size_needed = 0; + + if(FAILED(hr)||!fontCollection) + return; + + UINT32 familyCount = fontCollection->GetFontFamilyCount(); + + for (UINT32 i = 0; i < familyCount; ++i) + { + IDWriteFontFamily* fontFamily = NULL; + IDWriteLocalizedStrings* familyNames = NULL; + IDWriteLocalizedStrings* fontNames = NULL; + IDWriteLocalizedStrings* psNames = NULL; + BOOL exists = FALSE; + char* psName = NULL; + + // Get the font family. + hr = fontCollection->GetFontFamily(i, &fontFamily); + if (FAILED(hr)) + return; + + UINT32 fontCount = fontFamily->GetFontCount(); + for (UINT32 j = 0; j < fontCount; ++j) + { + hr = fontFamily->GetFont(j, &font); + if (FAILED(hr)) + return; + + meta.weight = font->GetWeight(); + font->GetMetrics(&metrics); + style = font->GetStyle(); + meta.slant = (style==DWRITE_FONT_STYLE_NORMAL)? FONT_SLANT_NONE: + (style==DWRITE_FONT_STYLE_OBLIQUE)? FONT_SLANT_OBLIQUE: + (style==DWRITE_FONT_STYLE_ITALIC)? FONT_SLANT_ITALIC : FONT_SLANT_NONE; + + hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME, &psNames, &exists); + if (FAILED(hr)) + return; + + if (exists) + { + hr = psNames->GetString(0, localeName, LOCALE_NAME_MAX_LENGTH + 1); + if (FAILED(hr)) + return; + + size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL); + psName = (char*)ass_aligned_alloc(32, size_needed); + WideCharToMultiByte(CP_UTF8, 0, localeName, -1, psName, size_needed, NULL, NULL); + } + + hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_FULL_NAME, &fontNames, &exists); + if (FAILED(hr)) + return; + + meta.n_fullname = fontNames->GetCount(); + meta.fullnames = (char **)calloc(meta.n_fullname, sizeof(char *)); + for (UINT32 k = 0; k < meta.n_fullname; ++k) + { + hr = fontNames->GetString(k,localeName, LOCALE_NAME_MAX_LENGTH + 1); + if (FAILED(hr)) + return; + + size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL); + char* mbName = (char *)malloc(size_needed); + WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName, size_needed, NULL, NULL); + meta.fullnames[k] = mbName; + } + + hr = fontFamily->GetFamilyNames(&familyNames); + if (FAILED(hr)) + return; + + meta.n_family = familyNames->GetCount(); + meta.families = (char **)calloc(meta.n_family, sizeof(char *)); + for (UINT32 k = 0; k < meta.n_family; ++k) + { + hr = familyNames->GetString(k, localeName, LOCALE_NAME_MAX_LENGTH + 1); + if (FAILED(hr)) + return; + + size_needed = WideCharToMultiByte(CP_UTF8, 0, localeName, -1, NULL, 0, NULL, NULL); + char* mbName = (char *)malloc(size_needed); + WideCharToMultiByte(CP_UTF8, 0, localeName, -1, mbName, size_needed, NULL, NULL); + meta.families[k] = mbName; + } + + ass_font_provider_add_font(provider, &meta, NULL, j, psName, font); + free(meta.fullnames); + free(meta.families); + } + } +} + +static ASS_FontProviderFuncs directwrite_callbacks = { + get_data, + check_glyph, + NULL, + destroy, + NULL +}; + +ASS_FontProvider * +ass_directwrite_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config) +{ + HRESULT hr = S_OK; + IDWriteFactory* dwFactory = NULL; + ASS_FontProvider *provider = NULL; + + hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + (IUnknown**)(&dwFactory)); + + if(FAILED(hr)) + { + ass_msg(lib, MSGL_WARN, "Failed to initialize directwrite."); + goto exit; + } + + + provider = ass_font_provider_new(selector, &directwrite_callbacks, dwFactory); + + scan_fonts(dwFactory,provider); +exit: + return provider; +} + +#endif diff --git a/libass/ass_directwrite.h b/libass/ass_directwrite.h new file mode 100644 index 0000000..054ea6b --- /dev/null +++ b/libass/ass_directwrite.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 Stephan Vedder + * + * This file is part of libass. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include "ass_types.h" +#include "ass_fontselect.h" + +#ifndef ASS_DIRECTWRITE_H +#define ASS_DIRECTWRITE_H + +#ifdef CONFIG_DIRECTWRITE + +ASS_FontProvider * +ass_directwrite_add_provider(ASS_Library *lib, ASS_FontSelector *selector, + const char *config); + +#endif + +#endif diff --git a/libass/ass_fontselect.c b/libass/ass_fontselect.c index bc1dec5..174fe1d 100644 --- a/libass/ass_fontselect.c +++ b/libass/ass_fontselect.c @@ -38,6 +38,7 @@ #include "ass_fontselect.h" #include "ass_fontconfig.h" #include "ass_coretext.h" +#include "ass_directwrite.h" #include "ass_font.h" #define ABS(x) ((x) < 0 ? -(x) : (x)) @@ -236,6 +237,24 @@ ass_font_provider_add_font(ASS_FontProvider *provider, ASS_FontSelector *selector = provider->parent; ASS_FontInfo *info; +#if 0 + int j; + printf("new font:\n"); + printf(" families: "); + for (j = 0; j < meta->n_family; j++) + printf("'%s' ", meta->families[j]); + printf("\n"); + printf(" fullnames: "); + for (j = 0; j < meta->n_fullname; j++) + printf("'%s' ", meta->fullnames[j]); + printf("\n"); + printf(" slant: %d\n", meta->slant); + printf(" weight: %d\n", meta->weight); + printf(" width: %d\n", meta->width); + printf(" path: %s\n", path); + printf(" index: %d\n", index); +#endif + weight = meta->weight; slant = meta->slant; width = meta->width; @@ -803,6 +822,9 @@ struct font_constructors font_constructors[] = { #endif #ifdef CONFIG_FONTCONFIG { ASS_FONTPROVIDER_FONTCONFIG, &ass_fontconfig_add_provider }, +#endif +#ifdef CONFIG_DIRECTWRITE + { ASS_FONTPROVIDER_DIRECTWRITE, &ass_directwrite_add_provider }, #endif { ASS_FONTPROVIDER_NONE, NULL }, }; diff --git a/libass/ass_utils.h b/libass/ass_utils.h index f249bc9..caff161 100644 --- a/libass/ass_utils.h +++ b/libass/ass_utils.h @@ -184,7 +184,7 @@ static inline int rot_key(double a) static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval) { - unsigned char *bp = buf; + unsigned char *bp = (unsigned char*)buf; size_t n = (len + 3) / 4; switch (len % 4) { -- cgit v1.2.3