diff --git a/cmake/Modules/FindFontconfig.cmake b/cmake/Modules/FindFontconfig.cmake new file mode 100644 index 000000000..321108cc6 --- /dev/null +++ b/cmake/Modules/FindFontconfig.cmake @@ -0,0 +1,39 @@ +# Once done these will be defined: +# +# FONTCONFIG_FOUND +# FONTCONFIG_INCLUDE_DIRS +# FONTCONFIG_LIBRARIES +# + +if(FONTCONFIG_INCLUDE_DIRS AND FONTCONFIG_LIBRARIES) + set(FONTCONFIG_FOUND TRUE) +else() + find_package(PkgConfig QUIET) + if (PKG_CONFIG_FOUND) + pkg_check_modules(_FONTCONFIG QUIET fontconfig) + endif() + + find_path(FONTCONFIG_INCLUDE_DIR + NAMES fontconfig/fontconfig.h + HINTS + ${_FONTCONFIG_INCLUDE_DIRS} + PATHS + /usr/include /usr/local/include /opt/local/include) + + find_library(FONTCONFIG_LIB + NAMES fontconfig + HINTS + ${_FONTCONFIG_LIBRARY_DIRS} + PATHS + /usr/lib /usr/local/lib /opt/local/lib) + + set(FONTCONFIG_INCLUDE_DIRS ${FONTCONFIG_INCLUDE_DIR} + CACHE PATH "fontconfig include dir") + set(FONTCONFIG_LIBRARIES "${FONTCONFIG_LIB}" + CACHE STRING "fontconfig libraries") + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Fontconfig DEFAULT_MSG FONTCONFIG_LIB + FONTCONFIG_INCLUDE_DIR) + mark_as_advanced(FONTCONFIG_INCLUDE_DIR FONTCONFIG_LIB) +endif() diff --git a/plugins/text-freetype2/CMakeLists.txt b/plugins/text-freetype2/CMakeLists.txt index 247a1d512..ab3b8c2e9 100644 --- a/plugins/text-freetype2/CMakeLists.txt +++ b/plugins/text-freetype2/CMakeLists.txt @@ -6,52 +6,26 @@ if(NOT FREETYPE_FOUND) return() endif() -if(APPLE) - find_package(Iconv QUIET) - if(NOT ICONV_FOUND) - message(STATUS "Iconv library not found, Freetype text plugin disabled") - return() - endif() - - find_library(COCOA Cocoa) - - set(text-freetype2_PLATFORM_SOURCES - find-font-cocoa.m - find-font-iconv.c) - - include_directories(${COCOA} - ${ICONV_INCLUDE_DIRS}) - - set(text-freetype2_PLATFORM_DEPS - ${COCOA} - ${ICONV_LIBRARIES}) - - set_source_files_properties(find-font-cocoa.m - PROPERTIES LANGUAGE C) -elseif(WIN32) +if(WIN32) set(text-freetype2_PLATFORM_SOURCES find-font-windows.c) else() - message(STATUS "Linux-specific code has yet to be written for the text plugin, just needs load_os_font_list written.. which, er, may or may not be a pain. (My apologies in advance, please don't strangle me)") - return() - - find_package(Iconv QUIET) - if(NOT ICONV_FOUND) - message(STATUS "Iconv library not found, Freetype text plugin disabled") + find_package(Fontconfig QUIET) + if(NOT FONTCONFIG_FOUND) + message(STATUS "fontconfig not found, Freetype text plugin disabled") return() endif() set(text-freetype2_PLATFORM_SOURCES - find-font-iconv.c) + find-font-unix.c) - include_directories(${ICONV_INCLUDE_DIR}) + include_directories(${FONTCONFIG_INCLUDE_DIRS}) endif() include_directories(${FREETYPE_INCLUDE_DIRS}) set(text-freetype2_SOURCES find-font.h - find-font.c obs-convenience.c text-functionality.c text-freetype2.c @@ -66,8 +40,10 @@ target_link_libraries(text-freetype2 ${text-freetype2_PLATFORM_DEPS} ${FREETYPE_LIBRARIES}) -if(UNIX AND ICONV_FOUND) - target_link_libraries(text-freetype2 ${ICONV_LIBRARIES}) +if(NOT WIN32) + if(FONTCONFIG_FOUND) + target_link_libraries(text-freetype2 ${FONTCONFIG_LIBRARIES}) + endif() endif() install_obs_plugin_with_data(text-freetype2 data) diff --git a/plugins/text-freetype2/find-font-cocoa.m b/plugins/text-freetype2/find-font-cocoa.m deleted file mode 100644 index dba3c6151..000000000 --- a/plugins/text-freetype2/find-font-cocoa.m +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include "find-font.h" -#include "text-freetype2.h" - -#import - -static inline void add_path_font(const char *path) -{ - FT_Face face; - FT_Long idx = 0; - FT_Long max_faces = 1; - - while (idx < max_faces) { - if (FT_New_Face(ft2_lib, path, idx, &face) != 0) - break; - - build_font_path_info(face, idx++, path); - max_faces = face->num_faces; - FT_Done_Face(face); - } -} - -static void add_path_fonts(NSFileManager *file_manager, NSString *path) -{ - NSArray *files = NULL; - - files = [file_manager contentsOfDirectoryAtPath:path error:nil]; - - for (NSString *file in files) { - NSString *full_path = [path stringByAppendingPathComponent:file]; - - add_path_font(full_path.fileSystemRepresentation); - } -} - -void load_os_font_list(void) -{ - @autoreleasepool { - BOOL is_dir; - NSArray *paths = NSSearchPathForDirectoriesInDomains( - NSLibraryDirectory, NSAllDomainsMask, true); - - for (NSString *path in paths) { - NSFileManager *file_manager = - [NSFileManager defaultManager]; - NSString *font_path = - [path stringByAppendingPathComponent:@"Fonts"]; - - bool folder_exists = [file_manager - fileExistsAtPath:font_path - isDirectory:&is_dir]; - - if (folder_exists && is_dir) - add_path_fonts(file_manager, font_path); - } - } -} diff --git a/plugins/text-freetype2/find-font-iconv.c b/plugins/text-freetype2/find-font-iconv.c deleted file mode 100644 index 21b96268f..000000000 --- a/plugins/text-freetype2/find-font-iconv.c +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include -#include "find-font.h" - -struct mac_font_mapping { - unsigned short encoding_id; - unsigned short language_id; - const char *code_page; -}; - -#define TT_MAC_LANGID_ANY 0xFFFF - -static const struct mac_font_mapping mac_codes[] = { - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ENGLISH, "macintosh"}, - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ICELANDIC,"x-mac-icelandic"}, - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_TURKISH, "x-mac-ce"}, - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_POLISH, "x-mac-ce"}, - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ROMANIAN, "x-mac-romanian"}, - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_CZECH, "x-mac-ce"}, - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_SLOVAK, "x-mac-ce"}, - {TT_MAC_ID_ROMAN, TT_MAC_LANGID_ANY, "macintosh"}, - {TT_MAC_ID_JAPANESE, TT_MAC_LANGID_JAPANESE, "Shift_JIS"}, - {TT_MAC_ID_JAPANESE, TT_MAC_LANGID_ANY, "Shift_JIS"}, - {TT_MAC_ID_KOREAN, TT_MAC_LANGID_KOREAN, "EUC-KR"}, - {TT_MAC_ID_KOREAN, TT_MAC_LANGID_ANY, "EUC-KR"}, - {TT_MAC_ID_ARABIC, TT_MAC_LANGID_ARABIC, "x-mac-arabic"}, - {TT_MAC_ID_ARABIC, TT_MAC_LANGID_URDU, "x-mac-farsi"}, - {TT_MAC_ID_ARABIC, TT_MAC_LANGID_FARSI, "x-mac-farsi"}, - {TT_MAC_ID_ARABIC, TT_MAC_LANGID_ANY, "x-mac-arabic"}, - {TT_MAC_ID_HEBREW, TT_MAC_LANGID_HEBREW, "x-mac-hebrew"}, - {TT_MAC_ID_HEBREW, TT_MAC_LANGID_ANY, "x-mac-hebrew"}, - {TT_MAC_ID_GREEK, TT_MAC_LANGID_ANY, "x-mac-greek"}, - {TT_MAC_ID_RUSSIAN, TT_MAC_LANGID_ANY, "x-mac-cyrillic"}, - {TT_MAC_ID_DEVANAGARI, TT_MAC_LANGID_ANY, "x-mac-devanagari"}, - {TT_MAC_ID_GURMUKHI, TT_MAC_LANGID_ANY, "x-mac-gurmukhi"}, - {TT_MAC_ID_GUJARATI, TT_MAC_LANGID_ANY, "x-mac-gujarati"}, - { - TT_MAC_ID_TRADITIONAL_CHINESE, - TT_MAC_LANGID_CHINESE_SIMPLIFIED, - "Big5" - }, - { - TT_MAC_ID_TRADITIONAL_CHINESE, - TT_MAC_LANGID_ANY, - "Big5" - }, - { - TT_MAC_ID_SIMPLIFIED_CHINESE, - TT_MAC_LANGID_CHINESE_SIMPLIFIED, - "GB2312" - }, - { - TT_MAC_ID_SIMPLIFIED_CHINESE, - TT_MAC_LANGID_ANY, - "GB2312" - } -}; - -const char *iso_codes[] = { - "us-ascii", - NULL, - "iso-8859-1" -}; - -const char *ms_codes[] = { - "UTF-16BE", - "UTF-16BE", - "Shift_JIS", - NULL, - "Big5", - NULL, - NULL, - NULL, - NULL, - NULL, - "UTF-16BE" -}; - -static const size_t mac_code_count = sizeof(mac_codes) / sizeof(mac_codes[0]); -static const size_t iso_code_count = sizeof(iso_codes) / sizeof(iso_codes[0]); -static const size_t ms_code_count = sizeof(ms_codes) / sizeof(ms_codes[0]); - -static const char *get_mac_code(uint16_t encoding_id, uint16_t language_id) -{ - for (size_t i = 0; i < mac_code_count; i++) { - const struct mac_font_mapping *mac_code = &mac_codes[i]; - - if (mac_code->encoding_id == encoding_id && - mac_code->language_id == language_id) - return mac_code->code_page; - } - - return NULL; -} - -static const char *get_code_page_for_font(uint16_t platform_id, - uint16_t encoding_id, uint16_t language_id) -{ - const char *ret; - - switch (platform_id) { - case TT_PLATFORM_APPLE_UNICODE: - return "UTF-16BE"; - case TT_PLATFORM_MACINTOSH: - ret = get_mac_code(encoding_id, language_id); - if (!ret) - ret = get_mac_code(encoding_id, TT_MAC_LANGID_ANY); - return ret; - case TT_PLATFORM_ISO: - if (encoding_id < iso_code_count) - return iso_codes[encoding_id]; - break; - case TT_PLATFORM_MICROSOFT: - if (encoding_id < ms_code_count) - return ms_codes[encoding_id]; - break; - } - - return NULL; -} - -char *sfnt_name_to_utf8(FT_SfntName *sfnt_name) -{ - const char *charset = get_code_page_for_font(sfnt_name->platform_id, - sfnt_name->encoding_id, sfnt_name->language_id); - char utf8[256]; - char *conv_in, *conv_out; - size_t in_len, out_len; - - if (!charset) { - blog(LOG_DEBUG, "invalid character set found, " - "platform_id: %d, encoding_id: %d, " - "language_id: %d", - sfnt_name->platform_id, - sfnt_name->encoding_id, - sfnt_name->language_id); - return NULL; - } - - iconv_t ic = iconv_open("UTF-8", charset); - if (ic == (iconv_t)-1) { - blog(LOG_WARNING, "couldn't intialize font code page " - "conversion: '%s' to 'utf-8': errno = %d", - charset, (int)errno); - return NULL; - } - - conv_in = (char*)sfnt_name->string; - conv_out = utf8; - in_len = sfnt_name->string_len; - out_len = 256; - - size_t n = iconv(ic, &conv_in, &in_len, &conv_out, &out_len); - if (n == (size_t)-1) { - blog(LOG_WARNING, "couldn't convert font name text: errno = %d", - (int)errno); - iconv_close(ic); - return NULL; - } - - iconv_close(ic); - *conv_out = 0; - return bstrdup(utf8); -} diff --git a/plugins/text-freetype2/find-font-unix.c b/plugins/text-freetype2/find-font-unix.c new file mode 100644 index 000000000..95a073878 --- /dev/null +++ b/plugins/text-freetype2/find-font-unix.c @@ -0,0 +1,73 @@ +/* +Copyright (C) 2014 by Leonhard Oelke + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include + +#include + +#include "find-font.h" +#include "text-freetype2.h" + +void free_os_font_list(void) +{ +} + +void load_os_font_list(void) +{ +} + +const char *get_font_path(const char *family, uint16_t size, const char *style, + uint32_t flags, FT_Long *idx) +{ + bool bold = !!(flags & OBS_FONT_BOLD); + bool italic = !!(flags & OBS_FONT_ITALIC); + FcPattern *pattern = FcPatternCreate(); + FcPattern *match = NULL; + bool success = false; + FcResult match_result; + + /* somewhat of a cheap hack */ + static __thread char result[512]; + + FcPatternAddString(pattern, FC_FAMILY, (const FcChar8*)family); + FcPatternAddString(pattern, FC_STYLE, (const FcChar8*)style); + FcPatternAddInteger(pattern, FC_WEIGHT, + bold ? FC_WEIGHT_BOLD : FC_WEIGHT_REGULAR); + FcPatternAddInteger(pattern, FC_SLANT, + italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); + FcPatternAddDouble(pattern, FC_SIZE, (double)size); + + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + match = FcFontMatch(NULL, pattern, &match_result); + if (match) { + FcChar8 *path = FcPatternFormat(match, + (const FcChar8*)"%{file}"); + strncpy(result, (char*)path, 511); + FcStrFree(path); + + int fc_index = 0; + FcPatternGetInteger(match, FC_INDEX, 1, &fc_index); + *idx = (FT_Long)fc_index; + + FcPatternDestroy(match); + success = true; + } + + FcPatternDestroy(pattern); + return success ? &result[0] : NULL; +} diff --git a/plugins/text-freetype2/find-font-windows.c b/plugins/text-freetype2/find-font-windows.c index fde8930fb..00bdb0247 100644 --- a/plugins/text-freetype2/find-font-windows.c +++ b/plugins/text-freetype2/find-font-windows.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include "find-font.h" @@ -8,7 +10,7 @@ #include #include -extern DARRAY(struct font_path_info) font_list; +DARRAY(struct font_path_info) font_list; struct mac_font_mapping { unsigned short encoding_id; @@ -155,7 +157,7 @@ static char *convert_utf16_be_to_utf8(FT_SfntName *sfnt_name) return utf8_str; } -char *sfnt_name_to_utf8(FT_SfntName *sfnt_name) +static char *sfnt_name_to_utf8(FT_SfntName *sfnt_name) { unsigned int code_page = get_code_page_for_font( sfnt_name->platform_id, @@ -190,6 +192,122 @@ char *sfnt_name_to_utf8(FT_SfntName *sfnt_name) return utf8_str; } +static void create_bitmap_sizes(struct font_path_info *info, FT_Face face) +{ + DARRAY(int) sizes; + + if (!info->is_bitmap) { + info->num_sizes = 0; + info->sizes = NULL; + return; + } + + da_init(sizes); + da_reserve(sizes, face->num_fixed_sizes); + + for (int i = 0; i < face->num_fixed_sizes; i++) { + int val = face->available_sizes[i].size >> 6; + da_push_back(sizes, &val); + } + + info->sizes = sizes.array; + info->num_sizes = face->num_fixed_sizes; +} + +static void add_font_path(FT_Face face, + FT_Long idx, + const char *family_in, + const char *style_in, + const char *path) +{ + if (!family_in || !style_in || !path) + return; + + struct dstr face_and_style = {0}; + struct font_path_info info; + + dstr_copy(&face_and_style, family_in); + if (face->style_name) { + struct dstr style = {0}; + + dstr_copy(&style, style_in); + dstr_replace(&style, "Bold", ""); + dstr_replace(&style, "Italic", ""); + dstr_replace(&style, " ", " "); + dstr_depad(&style); + + if (!dstr_is_empty(&style)) { + dstr_cat(&face_and_style, " "); + dstr_cat_dstr(&face_and_style, &style); + } + + dstr_free(&style); + } + + info.face_and_style = face_and_style.array; + info.full_len = face_and_style.len; + info.face_len = strlen(family_in); + + info.is_bitmap = !!(face->face_flags & FT_FACE_FLAG_FIXED_SIZES); + info.bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD); + info.italic = !!(face->style_flags & FT_STYLE_FLAG_ITALIC); + info.index = idx; + + info.path = bstrdup(path); + + create_bitmap_sizes(&info, face); + da_push_back(font_list, &info); + + /*blog(LOG_DEBUG, "name: %s\n\tstyle: %s\n\tpath: %s\n", + family_in, + style_in, + path);*/ +} + +static void build_font_path_info(FT_Face face, FT_Long idx, const char *path) +{ + FT_UInt num_names = FT_Get_Sfnt_Name_Count(face); + DARRAY(char*) family_names; + + da_init(family_names); + da_push_back(family_names, &face->family_name); + + for (FT_UInt i = 0; i < num_names; i++) { + FT_SfntName name; + char *family; + FT_Error ret = FT_Get_Sfnt_Name(face, i, &name); + + if (ret != 0 || name.name_id != TT_NAME_ID_FONT_FAMILY) + continue; + + family = sfnt_name_to_utf8(&name); + if (!family) + continue; + + for (size_t i = 0; i < family_names.num; i++) { + if (astrcmpi(family_names.array[i], family) == 0) { + bfree(family); + family = NULL; + break; + } + } + + if (family) + da_push_back(family_names, &family); + } + + for (size_t i = 0; i < family_names.num; i++) { + add_font_path(face, idx, family_names.array[i], + face->style_name, path); + + /* first item isn't our allocation */ + if (i > 0) + bfree(family_names.array[i]); + } + + da_free(family_names); +} + void load_os_font_list(void) { struct dstr path = {0}; @@ -246,3 +364,87 @@ void load_os_font_list(void) free_string: dstr_free(&path); } + +void free_os_font_list(void) +{ + for (size_t i = 0; i < font_list.num; i++) + font_path_info_free(font_list.array + i); + da_free(font_list); +} + +static inline size_t get_rating(struct font_path_info *info, struct dstr *cmp) +{ + const char *src = info->face_and_style; + const char *dst = cmp->array; + size_t num = 0; + + do { + char ch1 = (char)toupper(*src); + char ch2 = (char)toupper(*dst); + + if (ch1 != ch2) + break; + + num++; + } while (*src++ && *dst++); + + return num; +} + +const char *get_font_path(const char *family, uint16_t size, const char *style, + uint32_t flags, FT_Long *idx) +{ + const char *best_path = NULL; + double best_rating = 0.0; + struct dstr face_and_style = {0}; + struct dstr style_str = {0}; + bool bold = !!(flags & OBS_FONT_BOLD); + bool italic = !!(flags & OBS_FONT_ITALIC); + + if (!family) + return NULL; + + dstr_copy(&style_str, style); + dstr_replace(&style_str, "Bold", ""); + dstr_replace(&style_str, "Italic", ""); + dstr_replace(&style_str, " ", " "); + dstr_depad(&style_str); + + dstr_copy(&face_and_style, family); + if (!dstr_is_empty(&style_str)) { + dstr_cat(&face_and_style, " "); + dstr_cat_dstr(&face_and_style, &style_str); + } + + for (size_t i = 0; i < font_list.num; i++) { + struct font_path_info *info = font_list.array + i; + + double rating = (double)get_rating(info, &face_and_style); + if (rating < info->face_len) + continue; + + if (info->is_bitmap) { + int best_diff = 1000; + for (size_t j = 0; j < info->num_sizes; j++) { + int diff = abs(info->sizes[j] - size); + if (diff < best_diff) + best_diff = diff; + } + + rating /= (double)(best_diff + 1.0); + } + + if (info->bold == bold) rating += 1.0; + if (info->italic == italic) rating += 1.0; + + if (rating > best_rating) { + best_path = info->path; + *idx = info->index; + best_rating = rating; + } + } + + dstr_free(&style_str); + dstr_free(&face_and_style); + return best_path; +} diff --git a/plugins/text-freetype2/find-font.c b/plugins/text-freetype2/find-font.c deleted file mode 100644 index c1a3dfa8a..000000000 --- a/plugins/text-freetype2/find-font.c +++ /dev/null @@ -1,202 +0,0 @@ -#include -#include -#include "find-font.h" - -DARRAY(struct font_path_info) font_list; - -static void create_bitmap_sizes(struct font_path_info *info, FT_Face face) -{ - DARRAY(int) sizes; - - if (!info->is_bitmap) { - info->num_sizes = 0; - info->sizes = NULL; - return; - } - - da_init(sizes); - da_reserve(sizes, face->num_fixed_sizes); - - for (int i = 0; i < face->num_fixed_sizes; i++) { - int val = face->available_sizes[i].size >> 6; - da_push_back(sizes, &val); - } - - info->sizes = sizes.array; - info->num_sizes = face->num_fixed_sizes; -} - -static void add_font_path(FT_Face face, - FT_Long idx, - const char *family_in, - const char *style_in, - const char *path) -{ - struct dstr face_and_style = {0}; - struct font_path_info info; - - dstr_copy(&face_and_style, family_in); - if (face->style_name) { - struct dstr style = {0}; - - dstr_copy(&style, style_in); - dstr_replace(&style, "Bold", ""); - dstr_replace(&style, "Italic", ""); - dstr_replace(&style, " ", " "); - dstr_depad(&style); - - if (!dstr_is_empty(&style)) { - dstr_cat(&face_and_style, " "); - dstr_cat_dstr(&face_and_style, &style); - } - - dstr_free(&style); - } - - info.face_and_style = face_and_style.array; - info.full_len = face_and_style.len; - info.face_len = strlen(family_in); - - info.is_bitmap = !!(face->face_flags & FT_FACE_FLAG_FIXED_SIZES); - info.bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD); - info.italic = !!(face->style_flags & FT_STYLE_FLAG_ITALIC); - info.index = idx; - - info.path = bstrdup(path); - - create_bitmap_sizes(&info, face); - da_push_back(font_list, &info); - - /*blog(LOG_DEBUG, "name: %s\n\tstyle: %s\n\tpath: %s\n", - family_in, - style_in, - path);*/ -} - -void build_font_path_info(FT_Face face, FT_Long idx, const char *path) -{ - FT_UInt num_names = FT_Get_Sfnt_Name_Count(face); - DARRAY(char*) family_names; - - da_init(family_names); - da_push_back(family_names, &face->family_name); - - for (FT_UInt i = 0; i < num_names; i++) { - FT_SfntName name; - char *family; - FT_Error ret = FT_Get_Sfnt_Name(face, i, &name); - - if (ret != 0 || name.name_id != TT_NAME_ID_FONT_FAMILY) - continue; - - family = sfnt_name_to_utf8(&name); - if (!family) - continue; - - for (size_t i = 0; i < family_names.num; i++) { - if (astrcmpi(family_names.array[i], family) == 0) { - bfree(family); - family = NULL; - break; - } - } - - if (family) - da_push_back(family_names, &family); - } - - for (size_t i = 0; i < family_names.num; i++) { - add_font_path(face, idx, family_names.array[i], - face->style_name, path); - - /* first item isn't our allocation */ - if (i > 0) - bfree(family_names.array[i]); - } - - da_free(family_names); -} - -void free_os_font_list(void) -{ - for (size_t i = 0; i < font_list.num; i++) - font_path_info_free(font_list.array + i); - da_free(font_list); -} - -static inline size_t get_rating(struct font_path_info *info, struct dstr *cmp) -{ - const char *src = info->face_and_style; - const char *dst = cmp->array; - size_t num = 0; - - do { - char ch1 = (char)toupper(*src); - char ch2 = (char)toupper(*dst); - - if (ch1 != ch2) - break; - - num++; - } while (*src++ && *dst++); - - return num; -} - -const char *get_font_path(const char *family, uint16_t size, const char *style, - uint32_t flags, FT_Long *idx) -{ - const char *best_path = NULL; - double best_rating = 0.0; - struct dstr face_and_style = {0}; - struct dstr style_str = {0}; - bool bold = !!(flags & OBS_FONT_BOLD); - bool italic = !!(flags & OBS_FONT_ITALIC); - - if (!family) - return NULL; - - dstr_copy(&style_str, style); - dstr_replace(&style_str, "Bold", ""); - dstr_replace(&style_str, "Italic", ""); - dstr_replace(&style_str, " ", " "); - dstr_depad(&style_str); - - dstr_copy(&face_and_style, family); - if (!dstr_is_empty(&style_str)) { - dstr_cat(&face_and_style, " "); - dstr_cat_dstr(&face_and_style, &style_str); - } - - for (size_t i = 0; i < font_list.num; i++) { - struct font_path_info *info = font_list.array + i; - - double rating = (double)get_rating(info, &face_and_style); - if (rating < info->face_len) - continue; - - if (info->is_bitmap) { - int best_diff = 1000; - for (size_t j = 0; j < info->num_sizes; j++) { - int diff = abs(info->sizes[j] - size); - if (diff < best_diff) - best_diff = diff; - } - - rating /= (double)(best_diff + 1.0); - } - - if (info->bold == bold) rating += 1.0; - if (info->italic == italic) rating += 1.0; - - if (rating > best_rating) { - best_path = info->path; - *idx = info->index; - best_rating = rating; - } - } - - dstr_free(&style_str); - dstr_free(&face_and_style); - return best_path; -}