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.
This commit is contained in:
parent
428c89ad4a
commit
774731fbaf
39
cmake/Modules/FindFontconfig.cmake
Normal file
39
cmake/Modules/FindFontconfig.cmake
Normal file
@ -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()
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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
plugins/text-freetype2/find-font-unix.c
Normal file
73
plugins/text-freetype2/find-font-unix.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright (C) 2014 by Leonhard Oelke <leonhard@in-verted.de>
|
||||
|
||||
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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user