Forráskód Böngészése

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).
jp9000 10 éve
szülő
commit
e91f5384b4

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

@@ -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;
 }

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

@@ -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)
 {
 }

+ 43 - 0
plugins/text-freetype2/find-font-windows.c

@@ -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);
 }

+ 197 - 5
plugins/text-freetype2/find-font.c

@@ -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;

+ 11 - 10
plugins/text-freetype2/find-font.h

@@ -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,

+ 8 - 1
plugins/text-freetype2/text-freetype2.c

@@ -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);