From 73bcd7a69268381af14b7f8fc9d215f86782ff63 Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Tue, 31 Mar 2020 16:49:16 +0100 Subject: [PATCH] Enable correct vertical alignment of text (+ font rendering fixes) --- gfx/drivers_font/caca_font.c | 3 +- gfx/drivers_font/ctr_font.c | 16 +- gfx/drivers_font/d3d10_font.c | 17 +- gfx/drivers_font/d3d11_font.c | 16 +- gfx/drivers_font/d3d12_font.c | 17 +- gfx/drivers_font/d3d_w32_font.c | 3 +- gfx/drivers_font/gdi_font.c | 9 +- gfx/drivers_font/gl1_raster_font.c | 17 +- gfx/drivers_font/gl_core_raster_font.c | 17 +- gfx/drivers_font/gl_raster_font.c | 17 +- gfx/drivers_font/metal_raster_font.m | 12 +- gfx/drivers_font/ps2_font.c | 1 + gfx/drivers_font/sixel_font.c | 3 +- gfx/drivers_font/switch_font.c | 16 +- gfx/drivers_font/vga_font.c | 3 +- gfx/drivers_font/vita2d_font.c | 17 +- gfx/drivers_font/vulkan_raster_font.c | 17 +- gfx/drivers_font/wiiu_font.c | 16 +- gfx/drivers_font/xdk1_xfonts.c | 3 +- gfx/drivers_font_renderer/bitmap.h | 5 +- gfx/drivers_font_renderer/bitmapfont.c | 23 ++- gfx/drivers_font_renderer/coretext.c | 28 ++- gfx/drivers_font_renderer/freetype.c | 18 +- gfx/drivers_font_renderer/stb.c | 28 ++- gfx/drivers_font_renderer/stb_unicode.c | 50 ++++-- gfx/font_driver.c | 65 ++++++- gfx/font_driver.h | 14 +- menu/drivers/materialui.c | 221 ++++++++++++++---------- 28 files changed, 423 insertions(+), 249 deletions(-) diff --git a/gfx/drivers_font/caca_font.c b/gfx/drivers_font/caca_font.c index 8b8f0d7cfb..62ad35acef 100644 --- a/gfx/drivers_font/caca_font.c +++ b/gfx/drivers_font/caca_font.c @@ -143,5 +143,6 @@ font_renderer_t caca_font = { caca_font_get_glyph, /* get_glyph */ NULL, /* bind_block */ NULL, /* flush */ - caca_get_message_width /* get_message_width */ + caca_get_message_width, /* get_message_width */ + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font/ctr_font.c b/gfx/drivers_font/ctr_font.c index 0bef51cebb..34b4675644 100644 --- a/gfx/drivers_font/ctr_font.c +++ b/gfx/drivers_font/ctr_font.c @@ -312,14 +312,16 @@ static void ctr_font_render_message( const unsigned int color, float pos_x, float pos_y, unsigned width, unsigned height, unsigned text_align) { - int lines = 0; + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; if (!msg || !*msg) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { ctr_font_render_line(ctr, font, msg, strlen(msg), scale, color, pos_x, pos_y, @@ -327,7 +329,7 @@ static void ctr_font_render_message( return; } - line_height = scale / font->font_driver->get_line_height(font->font_data); + line_height = scale / line_metrics->height; for (;;) { @@ -454,14 +456,14 @@ static const struct font_glyph* ctr_font_get_glyph( return font->font_driver->get_glyph((void*)font->font_driver, code); } -static int ctr_font_get_line_height(void *data) +static bool ctr_font_get_line_metrics(void* data, struct font_line_metrics **metrics) { ctr_font_t* font = (ctr_font_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t ctr_font = @@ -474,5 +476,5 @@ font_renderer_t ctr_font = NULL, /* bind_block */ NULL, /* flush_block */ ctr_font_get_message_width, - ctr_font_get_line_height + ctr_font_get_line_metrics }; diff --git a/gfx/drivers_font/d3d10_font.c b/gfx/drivers_font/d3d10_font.c index 47df69a6e7..a3bedcdbb3 100644 --- a/gfx/drivers_font/d3d10_font.c +++ b/gfx/drivers_font/d3d10_font.c @@ -237,14 +237,16 @@ static void d3d10_font_render_message( unsigned height, unsigned text_align) { - int lines = 0; + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; if (!msg || !*msg) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { d3d10_font_render_line(d3d10, font, msg, strlen(msg), scale, color, pos_x, pos_y, @@ -252,8 +254,7 @@ static void d3d10_font_render_message( return; } - line_height = font->font_driver->get_line_height(font->font_data) - * scale / height; + line_height = line_metrics->height * scale / height; for (;;) { @@ -377,14 +378,14 @@ static const struct font_glyph* d3d10_font_get_glyph(void *data, uint32_t code) return font->font_driver->get_glyph((void*)font->font_driver, code); } -static int d3d10_font_get_line_height(void *data) +static bool d3d10_font_get_line_metrics(void* data, struct font_line_metrics **metrics) { d3d10_font_t* font = (d3d10_font_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t d3d10_font = { @@ -396,5 +397,5 @@ font_renderer_t d3d10_font = { NULL, /* bind_block */ NULL, /* flush */ d3d10_font_get_message_width, - d3d10_font_get_line_height + d3d10_font_get_line_metrics }; diff --git a/gfx/drivers_font/d3d11_font.c b/gfx/drivers_font/d3d11_font.c index b60ecd34e7..1a037523e6 100644 --- a/gfx/drivers_font/d3d11_font.c +++ b/gfx/drivers_font/d3d11_font.c @@ -234,14 +234,16 @@ static void d3d11_font_render_message( unsigned height, unsigned text_align) { + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; - int lines = 0; if (!msg || !*msg) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { d3d11_font_render_line(d3d11, font, msg, strlen(msg), scale, color, pos_x, pos_y, @@ -249,7 +251,7 @@ static void d3d11_font_render_message( return; } - line_height = font->font_driver->get_line_height(font->font_data) * scale / height; + line_height = line_metrics->height * scale / height; for (;;) { @@ -372,14 +374,14 @@ static const struct font_glyph* d3d11_font_get_glyph(void *data, uint32_t code) return font->font_driver->get_glyph((void*)font->font_driver, code); } -static int d3d11_font_get_line_height(void *data) +static bool d3d11_font_get_line_metrics(void* data, struct font_line_metrics **metrics) { d3d11_font_t* font = (d3d11_font_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t d3d11_font = { @@ -391,5 +393,5 @@ font_renderer_t d3d11_font = { NULL, /* bind_block */ NULL, /* flush */ d3d11_font_get_message_width, - d3d11_font_get_line_height + d3d11_font_get_line_metrics }; diff --git a/gfx/drivers_font/d3d12_font.c b/gfx/drivers_font/d3d12_font.c index 063123dba8..7ed6634d05 100644 --- a/gfx/drivers_font/d3d12_font.c +++ b/gfx/drivers_font/d3d12_font.c @@ -248,14 +248,16 @@ static void d3d12_font_render_message( unsigned height, unsigned text_align) { - int lines = 0; + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; if (!msg || !*msg) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { d3d12_font_render_line(d3d12, font, msg, strlen(msg), @@ -263,8 +265,7 @@ static void d3d12_font_render_message( return; } - line_height = font->font_driver->get_line_height(font->font_data) - * scale / height; + line_height = line_metrics->height * scale / height; for (;;) { @@ -386,14 +387,14 @@ static const struct font_glyph* d3d12_font_get_glyph( return font->font_driver->get_glyph((void*)font->font_driver, code); } -static int d3d12_font_get_line_height(void *data) +static bool d3d12_font_get_line_metrics(void* data, struct font_line_metrics **metrics) { d3d12_font_t* font = (d3d12_font_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t d3d12_font = { @@ -405,5 +406,5 @@ font_renderer_t d3d12_font = { NULL, /* bind_block */ NULL, /* flush */ d3d12_font_get_message_width, - d3d12_font_get_line_height + d3d12_font_get_line_metrics }; diff --git a/gfx/drivers_font/d3d_w32_font.c b/gfx/drivers_font/d3d_w32_font.c index 92158b3847..b4091e0bcd 100644 --- a/gfx/drivers_font/d3d_w32_font.c +++ b/gfx/drivers_font/d3d_w32_font.c @@ -236,5 +236,6 @@ font_renderer_t d3d_win32_font = { NULL, /* get_glyph */ NULL, /* bind_block */ NULL, /* flush */ - d3dfonts_w32_get_message_width + d3dfonts_w32_get_message_width, + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font/gdi_font.c b/gfx/drivers_font/gdi_font.c index 30c64fbb62..ecbf58a732 100644 --- a/gfx/drivers_font/gdi_font.c +++ b/gfx/drivers_font/gdi_font.c @@ -209,8 +209,9 @@ font_renderer_t gdi_font = { gdi_render_free_font, gdi_render_msg, "gdi font", - gdi_font_get_glyph, /* get_glyph */ - NULL, /* bind_block */ - NULL, /* flush */ - gdi_get_message_width /* get_message_width */ + gdi_font_get_glyph, /* get_glyph */ + NULL, /* bind_block */ + NULL, /* flush */ + gdi_get_message_width, /* get_message_width */ + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font/gl1_raster_font.c b/gfx/drivers_font/gl1_raster_font.c index 7b31a78881..5b62eee9bd 100644 --- a/gfx/drivers_font/gl1_raster_font.c +++ b/gfx/drivers_font/gl1_raster_font.c @@ -383,11 +383,13 @@ static void gl1_raster_font_render_message( const GLfloat color[4], GLfloat pos_x, GLfloat pos_y, unsigned text_align) { + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; - int lines = 0; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { gl1_raster_font_render_line(font, msg, (unsigned)strlen(msg), scale, color, pos_x, @@ -395,8 +397,7 @@ static void gl1_raster_font_render_message( return; } - line_height = (float) font->font_driver->get_line_height(font->font_data) * - scale / font->gl->vp.height; + line_height = line_metrics->height * scale / font->gl->vp.height; for (;;) { @@ -576,14 +577,14 @@ static void gl1_raster_font_bind_block(void *data, void *userdata) font->block = block; } -static int gl1_get_line_height(void *data) +static bool gl1_get_line_metrics(void* data, struct font_line_metrics **metrics) { gl1_raster_t *font = (gl1_raster_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t gl1_raster_font = { @@ -595,5 +596,5 @@ font_renderer_t gl1_raster_font = { gl1_raster_font_bind_block, gl1_raster_font_flush_block, gl1_get_message_width, - gl1_get_line_height + gl1_get_line_metrics }; diff --git a/gfx/drivers_font/gl_core_raster_font.c b/gfx/drivers_font/gl_core_raster_font.c index a9eeabb75a..b3094699c9 100644 --- a/gfx/drivers_font/gl_core_raster_font.c +++ b/gfx/drivers_font/gl_core_raster_font.c @@ -293,11 +293,13 @@ static void gl_core_raster_font_render_message( const GLfloat color[4], GLfloat pos_x, GLfloat pos_y, unsigned text_align) { + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; - int lines = 0; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { gl_core_raster_font_render_line(font, msg, (unsigned)strlen(msg), scale, color, pos_x, @@ -305,8 +307,7 @@ static void gl_core_raster_font_render_message( return; } - line_height = (float) font->font_driver->get_line_height(font->font_data) * - scale / font->gl->vp.height; + line_height = line_metrics->height * scale / font->gl->vp.height; for (;;) { @@ -477,14 +478,14 @@ static void gl_core_raster_font_bind_block(void *data, void *userdata) font->block = block; } -static int gl_core_get_line_height(void *data) +static bool gl_core_get_line_metrics(void* data, struct font_line_metrics **metrics) { gl_core_raster_t *font = (gl_core_raster_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t gl_core_raster_font = { @@ -496,5 +497,5 @@ font_renderer_t gl_core_raster_font = { gl_core_raster_font_bind_block, gl_core_raster_font_flush_block, gl_core_get_message_width, - gl_core_get_line_height + gl_core_get_line_metrics }; diff --git a/gfx/drivers_font/gl_raster_font.c b/gfx/drivers_font/gl_raster_font.c index 24ef42056f..783d6e84b9 100644 --- a/gfx/drivers_font/gl_raster_font.c +++ b/gfx/drivers_font/gl_raster_font.c @@ -362,11 +362,13 @@ static void gl_raster_font_render_message( const GLfloat color[4], GLfloat pos_x, GLfloat pos_y, unsigned text_align) { + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; - int lines = 0; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { gl_raster_font_render_line(font, msg, (unsigned)strlen(msg), scale, color, pos_x, @@ -374,8 +376,7 @@ static void gl_raster_font_render_message( return; } - line_height = (float) font->font_driver->get_line_height(font->font_data) * - scale / font->gl->vp.height; + line_height = line_metrics->height * scale / font->gl->vp.height; for (;;) { @@ -557,14 +558,14 @@ static void gl_raster_font_bind_block(void *data, void *userdata) font->block = block; } -static int gl_get_line_height(void *data) +static bool gl_get_line_metrics(void* data, struct font_line_metrics **metrics) { gl_raster_t *font = (gl_raster_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t gl_raster_font = { @@ -576,5 +577,5 @@ font_renderer_t gl_raster_font = { gl_raster_font_bind_block, gl_raster_font_flush_block, gl_get_message_width, - gl_get_line_height + gl_get_line_metrics }; diff --git a/gfx/drivers_font/metal_raster_font.m b/gfx/drivers_font/metal_raster_font.m index 06390c626c..724d8d4fff 100644 --- a/gfx/drivers_font/metal_raster_font.m +++ b/gfx/drivers_font/metal_raster_font.m @@ -350,15 +350,18 @@ static INLINE void write_quad6(SpriteVertex *pv, posY:(float)posY aligned:(unsigned)aligned { - /* If the font height is not supported just draw as usual */ - if (!_font_driver->get_line_height) + struct font_line_metrics *line_metrics = NULL; + + /* If font line metrics are not supported just draw as usual */ + if (!_font_driver->get_line_metrics || + !_font_driver->get_line_metrics(_font_data, &line_metrics)) { [self _renderLine:msg length:strlen(msg) scale:scale color:color posX:posX posY:posY aligned:aligned]; return; } int lines = 0; - float line_height = _font_driver->get_line_height(_font_data) * scale / height; + float line_height = line_metrics->height * scale / height; for (;;) { @@ -545,5 +548,6 @@ font_renderer_t metal_raster_font = { .get_glyph = metal_raster_font_get_glyph, NULL, /* bind_block */ NULL, /* flush_block */ - .get_message_width = metal_get_message_width + .get_message_width = metal_get_message_width, + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font/ps2_font.c b/gfx/drivers_font/ps2_font.c index ac4cef0f67..d0406a5b88 100644 --- a/gfx/drivers_font/ps2_font.c +++ b/gfx/drivers_font/ps2_font.c @@ -165,4 +165,5 @@ font_renderer_t ps2_font = { NULL, /* bind_block */ NULL, /* flush */ NULL, /* get_message_width */ + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font/sixel_font.c b/gfx/drivers_font/sixel_font.c index 6101166a93..884be5f2bd 100644 --- a/gfx/drivers_font/sixel_font.c +++ b/gfx/drivers_font/sixel_font.c @@ -141,5 +141,6 @@ font_renderer_t sixel_font = { sixel_font_get_glyph, /* get_glyph */ NULL, /* bind_block */ NULL, /* flush */ - sixel_get_message_width /* get_message_width */ + sixel_get_message_width, /* get_message_width */ + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font/switch_font.c b/gfx/drivers_font/switch_font.c index 88e3fcc532..5759c65f02 100644 --- a/gfx/drivers_font/switch_font.c +++ b/gfx/drivers_font/switch_font.c @@ -193,14 +193,16 @@ static void switch_font_render_message( const unsigned int color, float pos_x, float pos_y, unsigned text_align) { + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; - int lines = 0; if (!msg || !*msg) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { int msgLen = strlen(msg); if (msgLen <= AVG_GLPYH_LIMIT) @@ -211,7 +213,7 @@ static void switch_font_render_message( } return; } - line_height = scale / font->font_driver->get_line_height(font->font_data); + line_height = scale / line_metrics->height; for (;;) { @@ -312,13 +314,13 @@ static const struct font_glyph *switch_font_get_glyph( return font->font_driver->get_glyph((void *)font->font_driver, code); } -static int switch_font_get_line_height(void *data) +static bool switch_font_get_line_metrics(void* data, struct font_line_metrics **metrics) { switch_font_t *font = (switch_font_t *)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t switch_font = @@ -331,5 +333,5 @@ font_renderer_t switch_font = NULL, /* bind_block */ NULL, /* flush_block */ switch_font_get_message_width, - switch_font_get_line_height + switch_font_get_line_metrics }; diff --git a/gfx/drivers_font/vga_font.c b/gfx/drivers_font/vga_font.c index 3ff417c4cf..0b479e3e14 100644 --- a/gfx/drivers_font/vga_font.c +++ b/gfx/drivers_font/vga_font.c @@ -141,5 +141,6 @@ font_renderer_t vga_font = { vga_font_get_glyph, /* get_glyph */ NULL, /* bind_block */ NULL, /* flush */ - vga_get_message_width /* get_message_width */ + vga_get_message_width, /* get_message_width */ + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font/vita2d_font.c b/gfx/drivers_font/vita2d_font.c index 3b47d6cec0..cdd434822d 100644 --- a/gfx/drivers_font/vita2d_font.c +++ b/gfx/drivers_font/vita2d_font.c @@ -225,22 +225,23 @@ static void vita2d_font_render_message( const unsigned int color, float pos_x, float pos_y, unsigned width, unsigned height, unsigned text_align) { + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; - int lines = 0; if (!msg || !*msg) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { vita2d_font_render_line(font, msg, strlen(msg), scale, color, pos_x, pos_y, width, height, text_align); return; } - line_height = font->font_driver->get_line_height(font->font_data) * - scale / font->vita->vp.height; + line_height = line_metrics->height * scale / font->vita->vp.height; for (;;) { @@ -358,14 +359,14 @@ static const struct font_glyph *vita2d_font_get_glyph( return font->font_driver->get_glyph((void*)font->font_driver, code); } -static int vita2d_font_get_line_height(void *data) +static bool vita2d_font_get_line_metrics(void* data, struct font_line_metrics **metrics) { vita_font_t *font = (vita_font_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t vita2d_vita_font = { @@ -377,5 +378,5 @@ font_renderer_t vita2d_vita_font = { NULL, /* bind_block */ NULL, /* flush */ vita2d_font_get_message_width, - vita2d_font_get_line_height + vita2d_font_get_line_metrics }; diff --git a/gfx/drivers_font/vulkan_raster_font.c b/gfx/drivers_font/vulkan_raster_font.c index 720f4efd6e..3ba6567a5b 100644 --- a/gfx/drivers_font/vulkan_raster_font.c +++ b/gfx/drivers_font/vulkan_raster_font.c @@ -233,14 +233,16 @@ static void vulkan_raster_font_render_message( const float color[4], float pos_x, float pos_y, unsigned text_align) { - int lines = 0; + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; if (!msg || !*msg || !font->vk) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { if (font->vk) vulkan_raster_font_render_line(font, msg, strlen(msg), @@ -248,8 +250,7 @@ static void vulkan_raster_font_render_message( return; } - line_height = (float) font->font_driver->get_line_height(font->font_data) * - scale / font->vk->vp.height; + line_height = line_metrics->height * scale / font->vk->vp.height; for (;;) { @@ -452,14 +453,14 @@ static const struct font_glyph *vulkan_raster_font_get_glyph( return glyph; } -static int vulkan_get_line_height(void *data) +static bool vulkan_get_line_metrics(void* data, struct font_line_metrics **metrics) { vulkan_raster_t *font = (vulkan_raster_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t vulkan_raster_font = { @@ -471,5 +472,5 @@ font_renderer_t vulkan_raster_font = { NULL, /* bind_block */ NULL, /* flush_block */ vulkan_get_message_width, - vulkan_get_line_height + vulkan_get_line_metrics }; diff --git a/gfx/drivers_font/wiiu_font.c b/gfx/drivers_font/wiiu_font.c index 7b410702c9..0e5105d573 100644 --- a/gfx/drivers_font/wiiu_font.c +++ b/gfx/drivers_font/wiiu_font.c @@ -241,14 +241,16 @@ static void wiiu_font_render_message( const unsigned int color, float pos_x, float pos_y, unsigned width, unsigned height, unsigned text_align) { - int lines = 0; + struct font_line_metrics *line_metrics = NULL; + int lines = 0; float line_height; if (!msg || !*msg) return; - /* If the font height is not supported just draw as usual */ - if (!font->font_driver->get_line_height) + /* If font line metrics are not supported just draw as usual */ + if (!font->font_driver->get_line_metrics || + !font->font_driver->get_line_metrics(font->font_data, &line_metrics)) { wiiu_font_render_line(wiiu, font, msg, strlen(msg), scale, color, pos_x, pos_y, @@ -256,7 +258,7 @@ static void wiiu_font_render_message( return; } - line_height = scale / font->font_driver->get_line_height(font->font_data); + line_height = scale / line_metrics->height; for (;;) { @@ -381,14 +383,14 @@ static const struct font_glyph* wiiu_font_get_glyph( return font->font_driver->get_glyph((void*)font->font_driver, code); } -static int wiiu_font_get_line_height(void *data) +static bool wiiu_font_get_line_metrics(void* data, struct font_line_metrics **metrics) { wiiu_font_t* font = (wiiu_font_t*)data; if (!font || !font->font_driver || !font->font_data) return -1; - return font->font_driver->get_line_height(font->font_data); + return font->font_driver->get_line_metrics(font->font_data, metrics); } font_renderer_t wiiu_font = @@ -401,5 +403,5 @@ font_renderer_t wiiu_font = NULL, /* bind_block */ NULL, /* flush */ wiiu_font_get_message_width, - wiiu_font_get_line_height + wiiu_font_get_line_metrics }; diff --git a/gfx/drivers_font/xdk1_xfonts.c b/gfx/drivers_font/xdk1_xfonts.c index 60def69781..6cde9353d5 100644 --- a/gfx/drivers_font/xdk1_xfonts.c +++ b/gfx/drivers_font/xdk1_xfonts.c @@ -118,5 +118,6 @@ font_renderer_t d3d_xdk1_font = { NULL, /* get_glyph */ NULL, /* bind_block */ NULL, /* flush */ - NULL /* get_message_width */ + NULL, /* get_message_width */ + NULL /* get_line_metrics */ }; diff --git a/gfx/drivers_font_renderer/bitmap.h b/gfx/drivers_font_renderer/bitmap.h index 8483021532..59300d8b81 100644 --- a/gfx/drivers_font_renderer/bitmap.h +++ b/gfx/drivers_font_renderer/bitmap.h @@ -19,7 +19,10 @@ #define FONT_WIDTH 5 #define FONT_HEIGHT 10 -#define FONT_HEIGHT_BASELINE 8 +/* FONT_HEIGHT_BASELINE_OFFSET: + * Distance in pixels from top of character + * to baseline */ +#define FONT_HEIGHT_BASELINE_OFFSET 8 #define FONT_WIDTH_STRIDE (FONT_WIDTH + 1) #define FONT_HEIGHT_STRIDE (FONT_HEIGHT + 1) diff --git a/gfx/drivers_font_renderer/bitmapfont.c b/gfx/drivers_font_renderer/bitmapfont.c index ed5e72d542..4f18864e78 100644 --- a/gfx/drivers_font_renderer/bitmapfont.c +++ b/gfx/drivers_font_renderer/bitmapfont.c @@ -33,6 +33,7 @@ typedef struct bm_renderer unsigned scale_factor; struct font_glyph glyphs[BMP_ATLAS_SIZE]; struct font_atlas atlas; + struct font_line_metrics line_metrics; } bm_renderer_t; static struct font_atlas *font_renderer_bmp_get_atlas(void *data) @@ -113,11 +114,15 @@ static void *font_renderer_bmp_init(const char *font_path, float font_size) handle->glyphs[i].atlas_offset_x = x; handle->glyphs[i].atlas_offset_y = y; handle->glyphs[i].draw_offset_x = 0; - handle->glyphs[i].draw_offset_y = -FONT_HEIGHT_BASELINE * (int)handle->scale_factor; - handle->glyphs[i].advance_x = (FONT_WIDTH + 1) * handle->scale_factor; + handle->glyphs[i].draw_offset_y = -FONT_HEIGHT_BASELINE_OFFSET * handle->scale_factor; + handle->glyphs[i].advance_x = FONT_WIDTH_STRIDE * handle->scale_factor; handle->glyphs[i].advance_y = 0; } + handle->line_metrics.ascender = (float)FONT_HEIGHT_BASELINE_OFFSET * handle->scale_factor; + handle->line_metrics.descender = (float)(FONT_HEIGHT - FONT_HEIGHT_BASELINE_OFFSET) * handle->scale_factor; + handle->line_metrics.height = (float)FONT_HEIGHT_STRIDE * handle->scale_factor; + return handle; } @@ -135,14 +140,16 @@ static const char *font_renderer_bmp_get_default_font(void) return ""; } -static int font_renderer_bmp_get_line_height(void* data) +static bool font_renderer_bmp_get_line_metrics( + void* data, struct font_line_metrics **metrics) { - bm_renderer_t *handle = (bm_renderer_t*)data; + bm_renderer_t *handle = (bm_renderer_t*)data; - if (!handle) - return FONT_HEIGHT; + if (!handle) + return false; - return FONT_HEIGHT * handle->scale_factor; + *metrics = &handle->line_metrics; + return true; } font_renderer_driver_t bitmap_font_renderer = { @@ -152,5 +159,5 @@ font_renderer_driver_t bitmap_font_renderer = { font_renderer_bmp_free, font_renderer_bmp_get_default_font, "bitmap", - font_renderer_bmp_get_line_height, + font_renderer_bmp_get_line_metrics }; diff --git a/gfx/drivers_font_renderer/coretext.c b/gfx/drivers_font_renderer/coretext.c index 69568628a7..b4b0751921 100644 --- a/gfx/drivers_font_renderer/coretext.c +++ b/gfx/drivers_font_renderer/coretext.c @@ -52,7 +52,7 @@ typedef struct coretext_renderer struct font_atlas atlas; coretext_atlas_slot_t atlas_slots[CT_ATLAS_SIZE]; coretext_atlas_slot_t *uc_map[0x100]; - CGFloat metrics_height; + struct font_line_metrics line_metrics; } ct_font_renderer_t; static struct font_atlas *font_renderer_ct_get_atlas(void *data) @@ -162,9 +162,19 @@ static bool coretext_font_renderer_create_atlas(CTFontRef face, ct_font_renderer handle->atlas.width = max_width * CT_ATLAS_COLS; handle->atlas.height = max_height * CT_ATLAS_ROWS; - handle->metrics_height += CTFontGetAscent(face); - handle->metrics_height += CTFontGetDescent(face); - handle->metrics_height += CTFontGetLeading(face); + + handle->line_metrics.ascender = (float)CTFontGetAscent(face); + handle->line_metrics.descender = (float)CTFontGetDescent(face); + /* CTFontGetDescent() should return a positive value, + * but I have seen several reports online of the + * value being negative + * > Since I cannot test this on real hardware, add + * a simple safety check... */ + handle->line_metrics.descender = (handle->line_metrics.descender < 0.0f) ? + (-1.0f * handle->line_metrics.descender) : handle->line_metrics.descender; + handle->line_metrics.height = + handle->line_metrics.ascender + handle->line_metrics.descender + + (float)CTFontGetLeading(face); handle->atlas.buffer = (uint8_t*) calloc(handle->atlas.width * handle->atlas.height, 1); @@ -343,12 +353,14 @@ static const char *font_renderer_ct_get_default_font(void) return default_font; } -static int font_renderer_ct_get_line_height(void *data) +static bool font_renderer_ct_get_line_metrics( + void* data, struct font_line_metrics **metrics) { ct_font_renderer_t *handle = (ct_font_renderer_t*)data; if (!handle) - return 0; - return handle->metrics_height; + return false; + *metrics = &handle->line_metrics; + return true; } font_renderer_driver_t coretext_font_renderer = { @@ -358,5 +370,5 @@ font_renderer_driver_t coretext_font_renderer = { font_renderer_ct_free, font_renderer_ct_get_default_font, "coretext", - font_renderer_ct_get_line_height + font_renderer_ct_get_line_metrics }; diff --git a/gfx/drivers_font_renderer/freetype.c b/gfx/drivers_font_renderer/freetype.c index f3158bb00d..189630e731 100644 --- a/gfx/drivers_font_renderer/freetype.c +++ b/gfx/drivers_font_renderer/freetype.c @@ -54,6 +54,7 @@ typedef struct freetype_renderer freetype_atlas_slot_t atlas_slots[FT_ATLAS_SIZE]; freetype_atlas_slot_t* uc_map[0x100]; unsigned usage_counter; + struct font_line_metrics line_metrics; } ft_font_renderer_t; static struct font_atlas *font_renderer_ft_get_atlas(void *data) @@ -261,6 +262,10 @@ static void *font_renderer_ft_init(const char *font_path, float font_size) if (!font_renderer_create_atlas(handle, font_size)) goto error; + handle->line_metrics.ascender = (float)handle->face->size->metrics.ascender / 64.0f; + handle->line_metrics.descender = (float)(-handle->face->size->metrics.descender) / 64.0f; + handle->line_metrics.height = (float)handle->face->size->metrics.height / 64.0f; + return handle; error: @@ -315,12 +320,15 @@ static const char *font_renderer_ft_get_default_font(void) #endif } -static int font_renderer_ft_get_line_height(void* data) +static bool font_renderer_ft_get_line_metrics( + void* data, struct font_line_metrics **metrics) { ft_font_renderer_t *handle = (ft_font_renderer_t*)data; - if (!handle || !handle->face) - return 0; - return handle->face->size->metrics.height/64; + if (!handle) + return false; + + *metrics = &handle->line_metrics; + return true; } font_renderer_driver_t freetype_font_renderer = { @@ -330,5 +338,5 @@ font_renderer_driver_t freetype_font_renderer = { font_renderer_ft_free, font_renderer_ft_get_default_font, "freetype", - font_renderer_ft_get_line_height, + font_renderer_ft_get_line_metrics }; diff --git a/gfx/drivers_font_renderer/stb.c b/gfx/drivers_font_renderer/stb.c index 7a9a733239..f342254ea6 100644 --- a/gfx/drivers_font_renderer/stb.c +++ b/gfx/drivers_font_renderer/stb.c @@ -36,7 +36,7 @@ typedef struct { - int line_height; + struct font_line_metrics line_metrics; struct font_atlas atlas; struct font_glyph glyphs[256]; } stb_font_renderer_t; @@ -141,6 +141,7 @@ error: static void *font_renderer_stb_init(const char *font_path, float font_size) { int ascent, descent, line_gap; + float scale_factor; stbtt_fontinfo info; uint8_t *font_data = NULL; stb_font_renderer_t *self = (stb_font_renderer_t*) calloc(1, sizeof(*self)); @@ -161,12 +162,17 @@ static void *font_renderer_stb_init(const char *font_path, float font_size) goto error; stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap); - self->line_height = ascent - descent; - if (font_size < 0) - self->line_height *= stbtt_ScaleForMappingEmToPixels(&info, -font_size); - else - self->line_height *= stbtt_ScaleForPixelHeight(&info, font_size); + scale_factor = (font_size < 0) ? + stbtt_ScaleForMappingEmToPixels(&info, -font_size) : + stbtt_ScaleForPixelHeight(&info, font_size); + + /* Ascender, descender and line_gap values always + * end up ~0.5 pixels too small when scaled... + * > Add a manual correction factor */ + self->line_metrics.ascender = 0.5f + (float)ascent * scale_factor; + self->line_metrics.descender = 0.5f + (float)(-descent) * scale_factor; + self->line_metrics.height = 0.5f + (float)(ascent - descent + line_gap) * scale_factor; free(font_data); @@ -226,10 +232,14 @@ static const char *font_renderer_stb_get_default_font(void) return NULL; } -static int font_renderer_stb_get_line_height(void* data) +static bool font_renderer_stb_get_line_metrics( + void* data, struct font_line_metrics **metrics) { stb_font_renderer_t *handle = (stb_font_renderer_t*)data; - return handle->line_height; + if (!handle) + return false; + *metrics = &handle->line_metrics; + return true; } font_renderer_driver_t stb_font_renderer = { @@ -239,5 +249,5 @@ font_renderer_driver_t stb_font_renderer = { font_renderer_stb_free, font_renderer_stb_get_default_font, "stb", - font_renderer_stb_get_line_height, + font_renderer_stb_get_line_metrics }; diff --git a/gfx/drivers_font_renderer/stb_unicode.c b/gfx/drivers_font_renderer/stb_unicode.c index c3f2962caa..2395e77dae 100644 --- a/gfx/drivers_font_renderer/stb_unicode.c +++ b/gfx/drivers_font_renderer/stb_unicode.c @@ -57,8 +57,8 @@ typedef struct int max_glyph_width; int max_glyph_height; - int line_height; float scale_factor; + struct font_line_metrics line_metrics; struct font_atlas atlas; stb_unicode_atlas_slot_t atlas_slots[STB_UNICODE_ATLAS_SIZE]; @@ -66,13 +66,6 @@ typedef struct unsigned usage_counter; } stb_unicode_font_renderer_t; -/* Ugly little thing... */ -static int INLINE round_away_from_zero(float f) -{ - double round = (f < 0.0) ? floor((double)f) : ceil((double)f); - return (int)round; -} - static struct font_atlas *font_renderer_stb_unicode_get_atlas(void *data) { stb_unicode_font_renderer_t *self = (stb_unicode_font_renderer_t*)data; @@ -125,6 +118,8 @@ static const struct font_glyph *font_renderer_stb_unicode_get_glyph( uint8_t *dst = NULL; stb_unicode_atlas_slot_t* atlas_slot = NULL; stb_unicode_font_renderer_t *self = (stb_unicode_font_renderer_t*)data; + float glyph_advance_x = 0.0f; + float glyph_draw_offset_y = 0.0f; if(!self) return NULL; @@ -145,9 +140,9 @@ static const struct font_glyph *font_renderer_stb_unicode_get_glyph( atlas_slot = font_renderer_stb_unicode_get_slot(self); atlas_slot->charcode = charcode; atlas_slot->next = self->uc_map[map_id]; - self->uc_map[map_id] = atlas_slot; + self->uc_map[map_id] = atlas_slot; - glyph_index = stbtt_FindGlyphIndex(&self->info, charcode); + glyph_index = stbtt_FindGlyphIndex(&self->info, charcode); dst = (uint8_t*)self->atlas.buffer + atlas_slot->glyph.atlas_offset_x + atlas_slot->glyph.atlas_offset_y * self->atlas.width; @@ -171,15 +166,25 @@ static const struct font_glyph *font_renderer_stb_unicode_get_glyph( atlas_slot->glyph.width = self->max_glyph_width; atlas_slot->glyph.height = self->max_glyph_height; - atlas_slot->glyph.advance_x = round_away_from_zero((float)advance_width * self->scale_factor); + /* advance_x must always be rounded to the + * *nearest* integer */ + glyph_advance_x = (float)advance_width * self->scale_factor; + atlas_slot->glyph.advance_x = (int)((glyph_advance_x > 0.0f) ? + (glyph_advance_x + 0.5f) : (glyph_advance_x - 0.5f)); + /* advance_y is always zero */ atlas_slot->glyph.advance_y = 0; - atlas_slot->glyph.draw_offset_x = round_away_from_zero((float)x0 * self->scale_factor); - atlas_slot->glyph.draw_offset_y = round_away_from_zero((float)(-y1) * self->scale_factor); + /* draw_offset_x must always be rounded *down* + * to the nearest integer */ + atlas_slot->glyph.draw_offset_x = (int)((float)x0 * self->scale_factor); + /* draw_offset_y must always be rounded *up* + * to the nearest integer */ + glyph_draw_offset_y = (float)(-y1) * self->scale_factor; + atlas_slot->glyph.draw_offset_y = (int)((glyph_draw_offset_y < 0.0f) ? + floor((double)glyph_draw_offset_y) : ceil((double)glyph_draw_offset_y)); self->atlas.dirty = true; atlas_slot->last_used = self->usage_counter++; return &atlas_slot->glyph; - } static bool font_renderer_stb_unicode_create_atlas( @@ -259,7 +264,12 @@ static void *font_renderer_stb_unicode_init(const char *font_path, float font_si else self->scale_factor = stbtt_ScaleForPixelHeight(&self->info, font_size); - self->line_height = (ascent - descent) * self->scale_factor; + /* Ascender, descender and line_gap values always + * end up ~0.5 pixels too small when scaled... + * > Add a manual correction factor */ + self->line_metrics.ascender = 0.5f + (float)ascent * self->scale_factor; + self->line_metrics.descender = 0.5f + ((float)(-descent) * self->scale_factor); + self->line_metrics.height = 0.5f + (float)(ascent - descent + line_gap) * self->scale_factor; if (!font_renderer_stb_unicode_create_atlas(self, font_size)) goto error; @@ -321,10 +331,14 @@ static const char *font_renderer_stb_unicode_get_default_font(void) #endif } -static int font_renderer_stb_unicode_get_line_height(void* data) +static bool font_renderer_stb_unicode_get_line_metrics( + void* data, struct font_line_metrics **metrics) { stb_unicode_font_renderer_t *handle = (stb_unicode_font_renderer_t*)data; - return handle->line_height; + if (!handle) + return false; + *metrics = &handle->line_metrics; + return true; } font_renderer_driver_t stb_unicode_font_renderer = { @@ -334,5 +348,5 @@ font_renderer_driver_t stb_unicode_font_renderer = { font_renderer_stb_unicode_free, font_renderer_stb_unicode_get_default_font, "stb-unicode", - font_renderer_stb_unicode_get_line_height, + font_renderer_stb_unicode_get_line_metrics }; diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 1e2682009a..f57d0a1f1d 100644 --- a/gfx/font_driver.c +++ b/gfx/font_driver.c @@ -1083,16 +1083,67 @@ int font_driver_get_message_width(void *font_data, int font_driver_get_line_height(void *font_data, float scale) { - int line_height; + struct font_line_metrics *metrics = NULL; font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver); - /* First try the line height implementation */ - if (font && font->renderer && font->renderer->get_line_height) - if ((line_height = font->renderer->get_line_height(font->renderer_data)) != -1) - return (int)(line_height * roundf(scale)); + /* First try the line metrics implementation */ + if (font && font->renderer && font->renderer->get_line_metrics) + if ((font->renderer->get_line_metrics(font->renderer_data, &metrics))) + return (int)roundf(metrics->height * scale); - /* Else return an approximation (width of 'a') */ - return font_driver_get_message_width(font_data, "a", 1, scale); + /* Else return an approximation + * (uses a fudge of standard font metrics - mostly garbage...) + * > font_size = (width of 'a') / 0.6 + * > line_height = font_size * 1.7f */ + return (int)roundf(1.7f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f); +} + +int font_driver_get_line_ascender(void *font_data, float scale) +{ + struct font_line_metrics *metrics = NULL; + font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver); + + /* First try the line metrics implementation */ + if (font && font->renderer && font->renderer->get_line_metrics) + if ((font->renderer->get_line_metrics(font->renderer_data, &metrics))) + return (int)roundf(metrics->ascender * scale); + + /* Else return an approximation + * (uses a fudge of standard font metrics - mostly garbage...) + * > font_size = (width of 'a') / 0.6 + * > ascender = 1.58 * font_size * 0.75 */ + return (int)roundf(1.58f * 0.75f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f); +} + +int font_driver_get_line_descender(void *font_data, float scale) +{ + struct font_line_metrics *metrics = NULL; + font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver); + + /* First try the line metrics implementation */ + if (font && font->renderer && font->renderer->get_line_metrics) + if ((font->renderer->get_line_metrics(font->renderer_data, &metrics))) + return (int)roundf(metrics->descender * scale); + + /* Else return an approximation + * (uses a fudge of standard font metrics - mostly garbage...) + * > font_size = (width of 'a') / 0.6 + * > descender = 1.58 * font_size * 0.25 */ + return (int)roundf(1.58f * 0.25f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f); +} + +int font_driver_get_line_centre_offset(void *font_data, float scale) +{ + struct font_line_metrics *metrics = NULL; + font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver); + + /* First try the line metrics implementation */ + if (font && font->renderer && font->renderer->get_line_metrics) + if ((font->renderer->get_line_metrics(font->renderer_data, &metrics))) + return (int)roundf((metrics->ascender - metrics->descender) * 0.5f * scale); + + /* Else return an approximation... */ + return (int)roundf((1.58f * 0.5f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f) / 2.0f); } void font_driver_free(void *font_data) diff --git a/gfx/font_driver.h b/gfx/font_driver.h index 5f0d2e3144..ef929497d2 100644 --- a/gfx/font_driver.h +++ b/gfx/font_driver.h @@ -81,6 +81,13 @@ struct font_params enum text_alignment text_align; }; +struct font_line_metrics +{ + float height; + float ascender; + float descender; +}; + typedef struct font_renderer { void *(*init)(void *data, const char *font_path, @@ -96,7 +103,7 @@ typedef struct font_renderer void (*flush)(unsigned width, unsigned height, void *data); int (*get_message_width)(void *data, const char *msg, unsigned msg_len_full, float scale); - int (*get_line_height)(void* data); + bool (*get_line_metrics)(void* data, struct font_line_metrics **metrics); } font_renderer_t; typedef struct font_renderer_driver @@ -114,7 +121,7 @@ typedef struct font_renderer_driver const char *ident; - int (*get_line_height)(void* data); + bool (*get_line_metrics)(void* data, struct font_line_metrics **metrics); } font_renderer_driver_t; typedef struct @@ -159,6 +166,9 @@ void font_driver_init_osd( void font_driver_free_osd(void); int font_driver_get_line_height(void *font_data, float scale); +int font_driver_get_line_ascender(void *font_data, float scale); +int font_driver_get_line_descender(void *font_data, float scale); +int font_driver_get_line_centre_offset(void *font_data, float scale); extern font_renderer_t gl_raster_font; extern font_renderer_t gl_core_raster_font; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 70af7a9c00..827e5014be 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -1194,8 +1194,10 @@ typedef struct { font_data_t *font; video_font_raster_block_t raster_block; - int font_height; unsigned glyph_width; + int line_height; + int line_ascender; + int line_centre_offset; } materialui_font_data_t; #define MUI_BATTERY_PERCENT_MAX_LENGTH 12 @@ -1273,6 +1275,8 @@ typedef struct materialui_handle unsigned sys_bar_margin; unsigned landscape_entry_margin; unsigned entry_divider_width; + unsigned sublabel_gap; + unsigned sublabel_padding; /* Navigation bar parameters * Note: layout width and height are convenience @@ -1928,7 +1932,7 @@ static void materialui_render_messagebox(materialui_handle_t *mui, /* Get coordinates of message box centre */ x = video_width / 2; - y = (int)(y_centre - (list->size - 1) * (mui->font_data.list.font_height / 2)); + y = (int)(y_centre - (list->size * mui->font_data.list.line_height) / 2); /* TODO/FIXME: Reduce text scale if width or height * are too large to fit on screen */ @@ -1960,9 +1964,9 @@ static void materialui_render_messagebox(materialui_handle_t *mui, video_width, video_height, x - longest_width / 2.0 - mui->margin * 2.0, - y - mui->font_data.list.font_height / 2.0 - mui->margin * 2.0, + y - mui->margin * 2.0, longest_width + mui->margin * 4.0, - mui->font_data.list.font_height * list->size + mui->margin * 4.0, + mui->font_data.list.line_height * list->size + mui->margin * 4.0, video_width, video_height, mui->colors.surface_background); @@ -1976,8 +1980,7 @@ static void materialui_render_messagebox(materialui_handle_t *mui, gfx_display_draw_text( mui->font_data.list.font, line, x - longest_width/2.0, - y + i * mui->font_data.list.font_height - + mui->font_data.list.font_height / 3, + y + (i * mui->font_data.list.line_height) + mui->font_data.list.line_ascender, video_width, video_height, mui->colors.list_text, TEXT_ALIGN_LEFT, 1.0f, false, 0, true); } @@ -2061,7 +2064,7 @@ static void materialui_compute_entries_box( if (mui->list_view_type == MUI_LIST_VIEW_PLAYLIST_THUMB_DUAL_ICON) { /* One line of list text */ - float node_text_height = (float)mui->font_data.list.font_height; + float node_text_height = (float)mui->font_data.list.line_height; /* List text + thumbnail height + padding */ float node_entry_height = node_text_height + (float)mui->thumbnail_height_max + @@ -2140,7 +2143,7 @@ static void materialui_compute_entries_box( if (!string_is_empty(sublabel_str)) { - int sublabel_width_max = usable_width; + int sublabel_width_max = usable_width - (int)mui->sublabel_padding; /* If this is a default menu list with an icon, * must subtract icon size from sublabel width */ @@ -2157,8 +2160,8 @@ static void materialui_compute_entries_box( num_sublabel_lines = materialui_count_lines(wrapped_sublabel_str); } - node->text_height = mui->font_data.list.font_height + - (num_sublabel_lines * mui->font_data.hint.font_height); + node->text_height = mui->font_data.list.line_height + + (num_sublabel_lines * mui->font_data.hint.line_height); node->entry_height = node->text_height + mui->dip_base_unit_size / 10; @@ -2814,16 +2817,33 @@ static void materialui_render_menu_entry_default( * affects y offset positions */ if (!string_is_empty(entry_sublabel)) { - int sublabel_y = - entry_y + (int)(mui->dip_base_unit_size / 5.0f) + - (int)mui->font_data.list.font_height; + /* Note: Due to the way the selection highlight + * marker is drawn (height is effectively 1px larger + * than the entry height, to avoid visible seams), + * drawing the label+sublabel text at the exact centre + * of the entry gives the illusion of misalignment + * > Have to offset the label downwards by half a pixel + * (rounded up) */ + int vertical_margin = ((node->entry_height - node->text_height) / 2.0f) - (float)mui->sublabel_gap + 1.0f; + int sublabel_y; char wrapped_sublabel[MENU_SUBLABEL_MAX_LENGTH]; wrapped_sublabel[0] = '\0'; + /* Label + sublabel 'block' is drawn at the + * vertical centre of the current node. + * > Value icon is drawn in line with the centre + * of the part of the label above the baseline + * (needs a little extra padding at the top, since + * the line ascender is usually somewhat taller + * than the visible text) */ + label_y = entry_y + vertical_margin + mui->font_data.list.line_ascender; + value_icon_y = label_y + (mui->dip_base_unit_size / 60.0f) - (mui->font_data.list.line_ascender / 2.0f) - (mui->icon_size / 2.0f); + sublabel_y = entry_y + vertical_margin + mui->font_data.list.line_height + (int)mui->sublabel_gap + mui->font_data.hint.line_ascender; + /* Wrap sublabel string */ word_wrap(wrapped_sublabel, entry_sublabel, - (int)(usable_width / mui->font_data.hint.glyph_width), + (int)((usable_width - (int)mui->sublabel_padding) / mui->font_data.hint.glyph_width), true, 0); /* Draw sublabel string @@ -2839,22 +2859,13 @@ static void materialui_render_menu_entry_default( (entry_selected || touch_feedback_active) ? mui->colors.list_hint_text_highlighted : mui->colors.list_hint_text, TEXT_ALIGN_LEFT, 1.0f, false, 0, draw_text_outside || (sublabel_y < 0)); - - /* If we have a sublabel, entry label y position has a - * fixed vertical offset */ - label_y = entry_y + (int)(mui->dip_base_unit_size / 5.0f); - value_icon_y = entry_y + (int)((mui->dip_base_unit_size / 6.0f) - (mui->icon_size / 2.0f)); } else { /* If we don't have a sublabel, entry label is drawn - * at the vertical centre of the current node - * Note: Text is drawn relative to the baseline, - * so we can't do this accurately - but as a general - * rule of thumb, the descender of a font is at least - * 20% of it's height - so we just add (font_height / 5) */ - label_y = entry_y + (int)((node->entry_height / 2.0f) + (mui->font_data.list.font_height / 5.0f)); - value_icon_y = entry_y + (int)((node->entry_height / 2.0f) - (mui->icon_size / 2.0f)); + * at the vertical centre of the current node */ + label_y = entry_y + (node->entry_height / 2.0f) + mui->font_data.list.line_centre_offset; + value_icon_y = entry_y + (node->entry_height / 2.0f) - (mui->icon_size / 2.0f); } /* Draw entry value */ @@ -3048,16 +3059,7 @@ static void materialui_render_menu_entry_playlist_list( int entry_margin = (int)mui->margin + (int)mui->landscape_entry_margin; int usable_width = (int)width - (int)(mui->margin * 2) - (int)(mui->landscape_entry_margin * 2) - (int)mui->nav_bar_layout_width; - /* The label + sublabel text block is always drawn at - * the vertical centre of the current node - * Note: Text is drawn relative to the baseline, - * so we can't do this accurately - but tests - * indicate that the ascender of Material UI's - * font accounts for 7/20 of its height, so we - * just add (13/20) * font_height */ - int label_y = - entry_y + ((float)(node->entry_height - node->text_height) / 2.0f) + - (13.0f * (float)mui->font_data.list.font_height / 20.0f); + int label_y = 0; bool draw_text_outside = (x_offset != 0); /* Initial ticker configuration @@ -3149,6 +3151,53 @@ static void materialui_render_menu_entry_playlist_list( (int)mui->landscape_entry_margin : (int)mui->margin; } + /* Draw entry sublabel + * > Must be done before label, since it + * affects y offset positions */ + if (!string_is_empty(entry_sublabel)) + { + /* Note: Due to the way the selection highlight + * marker is drawn (height is effectively 1px larger + * than the entry height, to avoid visible seams), + * drawing the label+sublabel text at the exact centre + * of the entry gives the illusion of misalignment + * > Have to offset the label downwards by half a pixel + * (rounded up) */ + int vertical_margin = ((node->entry_height - node->text_height) / 2.0f) - (float)mui->sublabel_gap + 1.0f; + int sublabel_y; + char wrapped_sublabel[MENU_SUBLABEL_MAX_LENGTH]; + + wrapped_sublabel[0] = '\0'; + + /* Label + sublabel 'block' is drawn at the + * vertical centre of the current node */ + label_y = entry_y + vertical_margin + mui->font_data.list.line_ascender; + sublabel_y = entry_y + vertical_margin + mui->font_data.list.line_height + (int)mui->sublabel_gap + mui->font_data.hint.line_ascender; + + /* Wrap sublabel string */ + word_wrap(wrapped_sublabel, entry_sublabel, + (int)((usable_width - (int)mui->sublabel_padding) / mui->font_data.hint.glyph_width), + true, 0); + + /* Draw sublabel string + * > Note: We must allow text to be drawn off-screen + * if the current y position is negative, otherwise topmost + * entries with very long sublabels may get 'clipped' too + * early as they are scrolled upwards beyond the top edge + * of the screen */ + gfx_display_draw_text(mui->font_data.hint.font, wrapped_sublabel, + x_offset + entry_margin, + sublabel_y, + width, height, + (entry_selected || touch_feedback_active) ? + mui->colors.list_hint_text_highlighted : mui->colors.list_hint_text, + TEXT_ALIGN_LEFT, 1.0f, false, 0, draw_text_outside || (sublabel_y < 0)); + } + /* If we don't have a sublabel, entry label is drawn + * at the vertical centre of the current node */ + else + label_y = entry_y + (node->entry_height / 2.0f) + mui->font_data.list.line_centre_offset; + /* Draw entry label */ if (!string_is_empty(entry_label)) { @@ -3190,45 +3239,15 @@ static void materialui_render_menu_entry_playlist_list( } } - /* Draw entry sublabel */ - if (!string_is_empty(entry_sublabel)) - { - int sublabel_y = label_y + (int)mui->font_data.list.font_height; - char wrapped_sublabel[MENU_SUBLABEL_MAX_LENGTH]; - - wrapped_sublabel[0] = '\0'; - - /* Wrap sublabel string */ - word_wrap(wrapped_sublabel, entry_sublabel, - (int)(usable_width / mui->font_data.hint.glyph_width), - true, 0); - - /* Draw sublabel string - * > Note: We must allow text to be drawn off-screen - * if the current y position is negative, otherwise topmost - * entries with very long sublabels may get 'clipped' too - * early as they are scrolled upwards beyond the top edge - * of the screen */ - gfx_display_draw_text(mui->font_data.hint.font, wrapped_sublabel, - x_offset + entry_margin, - sublabel_y, - width, height, - (entry_selected || touch_feedback_active) ? - mui->colors.list_hint_text_highlighted : mui->colors.list_hint_text, - TEXT_ALIGN_LEFT, 1.0f, false, 0, draw_text_outside || (sublabel_y < 0)); - } - - /* When using the larger thumbnail views, the horizontal + /* When using thumbnail views, the horizontal * text area is unpleasantly vacuous, such that the * label + sublabel strings float in a sea of nothingness. * We can partially mitigate the visual 'emptiness' of this * by drawing a divider between entries. This is particularly * beneficial when dual thumbnails are enabled, since it - * 'ties' the left/right thumbnails together - * NOTE: This does not work at all for the smallest thumbnail - * list view, or when thumbnails are disabled - the result is - * just too 'busy'/visually cluttered */ - if ((mui->list_view_type == MUI_LIST_VIEW_PLAYLIST_THUMB_LIST_MEDIUM) || + * 'ties' the left/right thumbnails together */ + if ((mui->list_view_type == MUI_LIST_VIEW_PLAYLIST_THUMB_LIST_SMALL) || + (mui->list_view_type == MUI_LIST_VIEW_PLAYLIST_THUMB_LIST_MEDIUM) || (mui->list_view_type == MUI_LIST_VIEW_PLAYLIST_THUMB_LIST_LARGE)) { if (usable_width > 0) @@ -3323,8 +3342,9 @@ static void materialui_render_menu_entry_playlist_dual_icon( * with a small vertical margin */ float label_y = thumbnail_y + (float)mui->thumbnail_height_max + - ((float)mui->dip_base_unit_size / 10.0f) + - (9.0f * (float)mui->font_data.list.font_height / 20.0f); + ((float)mui->dip_base_unit_size / 20.0f) + + ((float)mui->font_data.list.line_height / 2.0f) + + (float)mui->font_data.list.line_centre_offset; bool draw_text_outside = (x_offset != 0); char label_buf[255]; @@ -3386,7 +3406,7 @@ static void materialui_render_menu_entry_playlist_dual_icon( (float)(x_offset + (int)mui->margin + (int)mui->landscape_entry_margin), thumbnail_y + (float)mui->thumbnail_height_max + ((float)mui->dip_base_unit_size / 10.0f) + - (float)mui->font_data.list.font_height, + (float)mui->font_data.list.line_height, (unsigned)usable_width, mui->entry_divider_width, width, @@ -3814,7 +3834,7 @@ static void materialui_render_header( int usable_title_bar_width = usable_sys_bar_width; size_t sys_bar_battery_width = 0; size_t sys_bar_clock_width = 0; - int sys_bar_text_y = (int)(((float)mui->sys_bar_height / 2.0f) + ((float)mui->font_data.hint.font_height / 4.0f)); + int sys_bar_text_y = (int)(((float)mui->sys_bar_height / 2.0f) + (float)mui->font_data.hint.line_centre_offset); int title_x = 0; bool show_back_icon = menu_entries_ctl(MENU_ENTRIES_CTL_SHOW_BACK, NULL); bool show_search_icon = mui->is_playlist || mui->is_file_list; @@ -4211,7 +4231,7 @@ static void materialui_render_header( gfx_display_draw_text(mui->font_data.title.font, menu_title_buf, title_x, - (int)(mui->sys_bar_height + (mui->title_bar_height / 2.0f) + (mui->font_data.title.font_height / 4.0f)), + (int)(mui->sys_bar_height + (mui->title_bar_height / 2.0f) + mui->font_data.title.line_centre_offset), width, height, mui->colors.header_text, TEXT_ALIGN_LEFT, 1.0f, false, 0, false); } @@ -5458,8 +5478,8 @@ static void materialui_set_thumbnail_dimensions(materialui_handle_t *mui) * > One line of list text + three lines of * hint text + padding */ mui->thumbnail_height_max = - mui->font_data.list.font_height + - (3 * mui->font_data.hint.font_height) + + mui->font_data.list.line_height + + (3 * mui->font_data.hint.line_height) + (mui->dip_base_unit_size / 10); /* Set thumbnail width based on max height @@ -5481,8 +5501,8 @@ static void materialui_set_thumbnail_dimensions(materialui_handle_t *mui) * > Two lines of list text + three lines of * hint text (no padding) */ mui->thumbnail_height_max = - (mui->font_data.list.font_height + - (3 * mui->font_data.hint.font_height)) * 2; + (mui->font_data.list.line_height + + (3 * mui->font_data.hint.line_height)) * 2; /* Set thumbnail width based on max height */ mui->thumbnail_width_max = @@ -5719,6 +5739,13 @@ static void materialui_layout(materialui_handle_t *mui, bool video_is_threaded) mui->entry_divider_width = (mui->last_scale_factor > 1.0f) ? (unsigned)(mui->last_scale_factor + 0.5f) : 1; + /* Additional vertical spacing between label and + * sublabel text */ + mui->sublabel_gap = mui->dip_base_unit_size / 42; + /* Additional horizontal padding inserted at the + * end of sublabel text to prevent line overflow */ + mui->sublabel_padding = mui->dip_base_unit_size / 20; + /* Note: We used to set scrollbar width here, but * since we now have several scrollbar parameters * that cannot be determined until materialui_compute_entries_box() @@ -5791,40 +5818,46 @@ static void materialui_layout(materialui_handle_t *mui, bool video_is_threaded) if (mui->font_data.title.font) { /* Calculate a more realistic ticker_limit */ - unsigned title_char_width = + int title_char_width = font_driver_get_message_width(mui->font_data.title.font, "a", 1, 1); - if (title_char_width) - mui->font_data.title.glyph_width = title_char_width; + if (title_char_width > 0) + mui->font_data.title.glyph_width = (unsigned)title_char_width; - /* Get font height */ - mui->font_data.title.font_height = font_driver_get_line_height(mui->font_data.title.font, 1.0f); + /* Get line metrics */ + mui->font_data.title.line_height = font_driver_get_line_height(mui->font_data.title.font, 1.0f); + mui->font_data.title.line_ascender = font_driver_get_line_ascender(mui->font_data.title.font, 1.0f); + mui->font_data.title.line_centre_offset = font_driver_get_line_centre_offset(mui->font_data.title.font, 1.0f); } if (mui->font_data.list.font) { /* Calculate a more realistic ticker_limit */ - unsigned list_char_width = + int list_char_width = font_driver_get_message_width(mui->font_data.list.font, "a", 1, 1); - if (list_char_width) - mui->font_data.list.glyph_width = list_char_width; + if (list_char_width > 0) + mui->font_data.list.glyph_width = (unsigned)list_char_width; - /* Get font height */ - mui->font_data.list.font_height = font_driver_get_line_height(mui->font_data.list.font, 1.0f); + /* Get line metrics */ + mui->font_data.list.line_height = font_driver_get_line_height(mui->font_data.list.font, 1.0f); + mui->font_data.list.line_ascender = font_driver_get_line_ascender(mui->font_data.list.font, 1.0f); + mui->font_data.list.line_centre_offset = font_driver_get_line_centre_offset(mui->font_data.list.font, 1.0f); } if (mui->font_data.hint.font) { /* Calculate a more realistic ticker_limit */ - unsigned hint_char_width = + int hint_char_width = font_driver_get_message_width(mui->font_data.hint.font, "t", 1, 1); - if (hint_char_width) - mui->font_data.hint.glyph_width = hint_char_width; + if (hint_char_width > 0) + mui->font_data.hint.glyph_width = (unsigned)hint_char_width; - /* Get font height */ - mui->font_data.hint.font_height = font_driver_get_line_height(mui->font_data.hint.font, 1.0f); + /* Get line metrics */ + mui->font_data.hint.line_height = font_driver_get_line_height(mui->font_data.hint.font, 1.0f); + mui->font_data.hint.line_ascender = font_driver_get_line_ascender(mui->font_data.hint.font, 1.0f); + mui->font_data.hint.line_centre_offset = font_driver_get_line_centre_offset(mui->font_data.hint.font, 1.0f); } /* When updating the layout, the system bar