Merge pull request #1057 from jgmdev/PR/font-additions

renderer fonts: additions and improvements
This commit is contained in:
Jefferson González 2022-06-23 18:09:53 -04:00 committed by GitHub
commit 6a8eed45c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 146 additions and 50 deletions

View File

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

View File

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

View File

@ -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<integer, string>
function renderer.font:get_path() end
---
---Toggles drawing debugging rectangles on the currently rendered sections
---of the window to help troubleshoot the renderer.

View File

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

View File

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

View File

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