summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-07-18 16:09:50 -0400
committerpommicket <pommicket@gmail.com>2023-07-19 19:02:27 -0400
commit94a6d21d4c2fe5fc2806cd28ae36a2b0e1928914 (patch)
tree4f37afc94b9bbac7571ee6a17a1a3a1d5dce0ba0
parentbe5dab846e38420961a68ff4503a48e2bd8bdf6b (diff)
new font management system
this lets us avoid reloading the font file from disk whenever the font size changes
-rw-r--r--command.c4
-rw-r--r--main.c5
-rw-r--r--ted.c55
-rw-r--r--ted.h12
-rw-r--r--text.c46
-rw-r--r--text.h2
-rw-r--r--valgrind_suppresions.txt85
7 files changed, 86 insertions, 123 deletions
diff --git a/command.c b/command.c
index 96c04b6..65d2072 100644
--- a/command.c
+++ b/command.c
@@ -532,7 +532,7 @@ void command_execute_ex(Ted *ted, Command c, CommandArgument full_argument, Comm
i64 new_text_size = settings->text_size + argument;
if (new_text_size >= TEXT_SIZE_MIN && new_text_size <= TEXT_SIZE_MAX) {
settings->text_size = (u16)new_text_size;
- ted_load_fonts(ted);
+ ted_change_text_size(ted, (float)new_text_size);
}
}
break;
@@ -541,7 +541,7 @@ void command_execute_ex(Ted *ted, Command c, CommandArgument full_argument, Comm
i64 new_text_size = settings->text_size - argument;
if (new_text_size >= TEXT_SIZE_MIN && new_text_size <= TEXT_SIZE_MAX) {
settings->text_size = (u16)new_text_size;
- ted_load_fonts(ted);
+ ted_change_text_size(ted, (float)new_text_size);
}
}
break;
diff --git a/main.c b/main.c
index 526eeb2..8fa816c 100644
--- a/main.c
+++ b/main.c
@@ -1,4 +1,6 @@
/*
+TODO:
+- clean up valgrind_suppresions.txt
FUTURE FEATURES:
- autodetect indentation (tabs vs spaces)
- font setting & support for multiple fonts to cover more characters
@@ -1214,8 +1216,7 @@ int main(int argc, char **argv) {
buffer_free(&ted->replace_buffer);
buffer_free(&ted->build_buffer);
buffer_free(&ted->argument_buffer);
- text_font_free(ted->font);
- text_font_free(ted->font_bold);
+ ted_free_fonts(ted);
config_free(ted);
macros_free(ted);
free(ted);
diff --git a/ted.c b/ted.c
index f526947..73a5969 100644
--- a/ted.c
+++ b/ted.c
@@ -287,31 +287,50 @@ Status ted_get_file(Ted const *ted, const char *name, char *out, size_t outsz) {
return false;
}
-// Loads font from filename into *out, freeing any font that was previously there.
-// *out is left unchanged on failure.
-static void ted_load_font(Ted *ted, const char *filename, Font **out) {
- char font_filename[TED_PATH_MAX];
- if (ted_get_file(ted, filename, font_filename, sizeof font_filename)) {
- Font *font = text_font_load(font_filename, ted_active_settings(ted)->text_size);
- if (font) {
- if (*out) {
- text_font_free(*out);
- }
- *out = font;
- } else {
- die("Couldn't load font: %s", text_get_err());
- }
- } else {
- die("Couldn't find font file. There is probably a problem with your ted installation.");
+static Font *ted_load_font(Ted *ted, const char *filename) {
+ char path[TED_PATH_MAX];
+ if (!ted_get_file(ted, filename, path, sizeof path)) {
+ die("Couldn't find font file %s", filename);
+ }
+
+ arr_foreach_ptr(ted->all_fonts, LoadedFont, f) {
+ if (paths_eq(path, f->path))
+ return f->font;
+ }
+
+ Font *font = text_font_load(path, ted_active_settings(ted)->text_size);
+ if (!font) {
+ die("Couldn't load font %s: %s\n", path, text_get_err());
}
+ LoadedFont *f = arr_addp(ted->all_fonts);
+ f->path = str_dup(path);
+ f->font = font;
+
+ return font;
}
void ted_load_fonts(Ted *ted) {
- ted_load_font(ted, "assets/font.ttf", &ted->font);
- ted_load_font(ted, "assets/font-bold.ttf", &ted->font_bold);
+ ted_free_fonts(ted);
+ ted->font = ted_load_font(ted, "assets/font.ttf");
+ ted->font_bold = ted_load_font(ted, "assets/font-bold.ttf");
}
+void ted_change_text_size(Ted *ted, float new_size) {
+ arr_foreach_ptr(ted->all_fonts, LoadedFont, f) {
+ text_font_change_size(f->font, new_size);
+ }
+}
+
+void ted_free_fonts(Ted *ted) {
+ arr_foreach_ptr(ted->all_fonts, LoadedFont, f) {
+ free(f->path);
+ text_font_free(f->font);
+ }
+ arr_clear(ted->all_fonts);
+ ted->font = NULL;
+ ted->font_bold = NULL;
+}
void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer) {
TextBuffer *search_buffer = find_search_buffer(ted);
diff --git a/ted.h b/ted.h
index 968b2ee..e3e75e1 100644
--- a/ted.h
+++ b/ted.h
@@ -725,6 +725,11 @@ typedef struct {
Action *actions;
} Macro;
+typedef struct {
+ char *path;
+ Font *font;
+} LoadedFont;
+
#define TED_MACRO_MAX 256
/// (almost) all data used by the ted application
@@ -739,6 +744,7 @@ typedef struct Ted {
bool executing_macro;
SDL_Window *window;
+ LoadedFont *all_fonts;
Font *font_bold;
Font *font;
TextBuffer *active_buffer;
@@ -1655,8 +1661,12 @@ TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path);
bool ted_save_all(Ted *ted);
/// reload all buffers from their files
void ted_reload_all(Ted *ted);
-/// Load all the fonts ted will use.
+/// Load all the fonts ted will use, freeing any previous ones.
void ted_load_fonts(Ted *ted);
+/// Change ted's font size. Avoid calling this super often since it trashes all current font textures.
+void ted_change_text_size(Ted *ted, float new_size);
+/// Free all of ted's fonts.
+void ted_free_fonts(Ted *ted);
/// Get likely root directory of project containing `path`.
/// The returned value should be freed.
char *ted_get_root_dir_of(Ted *ted, const char *path);
diff --git a/text.c b/text.c
index 670f2d0..bcca150 100644
--- a/text.c
+++ b/text.c
@@ -42,15 +42,13 @@ typedef struct {
GLuint tex;
bool needs_update;
unsigned char *pixels;
+ stbtt_pack_context pack_context;
TextTriangle *triangles;
} FontTexture;
struct Font {
bool force_monospace;
- float space_width; // width of the character ' '. calculated when font is loaded.
float char_height;
- stbtt_pack_context pack_context;
- stbtt_fontinfo stb_info;
FontTexture *textures; // dynamic array of textures
CharInfo *char_info[CHAR_BUCKET_COUNT]; // each entry is a dynamic array of char info
// TTF data (i.e. the contents of the TTF file)
@@ -144,7 +142,7 @@ static FontTexture *font_new_texture(Font *font) {
return NULL;
}
FontTexture *texture = arr_addp(font->textures);
- stbtt_PackBegin(&font->pack_context, pixels, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT,
+ stbtt_PackBegin(&texture->pack_context, pixels, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT,
FONT_TEXTURE_WIDTH, 1, NULL);
glGenTextures(1, &texture->tex);
PROFILE_TIME(end);
@@ -175,8 +173,10 @@ static void font_texture_update_if_needed(FontTexture *texture) {
static void font_texture_free(FontTexture *texture) {
glDeleteTextures(1, &texture->tex);
arr_free(texture->triangles);
- if (texture->pixels)
+ if (texture->pixels) {
free(texture->pixels);
+ stbtt_PackEnd(&texture->pack_context);
+ }
memset(texture, 0, sizeof *texture);
}
@@ -203,11 +203,11 @@ static Status text_load_char(Font *font, char32_t c, CharInfo *info) {
for (int i = 0; i < 2; i++) {
info->c = c;
info->texture = arr_len(font->textures) - 1;
- success = stbtt_PackFontRange(&font->pack_context, font->ttf_data, 0, font->char_height,
+ success = stbtt_PackFontRange(&texture->pack_context, font->ttf_data, 0, font->char_height,
(int)c, 1, &info->data);
if (success) break;
// texture is full; create a new one
- stbtt_PackEnd(&font->pack_context);
+ stbtt_PackEnd(&texture->pack_context);
font_texture_update_if_needed(texture);
free(texture->pixels);
texture->pixels = NULL;
@@ -257,11 +257,6 @@ Font *text_font_load(const char *ttf_filename, float font_size) {
if (bytes_read == file_size) {
font->char_height = font_size;
font->ttf_data = file_data;
- CharInfo space = {0};
- if (text_load_char(font, ' ', &space)) {
- // calculate width of the character ' '
- font->space_width = space.data.xadvance;
- }
} else {
text_set_err("Couldn't read font file.");
}
@@ -286,7 +281,6 @@ float text_font_char_height(Font *font) {
}
float text_font_char_width(Font *font, char32_t c) {
- if (c == ' ') return font->space_width;
CharInfo info = {0};
if (text_load_char(font, c, &info))
return info.data.xadvance;
@@ -358,7 +352,7 @@ top:
q.y1 += (float)floor(state->y);
if (font->force_monospace) {
- state->x += font->space_width; // ignore actual character width
+ state->x += text_font_char_width(font, ' ');
} else {
state->x = x + floor(state->x);
state->y = y + floor(state->y);
@@ -495,11 +489,29 @@ void text_get_size32(Font *font, const char32_t *text, u64 len, float *width, fl
if (height) *height = (float)render_state.y + font->char_height * (2/3.0f);
}
-void text_font_free(Font *font) {
- free(font->ttf_data);
+static void font_free_textures(Font *font) {
arr_foreach_ptr(font->textures, FontTexture, texture) {
font_texture_free(texture);
}
- arr_free(font->textures);
+ arr_clear(font->textures);
+}
+
+static void font_free_char_info(Font *font) {
+ for (u32 i = 0; i < CHAR_BUCKET_COUNT; i++) {
+ arr_free(font->char_info[i]);
+ }
+}
+
+void text_font_change_size(Font *font, float new_size) {
+ font_free_textures(font);
+ font_free_char_info(font);
+ font->char_height = new_size;
+}
+
+void text_font_free(Font *font) {
+ free(font->ttf_data);
+ font_free_textures(font);
+ font_free_char_info(font);
+ memset(font, 0, sizeof *font);
free(font);
}
diff --git a/text.h b/text.h
index c0cb260..79f99ad 100644
--- a/text.h
+++ b/text.h
@@ -68,6 +68,8 @@ const char *text_get_err(void);
void text_clear_err(void);
/// Load a TTF font found in ttf_filename with the given font size (character pixel height)
Font *text_font_load(const char *ttf_filename, float font_size);
+/// Change size of font. Avoid calling this function too often, since all font textures are trashed.
+void text_font_change_size(Font *font, float new_size);
/// Height of a character of this font in pixels.
float text_font_char_height(Font *font);
/// Width of the given character in pixels.
diff --git a/valgrind_suppresions.txt b/valgrind_suppresions.txt
index af09ee7..93c1872 100644
--- a/valgrind_suppresions.txt
+++ b/valgrind_suppresions.txt
@@ -155,42 +155,6 @@
{
<insert_a_suppression_name_here>
Memcheck:Addr8
- fun:strncmp
- fun:is_dst
- fun:_dl_dst_count
- fun:expand_dynamic_string_token
- fun:fillin_rpath.isra.0
- fun:decompose_rpath
- fun:cache_rpath
- fun:cache_rpath
- fun:_dl_map_object
- fun:openaux
- fun:_dl_catch_exception
- fun:_dl_map_object_deps
- fun:dl_open_worker
- fun:_dl_catch_exception
-}
-{
- <insert_a_suppression_name_here>
- Memcheck:Addr8
- fun:strncmp
- fun:is_dst
- fun:_dl_dst_substitute
- fun:fillin_rpath.isra.0
- fun:decompose_rpath
- fun:cache_rpath
- fun:cache_rpath
- fun:_dl_map_object
- fun:openaux
- fun:_dl_catch_exception
- fun:_dl_map_object_deps
- fun:dl_open_worker
- fun:_dl_catch_exception
- fun:_dl_open
-}
-{
- <insert_a_suppression_name_here>
- Memcheck:Addr8
obj:/usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0
obj:/usr/lib/x86_64-linux-gnu/libdrm.so.2.4.0
fun:drmGetDevice2
@@ -42907,52 +42871,7 @@
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: reachable
- fun:calloc
- fun:_dl_new_object
- fun:_dl_map_object_from_fd
- fun:_dl_map_object
- fun:openaux
- fun:_dl_catch_exception
- fun:_dl_map_object_deps
- fun:dl_open_worker
- fun:_dl_catch_exception
- fun:_dl_open
- fun:dlopen_doit
- fun:_dl_catch_exception
-}
-{
- <insert_a_suppression_name_here>
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:calloc
- fun:_ZN4llvm13StringMapImpl11RehashTableEj
- obj:/usr/lib/x86_64-linux-gnu/libLLVM-11.so.1
- obj:/usr/lib/x86_64-linux-gnu/libLLVM-11.so.1
- fun:_ZN4llvm2cl6Option11addArgumentEv
- obj:/usr/lib/x86_64-linux-gnu/libLLVM-11.so.1
- fun:call_init.part.0
- fun:call_init
- fun:_dl_init
- fun:_dl_catch_exception
- fun:dl_open_worker
- fun:_dl_catch_exception
- fun:_dl_open
-}
-{
- <insert_a_suppression_name_here>
- Memcheck:Leak
- match-leak-kinds: reachable
- fun:malloc
- obj:/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
- fun:call_init.part.0
- fun:call_init
- fun:_dl_init
- fun:_dl_catch_exception
- fun:dl_open_worker
- fun:_dl_catch_exception
- fun:_dl_open
- fun:dlopen_doit
+ ...
fun:_dl_catch_exception
- fun:_dl_catch_error
- fun:_dlerror_run
+ ...
}