diff --git a/data/plugins/language_md.lua b/data/plugins/language_md.lua index 93d937b1..64059d35 100644 --- a/data/plugins/language_md.lua +++ b/data/plugins/language_md.lua @@ -14,9 +14,7 @@ for _, attr in pairs({"bold", "italic", "bold_italic"}) do attributes["bold"] = true attributes["italic"] = true end - -- no way to copy user custom font with additional attributes :( - style.syntax_fonts["markdown_"..attr] = renderer.font.load( - DATADIR .. "/fonts/JetBrainsMono-Regular.ttf", + style.syntax_fonts["markdown_"..attr] = style.code_font:copy( style.code_font:get_size(), attributes ) diff --git a/data/plugins/scale.lua b/data/plugins/scale.lua index 2d638ddc..3aecb5f0 100644 --- a/data/plugins/scale.lua +++ b/data/plugins/scale.lua @@ -79,14 +79,14 @@ local function set_scale(scale) style.tab_width = style.tab_width * s for _, name in ipairs {"font", "big_font", "icon_font", "icon_big_font", "code_font"} do - style[name] = renderer.font.copy(style[name], s * style[name]:get_size()) + style[name]:set_size(s * style[name]:get_size()) end else - style.code_font = renderer.font.copy(style.code_font, s * style.code_font:get_size()) + style.code_font:set_size(s * style.code_font:get_size()) end for name, font in pairs(style.syntax_fonts) do - style.syntax_fonts[name] = renderer.font.copy(font, s * font:get_size()) + style.syntax_fonts[name]:set_size(s * font:get_size()) end -- restore scroll positions @@ -108,12 +108,10 @@ end local function inc_scale() set_scale(current_scale + scale_steps) - collectgarbage "step" end local function dec_scale() set_scale(current_scale - scale_steps) - collectgarbage "step" end diff --git a/docs/api/renderer.lua b/docs/api/renderer.lua index 8738a7c1..56fe4262 100644 --- a/docs/api/renderer.lua +++ b/docs/api/renderer.lua @@ -35,7 +35,7 @@ renderer.font = {} --- ---@param path string ---@param size number ----@param options renderer.fontoptions +---@param options? renderer.fontoptions --- ---@return renderer.font function renderer.font.load(path, size, options) end @@ -54,9 +54,10 @@ function renderer.font.group(fonts) end ---Clones a font object into a new one. --- ---@param size? number Optional new size for cloned font. +---@param options? renderer.fontoptions --- ---@return renderer.font -function renderer.font:copy(size) end +function renderer.font:copy(size, options) end --- ---Set the amount of characters that represent a tab. @@ -92,6 +93,13 @@ function renderer.font:get_size() end ---@param size number function renderer.font:set_size(size) end +--- +---Get the current path of the font as a string if a single font or as an +---array of strings if a group font. +--- +---@return string | table +function renderer.font:get_path() end + --- ---Toggles drawing debugging rectangles on the currently rendered sections ---of the window to help troubleshoot the renderer. diff --git a/src/api/renderer.c b/src/api/renderer.c index d4df58e3..c23e38ea 100644 --- a/src/api/renderer.c +++ b/src/api/renderer.c @@ -3,55 +3,83 @@ #include "../renderer.h" #include "../rencache.h" -static int f_font_load(lua_State *L) { - const char *filename = luaL_checkstring(L, 1); - float size = luaL_checknumber(L, 2); - unsigned int font_hinting = FONT_HINTING_SLIGHT, font_style = 0; - ERenFontAntialiasing font_antialiasing = FONT_ANTIALIASING_SUBPIXEL; +static int font_get_options( + lua_State *L, + ERenFontAntialiasing *antialiasing, + ERenFontHinting *hinting, + int *style +) { if (lua_gettop(L) > 2 && lua_istable(L, 3)) { lua_getfield(L, 3, "antialiasing"); if (lua_isstring(L, -1)) { - const char *antialiasing = lua_tostring(L, -1); - if (antialiasing) { - if (strcmp(antialiasing, "none") == 0) { - font_antialiasing = FONT_ANTIALIASING_NONE; - } else if (strcmp(antialiasing, "grayscale") == 0) { - font_antialiasing = FONT_ANTIALIASING_GRAYSCALE; - } else if (strcmp(antialiasing, "subpixel") == 0) { - font_antialiasing = FONT_ANTIALIASING_SUBPIXEL; + const char *antialiasing_str = lua_tostring(L, -1); + if (antialiasing_str) { + if (strcmp(antialiasing_str, "none") == 0) { + *antialiasing = FONT_ANTIALIASING_NONE; + } else if (strcmp(antialiasing_str, "grayscale") == 0) { + *antialiasing = FONT_ANTIALIASING_GRAYSCALE; + } else if (strcmp(antialiasing_str, "subpixel") == 0) { + *antialiasing = FONT_ANTIALIASING_SUBPIXEL; } else { - return luaL_error(L, "error in renderer.font.load, unknown antialiasing option: \"%s\"", antialiasing); + return luaL_error( + L, + "error in font options, unknown antialiasing option: \"%s\"", + antialiasing_str + ); } } } lua_getfield(L, 3, "hinting"); if (lua_isstring(L, -1)) { - const char *hinting = lua_tostring(L, -1); - if (hinting) { - if (strcmp(hinting, "slight") == 0) { - font_hinting = FONT_HINTING_SLIGHT; - } else if (strcmp(hinting, "none") == 0) { - font_hinting = FONT_HINTING_NONE; - } else if (strcmp(hinting, "full") == 0) { - font_hinting = FONT_HINTING_FULL; + const char *hinting_str = lua_tostring(L, -1); + if (hinting_str) { + if (strcmp(hinting_str, "slight") == 0) { + *hinting = FONT_HINTING_SLIGHT; + } else if (strcmp(hinting_str, "none") == 0) { + *hinting = FONT_HINTING_NONE; + } else if (strcmp(hinting_str, "full") == 0) { + *hinting = FONT_HINTING_FULL; } else { - return luaL_error(L, "error in renderer.font.load, unknown hinting option: \"%s\"", hinting); + return luaL_error( + L, + "error in font options, unknown hinting option: \"%s\"", + hinting + ); } } } + int style_local = 0; lua_getfield(L, 3, "italic"); if (lua_toboolean(L, -1)) - font_style |= FONT_STYLE_ITALIC; + style_local |= FONT_STYLE_ITALIC; lua_getfield(L, 3, "bold"); if (lua_toboolean(L, -1)) - font_style |= FONT_STYLE_BOLD; + style_local |= FONT_STYLE_BOLD; lua_getfield(L, 3, "underline"); if (lua_toboolean(L, -1)) - font_style |= FONT_STYLE_UNDERLINE; + style_local |= FONT_STYLE_UNDERLINE; lua_pop(L, 5); + + if (style_local != 0) + *style = style_local; } + + return 0; +} + +static int f_font_load(lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + float size = luaL_checknumber(L, 2); + int style = 0; + ERenFontHinting hinting = FONT_HINTING_SLIGHT; + ERenFontAntialiasing antialiasing = FONT_ANTIALIASING_SUBPIXEL; + + int ret_code = font_get_options(L, &antialiasing, &hinting, &style); + if (ret_code > 0) + return ret_code; + RenFont** font = lua_newuserdata(L, sizeof(RenFont*)); - *font = ren_font_load(filename, size, font_antialiasing, font_hinting, font_style); + *font = ren_font_load(filename, size, antialiasing, hinting, style); if (!*font) return luaL_error(L, "failed to load font"); luaL_setmetatable(L, API_TYPE_FONT); @@ -77,13 +105,21 @@ static int f_font_copy(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; bool table = font_retrieve(L, fonts, 1); float size = lua_gettop(L) >= 2 ? luaL_checknumber(L, 2) : ren_font_group_get_height(fonts); + int style = -1; + ERenFontHinting hinting = -1; + ERenFontAntialiasing antialiasing = -1; + + int ret_code = font_get_options(L, &antialiasing, &hinting, &style); + if (ret_code > 0) + return ret_code; + if (table) { lua_newtable(L); luaL_setmetatable(L, API_TYPE_FONT); } for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { RenFont** font = lua_newuserdata(L, sizeof(RenFont*)); - *font = ren_font_copy(fonts[i], size); + *font = ren_font_copy(fonts[i], size, antialiasing, hinting, style); if (!*font) return luaL_error(L, "failed to copy font"); luaL_setmetatable(L, API_TYPE_FONT); @@ -99,6 +135,22 @@ static int f_font_group(lua_State* L) { return 1; } +static int f_font_get_path(lua_State *L) { + RenFont* fonts[FONT_FALLBACK_MAX]; + bool table = font_retrieve(L, fonts, 1); + + if (table) { + lua_newtable(L); + } + for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { + const char* path = ren_font_get_path(fonts[i]); + lua_pushstring(L, path); + if (table) + lua_rawseti(L, -2, i+1); + } + return 1; +} + static int f_font_set_tab_size(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); int n = luaL_checknumber(L, 2); @@ -133,6 +185,13 @@ static int f_font_get_size(lua_State *L) { return 1; } +static int f_font_set_size(lua_State *L) { + RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); + float size = luaL_checknumber(L, 2); + ren_font_group_set_size(fonts, size); + return 0; +} + static RenColor checkcolor(lua_State *L, int idx, int def) { RenColor color; if (lua_isnoneornil(L, idx)) { @@ -240,6 +299,8 @@ static const luaL_Reg fontLib[] = { { "get_width", f_font_get_width }, { "get_height", f_font_get_height }, { "get_size", f_font_get_size }, + { "set_size", f_font_set_size }, + { "get_path", f_font_get_path }, { NULL, NULL } }; diff --git a/src/renderer.c b/src/renderer.c index 144e2e46..81888234 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -189,6 +189,19 @@ static RenFont* font_group_get_glyph(GlyphSet** set, GlyphMetric** metric, RenFo return fonts[0]; } +static void font_clear_glyph_cache(RenFont* font) { + for (int i = 0; i < SUBPIXEL_BITMAPS_CACHED; ++i) { + for (int j = 0; j < MAX_GLYPHSET; ++j) { + if (font->sets[i][j]) { + if (font->sets[i][j]->surface) + SDL_FreeSurface(font->sets[i][j]->surface); + free(font->sets[i][j]); + font->sets[i][j] = NULL; + } + } + } +} + RenFont* ren_font_load(const char* path, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, unsigned char style) { FT_Face face; if (FT_New_Face( library, path, 0, &face)) @@ -217,20 +230,20 @@ RenFont* ren_font_load(const char* path, float size, ERenFontAntialiasing antial return NULL; } -RenFont* ren_font_copy(RenFont* font, float size) { - return ren_font_load(font->path, size, font->antialiasing, font->hinting, font->style); +RenFont* ren_font_copy(RenFont* font, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, int style) { + antialiasing = antialiasing == -1 ? font->antialiasing : antialiasing; + hinting = hinting == -1 ? font->hinting : hinting; + style = style == -1 ? font->style : style; + + return ren_font_load(font->path, size, antialiasing, hinting, style); +} + +const char* ren_font_get_path(RenFont *font) { + return font->path; } void ren_font_free(RenFont* font) { - for (int i = 0; i < SUBPIXEL_BITMAPS_CACHED; ++i) { - for (int j = 0; j < MAX_GLYPHSET; ++j) { - if (font->sets[i][j]) { - if (font->sets[i][j]->surface) - SDL_FreeSurface(font->sets[i][j]->surface); - free(font->sets[i][j]); - } - } - } + font_clear_glyph_cache(font); FT_Done_Face(font->face); free(font); } @@ -253,6 +266,22 @@ int ren_font_group_get_tab_size(RenFont **fonts) { float ren_font_group_get_size(RenFont **fonts) { return fonts[0]->size; } + +void ren_font_group_set_size(RenFont **fonts, float size) { + const int surface_scale = renwin_surface_scale(&window_renderer); + for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { + font_clear_glyph_cache(fonts[i]); + FT_Face face = fonts[i]->face; + FT_Set_Pixel_Sizes(face, 0, (int)(size*surface_scale)); + fonts[i]->size = size; + fonts[i]->height = (short)((face->height / (float)face->units_per_EM) * size); + fonts[i]->baseline = (short)((face->ascender / (float)face->units_per_EM) * size); + FT_Load_Char(face, ' ', font_set_load_options(fonts[i])); + fonts[i]->space_advance = face->glyph->advance.x / 64.0f; + fonts[i]->tab_advance = fonts[i]->space_advance * 2; + } +} + int ren_font_group_get_height(RenFont **fonts) { return fonts[0]->height; } diff --git a/src/renderer.h b/src/renderer.h index 89c70d5e..57de549d 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -20,11 +20,13 @@ typedef struct { uint8_t b, g, r, a; } RenColor; typedef struct { int x, y, width, height; } RenRect; RenFont* ren_font_load(const char *filename, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, unsigned char style); -RenFont* ren_font_copy(RenFont* font, float size); +RenFont* ren_font_copy(RenFont* font, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, int style); +const char* ren_font_get_path(RenFont *font); void ren_font_free(RenFont *font); int ren_font_group_get_tab_size(RenFont **font); int ren_font_group_get_height(RenFont **font); float ren_font_group_get_size(RenFont **font); +void ren_font_group_set_size(RenFont **font, float size); void ren_font_group_set_tab_size(RenFont **font, int n); float ren_font_group_get_width(RenFont **font, const char *text); float ren_draw_text(RenFont **font, const char *text, float x, int y, RenColor color);