Lua expand multiple screen support

Some of the lcd functions had support for multiple screens but this wasn't
very safe since the screen number wasn't bounded within the screens[] array
This adds support for all the lcd functions along with checking that screen#
is bounded properly, adds around 600 bytes to devices with a remote screen
devices without a remote screen lock to SCREEN_MAIN

Change-Id: I618bbc7b3919c7b0ff375fb2d71949d7cab43c87
This commit is contained in:
William Wilgus 2018-10-27 06:24:27 -04:00
parent 80352c2c2d
commit df8233e4ab
3 changed files with 303 additions and 101 deletions

View file

@ -56,66 +56,6 @@
#define RB_WRAP(func) static int rock_##func(lua_State UNUSED_ATTR *L)
#define SIMPLE_VOID_WRAPPER(func) RB_WRAP(func) { (void)L; func(); return 0; }
/* Helper function for opt_viewport */
static void check_tablevalue(lua_State *L,
const char* key,
int tablepos,
void* res,
bool is_unsigned)
{
lua_getfield(L, tablepos, key); /* Find table[key] */
int val = lua_tointeger(L, -1);
if(is_unsigned)
*(unsigned*)res = (unsigned) val;
else
*(int*)res = val;
lua_pop(L, 1); /* Pop the value off the stack */
}
static inline struct viewport* opt_viewport(lua_State *L,
int narg,
struct viewport* vp,
struct viewport* alt)
{
if(lua_isnoneornil(L, narg))
return alt;
luaL_checktype(L, narg, LUA_TTABLE);
check_tablevalue(L, "x", narg, &vp->x, false);
check_tablevalue(L, "y", narg, &vp->y, false);
check_tablevalue(L, "width", narg, &vp->width, false);
check_tablevalue(L, "height", narg, &vp->height, false);
#ifdef HAVE_LCD_BITMAP
check_tablevalue(L, "font", narg, &vp->font, false);
check_tablevalue(L, "drawmode", narg, &vp->drawmode, false);
#endif
#if LCD_DEPTH > 1
check_tablevalue(L, "fg_pattern", narg, &vp->fg_pattern, true);
check_tablevalue(L, "bg_pattern", narg, &vp->bg_pattern, true);
#endif
return vp;
}
RB_WRAP(set_viewport)
{
static struct viewport vp;
int screen = luaL_optint(L, 2, SCREEN_MAIN);
rb->screens[screen]->set_viewport(opt_viewport(L, 1, &vp, NULL));
return 0;
}
RB_WRAP(clear_viewport)
{
int screen = luaL_optint(L, 1, SCREEN_MAIN);
rb->screens[screen]->clear_viewport();
return 0;
}
RB_WRAP(current_tick)
{
lua_pushinteger(L, *rb->current_tick);
@ -172,25 +112,6 @@ RB_WRAP(touchscreen_get_mode)
}
#endif
RB_WRAP(font_getstringsize)
{
const unsigned char* str = luaL_checkstring(L, 1);
int fontnumber = luaL_checkint(L, 2);
int w, h;
if (fontnumber == FONT_UI)
fontnumber = rb->global_status->font_id[SCREEN_MAIN];
else
fontnumber = FONT_SYSFIXED;
int result = rb->font_getstringsize(str, &w, &h, fontnumber);
lua_pushinteger(L, result);
lua_pushinteger(L, w);
lua_pushinteger(L, h);
return 3;
}
RB_WRAP(current_path)
{
return get_current_path(L, 1);
@ -507,9 +428,6 @@ static const luaL_Reg rocklib[] =
RB_FUNC(kbd_input),
RB_FUNC(font_getstringsize),
RB_FUNC(set_viewport),
RB_FUNC(clear_viewport),
RB_FUNC(current_path),
RB_FUNC(gui_syncyesno_run),
RB_FUNC(do_menu),
@ -563,6 +481,11 @@ LUALIB_API int luaopen_rock(lua_State *L)
RB_CONSTANT(LCD_DEPTH),
RB_CONSTANT(LCD_HEIGHT),
RB_CONSTANT(LCD_WIDTH),
#ifdef HAVE_REMOTE_LCD
RB_CONSTANT(LCD_REMOTE_DEPTH),
RB_CONSTANT(LCD_REMOTE_HEIGHT),
RB_CONSTANT(LCD_REMOTE_WIDTH),
#endif
RB_CONSTANT(FONT_SYSFIXED),
RB_CONSTANT(FONT_UI),

View file

@ -73,6 +73,14 @@ my @forbidden_functions = ('^open$',
'^codec_',
'^timer_',
'^lcd_(mono_)?+bitmap',
'^lcd_(draw|fill|update_)rect$',
'^lcd_draw(line|pixel)$',
'^lcd_(h|v)line$',
'^lcd_(update|clear_display|set_drawmode)$',
'^lcd_setfont$',
'^lcd_(set|get)_(fore|back)ground$',
'^lcd_put(s|sxy|s_scroll)$',
'^lcd_scroll_stop$',
'^__.+$',
'^.+_(un)?cached$',
'^audio_.+$',

View file

@ -1217,21 +1217,180 @@ static const struct luaL_reg rli_lib [] =
*/
#define RB_WRAP(func) static int rock_##func(lua_State UNUSED_ATTR *L)
#if defined NB_SCREENS && (NB_SCREENS > 1)
#define RB_SCREENS(luastate, narg, func, ...) \
rb->screens[get_screen(luastate, narg)]->func(__VA_ARGS__)
static int get_screen(lua_State *L, int narg)
{
int screen = luaL_optint(L, narg, SCREEN_MAIN);
if(screen < SCREEN_MAIN)
screen = SCREEN_MAIN;
else if(screen > NB_SCREENS)
screen = NB_SCREENS;
return screen;
}
#else /* only SCREEN_MAIN exists */
#define RB_SCREENS(luastate, narg, func, ...) \
rb->screens[SCREEN_MAIN]->func(__VA_ARGS__)
#endif
RB_WRAP(lcd_update)
{
RB_SCREENS(L, 1, update);
return 0;
}
RB_WRAP(lcd_clear_display)
{
RB_SCREENS(L, 1, clear_display);
return 0;
}
RB_WRAP(lcd_set_drawmode)
{
int mode = (int) luaL_checkint(L, 1);
RB_SCREENS(L, 2, set_drawmode, mode);
return 0;
}
/* helper function for lcd_puts functions */
static const unsigned char * lcd_putshelper(lua_State *L, int *x, int *y)
{
*x = (int) luaL_checkint(L, 1);
*y = (int) luaL_checkint(L, 2);
return luaL_checkstring(L, 3);
}
RB_WRAP(lcd_putsxy)
{
int x, y;
const unsigned char *string = lcd_putshelper(L, &x, &y);
RB_SCREENS(L, 4, putsxy, x, y, string);
return 0;
}
RB_WRAP(lcd_puts)
{
int x, y;
const unsigned char * string = lcd_putshelper(L, &x, &y);
RB_SCREENS(L, 4, puts, x, y, string);
return 0;
}
RB_WRAP(lcd_puts_scroll)
{
int x, y;
const unsigned char * string = lcd_putshelper(L, &x, &y);
bool result = RB_SCREENS(L, 4, puts_scroll, x, y, string);
lua_pushboolean(L, result);
return 1;
}
RB_WRAP(lcd_scroll_stop)
{
RB_SCREENS(L, 1, scroll_stop);
return 0;
}
/* Helper function for opt_viewport */
static int check_tablevalue(lua_State *L, const char* key, int tablepos)
{
lua_getfield(L, tablepos, key); /* Find table[key] */
int val = lua_tointeger(L, -1);
lua_pop(L, 1); /* Pop the value off the stack */
return val;
}
static inline struct viewport* opt_viewport(lua_State *L,
int narg,
struct viewport* vp,
struct viewport* alt)
{
if(lua_isnoneornil(L, narg))
return alt;
luaL_checktype(L, narg, LUA_TTABLE);
vp->x = check_tablevalue(L, "x", narg);
vp->y = check_tablevalue(L, "y", narg);
vp->width = check_tablevalue(L, "width", narg);
vp->height = check_tablevalue(L, "height", narg);
#ifdef HAVE_LCD_BITMAP
vp->font = check_tablevalue(L, "font", narg);
vp->drawmode = check_tablevalue(L, "drawmode", narg);
#endif
#if LCD_DEPTH > 1
vp->fg_pattern = (unsigned int) check_tablevalue(L, "fg_pattern", narg);
vp->bg_pattern = (unsigned int) check_tablevalue(L, "bg_pattern", narg);
#endif
return vp;
}
RB_WRAP(set_viewport)
{
static struct viewport vp;
RB_SCREENS(L, 2, set_viewport, opt_viewport(L, 1, &vp, NULL));
return 0;
}
RB_WRAP(clear_viewport)
{
RB_SCREENS(L, 1, clear_viewport);
return 0;
}
RB_WRAP(font_getstringsize)
{
const unsigned char* str = luaL_checkstring(L, 1);
int fontnumber = lua_tointeger(L, 2);
int w, h, result;
if (fontnumber == FONT_UI)
fontnumber = rb->global_status->font_id[SCREEN_MAIN];
else
fontnumber = FONT_SYSFIXED;
if lua_isnil(L, 2)
result = RB_SCREENS(L, 3, getstringsize, str, &w, &h);
else
result = rb->font_getstringsize(str, &w, &h, fontnumber);
lua_pushinteger(L, result);
lua_pushinteger(L, w);
lua_pushinteger(L, h);
return 3;
}
#ifdef HAVE_LCD_BITMAP
RB_WRAP(lcd_framebuffer)
{
rli_wrap(L, rb->lcd_framebuffer, LCD_WIDTH, LCD_HEIGHT);
return 1;
}
/* helper function for lcd_xxx_bitmap functions */
static int get_bmp_bounds(lua_State *L, int npos, int *x, int *y, int *w, int* h)
RB_WRAP(lcd_setfont)
{
*x = luaL_checkint(L, npos);
*y = luaL_checkint(L, npos + 1);
*w = luaL_checkint(L, npos + 2);
*h = luaL_checkint(L, npos + 3);
return luaL_optint(L, npos + 4, SCREEN_MAIN);
int font = (int) luaL_checkint(L, 1);
RB_SCREENS(L, 2, setfont, font);
return 0;
}
/* helper function for lcd_xxx_bitmap/rect functions */
static void get_rect_bounds(lua_State *L, int narg, int *x, int *y, int *w, int* h)
{
*x = luaL_checkint(L, narg);
*y = luaL_checkint(L, narg + 1);
*w = luaL_checkint(L, narg + 2);
*h = luaL_checkint(L, narg + 3);
}
RB_WRAP(lcd_mono_bitmap_part)
@ -1241,9 +1400,10 @@ RB_WRAP(lcd_mono_bitmap_part)
int src_y = luaL_checkint(L, 3);
int stride = luaL_checkint(L, 4);
int x, y, width, height;
int screen = get_bmp_bounds(L, 5, &x, &y, &width, &height);
get_rect_bounds(L, 5, &x, &y, &width, &height);
rb->screens[screen]->mono_bitmap_part((const unsigned char *)src->data, src_x, src_y, stride, x, y, width, height);
RB_SCREENS(L, 9, mono_bitmap_part, (const unsigned char *)src->data,
src_x, src_y, stride, x, y, width, height);
return 0;
}
@ -1251,9 +1411,9 @@ RB_WRAP(lcd_mono_bitmap)
{
struct rocklua_image *src = rli_checktype(L, 1);
int x, y, width, height;
int screen = get_bmp_bounds(L, 2, &x, &y, &width, &height);
get_rect_bounds(L, 2, &x, &y, &width, &height);
rb->screens[screen]->mono_bitmap((const unsigned char *)src->data, x, y, width, height);
RB_SCREENS(L, 6, mono_bitmap, (const unsigned char *)src->data, x, y, width, height);
return 0;
}
@ -1265,9 +1425,9 @@ RB_WRAP(lcd_bitmap_part)
int src_y = luaL_checkint(L, 3);
int stride = luaL_checkint(L, 4);
int x, y, width, height;
int screen = get_bmp_bounds(L, 5, &x, &y, &width, &height);
get_rect_bounds(L, 5, &x, &y, &width, &height);
rb->screens[screen]->bitmap_part(src->data, src_x, src_y, stride, x, y, width, height);
RB_SCREENS(L, 9, bitmap_part, src->data, src_x, src_y, stride, x, y, width, height);
return 0;
}
@ -1275,9 +1435,9 @@ RB_WRAP(lcd_bitmap)
{
struct rocklua_image *src = rli_checktype(L, 1);
int x, y, width, height;
int screen = get_bmp_bounds(L, 2, &x, &y, &width, &height);
get_rect_bounds(L, 2, &x, &y, &width, &height);
rb->screens[screen]->bitmap(src->data, x, y, width, height);
RB_SCREENS(L, 6, bitmap, src->data, x, y, width, height);
return 0;
}
@ -1291,6 +1451,35 @@ RB_WRAP(lcd_get_backdrop)
return 1;
}
RB_WRAP(lcd_set_foreground)
{
unsigned foreground = (unsigned) luaL_checkint(L, 1);
RB_SCREENS(L, 2, set_foreground, foreground);
return 0;
}
RB_WRAP(lcd_get_foreground)
{
unsigned result = RB_SCREENS(L, 1, get_foreground);
lua_pushinteger(L, result);
return 1;
}
RB_WRAP(lcd_set_background)
{
unsigned background = (unsigned) luaL_checkint(L, 1);
RB_SCREENS(L, 2, set_background, background);
return 0;
}
RB_WRAP(lcd_get_background)
{
unsigned result = RB_SCREENS(L, 1, get_background);
lua_pushinteger(L, result);
return 1;
}
#endif /* LCD_DEPTH > 1 */
#if LCD_DEPTH == 16
@ -1301,9 +1490,10 @@ RB_WRAP(lcd_bitmap_transparent_part)
int src_y = luaL_checkint(L, 3);
int stride = luaL_checkint(L, 4);
int x, y, width, height;
int screen = get_bmp_bounds(L, 5, &x, &y, &width, &height);
get_rect_bounds(L, 5, &x, &y, &width, &height);
rb->screens[screen]->transparent_bitmap_part(src->data, src_x, src_y, stride, x, y, width, height);
RB_SCREENS(L, 9, transparent_bitmap_part, src->data, src_x,
src_y, stride, x, y, width, height);
return 0;
}
@ -1311,13 +1501,71 @@ RB_WRAP(lcd_bitmap_transparent)
{
struct rocklua_image *src = rli_checktype(L, 1);
int x, y, width, height;
int screen = get_bmp_bounds(L, 2, &x, &y, &width, &height);
get_rect_bounds(L, 2, &x, &y, &width, &height);
rb->screens[screen]->transparent_bitmap(src->data, x, y, width, height);
RB_SCREENS(L, 6, transparent_bitmap, src->data, x, y, width, height);
return 0;
}
#endif /* LCD_DEPTH == 16 */
RB_WRAP(lcd_update_rect)
{
int x, y, width, height;
get_rect_bounds(L, 1, &x, &y, &width, &height);
RB_SCREENS(L, 5, update_rect, x, y, width, height);
return 0;
}
RB_WRAP(lcd_drawrect)
{
int x, y, width, height;
get_rect_bounds(L, 1, &x, &y, &width, &height);
RB_SCREENS(L, 5, drawrect, x, y, width, height);
return 0;
}
RB_WRAP(lcd_fillrect)
{
int x, y, width, height;
get_rect_bounds(L, 1, &x, &y, &width, &height);
RB_SCREENS(L, 5, fillrect, x, y, width, height);
return 0;
}
RB_WRAP(lcd_drawline)
{
int x1, y1, x2, y2;
get_rect_bounds(L, 1, &x1, &y1, &x2, &y2);
RB_SCREENS(L, 5, drawline, x1, y1, x2, y2);
return 0;
}
RB_WRAP(lcd_hline)
{
int x1 = (int) luaL_checkint(L, 1);
int x2 = (int) luaL_checkint(L, 2);
int y = (int) luaL_checkint(L, 3);
RB_SCREENS(L, 4, hline, x1, x2, y);
return 0;
}
RB_WRAP(lcd_vline)
{
int x = (int) luaL_checkint(L, 1);
int y1 = (int) luaL_checkint(L, 2);
int y2 = (int) luaL_checkint(L, 3);
RB_SCREENS(L, 4, vline, x, y1, y2);
return 0;
}
RB_WRAP(lcd_drawpixel)
{
int x = (int) luaL_checkint(L, 1);
int y = (int) luaL_checkint(L, 2);
RB_SCREENS(L, 3, drawpixel, x, y);
return 0;
}
#endif /* defined(LCD_BITMAP) */
#ifdef HAVE_LCD_COLOR
@ -1377,19 +1625,42 @@ RB_WRAP(read_bmp_file)
static const luaL_Reg rocklib_img[] =
{
/* Graphics */
R(lcd_update),
R(lcd_clear_display),
R(lcd_set_drawmode),
R(lcd_putsxy),
R(lcd_puts),
R(lcd_puts_scroll),
R(lcd_scroll_stop),
R(set_viewport),
R(clear_viewport),
R(font_getstringsize),
#ifdef HAVE_LCD_BITMAP
R(lcd_framebuffer),
R(lcd_setfont),
R(lcd_mono_bitmap_part),
R(lcd_mono_bitmap),
#if LCD_DEPTH > 1
R(lcd_get_backdrop),
R(lcd_bitmap_part),
R(lcd_bitmap),
R(lcd_set_foreground),
R(lcd_get_foreground),
R(lcd_set_background),
R(lcd_get_background),
#endif
#if LCD_DEPTH == 16
R(lcd_bitmap_transparent_part),
R(lcd_bitmap_transparent),
#endif
R(lcd_update_rect),
R(lcd_drawrect),
R(lcd_fillrect),
R(lcd_drawline),
R(lcd_hline),
R(lcd_vline),
R(lcd_drawpixel),
#endif /*HAVE_LCD_BITMAP*/
#ifdef HAVE_LCD_COLOR
R(lcd_rgbpack),