Introduce subpixel text positioning within rencache
In order to fix the issue with cursor positioning a subpixel-aware draw text operation within rencache was required. With this modification the cursor positioning problem is completely resolved. A new function renderer.draw_text_subpixel is introduced to perform consecutive, inline, text drawings with subpixel accuracy.
This commit is contained in:
parent
9ff6a0325e
commit
3426bc5d73
|
@ -309,11 +309,12 @@ end
|
||||||
|
|
||||||
|
|
||||||
function DocView:draw_line_text(idx, x, y)
|
function DocView:draw_line_text(idx, x, y)
|
||||||
local tx, ty = x, y + self:get_line_text_y_offset()
|
|
||||||
local font = self:get_font()
|
local font = self:get_font()
|
||||||
|
local subpixel_scale = font:subpixel_scale()
|
||||||
|
local tx, ty = subpixel_scale * x, y + self:get_line_text_y_offset()
|
||||||
for _, type, text in self.doc.highlighter:each_token(idx) do
|
for _, type, text in self.doc.highlighter:each_token(idx) do
|
||||||
local color = style.syntax[type]
|
local color = style.syntax[type]
|
||||||
tx = renderer.draw_text(font, text, tx, ty, color)
|
tx = renderer.draw_text_subpixel(font, text, tx, ty, color)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -78,20 +78,33 @@ static int f_draw_text(lua_State *L) {
|
||||||
int x = luaL_checknumber(L, 3);
|
int x = luaL_checknumber(L, 3);
|
||||||
int y = luaL_checknumber(L, 4);
|
int y = luaL_checknumber(L, 4);
|
||||||
RenColor color = checkcolor(L, 5, 255);
|
RenColor color = checkcolor(L, 5, 255);
|
||||||
x = rencache_draw_text(*font, text, x, y, color);
|
x = rencache_draw_text(*font, text, x, y, color, false);
|
||||||
lua_pushnumber(L, x);
|
lua_pushnumber(L, x);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int f_draw_text_subpixel(lua_State *L) {
|
||||||
|
RenFont **font = luaL_checkudata(L, 1, API_TYPE_FONT);
|
||||||
|
const char *text = luaL_checkstring(L, 2);
|
||||||
|
int x_subpixel = luaL_checknumber(L, 3);
|
||||||
|
int y = luaL_checknumber(L, 4);
|
||||||
|
RenColor color = checkcolor(L, 5, 255);
|
||||||
|
x_subpixel = rencache_draw_text(*font, text, x_subpixel, y, color, true);
|
||||||
|
lua_pushnumber(L, x_subpixel);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const luaL_Reg lib[] = {
|
static const luaL_Reg lib[] = {
|
||||||
{ "show_debug", f_show_debug },
|
{ "show_debug", f_show_debug },
|
||||||
{ "get_size", f_get_size },
|
{ "get_size", f_get_size },
|
||||||
{ "begin_frame", f_begin_frame },
|
{ "begin_frame", f_begin_frame },
|
||||||
{ "end_frame", f_end_frame },
|
{ "end_frame", f_end_frame },
|
||||||
{ "set_clip_rect", f_set_clip_rect },
|
{ "set_clip_rect", f_set_clip_rect },
|
||||||
{ "draw_rect", f_draw_rect },
|
{ "draw_rect", f_draw_rect },
|
||||||
{ "draw_text", f_draw_text },
|
{ "draw_text", f_draw_text },
|
||||||
|
{ "draw_text_subpixel", f_draw_text_subpixel },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,15 @@
|
||||||
#define CELL_SIZE 96
|
#define CELL_SIZE 96
|
||||||
#define COMMAND_BUF_SIZE (1024 * 512)
|
#define COMMAND_BUF_SIZE (1024 * 512)
|
||||||
|
|
||||||
enum { FREE_FONT, SET_CLIP, DRAW_TEXT, DRAW_RECT };
|
enum { FREE_FONT, SET_CLIP, DRAW_TEXT, DRAW_RECT, DRAW_TEXT_SUBPIXEL };
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int type, size;
|
int type, size;
|
||||||
RenRect rect;
|
RenRect rect;
|
||||||
RenColor color;
|
RenColor color;
|
||||||
RenFont *font;
|
RenFont *font;
|
||||||
|
short int subpixel_scale;
|
||||||
|
short int x_subpixel_offset;
|
||||||
int tab_width;
|
int tab_width;
|
||||||
char text[0];
|
char text[0];
|
||||||
} Command;
|
} Command;
|
||||||
|
@ -128,29 +130,30 @@ void rencache_draw_rect(RenRect rect, RenColor color) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color, bool draw_subpixel) {
|
||||||
int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
|
|
||||||
int subpixel_scale;
|
int subpixel_scale;
|
||||||
|
int w_subpixel = ren_get_font_width(font, text, &subpixel_scale);
|
||||||
RenRect rect;
|
RenRect rect;
|
||||||
rect.x = x;
|
rect.x = (draw_subpixel ? ren_font_subpixel_round(x, subpixel_scale, -1) : x);
|
||||||
rect.y = y;
|
rect.y = y;
|
||||||
int w = ren_get_font_width(font, text, &subpixel_scale);
|
rect.width = ren_font_subpixel_round(w_subpixel, subpixel_scale, 0);
|
||||||
rect.width = ren_font_subpixel_round(w, subpixel_scale, 0);
|
|
||||||
rect.height = ren_get_font_height(font);
|
rect.height = ren_get_font_height(font);
|
||||||
|
|
||||||
if (rects_overlap(screen_rect, rect)) {
|
if (rects_overlap(screen_rect, rect)) {
|
||||||
int sz = strlen(text) + 1;
|
int sz = strlen(text) + 1;
|
||||||
Command *cmd = push_command(DRAW_TEXT, sizeof(Command) + sz);
|
Command *cmd = push_command(draw_subpixel ? DRAW_TEXT_SUBPIXEL : DRAW_TEXT, sizeof(Command) + sz);
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
memcpy(cmd->text, text, sz);
|
memcpy(cmd->text, text, sz);
|
||||||
cmd->color = color;
|
cmd->color = color;
|
||||||
cmd->font = font;
|
cmd->font = font;
|
||||||
cmd->rect = rect;
|
cmd->rect = rect;
|
||||||
|
cmd->subpixel_scale = (draw_subpixel ? subpixel_scale : 1);
|
||||||
|
cmd->x_subpixel_offset = x - subpixel_scale * rect.x;
|
||||||
cmd->tab_width = ren_get_font_tab_width(font);
|
cmd->tab_width = ren_get_font_tab_width(font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return x + rect.width;
|
return x + (draw_subpixel ? w_subpixel : rect.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,6 +264,10 @@ void rencache_end_frame(void) {
|
||||||
ren_set_font_tab_width(cmd->font, cmd->tab_width);
|
ren_set_font_tab_width(cmd->font, cmd->tab_width);
|
||||||
ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color);
|
ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color);
|
||||||
break;
|
break;
|
||||||
|
case DRAW_TEXT_SUBPIXEL:
|
||||||
|
ren_set_font_tab_width(cmd->font, cmd->tab_width);
|
||||||
|
ren_draw_text_subpixel(cmd->font, cmd->text, cmd->subpixel_scale * cmd->rect.x + cmd->x_subpixel_offset, cmd->rect.y, cmd->color);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ void rencache_show_debug(bool enable);
|
||||||
void rencache_free_font(RenFont *font);
|
void rencache_free_font(RenFont *font);
|
||||||
void rencache_set_clip_rect(RenRect rect);
|
void rencache_set_clip_rect(RenRect rect);
|
||||||
void rencache_draw_rect(RenRect rect, RenColor color);
|
void rencache_draw_rect(RenRect rect, RenColor color);
|
||||||
int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color);
|
int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color, bool draw_subpixel);
|
||||||
void rencache_invalidate(void);
|
void rencache_invalidate(void);
|
||||||
void rencache_begin_frame(void);
|
void rencache_begin_frame(void);
|
||||||
void rencache_end_frame(void);
|
void rencache_end_frame(void);
|
||||||
|
|
|
@ -284,26 +284,31 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
|
|
||||||
|
void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int y, RenColor color) {
|
||||||
const char *p = text;
|
const char *p = text;
|
||||||
unsigned codepoint;
|
unsigned codepoint;
|
||||||
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
SDL_Surface *surf = SDL_GetWindowSurface(window);
|
||||||
FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
|
FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
|
||||||
const int subpixel_scale = FR_Subpixel_Scale(font->renderer);
|
|
||||||
int x_mult = subpixel_scale * x;
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
p = utf8_to_codepoint(p, &codepoint);
|
p = utf8_to_codepoint(p, &codepoint);
|
||||||
GlyphSet *set = get_glyphset(font, codepoint);
|
GlyphSet *set = get_glyphset(font, codepoint);
|
||||||
FR_Bitmap_Glyph_Metrics *g = &set->glyphs[codepoint & 0xff];
|
FR_Bitmap_Glyph_Metrics *g = &set->glyphs[codepoint & 0xff];
|
||||||
if (color.a != 0) {
|
if (color.a != 0) {
|
||||||
FR_Blend_Glyph(font->renderer, &clip,
|
FR_Blend_Glyph(font->renderer, &clip,
|
||||||
x_mult, y, (uint8_t *) surf->pixels, surf->w, set->image, g, color_fr);
|
x_subpixel, y, (uint8_t *) surf->pixels, surf->w, set->image, g, color_fr);
|
||||||
}
|
}
|
||||||
x_mult += g->xadvance;
|
x_subpixel += g->xadvance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
|
||||||
|
const int subpixel_scale = FR_Subpixel_Scale(font->renderer);
|
||||||
|
ren_draw_text_subpixel(font, text, subpixel_scale * x, y, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int ren_font_subpixel_round(int width, int subpixel_scale, int orientation) {
|
int ren_font_subpixel_round(int width, int subpixel_scale, int orientation) {
|
||||||
int w_mult;
|
int w_mult;
|
||||||
if (orientation < 0) {
|
if (orientation < 0) {
|
||||||
|
|
|
@ -42,5 +42,6 @@ int ren_font_subpixel_round(int width, int subpixel_scale, int orientation);
|
||||||
void ren_draw_rect(RenRect rect, RenColor color);
|
void ren_draw_rect(RenRect rect, RenColor color);
|
||||||
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color);
|
void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color);
|
||||||
void 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);
|
||||||
|
void ren_draw_text_subpixel(RenFont *font, const char *text, int x_subpixel, int y, RenColor color);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue