forked from enlightenment/efl
Evas filters: Implement Lua classes for colors & buffer
Reuse previous code for buffer. Keeps API stability. The new class "color" is here for a more convenient color representation. This way, colors can be represented in more natural ways like: {r,g,b[,a]}, 0xaarrggbb, "red", "#rrggbb" Class color is implemented in pure Lua, and adds a .lua file to Evas' share folder.
This commit is contained in:
parent
93797e3b0d
commit
f3e16bc485
|
@ -2204,3 +2204,11 @@ installed_evasluadir = $(datadir)/elua/modules/evas
|
|||
nodist_installed_evaslua_DATA = $(generated_evas_lua_all)
|
||||
|
||||
endif
|
||||
|
||||
# Evas filters Lua stuff
|
||||
evas_filters_lua = \
|
||||
lib/evas/filters/lua/color.lua \
|
||||
$(NULL)
|
||||
|
||||
installed_evasfiltersdir = $(datadir)/evas/filters/lua
|
||||
dist_installed_evasfilters_DATA = $(evas_filters_lua)
|
||||
|
|
|
@ -680,6 +680,16 @@ _evas_module_libdir_get(void)
|
|||
return eina_prefix_lib_get(pfx);
|
||||
}
|
||||
|
||||
const char *
|
||||
_evas_module_datadir_get(void)
|
||||
{
|
||||
if (!pfx) pfx = eina_prefix_new
|
||||
(NULL, _evas_module_libdir_get, "EVAS", "evas", "checkme",
|
||||
PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
|
||||
if (!pfx) return NULL;
|
||||
return eina_prefix_data_get(pfx);
|
||||
}
|
||||
|
||||
EAPI const char *
|
||||
evas_cserve_path_get(void)
|
||||
{
|
||||
|
|
|
@ -2002,6 +2002,7 @@ void
|
|||
evas_filter_shutdown()
|
||||
{
|
||||
if ((--init_cnt) > 0) return;
|
||||
evas_filter_parser_shutdown();
|
||||
eina_log_domain_unregister(_evas_filter_log_dom);
|
||||
_evas_filter_log_dom = 0;
|
||||
}
|
||||
|
|
|
@ -215,35 +215,6 @@
|
|||
@since 1.9
|
||||
*/
|
||||
|
||||
// Map of the most common HTML color names
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
DATA32 value;
|
||||
} color_map[] =
|
||||
{
|
||||
{ "white", 0xFFFFFFFF },
|
||||
{ "black", 0xFF000000 },
|
||||
{ "red", 0xFFFF0000 },
|
||||
{ "green", 0xFF008000 },
|
||||
{ "blue", 0xFF0000FF },
|
||||
{ "darkblue", 0xFF0000A0 },
|
||||
{ "yellow", 0xFFFFFF00 },
|
||||
{ "magenta", 0xFFFF00FF },
|
||||
{ "cyan", 0xFF00FFFF },
|
||||
{ "orange", 0xFFFFA500 },
|
||||
{ "purple", 0xFF800080 },
|
||||
{ "brown", 0xFFA52A2A },
|
||||
{ "maroon", 0xFF800000 },
|
||||
{ "lime", 0xFF00FF00 },
|
||||
{ "gray", 0xFF808080 },
|
||||
{ "grey", 0xFF808080 },
|
||||
{ "silver", 0xFFC0C0C0 },
|
||||
{ "olive", 0xFF808000 },
|
||||
{ "invisible", 0x00000000 },
|
||||
{ "transparent", 0x00000000 }
|
||||
};
|
||||
|
||||
static struct
|
||||
{
|
||||
const char *name;
|
||||
|
@ -265,9 +236,15 @@ static struct
|
|||
{ "stretch_xy", EVAS_FILTER_FILL_MODE_STRETCH_XY }
|
||||
};
|
||||
|
||||
static const char *_lua_buffer_meta = "Filter.buffer";
|
||||
static const char *_lua_buffer_meta = "buffer";
|
||||
static const char *_lua_color_meta = "color";
|
||||
#define _lua_methods_table "__methods"
|
||||
#define _lua_register_func "__register"
|
||||
#define _lua_errfunc_name "__backtrace"
|
||||
|
||||
static Evas_Filter_Fill_Mode _fill_mode_get(Evas_Filter_Instruction *instr);
|
||||
static Eina_Bool _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr);
|
||||
static int _lua_backtrace(lua_State *L);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -618,46 +595,6 @@ _bool_parse(const char *str, Eina_Bool *b)
|
|||
|
||||
#define PARSE_CHECK(a) do { if (!(a)) { ERR("Parsing failed because '%s' is false at %s:%d", #a, __FUNCTION__, __LINE__); PARSE_ABORT(); goto end; } } while (0)
|
||||
|
||||
static Eina_Bool
|
||||
_color_parse(const char *word, DATA32 *color)
|
||||
{
|
||||
DATA32 value;
|
||||
Eina_Bool success = EINA_FALSE;
|
||||
|
||||
PARSE_CHECK(word && *word);
|
||||
|
||||
errno = 0;
|
||||
if (*word == '#')
|
||||
{
|
||||
unsigned char a, r, g, b;
|
||||
int slen = strlen(word);
|
||||
PARSE_CHECK(evas_common_format_color_parse(word, slen, &r, &g, &b, &a));
|
||||
value = ARGB_JOIN(a, r, g, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int k;
|
||||
for (k = 0; k < (sizeof(color_map) / sizeof(color_map[0])); k++)
|
||||
{
|
||||
if (!strcasecmp(word, color_map[k].name))
|
||||
{
|
||||
if (color) *color = color_map[k].value;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
}
|
||||
PARSE_CHECK(!"color name not found");
|
||||
}
|
||||
|
||||
if ((value & 0xFF000000) == 0 && (value != 0))
|
||||
value |= 0xFF000000;
|
||||
|
||||
if (color) *color = value;
|
||||
success = EINA_TRUE;
|
||||
|
||||
end:
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Buffers */
|
||||
static Buffer *
|
||||
_buffer_get(Evas_Filter_Program *pgm, const char *name)
|
||||
|
@ -679,16 +616,19 @@ _lua_buffer_push(lua_State *L, Buffer *buf)
|
|||
{
|
||||
Buffer **ptr;
|
||||
|
||||
lua_getglobal(L, buf->name);
|
||||
ptr = lua_newuserdata(L, sizeof(Buffer **));
|
||||
lua_getglobal(L, buf->name);//+1
|
||||
ptr = lua_newuserdata(L, sizeof(Buffer **));//+1
|
||||
*ptr = buf;
|
||||
luaL_getmetatable(L, _lua_buffer_meta);
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, buf->name);
|
||||
luaL_getmetatable(L, _lua_buffer_meta);//+1
|
||||
lua_setmetatable(L, -2);//-1
|
||||
lua_setglobal(L, buf->name);//-1
|
||||
lua_pop(L, 1);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
// Begin of Lua metamethods and stuff
|
||||
|
||||
static int
|
||||
_lua_buffer_tostring(lua_State *L)
|
||||
{
|
||||
|
@ -717,12 +657,12 @@ _lua_buffer_index(lua_State *L)
|
|||
key = lua_tostring(L, 2);
|
||||
if (!key) return 0;
|
||||
|
||||
if (!strcmp(key, "width"))
|
||||
if (!strcmp(key, "w") || !strcmp(key, "width"))
|
||||
{
|
||||
lua_pushinteger(L, buf->w);
|
||||
return 1;
|
||||
}
|
||||
else if (!strcmp(key, "height"))
|
||||
else if (!strcmp(key, "h") || !strcmp(key, "height"))
|
||||
{
|
||||
lua_pushinteger(L, buf->h);
|
||||
return 1;
|
||||
|
@ -754,69 +694,30 @@ _lua_buffer_index(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
else
|
||||
return luaL_error(L, "Unknown index '%s' for a buffer", key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// remove metatable from first argument if this is a __call metafunction
|
||||
static inline int
|
||||
_lua_implicit_metatable_drop(lua_State *L, const char *name)
|
||||
{
|
||||
int ret = 0;
|
||||
if (lua_istable(L, 1) && lua_getmetatable(L, 1))
|
||||
{
|
||||
DBG("Unknown index '%s' for a buffer", key);
|
||||
return 0;
|
||||
luaL_getmetatable(L, name);
|
||||
if (lua_equal(L, -1, -2))
|
||||
{
|
||||
lua_remove(L, 1);
|
||||
ret = 1;
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_lua_buffer_width(lua_State *L)
|
||||
{
|
||||
Buffer *buf, **pbuf;
|
||||
pbuf = lua_touserdata(L, 1);
|
||||
buf = pbuf ? *pbuf : NULL;
|
||||
if (!buf) return 0;
|
||||
lua_pushnumber(L, buf->w);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lua_buffer_height(lua_State *L)
|
||||
{
|
||||
Buffer *buf, **pbuf;
|
||||
pbuf = lua_touserdata(L, 1);
|
||||
buf = pbuf ? *pbuf : NULL;
|
||||
if (!buf) return 0;
|
||||
lua_pushnumber(L, buf->h);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lua_buffer_type(lua_State *L)
|
||||
{
|
||||
Buffer *buf, **pbuf;
|
||||
pbuf = lua_touserdata(L, 1);
|
||||
buf = pbuf ? *pbuf : NULL;
|
||||
if (!buf) return 0;
|
||||
lua_pushstring(L, buf->alpha ? "alpha" : "rgba");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lua_buffer_name(lua_State *L)
|
||||
{
|
||||
Buffer *buf, **pbuf;
|
||||
pbuf = lua_touserdata(L, 1);
|
||||
buf = pbuf ? *pbuf : NULL;
|
||||
if (!buf) return 0;
|
||||
lua_pushstring(L, buf->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
_lua_buffer_source(lua_State *L)
|
||||
{
|
||||
Buffer *buf, **pbuf;
|
||||
pbuf = lua_touserdata(L, 1);
|
||||
buf = pbuf ? *pbuf : NULL;
|
||||
if (!buf) return 0;
|
||||
if (!buf->proxy)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
lua_pushstring(L, buf->proxy);
|
||||
return 1;
|
||||
}
|
||||
// End of all lua metamethods and stuff
|
||||
|
||||
static Buffer *
|
||||
_buffer_add(Evas_Filter_Program *pgm, const char *name, Eina_Bool alpha,
|
||||
|
@ -868,6 +769,19 @@ _buffer_del(Buffer *buf)
|
|||
free(buf);
|
||||
}
|
||||
|
||||
static const int this_is_not_a_cat = 42;
|
||||
|
||||
static Evas_Filter_Program *
|
||||
_lua_program_get(lua_State *L)
|
||||
{
|
||||
Evas_Filter_Program *pgm;
|
||||
lua_pushlightuserdata(L, (void *) &this_is_not_a_cat);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
pgm = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return pgm;
|
||||
}
|
||||
|
||||
/* Instruction definitions */
|
||||
|
||||
/**
|
||||
|
@ -935,20 +849,33 @@ _buffer_instruction_parse_run(lua_State *L,
|
|||
return ok;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_buffer_instruction_prepare(Evas_Filter_Program *pgm EINA_UNUSED,
|
||||
Evas_Filter_Instruction *instr)
|
||||
static int
|
||||
_lua_buffer_new(lua_State *L)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcmp(instr->name, "buffer"), EINA_FALSE);
|
||||
// Reuse old "buffer" instruction code
|
||||
Evas_Filter_Program *pgm = _lua_program_get(L);
|
||||
Evas_Filter_Instruction *instr;
|
||||
|
||||
instr = _instruction_new(_lua_buffer_meta);
|
||||
instr->type = EVAS_FILTER_MODE_BUFFER;
|
||||
instr->parse_run = _buffer_instruction_parse_run;
|
||||
_instruction_param_seq_add(instr, "type", VT_STRING, "rgba");
|
||||
_instruction_param_seq_add(instr, "src", VT_BUFFER, NULL);
|
||||
|
||||
return EINA_TRUE;
|
||||
// drop "buffer" metatable
|
||||
_lua_implicit_metatable_drop(L, _lua_buffer_meta);
|
||||
|
||||
if (!_lua_instruction_run(L, instr))
|
||||
{
|
||||
_instruction_del(instr);
|
||||
return luaL_error(L, "buffer instanciation failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
pgm->instructions = eina_inlist_append(pgm->instructions, EINA_INLIST_GET(instr));
|
||||
}
|
||||
|
||||
return instr->return_count;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1329,9 +1256,10 @@ _lua_curve_points_func(lua_State *L, int i, Evas_Filter_Program *pgm EINA_UNUSED
|
|||
case LUA_TFUNCTION:
|
||||
for (k = 0; k < 256; k++)
|
||||
{
|
||||
lua_getglobal(L, _lua_errfunc_name);
|
||||
lua_pushvalue(L, i);
|
||||
lua_pushinteger(L, k);
|
||||
if (!lua_pcall(L, 1, 1, 0))
|
||||
if (!lua_pcall(L, 1, 1, -3))
|
||||
{
|
||||
if (!lua_isnumber(L, -1))
|
||||
{
|
||||
|
@ -1932,17 +1860,21 @@ evas_filter_program_del(Evas_Filter_Program *pgm)
|
|||
free(pgm);
|
||||
}
|
||||
|
||||
static const int this_is_not_a_cat = 42;
|
||||
|
||||
static Evas_Filter_Program *
|
||||
_lua_program_get(lua_State *L)
|
||||
// [-1, +1, e] -- converts the top of the stack to a valid 'color' object
|
||||
static Eina_Bool
|
||||
_lua_convert_color(lua_State *L)
|
||||
{
|
||||
Evas_Filter_Program *pgm;
|
||||
lua_pushlightuserdata(L, (void *) &this_is_not_a_cat);
|
||||
lua_gettable(L, LUA_REGISTRYINDEX);
|
||||
pgm = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
return pgm;
|
||||
int top = lua_gettop(L);
|
||||
lua_getglobal(L, _lua_errfunc_name); //+1
|
||||
lua_getglobal(L, _lua_color_meta); //+1 (mt)
|
||||
lua_getfield(L, -1, "__call"); //+1 (func)
|
||||
lua_pushvalue(L, -2); //+1 (mt)
|
||||
lua_pushvalue(L, top); //+1 (argument)
|
||||
if (lua_pcall(L, 2, 1, top + 1) != 0)
|
||||
return EINA_FALSE;
|
||||
lua_insert(L, top);
|
||||
lua_settop(L, top);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
|
@ -1954,10 +1886,12 @@ _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
|
|||
if (param->set)
|
||||
{
|
||||
ERR("Parameter %s has already been set", param->name);
|
||||
luaL_error(L, "Parameter %s has already been set", param->name);
|
||||
return 0;
|
||||
return luaL_error(L, "Parameter %s has already been set", param->name);
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
i = lua_gettop(L) + i + 1;
|
||||
|
||||
switch (param->type)
|
||||
{
|
||||
case VT_BOOL:
|
||||
|
@ -1992,35 +1926,45 @@ _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
|
|||
param->value.s = strdup(lua_tostring(L, i));
|
||||
break;
|
||||
case VT_COLOR:
|
||||
if ((lua_isnumber(L, i)) || (lua_type(L, i) == LUA_TSTRING))
|
||||
{
|
||||
int A, R, G, B;
|
||||
DATA32 color;
|
||||
|
||||
if (lua_isnumber(L, i))
|
||||
color = (DATA32) lua_tonumber(L, i);
|
||||
else
|
||||
{
|
||||
if (!_color_parse(lua_tostring(L, i), &color))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
A = A_VAL(&color);
|
||||
R = R_VAL(&color);
|
||||
G = G_VAL(&color);
|
||||
B = B_VAL(&color);
|
||||
if (!A && (R || G || B)) A = 0xFF;
|
||||
if ((A < R) || (A < G) || (A < B))
|
||||
{
|
||||
ERR("Argument '%s' of function '%s' is not a valid premultiplied RGBA value!",
|
||||
param->name, instr->name);
|
||||
evas_color_argb_premul(A, &R, &G, &B);
|
||||
//goto fail;
|
||||
}
|
||||
param->value.c = ARGB_JOIN(A, R, G, B);
|
||||
}
|
||||
else
|
||||
goto fail;
|
||||
{
|
||||
// Auto convert values to a color() if they aren't one already
|
||||
int cid = 0, pop = 0, A, R, G, B;
|
||||
if (lua_istable(L, i))
|
||||
{
|
||||
luaL_getmetatable(L, _lua_color_meta);
|
||||
lua_getmetatable(L, i);
|
||||
if (!lua_isnil(L, -1) && lua_equal(L, -2, -1))
|
||||
{
|
||||
// this is a color already
|
||||
cid = i;
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
if (!cid)
|
||||
{
|
||||
lua_pushvalue(L, i); //+1 (arg)
|
||||
if (!_lua_convert_color(L)) //-1/+1
|
||||
{
|
||||
ERR("Failed to convert color: %s", lua_tostring(L, -1));
|
||||
goto fail;
|
||||
}
|
||||
cid = lua_gettop(L);
|
||||
pop = 1;
|
||||
}
|
||||
if (!lua_istable(L, cid))
|
||||
goto fail;
|
||||
lua_getfield(L, cid, "a");
|
||||
A = lua_tointeger(L, -1);
|
||||
lua_getfield(L, cid, "r");
|
||||
R = lua_tointeger(L, -1);
|
||||
lua_getfield(L, cid, "g");
|
||||
G = lua_tointeger(L, -1);
|
||||
lua_getfield(L, cid, "b");
|
||||
B = lua_tointeger(L, -1);
|
||||
lua_pop(L, pop + 4);
|
||||
evas_color_argb_premul(A, &R, &G, &B);
|
||||
param->value.c = ARGB_JOIN(A, R, G, B);
|
||||
}
|
||||
break;
|
||||
case VT_BUFFER:
|
||||
{
|
||||
|
@ -2051,13 +1995,15 @@ _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (i != lua_gettop(L))
|
||||
ERR("something is wrong");
|
||||
|
||||
param->set = EINA_TRUE;
|
||||
return EINA_TRUE;
|
||||
|
||||
fail:
|
||||
ERR("Invalid value for parameter %s", param->name);
|
||||
luaL_error(L, "Invalid value for parameter %s", param->name);
|
||||
return EINA_FALSE;
|
||||
return luaL_error(L, "Invalid value for parameter %s", param->name);
|
||||
}
|
||||
|
||||
static Instruction_Param *
|
||||
|
@ -2089,7 +2035,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
|
|||
if (eina_inlist_count(instr->params) < argc)
|
||||
{
|
||||
ERR("Too many arguments passed to the instruction %s", instr->name);
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
if (lua_istable(L, 1))
|
||||
|
@ -2097,7 +2043,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
|
|||
if (argc > 1)
|
||||
{
|
||||
ERR("Too many arguments passed to the instruction %s (in table mode)", instr->name);
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
|
@ -2110,7 +2056,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
|
|||
if (!param)
|
||||
{
|
||||
ERR("Parameter %s does not exist", name);
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
}
|
||||
else if (lua_isnumber(L, -2))
|
||||
|
@ -2120,24 +2066,24 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
|
|||
if (!param)
|
||||
{
|
||||
ERR("Too many parameters for the function %s", instr->name);
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
if (!param->allow_seq)
|
||||
{
|
||||
ERR("The parameter %s must be referred to by name in function %s",
|
||||
param->name, instr->name);
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Invalid type for the parameter key in function %s", instr->name);
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
if (!_lua_parameter_parse(pgm, L, instr, param, -1))
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
@ -2147,7 +2093,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
|
|||
{
|
||||
if ((++i) > argc) break;
|
||||
if (!_lua_parameter_parse(pgm, L, instr, param, i))
|
||||
goto fail;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2161,11 +2107,6 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
|
|||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
|
||||
fail:
|
||||
ERR("Invalid parameters for instruction %s", instr->name);
|
||||
luaL_error(L, "Invalid parameters for instruction %s", instr->name);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2174,18 +2115,14 @@ _lua_generic_function(lua_State *L, const char *name,
|
|||
{
|
||||
Evas_Filter_Program *pgm = _lua_program_get(L);
|
||||
Evas_Filter_Instruction *instr;
|
||||
Eina_Bool ok;
|
||||
|
||||
instr = _instruction_new(name);
|
||||
prepare(pgm, instr);
|
||||
ok = _lua_instruction_run(L, instr);
|
||||
|
||||
if (!ok)
|
||||
if (!_lua_instruction_run(L, instr))
|
||||
{
|
||||
ERR("Instruction parsing failed");
|
||||
_instruction_del(instr);
|
||||
lua_error(L);
|
||||
return 0;
|
||||
return luaL_error(L, "Instruction parsing failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2212,33 +2149,14 @@ _lua_print(lua_State *L)
|
|||
|
||||
for (i = 1; i <= nargs; i++)
|
||||
{
|
||||
if (lua_isstring(L, i))
|
||||
eina_strbuf_append(s, lua_tostring(L, i));
|
||||
else if (lua_isnumber(L, i))
|
||||
{
|
||||
double d = lua_tonumber(L, i);
|
||||
|
||||
if (fabs(d - floor(d)) < 0.000001)
|
||||
eina_strbuf_append_printf(s, "%d", (int) d);
|
||||
else
|
||||
eina_strbuf_append_printf(s, "%f", d);
|
||||
}
|
||||
else if (luaL_checkudata(L, i, _lua_buffer_meta))
|
||||
{
|
||||
Buffer *buf, **pbuf;
|
||||
pbuf = lua_touserdata(L, i);
|
||||
buf = pbuf ? *pbuf : NULL;
|
||||
if (!buf)
|
||||
eina_strbuf_append(s, "Buffer[null]");
|
||||
else
|
||||
eina_strbuf_append_printf(s, "Buffer[#%d %dx%d %s%s%s]",
|
||||
buf->cid, buf->w, buf->h,
|
||||
buf->alpha ? "alpha" : "rgba",
|
||||
buf->proxy ? " src: " : "",
|
||||
buf->proxy ? buf->proxy : "");
|
||||
}
|
||||
else
|
||||
eina_strbuf_append(s, "<>");
|
||||
const char *str;
|
||||
lua_getglobal(L, _lua_errfunc_name);
|
||||
lua_getglobal(L, "tostring"); //+1
|
||||
lua_pushvalue(L, i); //+1
|
||||
lua_pcall(L, 1, 1, -3); //-2/+1
|
||||
str = lua_tostring(L, -1);
|
||||
eina_strbuf_append(s, str ? str : "(nil)");
|
||||
lua_pop(L, 2);
|
||||
eina_strbuf_append_char(s, ' ');
|
||||
}
|
||||
|
||||
|
@ -2264,7 +2182,6 @@ _lua_##name(lua_State *L) \
|
|||
lua_pushcfunction(L, _lua_##name); \
|
||||
lua_setglobal(L, #name);
|
||||
|
||||
LUA_GENERIC_FUNCTION(buffer)
|
||||
LUA_GENERIC_FUNCTION(blend)
|
||||
LUA_GENERIC_FUNCTION(blur)
|
||||
LUA_GENERIC_FUNCTION(bump)
|
||||
|
@ -2276,21 +2193,98 @@ LUA_GENERIC_FUNCTION(mask)
|
|||
LUA_GENERIC_FUNCTION(padding_set)
|
||||
LUA_GENERIC_FUNCTION(transform)
|
||||
|
||||
static const luaL_Reg buffer_methods[] = {
|
||||
{ "width", _lua_buffer_width },
|
||||
{ "height", _lua_buffer_height },
|
||||
{ "type", _lua_buffer_type },
|
||||
{ "name", _lua_buffer_name },
|
||||
{ "source", _lua_buffer_source },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg buffer_meta[] = {
|
||||
static const luaL_Reg _lua_buffer_metamethods[] = {
|
||||
{ "__call", _lua_buffer_new },
|
||||
{ "__tostring", _lua_buffer_tostring },
|
||||
{ "__index", _lua_buffer_index },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static char *_lua_color_code = NULL;
|
||||
|
||||
static inline void
|
||||
_lua_import_path_get(char *path, size_t len, const char *name)
|
||||
{
|
||||
const char *pfx = _evas_module_datadir_get();
|
||||
struct stat st;
|
||||
size_t r;
|
||||
|
||||
//#ifdef FILTERS_DEBUG
|
||||
// This is a hack to fetch the most recent file from source
|
||||
if (stat(path, &st) == -1)
|
||||
{
|
||||
char *sep = evas_file_path_join("", "");
|
||||
char *src = strdup(__FILE__);
|
||||
char *slash = strrchr(src, *sep);
|
||||
if (slash)
|
||||
{
|
||||
*slash = '\0';
|
||||
if (*src == '/')
|
||||
r = snprintf(path, len - 1, "%s/lua/%s.lua", src, name);
|
||||
else // abs_srcdir is unknown here
|
||||
r = snprintf(path, len - 1, "%s/src/%s/lua/%s.lua", PACKAGE_BUILD_DIR, src, name);
|
||||
if (r >= len) path[len - 1] = '\0';
|
||||
}
|
||||
free(sep);
|
||||
free(src);
|
||||
if (!stat(path, &st)) return;
|
||||
}
|
||||
//#endif
|
||||
|
||||
r = snprintf(path, len - 1, "%s/filters/lua/%s.lua", pfx ? pfx : ".", name);
|
||||
if (r >= len) path[len - 1] = '\0';
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_lua_import_class(lua_State *L, const char *name, char **code)
|
||||
{
|
||||
// Load code from file
|
||||
if (!*code)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
Eina_File *f;
|
||||
void *map;
|
||||
size_t sz;
|
||||
|
||||
_lua_import_path_get(path, PATH_MAX, name);
|
||||
f = eina_file_open(path, EINA_FALSE);
|
||||
if (!f) return EINA_FALSE;
|
||||
sz = eina_file_size_get(f);
|
||||
*code = malloc(sz);
|
||||
if (!*code) return EINA_FALSE;
|
||||
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
|
||||
if (!map) return EINA_FALSE;
|
||||
memcpy(*code, map, sz);
|
||||
eina_file_map_free(f, map);
|
||||
eina_file_close(f);
|
||||
}
|
||||
|
||||
if (!luaL_dostring(L, *code)) //+1
|
||||
{
|
||||
lua_getglobal(L, _lua_errfunc_name); //+1
|
||||
lua_pushliteral(L, _lua_register_func); //+1
|
||||
lua_rawget(L, -3); //-1/+1
|
||||
if (lua_isfunction(L, -1))
|
||||
{
|
||||
lua_getglobal(L, "_G"); //+1
|
||||
if (lua_pcall(L, 1, 0, -3) != 0) //-2
|
||||
{
|
||||
ERR("Failed to register globals for '%s': %s", name, lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else lua_pop(L, 1);
|
||||
lua_pop(L, 1); // -1 (errfunc)
|
||||
lua_setglobal(L, name); //-1
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Lua class '%s' could not be loaded: %s", name, lua_tostring(L, -1));
|
||||
return EINA_FALSE;
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_filter_program_buffers_set(Evas_Filter_Program *pgm)
|
||||
{
|
||||
|
@ -2311,6 +2305,27 @@ _filter_program_buffers_set(Evas_Filter_Program *pgm)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_lua_class_create(lua_State *L, const char *name,
|
||||
const luaL_Reg *meta, const luaL_Reg *methods)
|
||||
{
|
||||
luaL_newmetatable(L, name);
|
||||
luaL_register(L, NULL, meta);
|
||||
lua_pushliteral(L, "__metatable");
|
||||
lua_pushvalue(L, -2);
|
||||
lua_rawset(L, -3);
|
||||
if (methods)
|
||||
{
|
||||
lua_pushliteral(L, _lua_methods_table);
|
||||
lua_newtable(L);
|
||||
luaL_register(L, NULL, methods);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, name);
|
||||
}
|
||||
|
||||
static lua_State *
|
||||
_lua_state_create(Evas_Filter_Program *pgm)
|
||||
{
|
||||
|
@ -2327,19 +2342,24 @@ _lua_state_create(Evas_Filter_Program *pgm)
|
|||
luaopen_table(L);
|
||||
luaopen_string(L);
|
||||
luaopen_math(L);
|
||||
luaopen_debug(L);
|
||||
lua_settop(L, 0);
|
||||
|
||||
// Implement print
|
||||
lua_getglobal(L, "_G");
|
||||
luaL_register(L, NULL, printlib);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// Add backtrace error function
|
||||
lua_pushcfunction(L, _lua_backtrace);
|
||||
lua_setglobal(L, _lua_errfunc_name);
|
||||
|
||||
// Store program
|
||||
lua_pushlightuserdata(L, (void *) &this_is_not_a_cat);
|
||||
lua_pushlightuserdata(L, pgm);
|
||||
lua_settable(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Register functions
|
||||
PUSH_LUA_FUNCTION(buffer)
|
||||
PUSH_LUA_FUNCTION(blend)
|
||||
PUSH_LUA_FUNCTION(blur)
|
||||
PUSH_LUA_FUNCTION(bump)
|
||||
|
@ -2351,13 +2371,6 @@ _lua_state_create(Evas_Filter_Program *pgm)
|
|||
PUSH_LUA_FUNCTION(padding_set)
|
||||
PUSH_LUA_FUNCTION(transform)
|
||||
|
||||
// Register special variables
|
||||
for (unsigned k = 0; k < (sizeof(color_map) / sizeof(color_map[0])); k++)
|
||||
{
|
||||
lua_pushnumber(L, color_map[k].value);
|
||||
lua_setglobal(L, color_map[k].name);
|
||||
}
|
||||
|
||||
for (unsigned k = 0; k < (sizeof(fill_modes) / sizeof(fill_modes[0])); k++)
|
||||
{
|
||||
if (strcmp("repeat", fill_modes[k].name))
|
||||
|
@ -2391,18 +2404,40 @@ _lua_state_create(Evas_Filter_Program *pgm)
|
|||
lua_setglobal(L, booleans[k].name);
|
||||
}
|
||||
|
||||
// Register buffer meta stuff
|
||||
luaL_openlib(L, _lua_buffer_meta, buffer_methods, 0);
|
||||
luaL_newmetatable(L, _lua_buffer_meta);
|
||||
luaL_openlib(L, NULL, buffer_meta, 0);
|
||||
lua_pushliteral(L, "__metatable");
|
||||
lua_pushvalue(L, -3);
|
||||
lua_rawset(L, -3);
|
||||
lua_pop(L, 1);
|
||||
// Create buffer class based on userdata
|
||||
_lua_class_create(L, _lua_buffer_meta, _lua_buffer_metamethods, NULL);
|
||||
|
||||
// Load color class
|
||||
if (!_lua_import_class(L, _lua_color_meta, &_lua_color_code))
|
||||
ERR("Could not load color class!");
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
static int
|
||||
_lua_backtrace(lua_State *L)
|
||||
{
|
||||
if (!lua_isstring(L, 1)) /* 'message' not a string? */
|
||||
return 1; /* keep it intact */
|
||||
ERR("Lua error: %s", lua_tolstring(L, 1, NULL));
|
||||
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
|
||||
if (!lua_istable(L, -1))
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
lua_getfield(L, -1, "traceback");
|
||||
if (!lua_isfunction(L, -1))
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
return 1;
|
||||
}
|
||||
lua_pushvalue(L, 1); /* pass error message */
|
||||
lua_pushinteger(L, 2); /* skip this function and traceback */
|
||||
lua_call(L, 2, 1); /* call debug.traceback */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef FILTERS_LEGACY_COMPAT
|
||||
// This function is here to avoid breaking the ABI too much.
|
||||
// It should not stay here long, only until all client apps have changed the filters' code to Lua.
|
||||
|
@ -2545,8 +2580,10 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
|
|||
* }
|
||||
*/
|
||||
|
||||
#define JOINC(k) ARGB_JOIN(pgm->state.k.a, pgm->state.k.r, pgm->state.k.g, pgm->state.k.b)
|
||||
#define JOINC(k) (double) ({ DATA32 d; int A = pgm->state.k.a, R = pgm->state.k.r, G = pgm->state.k.g, B = pgm->state.k.b; \
|
||||
evas_color_argb_unpremul(A, &R, &G, &B); d = ARGB_JOIN(A, R, G, B); d; })
|
||||
#define SETFIELD(name, val) do { lua_pushnumber(L, val); lua_setfield(L, -2, name); } while(0)
|
||||
#define SETCOLOR(name, val) do { lua_pushnumber(L, val); _lua_convert_color(L); lua_setfield(L, -2, name); } while(0)
|
||||
|
||||
// TODO: Mark program as dependent on some values so we can improve
|
||||
// the changed flag (ie. re-run the filter only when required)
|
||||
|
@ -2555,7 +2592,7 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
|
|||
|
||||
lua_newtable(L); // "state"
|
||||
{
|
||||
SETFIELD("color", JOINC(color));
|
||||
SETCOLOR("color", JOINC(color));
|
||||
SETFIELD("scale", pgm->state.scale);
|
||||
SETFIELD("pos", pgm->state.pos);
|
||||
lua_newtable(L); // "cur"
|
||||
|
@ -2577,10 +2614,10 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
|
|||
}
|
||||
lua_newtable(L); // "text"
|
||||
{
|
||||
SETFIELD("outline", JOINC(text.outline));
|
||||
SETFIELD("shadow", JOINC(text.shadow));
|
||||
SETFIELD("glow", JOINC(text.glow));
|
||||
SETFIELD("glow2", JOINC(text.glow2));
|
||||
SETCOLOR("outline", JOINC(text.outline));
|
||||
SETCOLOR("shadow", JOINC(text.shadow));
|
||||
SETCOLOR("glow", JOINC(text.glow));
|
||||
SETCOLOR("glow2", JOINC(text.glow2));
|
||||
lua_setfield(L, -2, "text");
|
||||
}
|
||||
}
|
||||
|
@ -2588,6 +2625,7 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
|
|||
|
||||
#undef JOINC
|
||||
#undef SETFIELD
|
||||
#undef SETCOLOR
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2656,8 +2694,9 @@ evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str)
|
|||
{
|
||||
pgm->lua_func = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
_filter_program_reset(pgm);
|
||||
lua_getglobal(L, _lua_errfunc_name);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, pgm->lua_func);
|
||||
ok = !lua_pcall(L, 0, LUA_MULTRET, 0);
|
||||
ok = !lua_pcall(L, 0, LUA_MULTRET, -2);
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
|
@ -3382,8 +3421,9 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx,
|
|||
{
|
||||
pgm->changed = EINA_FALSE;
|
||||
_filter_program_reset(pgm);
|
||||
lua_getglobal(pgm->L, _lua_errfunc_name);
|
||||
lua_rawgeti(pgm->L, LUA_REGISTRYINDEX, pgm->lua_func);
|
||||
success = !lua_pcall(pgm->L, 0, LUA_MULTRET, 0);
|
||||
success = !lua_pcall(pgm->L, 0, LUA_MULTRET, -2);
|
||||
if (!success)
|
||||
{
|
||||
const char *msg = lua_tostring(pgm->L, -1);
|
||||
|
@ -3416,3 +3456,10 @@ end:
|
|||
if (dc) ENFN->context_free(ENDT, dc);
|
||||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
evas_filter_parser_shutdown(void)
|
||||
{
|
||||
free(_lua_color_code);
|
||||
_lua_color_code = NULL;
|
||||
}
|
||||
|
|
|
@ -268,4 +268,6 @@ Eina_Bool evas_filter_interpolate(DATA8* output /* 256 values */, int
|
|||
Evas_Filter_Command *_evas_filter_command_get(Evas_Filter_Context *ctx, int cmdid);
|
||||
int evas_filter_smallest_pow2_larger_than(int val);
|
||||
|
||||
void evas_filter_parser_shutdown(void);
|
||||
|
||||
#endif // EVAS_FILTER_PRIVATE_H
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
--[[
|
||||
A simple 'color' class for Evas filters.
|
||||
|
||||
The default alpha value will be 255 unless specified,
|
||||
which means the default color is opaque black.
|
||||
|
||||
r,g,b,a values range from 0 to 255 and are straight
|
||||
(ie. NOT pre-multiplied).
|
||||
--]]
|
||||
|
||||
local __color, __inrange, __color_parse
|
||||
|
||||
--[[Checks that a number is valid and in the range 0-255]]
|
||||
__inrange = function(a)
|
||||
if ((not tonumber(a)) or (tonumber(a) < 0) or (tonumber(a) > 255)) then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Parses a string of one of the formats:
|
||||
1. "#RRGGBB"
|
||||
2. "#RRGGBBAA"
|
||||
3. "#RGB"
|
||||
4. "#RGBA"
|
||||
To the rgba values.
|
||||
Same as evas_common_format_color_parse, except we don't premultiply here.
|
||||
--]]
|
||||
__color_parse = function(str)
|
||||
local r,g,b,a
|
||||
if not str then return 0,0,0,0 end
|
||||
if not string.match(str, "^#[%x]+$") then return 0,0,0,0 end
|
||||
len = string.len(str)
|
||||
if len == 7 then -- #rrggbb
|
||||
r = tonumber(string.sub(str, 2, 3), 16)
|
||||
g = tonumber(string.sub(str, 4, 5), 16)
|
||||
b = tonumber(string.sub(str, 6, 7), 16)
|
||||
a = 0xff
|
||||
return r,g,b,a
|
||||
end
|
||||
if len == 9 then -- #rrggbbaa
|
||||
r = tonumber(string.sub(str, 2, 3), 16)
|
||||
g = tonumber(string.sub(str, 4, 5), 16)
|
||||
b = tonumber(string.sub(str, 6, 7), 16)
|
||||
a = tonumber(string.sub(str, 8, 9), 16)
|
||||
return r,g,b,a
|
||||
end
|
||||
if len == 4 then -- #rgb
|
||||
r = tonumber(string.sub(str, 2, 2), 16)
|
||||
g = tonumber(string.sub(str, 3, 3), 16)
|
||||
b = tonumber(string.sub(str, 4, 4), 16)
|
||||
r = (r * 0x10) + r
|
||||
g = (g * 0x10) + g
|
||||
b = (b * 0x10) + b
|
||||
a = 0xff
|
||||
return r,g,b,a
|
||||
end
|
||||
if len == 5 then -- #rgba
|
||||
r = tonumber(string.sub(str, 2, 2), 16)
|
||||
g = tonumber(string.sub(str, 3, 3), 16)
|
||||
b = tonumber(string.sub(str, 4, 4), 16)
|
||||
a = tonumber(string.sub(str, 5, 5), 16)
|
||||
r = (r * 0x10) + r
|
||||
g = (g * 0x10) + g
|
||||
b = (b * 0x10) + b
|
||||
a = (a * 0x10) + a
|
||||
return r,g,b,a
|
||||
end
|
||||
return 0,0,0,255
|
||||
end
|
||||
|
||||
__color = {
|
||||
__names = {
|
||||
white = 0xFFFFFFFF,
|
||||
black = 0xFF000000,
|
||||
red = 0xFFFF0000,
|
||||
green = 0xFF008000,
|
||||
blue = 0xFF0000FF,
|
||||
darkblue = 0xFF0000A0,
|
||||
yellow = 0xFFFFFF00,
|
||||
magenta = 0xFFFF00FF,
|
||||
cyan = 0xFF00FFFF,
|
||||
orange = 0xFFFFA500,
|
||||
purple = 0xFF800080,
|
||||
brown = 0xFFA52A2A,
|
||||
maroon = 0xFF800000,
|
||||
lime = 0xFF00FF00,
|
||||
gray = 0xFF808080,
|
||||
grey = 0xFF808080,
|
||||
silver = 0xFFC0C0C0,
|
||||
olive = 0xFF808000,
|
||||
invisible = 0x00000000,
|
||||
transparent = 0x00000000
|
||||
},
|
||||
|
||||
__methods = {
|
||||
--[[
|
||||
Assign a value to a color object.
|
||||
|
||||
Accepted formats include:
|
||||
- 'colorname' (eg. 'red')
|
||||
- another color object
|
||||
- {r,g,b} or {r,g,b,a}
|
||||
- a single integer value from 0x00000000 to 0xFFFFFFFF (0xAARRGGBB)
|
||||
- 3 or 4 arguments (c:set(r,g,b) or c:set(r,g,b,a))
|
||||
- a string like "#aarrggbb"
|
||||
--]]
|
||||
set = function (self, A, B, C, D)
|
||||
-- nil
|
||||
if not A then
|
||||
return self:set(0xFF000000)
|
||||
end
|
||||
|
||||
-- name or #value or 0xvalue
|
||||
if (type(A) == 'string') then
|
||||
if string.sub(A, 1, 1) == "#" then
|
||||
return self:set(__color_parse(A))
|
||||
end
|
||||
if string.sub(A, 1, 2) == "0x" then
|
||||
return self:set(tonumber(A))
|
||||
end
|
||||
return self:set(__color.__names[A])
|
||||
end
|
||||
|
||||
-- another color
|
||||
if (getmetatable(A) == getmetatable(self)) then
|
||||
self.r = math.floor(A.r)
|
||||
self.g = math.floor(A.g)
|
||||
self.b = math.floor(A.b)
|
||||
self.a = math.floor(A.a)
|
||||
return self
|
||||
end
|
||||
|
||||
-- input {r,g,b} or {r,g,b,a}
|
||||
if (type(A) == 'table') then
|
||||
if ((not __inrange(A[1])) or (not __inrange(A[2])) or (not __inrange(A[3]))) then
|
||||
error('Invalid color value: ' .. tostring(A[1]) .. " , " .. tostring(A[2]) .. " , " .. tostring(A[3]))
|
||||
end
|
||||
self.r = math.floor(A[1])
|
||||
self.g = math.floor(A[2])
|
||||
self.b = math.floor(A[3])
|
||||
if (__inrange(A[4])) then self.a = math.floor(A[4]) else self.a = 255 end
|
||||
return self
|
||||
end
|
||||
|
||||
-- input single value 0xAARRGGBB
|
||||
if ((B == nil) and (type(A) == 'number')) then
|
||||
A = math.floor(A) -- % 0x100000000
|
||||
if ((A < 0) or (A > 0xFFFFFFFF)) then
|
||||
error('Invalid color value: ' .. string.format("0x%x", A))
|
||||
end
|
||||
self.a = math.floor(A / 0x1000000)
|
||||
self.r = math.floor((A / 0x10000) % 0x100)
|
||||
self.g = math.floor((A / 0x100) % 0x100)
|
||||
self.b = math.floor(A % 0x100)
|
||||
return self
|
||||
end
|
||||
|
||||
-- simplest method (r,g,b[,a])
|
||||
if ((not __inrange(A)) or (not __inrange(B)) or (not __inrange(C))) then
|
||||
error('Invalid color value: ' .. tostring(A) .. " , " .. tostring(B) .. " , " .. tostring(C))
|
||||
end
|
||||
if (__inrange(D)) then self.a = math.floor(D) else self.a = 255 end
|
||||
self.r = math.floor(A)
|
||||
self.g = math.floor(B)
|
||||
self.b = math.floor(C)
|
||||
return self
|
||||
end,
|
||||
|
||||
--[[
|
||||
Multiply a color by a value (another color or an alpha value).
|
||||
Returns a new value.
|
||||
--]]
|
||||
mul = function (self, A)
|
||||
local C = __color(self)
|
||||
if tonumber(A) ~= nil then
|
||||
C.a = C.a * tonumber(A) / 255
|
||||
else
|
||||
A = __color(A)
|
||||
C.r = C.r * A.r / 255
|
||||
C.g = C.g * A.g / 255
|
||||
C.b = C.b * A.b / 255
|
||||
C.a = C.a * A.a / 255
|
||||
end
|
||||
return C
|
||||
end,
|
||||
|
||||
--[[
|
||||
Add a color to another.
|
||||
Returns a new value.
|
||||
--]]
|
||||
add = function (self, A)
|
||||
local C = __color(self)
|
||||
A = __color(A)
|
||||
C.a = math.min(C.a + A.a, 255)
|
||||
C.r = math.min(C.r + A.r, 255)
|
||||
C.g = math.min(C.g + A.g, 255)
|
||||
C.b = math.min(C.b + A.b, 255)
|
||||
return C
|
||||
end,
|
||||
|
||||
--[[
|
||||
Alpha blending function: A:blend(B) returns A.a*A.rgb + B.a*(255-A.a)*B.rgb
|
||||
This blends A on top of B.
|
||||
Returns a new value.
|
||||
--]]
|
||||
blend = function (self, A)
|
||||
local C = __color(self)
|
||||
A = __color(A)
|
||||
C.r = ((C.a * C.r) / 255) + ((255 - C.a) * A.a) * A.r / (255 * 255);
|
||||
C.g = ((C.a * C.g) / 255) + ((255 - C.a) * A.a) * A.g / (255 * 255);
|
||||
C.b = ((C.a * C.b) / 255) + ((255 - C.a) * A.a) * A.b / (255 * 255);
|
||||
C.a = C.a + ((255 - C.a) * A.a) / 255;
|
||||
return C
|
||||
end
|
||||
},
|
||||
|
||||
__index = function (self, key)
|
||||
methods = getmetatable(self).__methods
|
||||
if (rawget(methods, key)) then return rawget(methods, key) end
|
||||
error('Invalid index \'' .. tostring(key) .. '\' for a color')
|
||||
end,
|
||||
|
||||
__tostring = function (self)
|
||||
return string.format('#%02x%02x%02x%02x', self.r, self.g, self.b, self.a)
|
||||
end,
|
||||
|
||||
__call = function (mt, ...)
|
||||
local C = {}
|
||||
setmetatable(C, mt)
|
||||
return C:set(...)
|
||||
end,
|
||||
|
||||
__mul = function (self, ...)
|
||||
return __color(self):mul(...)
|
||||
end,
|
||||
|
||||
__add = function (self, ...)
|
||||
return __color(self):add(...)
|
||||
end,
|
||||
|
||||
-- Register all global values into global env (_G)
|
||||
__register = function (tbl)
|
||||
for k, v in pairs(__color.__names) do
|
||||
rawset(tbl, k, __color(v))
|
||||
end
|
||||
end,
|
||||
|
||||
-- Test case
|
||||
__test = function ()
|
||||
local A, B, C
|
||||
|
||||
C = __color()
|
||||
assert(tostring(C) == '#000000ff')
|
||||
C:set({0xFE, 0xAB, 0x12})
|
||||
assert(tostring(C) == '#feab12ff')
|
||||
C:set(0xFFFEAB99)
|
||||
assert(tostring(C) == '#feab99ff')
|
||||
C:set()
|
||||
assert(tostring(C) == '#000000ff')
|
||||
C:set(0xfe, 0xab, 0x12, 0xff)
|
||||
assert(tostring(C) == '#feab12ff')
|
||||
C = __color{0xfe, 0xab, 0x12}
|
||||
assert(tostring(C) == '#feab12ff')
|
||||
B = __color(C)
|
||||
assert(tostring(B) == '#feab12ff')
|
||||
B = B * 128
|
||||
assert(tostring(B) == '#feab1280')
|
||||
A = B * C
|
||||
assert(tostring(A) == '#fd720180')
|
||||
A = B + C
|
||||
assert(tostring(A) == '#ffff24ff')
|
||||
A = __color(0xFF012345):blend(0xFFFFFFFF)
|
||||
assert(tostring(A) == '#012345ff')
|
||||
A = __color(0x00012345):blend(0xFFFFFFFF)
|
||||
assert(tostring(A) == '#ffffffff')
|
||||
A = __color(0x80102030):blend(0xFFFFFFFF)
|
||||
assert(tostring(A) == '#878f97ff') -- check this
|
||||
A = __color(0x80102030):blend("transparent")
|
||||
assert(tostring(A) == '#08101880')
|
||||
A = __color("#ff0000ff") * 255
|
||||
assert(tostring(A) == '#ff0000ff')
|
||||
A = A * 0x80
|
||||
assert(tostring(A) == '#ff000080')
|
||||
assert(tostring(__color('#123')) == '#112233ff')
|
||||
assert(tostring(__color('#1234')) == '#11223344')
|
||||
assert(tostring(__color('#123456')) == '#123456ff')
|
||||
assert(tostring(__color('#12345678')) == '#12345678')
|
||||
|
||||
__color.__register(_G)
|
||||
assert(tostring(white) == '#ffffffff')
|
||||
assert(tostring(red) == '#ff0000ff')
|
||||
|
||||
print('All color tests passed')
|
||||
return true
|
||||
end
|
||||
}
|
||||
setmetatable(__color, __color)
|
||||
if arg and arg[1] == "-t" then __color.__test() end
|
||||
return __color
|
|
@ -1840,6 +1840,7 @@ void _evas_unwalk(Evas_Public_Data *e_pd);
|
|||
// expose for use in engines
|
||||
EAPI int _evas_module_engine_inherit(Evas_Func *funcs, char *name);
|
||||
EAPI const char *_evas_module_libdir_get(void);
|
||||
const char *_evas_module_datadir_get(void);
|
||||
|
||||
Eina_Bool evas_render_mapped(Evas_Public_Data *e, Evas_Object *obj,
|
||||
Evas_Object_Protected_Data *source_pd,
|
||||
|
|
Loading…
Reference in New Issue