cache font name/path for system fonts

This commit is contained in:
UnknownShadow200 2018-11-28 02:03:01 +11:00
parent 6b8d5db100
commit c1d4e67fa0
5 changed files with 69 additions and 36 deletions

View File

@ -10,5 +10,4 @@ void ErrorHandler_Init(void);
void ErrorHandler_Log(const String* msg); void ErrorHandler_Log(const String* msg);
void ErrorHandler_Fail(const char* raw_msg); void ErrorHandler_Fail(const char* raw_msg);
CC_NOINLINE void ErrorHandler_Fail2(ReturnCode result, const char* raw_msg); CC_NOINLINE void ErrorHandler_Fail2(ReturnCode result, const char* raw_msg);
#define ErrorHandler_CheckOrFail(result, raw_msg) if (result) { ErrorHandler_Fail2(result, raw_msg); }
#endif #endif

View File

@ -7,6 +7,7 @@
#include "Funcs.h" #include "Funcs.h"
#include "AsyncDownloader.h" #include "AsyncDownloader.h"
#include "Bitmap.h" #include "Bitmap.h"
#include "Window.h"
#define FT_EXPORT(x) extern x #define FT_EXPORT(x) extern x
#include "freetype/ft2build.h" #include "freetype/ft2build.h"
@ -799,7 +800,8 @@ void Waitable_WaitFor(void* handle, uint32_t milliseconds) {
*#########################################################################################################################*/ *#########################################################################################################################*/
static FT_Library ft_lib; static FT_Library ft_lib;
static struct FT_MemoryRec_ ft_mem; static struct FT_MemoryRec_ ft_mem;
static StringsBuffer norm_fonts, bold_fonts; static struct EntryList font_list;
static bool font_list_changed;
static void Font_Init(void); static void Font_Init(void);
#define DPI_PIXEL 72 #define DPI_PIXEL 72
@ -870,21 +872,31 @@ static int Font_Find(const String* name, StringsBuffer* entries) {
} }
void Font_GetNames(StringsBuffer* buffer) { void Font_GetNames(StringsBuffer* buffer) {
String faceName; String entry, name, path;
int i; int i;
if (!norm_fonts.Count) Font_Init(); if (!font_list.Entries.Count) Font_Init();
for (i = 1; i < norm_fonts.Count; i += 2) { for (i = 0; i < font_list.Entries.Count; i++) {
faceName = StringsBuffer_UNSAFE_Get(&norm_fonts, i); entry = StringsBuffer_UNSAFE_Get(&font_list.Entries, i);
StringsBuffer_Add(buffer, &faceName); String_UNSAFE_Separate(&entry, font_list.Separator, &name, &path);
/* remove " B"/" R" at end of font name */
if (name.length < 2) continue;
name.length -= 2;
StringsBuffer_Add(buffer, &name);
} }
} }
void Font_Make(FontDesc* desc, const String* fontName, int size, int style) { static String Font_Lookup(const String* fontName, const char type) {
StringsBuffer* entries; String name; char nameBuffer[STRING_SIZE + 2];
int idx; String_InitArray(name, nameBuffer);
String path;
String_Format2(&name, "%s %r", fontName, &type);
return EntryList_UNSAFE_Get(&font_list, &name);
}
void Font_Make(FontDesc* desc, const String* fontName, int size, int style) {
String path;
FT_Stream stream; FT_Stream stream;
FT_Open_Args args; FT_Open_Args args;
FT_Face face; FT_Face face;
@ -892,19 +904,13 @@ void Font_Make(FontDesc* desc, const String* fontName, int size, int style) {
desc->Size = size; desc->Size = size;
desc->Style = style; desc->Style = style;
if (!norm_fonts.Count) Font_Init();
idx = -1; if (!font_list.Entries.Count) Font_Init();
entries = &bold_fonts; path = String_Empty;
if (style & FONT_STYLE_BOLD) { idx = Font_Find(fontName, entries); }
if (idx == -1) { if (style & FONT_STYLE_BOLD) path = Font_Lookup(fontName, 'B');
entries = &norm_fonts; if (!path.length) path = Font_Lookup(fontName, 'R');
idx = Font_Find(fontName, entries); if (!path.length) ErrorHandler_Fail("Unknown font");
}
if (idx == -1) ErrorHandler_Fail("Unknown font");
path = StringsBuffer_UNSAFE_Get(entries, idx - 1);
stream = Mem_AllocCleared(1, sizeof(FT_StreamRec), "leaky font"); /* TODO: LEAKS MEMORY!!! */ stream = Mem_AllocCleared(1, sizeof(FT_StreamRec), "leaky font"); /* TODO: LEAKS MEMORY!!! */
if (!Font_MakeArgs(&path, stream, &args)) return; if (!Font_MakeArgs(&path, stream, &args)) return;
@ -941,15 +947,14 @@ void Font_Free(FontDesc* desc) {
desc->Handle = NULL; desc->Handle = NULL;
} }
static void Font_Add(const String* path, FT_Face face, StringsBuffer* entries, const char* defStyle) { static void Font_Add(const String* path, FT_Face face, char type, const char* defStyle) {
String name; char nameBuffer[STRING_SIZE]; String name; char nameBuffer[STRING_SIZE];
String style; String style;
if (!face->family_name || !(face->face_flags & FT_FACE_FLAG_SCALABLE)) return; if (!face->family_name || !(face->face_flags & FT_FACE_FLAG_SCALABLE)) return;
StringsBuffer_Add(entries, path);
String_InitArray(name, nameBuffer); String_InitArray(name, nameBuffer);
String_AppendConst(&name, face->family_name); String_AppendConst(&name, face->family_name);
/* don't want 'Arial Regular' or 'Arial Bold' */ /* don't want 'Arial Regular' or 'Arial Bold' */
if (face->style_name) { if (face->style_name) {
style = String_FromReadonly(face->style_name); style = String_FromReadonly(face->style_name);
@ -959,14 +964,19 @@ static void Font_Add(const String* path, FT_Face face, StringsBuffer* entries, c
} }
Platform_Log1("Face: %s", &name); Platform_Log1("Face: %s", &name);
StringsBuffer_Add(entries, &name); String_Append(&name, ' '); String_Append(&name, type);
EntryList_Set(&font_list, &name, path);
font_list_changed = true;
} }
static void Font_DirCallback(const String* path, void* obj) { static void Font_DirCallback(const String* path, void* obj) {
static String fonExt = String_FromConst(".fon");
String entry, name, fontPath;
FT_StreamRec stream = { 0 }; FT_StreamRec stream = { 0 };
FT_Open_Args args; FT_Open_Args args;
FT_Face face; FT_Face face;
FT_Error err; FT_Error err;
int i, flags;
if (!Font_MakeArgs(path, &stream, &args)) return; if (!Font_MakeArgs(path, &stream, &args)) return;
@ -979,13 +989,28 @@ static void Font_DirCallback(const String* path, void* obj) {
args.pathname = filename.buffer; args.pathname = filename.buffer;
#endif #endif
/* If font is already known good, skip it */
for (i = 0; i < font_list.Entries.Count; i++) {
entry = StringsBuffer_UNSAFE_Get(&font_list.Entries, i);
String_UNSAFE_Separate(&entry, font_list.Separator, &name, &fontPath);
if (String_CaselessEquals(path, &fontPath)) return;
}
/* Completely skip windows .FON files */
if (String_CaselessEnds(path, &fonExt)) return;
err = FT_New_Face(ft_lib, &args, 0, &face); err = FT_New_Face(ft_lib, &args, 0, &face);
if (err) { stream.close(&stream); return; } if (err) { stream.close(&stream); return; }
flags = face->style_flags;
if (face->style_flags == FT_STYLE_FLAG_BOLD) { if (flags == (FT_STYLE_FLAG_BOLD | FT_STYLE_FLAG_ITALIC)) {
Font_Add(path, face, &bold_fonts, "Bold"); Font_Add(path, face, 'Z', "Bold Italic");
} else if (face->style_flags == 0) { } else if (flags == FT_STYLE_FLAG_BOLD) {
Font_Add(path, face, &norm_fonts, "Regular"); Font_Add(path, face, 'B', "Bold");
} else if (flags == FT_STYLE_FLAG_ITALIC) {
Font_Add(path, face, 'I', "Italic");
} else if (flags == 0) {
Font_Add(path, face, 'R', "Regular");
} }
FT_Done_Face(face); FT_Done_Face(face);
} }
@ -1083,6 +1108,7 @@ static void* FT_ReallocWrapper(FT_Memory memory, long cur_size, long new_size, v
return Mem_Realloc(block, new_size, 1, "Freetype data"); return Mem_Realloc(block, new_size, 1, "Freetype data");
} }
#define FONT_CACHE_FILE "fontcache.txt"
static void Font_Init(void) { static void Font_Init(void) {
#ifdef CC_BUILD_WIN #ifdef CC_BUILD_WIN
static String dir = String_FromConst("C:\\Windows\\fonts"); static String dir = String_FromConst("C:\\Windows\\fonts");
@ -1096,6 +1122,7 @@ static void Font_Init(void) {
#ifdef CC_BUILD_OSX #ifdef CC_BUILD_OSX
static String dir = String_FromConst("/Library/Fonts"); static String dir = String_FromConst("/Library/Fonts");
#endif #endif
static String cachePath = String_FromConst(FONT_CACHE_FILE);
FT_Error err; FT_Error err;
ft_mem.alloc = FT_AllocWrapper; ft_mem.alloc = FT_AllocWrapper;
@ -1107,7 +1134,14 @@ static void Font_Init(void) {
FT_Add_Default_Modules(ft_lib); FT_Add_Default_Modules(ft_lib);
FT_Set_Default_Properties(ft_lib); FT_Set_Default_Properties(ft_lib);
if (!File_Exists(&cachePath)) {
Window_ShowDialog("One time load", "Initialising font cache, this can take several seconds.");
}
EntryList_Init(&font_list, NULL, FONT_CACHE_FILE, '=');
Directory_Enum(&dir, NULL, Font_DirCallback); Directory_Enum(&dir, NULL, Font_DirCallback);
if (font_list_changed) EntryList_Save(&font_list);
} }

View File

@ -908,7 +908,7 @@ void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mod
win_handle = XCreateWindow(win_display, win_rootWin, x, y, width, height, win_handle = XCreateWindow(win_display, win_rootWin, x, y, width, height,
0, win_visual.depth /* CopyFromParent*/, InputOutput, win_visual.visual, 0, win_visual.depth /* CopyFromParent*/, InputOutput, win_visual.visual,
CWColormap | CWEventMask | CWBackPixel | CWBorderPixel, &attributes); CWColormap | CWEventMask | CWBackPixel | CWBorderPixel, &attributes);
if (!win_handle) ErrorHandler_Fail("XCreateWindow call failed"); if (!win_handle) ErrorHandler_Fail("XCreateWindow failed");
hints.base_width = width; hints.base_width = width;
hints.base_height = height; hints.base_height = height;
@ -1616,13 +1616,13 @@ void GLContext_Init(struct GraphicsMode* mode) {
Platform_LogConst("Context create failed. Trying indirect..."); Platform_LogConst("Context create failed. Trying indirect...");
ctx_Handle = glXCreateContext(win_display, &win_visual, NULL, false); ctx_Handle = glXCreateContext(win_display, &win_visual, NULL, false);
} }
if (!ctx_Handle) ErrorHandler_Fail("Failed to create context"); if (!ctx_Handle) ErrorHandler_Fail("Failed to create OpenGL context");
if (!glXIsDirect(win_display, ctx_Handle)) { if (!glXIsDirect(win_display, ctx_Handle)) {
Platform_LogConst("== WARNING: Context is not direct =="); Platform_LogConst("== WARNING: Context is not direct ==");
} }
if (!glXMakeCurrent(win_display, win_handle, ctx_Handle)) { if (!glXMakeCurrent(win_display, win_handle, ctx_Handle)) {
ErrorHandler_Fail("Failed to make context current."); ErrorHandler_Fail("Failed to make OpenGL context current.");
} }
/* GLX may return non-null function pointers that don't actually work */ /* GLX may return non-null function pointers that don't actually work */