mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-19 04:26:52 -04:00
cache font name/path for system fonts
This commit is contained in:
parent
6b8d5db100
commit
c1d4e67fa0
@ -1004,8 +1004,8 @@ static ReturnCode GZip_StreamWriteFirst(struct Stream* stream, uint8_t* data, ui
|
|||||||
|
|
||||||
void GZip_MakeStream(struct Stream* stream, struct GZipState* state, struct Stream* underlying) {
|
void GZip_MakeStream(struct Stream* stream, struct GZipState* state, struct Stream* underlying) {
|
||||||
Deflate_MakeStream(stream, &state->Base, underlying);
|
Deflate_MakeStream(stream, &state->Base, underlying);
|
||||||
state->Crc32 = 0xFFFFFFFFUL;
|
state->Crc32 = 0xFFFFFFFFUL;
|
||||||
state->Size = 0;
|
state->Size = 0;
|
||||||
stream->Write = GZip_StreamWriteFirst;
|
stream->Write = GZip_StreamWriteFirst;
|
||||||
stream->Close = GZip_StreamClose;
|
stream->Close = GZip_StreamClose;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user