Browse Source

Use fontconfig for linux/mac

This uses fontconfig for looking up font files for freetype to use on
both linux and mac.  It's apparently a bit more optimal and prevents us
from having to worry about the load time on the mac version as well.

Refactored and moved all the old code to the find-font-windows.c file,
as it's no longer used on anything but windows.
fryshorts 11 years ago
parent
commit
774731fbaf

+ 39 - 0
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()

+ 10 - 34
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)

+ 0 - 57
plugins/text-freetype2/find-font-cocoa.m

@@ -1,57 +0,0 @@
-#include <util/darray.h>
-#include "find-font.h"
-#include "text-freetype2.h"
-
-#import <Foundation/Foundation.h>
-
-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);
-		}
-	}
-}

+ 0 - 164
plugins/text-freetype2/find-font-iconv.c

@@ -1,164 +0,0 @@
-#include <iconv.h>
-#include <errno.h>
-#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);
-}

+ 73 - 0
plugins/text-freetype2/find-font-unix.c

@@ -0,0 +1,73 @@
+/*
+Copyright (C) 2014 by Leonhard Oelke <[email protected]>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+#include <fontconfig/fontconfig.h>
+
+#include <util/dstr.h>
+
+#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;
+}

+ 204 - 2
plugins/text-freetype2/find-font-windows.c

@@ -1,3 +1,5 @@
+#include <ctype.h>
+#include <obs.h>
 #include <util/dstr.h>
 #include <util/darray.h>
 #include "find-font.h"
@@ -8,7 +10,7 @@
 #include <shellapi.h>
 #include <shlobj.h>
 
-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;
+}

+ 0 - 202
plugins/text-freetype2/find-font.c

@@ -1,202 +0,0 @@
-#include <ctype.h>
-#include <obs.h>
-#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;
-}