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.
132 lines
3.2 KiB
C
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;
|
|
}
|