text-freetype2: Cache data to reduce load time
This caches the font list data to a file to minimize load times. Font data will be refreshed when any font files are added/removed, based upon a checksum of the font file names and dates (if available).master
parent
f29ac7770c
commit
e91f5384b4
|
@ -1,9 +1,12 @@
|
|||
#include <util/darray.h>
|
||||
#include <util/crc32.h>
|
||||
#include "find-font.h"
|
||||
#include "text-freetype2.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern void save_font_list(void);
|
||||
|
||||
static inline void add_path_font(const char *path)
|
||||
{
|
||||
FT_Face face;
|
||||
|
@ -53,5 +56,59 @@ void load_os_font_list(void)
|
|||
if (folder_exists && is_dir)
|
||||
add_path_fonts(file_manager, font_path);
|
||||
}
|
||||
|
||||
save_font_list();
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t add_font_checksum(uint32_t checksum, const char *path)
|
||||
{
|
||||
if (path && *path)
|
||||
checksum = calc_crc32(checksum, path, strlen(path));
|
||||
return checksum;
|
||||
}
|
||||
|
||||
static uint32_t add_font_checksum_path(uint32_t checksum,
|
||||
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];
|
||||
|
||||
checksum = add_font_checksum(checksum,
|
||||
full_path.fileSystemRepresentation);
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
uint32_t get_font_checksum(void)
|
||||
{
|
||||
uint32_t checksum = 0;
|
||||
|
||||
@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)
|
||||
checksum = add_font_checksum_path(checksum,
|
||||
file_manager, font_path);
|
||||
}
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,11 @@ void free_os_font_list(void)
|
|||
{
|
||||
}
|
||||
|
||||
bool load_cached_os_font_list(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void load_os_font_list(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <util/dstr.h>
|
||||
#include <util/darray.h>
|
||||
#include <util/crc32.h>
|
||||
#include "find-font.h"
|
||||
#include "text-freetype2.h"
|
||||
|
||||
|
@ -9,6 +10,7 @@
|
|||
#include <shlobj.h>
|
||||
|
||||
extern DARRAY(struct font_path_info) font_list;
|
||||
extern void save_font_list(void);
|
||||
|
||||
struct mac_font_mapping {
|
||||
unsigned short encoding_id;
|
||||
|
@ -191,6 +193,45 @@ char *sfnt_name_to_utf8(FT_SfntName *sfnt_name)
|
|||
return utf8_str;
|
||||
}
|
||||
|
||||
uint32_t get_font_checksum(void)
|
||||
{
|
||||
uint32_t checksum = 0;
|
||||
struct dstr path = {0};
|
||||
HANDLE handle;
|
||||
WIN32_FIND_DATAA wfd;
|
||||
|
||||
dstr_reserve(&path, MAX_PATH);
|
||||
|
||||
HRESULT res = SHGetFolderPathA(NULL, CSIDL_FONTS, NULL,
|
||||
SHGFP_TYPE_CURRENT, path.array);
|
||||
if (res != S_OK) {
|
||||
blog(LOG_WARNING, "Error finding windows font folder");
|
||||
return 0;
|
||||
}
|
||||
|
||||
path.len = strlen(path.array);
|
||||
dstr_cat(&path, "\\*.*");
|
||||
|
||||
handle = FindFirstFileA(path.array, &wfd);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
goto free_string;
|
||||
|
||||
dstr_resize(&path, path.len - 4);
|
||||
|
||||
do {
|
||||
checksum = calc_crc32(checksum, &wfd.ftLastWriteTime,
|
||||
sizeof(FILETIME));
|
||||
checksum = calc_crc32(checksum, wfd.cFileName,
|
||||
strlen(wfd.cFileName));
|
||||
} while (FindNextFileA(handle, &wfd));
|
||||
|
||||
FindClose(handle);
|
||||
|
||||
free_string:
|
||||
dstr_free(&path);
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void load_os_font_list(void)
|
||||
{
|
||||
struct dstr path = {0};
|
||||
|
@ -244,6 +285,8 @@ void load_os_font_list(void)
|
|||
|
||||
FindClose(handle);
|
||||
|
||||
save_font_list();
|
||||
|
||||
free_string:
|
||||
dstr_free(&path);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,201 @@
|
|||
#include <util/file-serializer.h>
|
||||
#include <ctype.h>
|
||||
#include <obs.h>
|
||||
#include <time.h>
|
||||
#include <obs-module.h>
|
||||
#include "find-font.h"
|
||||
|
||||
DARRAY(struct font_path_info) font_list;
|
||||
|
||||
static inline bool read_data(struct serializer *s, void *data, size_t size)
|
||||
{
|
||||
return s_read(s, data, size) == size;
|
||||
}
|
||||
|
||||
static inline bool write_data(struct serializer *s, const void *data,
|
||||
size_t size)
|
||||
{
|
||||
return s_write(s, data, size) == size;
|
||||
}
|
||||
|
||||
#define read_var(s, data) read_data(s, &data, sizeof(data))
|
||||
#define write_var(s, data) write_data(s, &data, sizeof(data))
|
||||
|
||||
static bool read_str(struct serializer *s, char **p_str)
|
||||
{
|
||||
size_t size;
|
||||
char *str;
|
||||
|
||||
if (!read_var(s, size))
|
||||
return false;
|
||||
|
||||
str = bmalloc(size + 1);
|
||||
if (size && !read_data(s, str, size)) {
|
||||
bfree(str);
|
||||
return false;
|
||||
}
|
||||
|
||||
str[size] = 0;
|
||||
*p_str = str;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_str(struct serializer *s, const char *str)
|
||||
{
|
||||
size_t size = str ? strlen(str) : 0;
|
||||
|
||||
if (!write_var(s, size))
|
||||
return false;
|
||||
if (size && !write_data(s, str, size))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool load_cached_font_list(struct serializer *s)
|
||||
{
|
||||
bool success = true;
|
||||
int count;
|
||||
|
||||
success = read_var(s, count);
|
||||
if (!success) return false;
|
||||
|
||||
da_init(font_list);
|
||||
da_resize(font_list, count);
|
||||
|
||||
#define do_read(var) \
|
||||
success = read_var(s, var); \
|
||||
if (!success) break
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct font_path_info *info = &font_list.array[i];
|
||||
|
||||
success = read_str(s, &info->face_and_style);
|
||||
if (!success) break;
|
||||
|
||||
do_read(info->full_len);
|
||||
do_read(info->face_len);
|
||||
do_read(info->is_bitmap);
|
||||
do_read(info->num_sizes);
|
||||
|
||||
info->sizes = bmalloc(sizeof(int) * info->num_sizes);
|
||||
success = read_data(s, info->sizes,
|
||||
sizeof(int) * info->num_sizes);
|
||||
if (!success) break;
|
||||
|
||||
do_read(info->bold);
|
||||
|
||||
success = read_str(s, &info->path);
|
||||
if (!success) break;
|
||||
|
||||
do_read(info->italic);
|
||||
do_read(info->index);
|
||||
}
|
||||
|
||||
#undef do_read
|
||||
|
||||
if (!success) {
|
||||
free_os_font_list();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern uint32_t get_font_checksum();
|
||||
static const uint32_t font_cache_ver = 1;
|
||||
|
||||
bool load_cached_os_font_list(void)
|
||||
{
|
||||
char *file_name = obs_module_config_path("font_data.bin");
|
||||
uint32_t old_checksum;
|
||||
uint32_t new_checksum;
|
||||
struct serializer s;
|
||||
uint32_t ver;
|
||||
bool success;
|
||||
|
||||
success = file_input_serializer_init(&s, file_name);
|
||||
bfree(file_name);
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
success = read_data(&s, &ver, sizeof(ver));
|
||||
|
||||
if (!success || ver != font_cache_ver) {
|
||||
success = false;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
success = s_read(&s, &old_checksum, sizeof(old_checksum));
|
||||
new_checksum = get_font_checksum();
|
||||
|
||||
if (!success || old_checksum != new_checksum) {
|
||||
success = false;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
success = load_cached_font_list(&s);
|
||||
|
||||
finish:
|
||||
file_input_serializer_free(&s);
|
||||
return success;
|
||||
}
|
||||
|
||||
void save_font_list(void)
|
||||
{
|
||||
char *file_name = obs_module_config_path("font_data.bin");
|
||||
uint32_t font_checksum = get_font_checksum();
|
||||
int font_count = (int)font_list.num;
|
||||
struct serializer s;
|
||||
bool success = false;
|
||||
|
||||
if (font_checksum)
|
||||
success = file_output_serializer_init_safe(&s, file_name,
|
||||
"tmp");
|
||||
bfree(file_name);
|
||||
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
success = write_var(&s, font_cache_ver);
|
||||
if (!success) return;
|
||||
success = write_var(&s, font_checksum);
|
||||
if (!success) return;
|
||||
success = write_var(&s, font_count);
|
||||
if (!success) return;
|
||||
|
||||
#define do_write(var) \
|
||||
success = write_var(&s, var); \
|
||||
if (!success) break
|
||||
|
||||
for (size_t i = 0; i < font_list.num; i++) {
|
||||
struct font_path_info *info = &font_list.array[i];
|
||||
|
||||
success = write_str(&s, info->face_and_style);
|
||||
if (!success) break;
|
||||
|
||||
do_write(info->full_len);
|
||||
do_write(info->face_len);
|
||||
do_write(info->is_bitmap);
|
||||
do_write(info->num_sizes);
|
||||
|
||||
success = write_data(&s, info->sizes,
|
||||
sizeof(int) * info->num_sizes);
|
||||
if (!success) break;
|
||||
|
||||
do_write(info->bold);
|
||||
|
||||
success = write_str(&s, info->path);
|
||||
if (!success) break;
|
||||
|
||||
do_write(info->italic);
|
||||
do_write(info->index);
|
||||
}
|
||||
|
||||
#undef do_write
|
||||
|
||||
file_output_serializer_free(&s);
|
||||
}
|
||||
|
||||
static void create_bitmap_sizes(struct font_path_info *info, FT_Face face)
|
||||
{
|
||||
DARRAY(int) sizes;
|
||||
|
@ -23,7 +215,7 @@ static void create_bitmap_sizes(struct font_path_info *info, FT_Face face)
|
|||
}
|
||||
|
||||
info->sizes = sizes.array;
|
||||
info->num_sizes = face->num_fixed_sizes;
|
||||
info->num_sizes = (uint32_t)face->num_fixed_sizes;
|
||||
}
|
||||
|
||||
static void add_font_path(FT_Face face,
|
||||
|
@ -57,8 +249,8 @@ static void add_font_path(FT_Face face,
|
|||
}
|
||||
|
||||
info.face_and_style = face_and_style.array;
|
||||
info.full_len = face_and_style.len;
|
||||
info.face_len = strlen(family_in);
|
||||
info.full_len = (uint32_t)face_and_style.len;
|
||||
info.face_len = (uint32_t)strlen(family_in);
|
||||
|
||||
info.is_bitmap = !!(face->face_flags & FT_FACE_FLAG_FIXED_SIZES);
|
||||
info.bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD);
|
||||
|
@ -182,7 +374,7 @@ const char *get_font_path(const char *family, uint16_t size, const char *style,
|
|||
|
||||
if (info->is_bitmap) {
|
||||
int best_diff = 1000;
|
||||
for (size_t j = 0; j < info->num_sizes; j++) {
|
||||
for (uint32_t j = 0; j < info->num_sizes; j++) {
|
||||
int diff = abs(info->sizes[j] - size);
|
||||
if (diff < best_diff)
|
||||
best_diff = diff;
|
||||
|
|
|
@ -9,19 +9,19 @@
|
|||
#include <util/darray.h>
|
||||
|
||||
struct font_path_info {
|
||||
char *face_and_style;
|
||||
size_t full_len;
|
||||
size_t face_len;
|
||||
char *face_and_style;
|
||||
uint32_t full_len;
|
||||
uint32_t face_len;
|
||||
|
||||
bool is_bitmap;
|
||||
size_t num_sizes;
|
||||
int *sizes;
|
||||
bool is_bitmap;
|
||||
uint32_t num_sizes;
|
||||
int *sizes;
|
||||
|
||||
bool bold;
|
||||
bool italic;
|
||||
bool bold;
|
||||
bool italic;
|
||||
|
||||
char *path;
|
||||
FT_Long index;
|
||||
char *path;
|
||||
FT_Long index;
|
||||
};
|
||||
|
||||
static inline void font_path_info_free(struct font_path_info *info)
|
||||
|
@ -34,6 +34,7 @@ static inline void font_path_info_free(struct font_path_info *info)
|
|||
extern void build_font_path_info(FT_Face face, FT_Long idx, const char *path);
|
||||
extern char *sfnt_name_to_utf8(FT_SfntName *sfnt_name);
|
||||
|
||||
extern bool load_cached_os_font_list(void);
|
||||
extern void load_os_font_list(void);
|
||||
extern void free_os_font_list(void);
|
||||
extern const char *get_font_path(const char *family, uint16_t size,
|
||||
|
|
|
@ -48,6 +48,12 @@ static struct obs_source_info freetype2_source_info = {
|
|||
|
||||
bool obs_module_load()
|
||||
{
|
||||
char *config_dir = obs_module_config_path(NULL);
|
||||
if (config_dir) {
|
||||
os_mkdirs(config_dir);
|
||||
bfree(config_dir);
|
||||
}
|
||||
|
||||
FT_Init_FreeType(&ft2_lib);
|
||||
|
||||
if (ft2_lib == NULL) {
|
||||
|
@ -55,7 +61,8 @@ bool obs_module_load()
|
|||
return false;
|
||||
}
|
||||
|
||||
load_os_font_list();
|
||||
if (!load_cached_os_font_list())
|
||||
load_os_font_list();
|
||||
|
||||
obs_register_source(&freetype2_source_info);
|
||||
|
||||
|
|
Loading…
Reference in New Issue