Files
deb-lite-xl/src/api/renderer.c
T
Francesco Abbate aa0b2bb5fc Fix crash problem with rencache and font access
In some cases rencache was using a FontDesc pointer that was actually freed by
Lua giving segfaults errors.

In addition, some FontDesc object were not freed in some cases if the
rencache_end_frame was not called when performing the "restart" command.

The invalid access problem can happen because rencache keep some pointers to
FontDesc object but these are Lua userdata that Lua can dispose of. This
situation is prone to hard errors and we should avoid to keep pointers to
objects managed by Lua.

To this purpose we use luaL_ref/unref to bind the FontDesc into the Lua's
registry while rencache need them. We still keeps pointer to FontDesc object but
using luaL_ref we are assured they will not be disposed by Lua.

Since we are using luaL_ref/unref to inform the GC about when the objects are in
use we can now finalize the objects directly when Lua collects them. Previously
the GC metamethods was issuing a FREE command to rencache and the font was
actually freed only from the rencache_end_frame function.
2021-05-21 23:38:54 +02:00

132 lines
3.2 KiB
C

#include "api.h"
#include "renderer.h"
#include "rencache.h"
static RenColor checkcolor(lua_State *L, int idx, int def) {
RenColor color;
if (lua_isnoneornil(L, idx)) {
return (RenColor) { def, def, def, 255 };
}
lua_rawgeti(L, idx, 1);
lua_rawgeti(L, idx, 2);
lua_rawgeti(L, idx, 3);
lua_rawgeti(L, idx, 4);
color.r = luaL_checknumber(L, -4);
color.g = luaL_checknumber(L, -3);
color.b = luaL_checknumber(L, -2);
color.a = luaL_optnumber(L, -1, 255);
lua_pop(L, 4);
return color;
}
static int f_show_debug(lua_State *L) {
luaL_checkany(L, 1);
rencache_show_debug(lua_toboolean(L, 1));
return 0;
}
static int f_get_size(lua_State *L) {
int w, h;
ren_get_size(&w, &h);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
}
static int f_begin_frame(lua_State *L) {
rencache_begin_frame(L);
return 0;
}
static int f_end_frame(lua_State *L) {
rencache_end_frame(L);
return 0;
}
static int f_set_clip_rect(lua_State *L) {
RenRect rect;
rect.x = luaL_checknumber(L, 1);
rect.y = luaL_checknumber(L, 2);
rect.width = luaL_checknumber(L, 3);
rect.height = luaL_checknumber(L, 4);
rencache_set_clip_rect(rect);
return 0;
}
static int f_draw_rect(lua_State *L) {
RenRect rect;
rect.x = luaL_checknumber(L, 1);
rect.y = luaL_checknumber(L, 2);
rect.width = luaL_checknumber(L, 3);
rect.height = luaL_checknumber(L, 4);
RenColor color = checkcolor(L, 5, 255);
rencache_draw_rect(rect, color);
return 0;
}
static int draw_text_subpixel_impl(lua_State *L, bool draw_subpixel) {
FontDesc *font_desc = luaL_checkudata(L, 1, API_TYPE_FONT);
const char *text = luaL_checkstring(L, 2);
/* The coordinate below will be in subpixel iff draw_subpixel is true.
Otherwise it will be in pixels. */
int x_subpixel = luaL_checknumber(L, 3);
int y = luaL_checknumber(L, 4);
RenColor color = checkcolor(L, 5, 255);
CPReplaceTable *rep_table;
RenColor replace_color;
if (lua_gettop(L) >= 7) {
rep_table = luaL_checkudata(L, 6, API_TYPE_REPLACE);
replace_color = checkcolor(L, 7, 255);
} else {
rep_table = NULL;
replace_color = (RenColor) {0};
}
x_subpixel = rencache_draw_text(L, font_desc, 1, text, x_subpixel, y, color, draw_subpixel, rep_table, replace_color);
lua_pushnumber(L, x_subpixel);
return 1;
}
static int f_draw_text(lua_State *L) {
return draw_text_subpixel_impl(L, false);
}
static int f_draw_text_subpixel(lua_State *L) {
return draw_text_subpixel_impl(L, true);
}
static const luaL_Reg lib[] = {
{ "show_debug", f_show_debug },
{ "get_size", f_get_size },
{ "begin_frame", f_begin_frame },
{ "end_frame", f_end_frame },
{ "set_clip_rect", f_set_clip_rect },
{ "draw_rect", f_draw_rect },
{ "draw_text", f_draw_text },
{ "draw_text_subpixel", f_draw_text_subpixel },
{ NULL, NULL }
};
int luaopen_renderer_font(lua_State *L);
int luaopen_renderer_replacements(lua_State *L);
int luaopen_renderer(lua_State *L) {
luaL_newlib(L, lib);
luaopen_renderer_font(L);
lua_setfield(L, -2, "font");
luaopen_renderer_replacements(L);
lua_setfield(L, -2, "replacements");
return 1;
}