From 9ff6a0325edd123fb68ddbe9c59a747b384c27d0 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Sat, 6 Mar 2021 16:18:24 +0100 Subject: [PATCH] Mostly fix problem of offset with cursor positioning when using mouse In order to get right the cursor position on text on mouse clicks it is needed to take into account text's subpixel positioning. This fix mostly corrects the problem but cursor positioning is still somewhat inaccurate for long lines due to repeated commands to draw a text along a line. Repeated draw text calls make the subpixel information lost and small errors will add-up. --- data/core/docview.lua | 8 +++++--- lib/font_renderer/font_renderer.h | 2 -- src/api/renderer_font.c | 31 +++++++++++++++++++++++++------ src/rencache.c | 4 +++- src/renderer.c | 29 ++++++++++++++++++++++++----- src/renderer.h | 6 ++++-- 6 files changed, 61 insertions(+), 19 deletions(-) diff --git a/data/core/docview.lua b/data/core/docview.lua index 57383da7..7e6dcf30 100644 --- a/data/core/docview.lua +++ b/data/core/docview.lua @@ -152,10 +152,12 @@ function DocView:get_x_offset_col(line, x) local text = self.doc.lines[line] local xoffset, last_i, i = 0, 1, 1 + local subpixel_scale = self:get_font():subpixel_scale(); + local x_subpixel = subpixel_scale * x + subpixel_scale / 2 for char in common.utf8_chars(text) do - local w = self:get_font():get_width(char) - if xoffset >= x then - return (xoffset - x > w / 2) and last_i or i + local w = self:get_font():get_width_subpixel(char) + if xoffset >= subpixel_scale * x then + return (xoffset - x_subpixel > w / 2) and last_i or i end xoffset = xoffset + w last_i = i diff --git a/lib/font_renderer/font_renderer.h b/lib/font_renderer/font_renderer.h index 69696340..019d2ae7 100644 --- a/lib/font_renderer/font_renderer.h +++ b/lib/font_renderer/font_renderer.h @@ -51,8 +51,6 @@ void FR_Blend_Glyph(FR_Renderer *font_renderer, const FR_Bitmap_Glyph_Metrics *glyph, FR_Color color); int FR_Subpixel_Scale(FR_Renderer *); -#define FR_XADVANCE_TO_PIXELS(x, scale) (((x) + (scale) / 2) / (scale)) - #ifdef __cplusplus } #endif diff --git a/src/api/renderer_font.c b/src/api/renderer_font.c index 0dea11ae..744ea808 100644 --- a/src/api/renderer_font.c +++ b/src/api/renderer_font.c @@ -66,7 +66,24 @@ static int f_gc(lua_State *L) { static int f_get_width(lua_State *L) { RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); const char *text = luaL_checkstring(L, 2); - lua_pushnumber(L, ren_get_font_width(*self, text) ); + int subpixel_scale; + int w = ren_get_font_width(*self, text, &subpixel_scale); + lua_pushnumber(L, ren_font_subpixel_round(w, subpixel_scale, 0)); + return 1; +} + + +static int f_subpixel_scale(lua_State *L) { + RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); + lua_pushnumber(L, ren_get_font_subpixel_scale(*self)); + return 1; +} + + +static int f_get_width_subpixel(lua_State *L) { + RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT); + const char *text = luaL_checkstring(L, 2); + lua_pushnumber(L, ren_get_font_width(*self, text, NULL)); return 1; } @@ -79,11 +96,13 @@ static int f_get_height(lua_State *L) { static const luaL_Reg lib[] = { - { "__gc", f_gc }, - { "load", f_load }, - { "set_tab_width", f_set_tab_width }, - { "get_width", f_get_width }, - { "get_height", f_get_height }, + { "__gc", f_gc }, + { "load", f_load }, + { "set_tab_width", f_set_tab_width }, + { "get_width", f_get_width }, + { "get_width_subpixel", f_get_width_subpixel }, + { "get_height", f_get_height }, + { "subpixel_scale", f_subpixel_scale }, { NULL, NULL } }; diff --git a/src/rencache.c b/src/rencache.c index 5c6de328..2c45baf4 100644 --- a/src/rencache.c +++ b/src/rencache.c @@ -130,10 +130,12 @@ void rencache_draw_rect(RenRect rect, RenColor color) { int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) { + int subpixel_scale; RenRect rect; rect.x = x; rect.y = y; - rect.width = ren_get_font_width(font, text); + int w = ren_get_font_width(font, text, &subpixel_scale); + rect.width = ren_font_subpixel_round(w, subpixel_scale, 0); rect.height = ren_get_font_height(font); if (rects_overlap(screen_rect, rect)) { diff --git a/src/renderer.c b/src/renderer.c index 6b31aaca..262f5814 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -179,18 +179,20 @@ int ren_get_font_tab_width(RenFont *font) { } -int ren_get_font_width(RenFont *font, const char *text) { +int ren_get_font_width(RenFont *font, const char *text, int *subpixel_scale) { int x = 0; const char *p = text; unsigned codepoint; - const int subpixel_scale = FR_Subpixel_Scale(font->renderer); while (*p) { p = utf8_to_codepoint(p, &codepoint); GlyphSet *set = get_glyphset(font, codepoint); FR_Bitmap_Glyph_Metrics *g = &set->glyphs[codepoint & 0xff]; x += g->xadvance; } - return FR_XADVANCE_TO_PIXELS(x, subpixel_scale); + if (subpixel_scale) { + *subpixel_scale = FR_Subpixel_Scale(font->renderer); + } + return x; } @@ -282,7 +284,7 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) } } -int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) { +void ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) { const char *p = text; unsigned codepoint; SDL_Surface *surf = SDL_GetWindowSurface(window); @@ -299,5 +301,22 @@ int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) } x_mult += g->xadvance; } - return FR_XADVANCE_TO_PIXELS(x_mult, subpixel_scale); +} + + +int ren_font_subpixel_round(int width, int subpixel_scale, int orientation) { + int w_mult; + if (orientation < 0) { + w_mult = width; + } else if (orientation == 0) { + w_mult = width + subpixel_scale / 2; + } else { + w_mult = width + subpixel_scale - 1; + } + return w_mult / subpixel_scale; +} + + +int ren_get_font_subpixel_scale(RenFont *font) { + return FR_Subpixel_Scale(font->renderer); } diff --git a/src/renderer.h b/src/renderer.h index 3b041846..39551de8 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -34,11 +34,13 @@ RenFont* ren_load_font(const char *filename, float size, unsigned int renderer_f void ren_free_font(RenFont *font); void ren_set_font_tab_width(RenFont *font, int n); int ren_get_font_tab_width(RenFont *font); -int ren_get_font_width(RenFont *font, const char *text); +int ren_get_font_width(RenFont *font, const char *text, int *subpixel_scale); int ren_get_font_height(RenFont *font); +int ren_get_font_subpixel_scale(RenFont *font); +int ren_font_subpixel_round(int width, int subpixel_scale, int orientation); void ren_draw_rect(RenRect rect, RenColor color); void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color); -int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color); +void ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color); #endif