summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJean-Philippe Andre <jp.andre@samsung.com>2015-06-04 19:42:38 +0900
committerJean-Philippe Andre <jp.andre@samsung.com>2015-06-25 14:36:08 +0900
commitf3e16bc4854268cecc19a38671c6f68071b7955b (patch)
tree5ee235f1985609026726c92a7b7c61ff5f87c525 /src
parent93797e3b0d30b02004da33f5fa350a4d64568e9b (diff)
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.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile_Evas.am8
-rw-r--r--src/lib/evas/file/evas_module.c10
-rw-r--r--src/lib/evas/filters/evas_filter.c1
-rw-r--r--src/lib/evas/filters/evas_filter_parser.c581
-rw-r--r--src/lib/evas/filters/evas_filter_private.h2
-rw-r--r--src/lib/evas/filters/lua/color.lua302
-rw-r--r--src/lib/evas/include/evas_private.h1
7 files changed, 638 insertions, 267 deletions
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index 941e1d2..ef59a2f 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -2204,3 +2204,11 @@ installed_evasluadir = $(datadir)/elua/modules/evas
2204nodist_installed_evaslua_DATA = $(generated_evas_lua_all) 2204nodist_installed_evaslua_DATA = $(generated_evas_lua_all)
2205 2205
2206endif 2206endif
2207
2208# Evas filters Lua stuff
2209evas_filters_lua = \
2210lib/evas/filters/lua/color.lua \
2211$(NULL)
2212
2213installed_evasfiltersdir = $(datadir)/evas/filters/lua
2214dist_installed_evasfilters_DATA = $(evas_filters_lua)
diff --git a/src/lib/evas/file/evas_module.c b/src/lib/evas/file/evas_module.c
index ead2612..bafc6e7 100644
--- a/src/lib/evas/file/evas_module.c
+++ b/src/lib/evas/file/evas_module.c
@@ -680,6 +680,16 @@ _evas_module_libdir_get(void)
680 return eina_prefix_lib_get(pfx); 680 return eina_prefix_lib_get(pfx);
681} 681}
682 682
683const char *
684_evas_module_datadir_get(void)
685{
686 if (!pfx) pfx = eina_prefix_new
687 (NULL, _evas_module_libdir_get, "EVAS", "evas", "checkme",
688 PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
689 if (!pfx) return NULL;
690 return eina_prefix_data_get(pfx);
691}
692
683EAPI const char * 693EAPI const char *
684evas_cserve_path_get(void) 694evas_cserve_path_get(void)
685{ 695{
diff --git a/src/lib/evas/filters/evas_filter.c b/src/lib/evas/filters/evas_filter.c
index 1e369f0..d420929 100644
--- a/src/lib/evas/filters/evas_filter.c
+++ b/src/lib/evas/filters/evas_filter.c
@@ -2002,6 +2002,7 @@ void
2002evas_filter_shutdown() 2002evas_filter_shutdown()
2003{ 2003{
2004 if ((--init_cnt) > 0) return; 2004 if ((--init_cnt) > 0) return;
2005 evas_filter_parser_shutdown();
2005 eina_log_domain_unregister(_evas_filter_log_dom); 2006 eina_log_domain_unregister(_evas_filter_log_dom);
2006 _evas_filter_log_dom = 0; 2007 _evas_filter_log_dom = 0;
2007} 2008}
diff --git a/src/lib/evas/filters/evas_filter_parser.c b/src/lib/evas/filters/evas_filter_parser.c
index c5f409d..8992dcb 100644
--- a/src/lib/evas/filters/evas_filter_parser.c
+++ b/src/lib/evas/filters/evas_filter_parser.c
@@ -215,35 +215,6 @@
215 @since 1.9 215 @since 1.9
216 */ 216 */
217 217
218// Map of the most common HTML color names
219static struct
220{
221 const char *name;
222 DATA32 value;
223} color_map[] =
224{
225 { "white", 0xFFFFFFFF },
226 { "black", 0xFF000000 },
227 { "red", 0xFFFF0000 },
228 { "green", 0xFF008000 },
229 { "blue", 0xFF0000FF },
230 { "darkblue", 0xFF0000A0 },
231 { "yellow", 0xFFFFFF00 },
232 { "magenta", 0xFFFF00FF },
233 { "cyan", 0xFF00FFFF },
234 { "orange", 0xFFFFA500 },
235 { "purple", 0xFF800080 },
236 { "brown", 0xFFA52A2A },
237 { "maroon", 0xFF800000 },
238 { "lime", 0xFF00FF00 },
239 { "gray", 0xFF808080 },
240 { "grey", 0xFF808080 },
241 { "silver", 0xFFC0C0C0 },
242 { "olive", 0xFF808000 },
243 { "invisible", 0x00000000 },
244 { "transparent", 0x00000000 }
245};
246
247static struct 218static struct
248{ 219{
249 const char *name; 220 const char *name;
@@ -265,9 +236,15 @@ static struct
265 { "stretch_xy", EVAS_FILTER_FILL_MODE_STRETCH_XY } 236 { "stretch_xy", EVAS_FILTER_FILL_MODE_STRETCH_XY }
266}; 237};
267 238
268static const char *_lua_buffer_meta = "Filter.buffer"; 239static const char *_lua_buffer_meta = "buffer";
240static const char *_lua_color_meta = "color";
241#define _lua_methods_table "__methods"
242#define _lua_register_func "__register"
243#define _lua_errfunc_name "__backtrace"
269 244
270static Evas_Filter_Fill_Mode _fill_mode_get(Evas_Filter_Instruction *instr); 245static Evas_Filter_Fill_Mode _fill_mode_get(Evas_Filter_Instruction *instr);
246static Eina_Bool _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr);
247static int _lua_backtrace(lua_State *L);
271 248
272typedef enum 249typedef enum
273{ 250{
@@ -618,46 +595,6 @@ _bool_parse(const char *str, Eina_Bool *b)
618 595
619#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) 596#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)
620 597
621static Eina_Bool
622_color_parse(const char *word, DATA32 *color)
623{
624 DATA32 value;
625 Eina_Bool success = EINA_FALSE;
626
627 PARSE_CHECK(word && *word);
628
629 errno = 0;
630 if (*word == '#')
631 {
632 unsigned char a, r, g, b;
633 int slen = strlen(word);
634 PARSE_CHECK(evas_common_format_color_parse(word, slen, &r, &g, &b, &a));
635 value = ARGB_JOIN(a, r, g, b);
636 }
637 else
638 {
639 unsigned int k;
640 for (k = 0; k < (sizeof(color_map) / sizeof(color_map[0])); k++)
641 {
642 if (!strcasecmp(word, color_map[k].name))
643 {
644 if (color) *color = color_map[k].value;
645 return EINA_TRUE;
646 }
647 }
648 PARSE_CHECK(!"color name not found");
649 }
650
651 if ((value & 0xFF000000) == 0 && (value != 0))
652 value |= 0xFF000000;
653
654 if (color) *color = value;
655 success = EINA_TRUE;
656
657end:
658 return success;
659}
660
661/* Buffers */ 598/* Buffers */
662static Buffer * 599static Buffer *
663_buffer_get(Evas_Filter_Program *pgm, const char *name) 600_buffer_get(Evas_Filter_Program *pgm, const char *name)
@@ -679,16 +616,19 @@ _lua_buffer_push(lua_State *L, Buffer *buf)
679{ 616{
680 Buffer **ptr; 617 Buffer **ptr;
681 618
682 lua_getglobal(L, buf->name); 619 lua_getglobal(L, buf->name);//+1
683 ptr = lua_newuserdata(L, sizeof(Buffer **)); 620 ptr = lua_newuserdata(L, sizeof(Buffer **));//+1
684 *ptr = buf; 621 *ptr = buf;
685 luaL_getmetatable(L, _lua_buffer_meta); 622 luaL_getmetatable(L, _lua_buffer_meta);//+1
686 lua_setmetatable(L, -2); 623 lua_setmetatable(L, -2);//-1
687 lua_setglobal(L, buf->name); 624 lua_setglobal(L, buf->name);//-1
625 lua_pop(L, 1);
688 626
689 return EINA_TRUE; 627 return EINA_TRUE;
690} 628}
691 629
630// Begin of Lua metamethods and stuff
631
692static int 632static int
693_lua_buffer_tostring(lua_State *L) 633_lua_buffer_tostring(lua_State *L)
694{ 634{
@@ -717,12 +657,12 @@ _lua_buffer_index(lua_State *L)
717 key = lua_tostring(L, 2); 657 key = lua_tostring(L, 2);
718 if (!key) return 0; 658 if (!key) return 0;
719 659
720 if (!strcmp(key, "width")) 660 if (!strcmp(key, "w") || !strcmp(key, "width"))
721 { 661 {
722 lua_pushinteger(L, buf->w); 662 lua_pushinteger(L, buf->w);
723 return 1; 663 return 1;
724 } 664 }
725 else if (!strcmp(key, "height")) 665 else if (!strcmp(key, "h") || !strcmp(key, "height"))
726 { 666 {
727 lua_pushinteger(L, buf->h); 667 lua_pushinteger(L, buf->h);
728 return 1; 668 return 1;
@@ -754,69 +694,30 @@ _lua_buffer_index(lua_State *L)
754 return 1; 694 return 1;
755 } 695 }
756 else 696 else
757 { 697 return luaL_error(L, "Unknown index '%s' for a buffer", key);
758 DBG("Unknown index '%s' for a buffer", key);
759 return 0;
760 }
761}
762 698
763static int 699 return 0;
764_lua_buffer_width(lua_State *L)
765{
766 Buffer *buf, **pbuf;
767 pbuf = lua_touserdata(L, 1);
768 buf = pbuf ? *pbuf : NULL;
769 if (!buf) return 0;
770 lua_pushnumber(L, buf->w);
771 return 1;
772}
773
774static int
775_lua_buffer_height(lua_State *L)
776{
777 Buffer *buf, **pbuf;
778 pbuf = lua_touserdata(L, 1);
779 buf = pbuf ? *pbuf : NULL;
780 if (!buf) return 0;
781 lua_pushnumber(L, buf->h);
782 return 1;
783}
784
785static int
786_lua_buffer_type(lua_State *L)
787{
788 Buffer *buf, **pbuf;
789 pbuf = lua_touserdata(L, 1);
790 buf = pbuf ? *pbuf : NULL;
791 if (!buf) return 0;
792 lua_pushstring(L, buf->alpha ? "alpha" : "rgba");
793 return 1;
794} 700}
795 701
796static int 702// remove metatable from first argument if this is a __call metafunction
797_lua_buffer_name(lua_State *L) 703static inline int
704_lua_implicit_metatable_drop(lua_State *L, const char *name)
798{ 705{
799 Buffer *buf, **pbuf; 706 int ret = 0;
800 pbuf = lua_touserdata(L, 1); 707 if (lua_istable(L, 1) && lua_getmetatable(L, 1))
801 buf = pbuf ? *pbuf : NULL; 708 {
802 if (!buf) return 0; 709 luaL_getmetatable(L, name);
803 lua_pushstring(L, buf->name); 710 if (lua_equal(L, -1, -2))
804 return 1; 711 {
712 lua_remove(L, 1);
713 ret = 1;
714 }
715 lua_pop(L, 2);
716 }
717 return ret;
805} 718}
806 719
807static int 720// End of all lua metamethods and stuff
808_lua_buffer_source(lua_State *L)
809{
810 Buffer *buf, **pbuf;
811 pbuf = lua_touserdata(L, 1);
812 buf = pbuf ? *pbuf : NULL;
813 if (!buf) return 0;
814 if (!buf->proxy)
815 lua_pushnil(L);
816 else
817 lua_pushstring(L, buf->proxy);
818 return 1;
819}
820 721
821static Buffer * 722static Buffer *
822_buffer_add(Evas_Filter_Program *pgm, const char *name, Eina_Bool alpha, 723_buffer_add(Evas_Filter_Program *pgm, const char *name, Eina_Bool alpha,
@@ -868,6 +769,19 @@ _buffer_del(Buffer *buf)
868 free(buf); 769 free(buf);
869} 770}
870 771
772static const int this_is_not_a_cat = 42;
773
774static Evas_Filter_Program *
775_lua_program_get(lua_State *L)
776{
777 Evas_Filter_Program *pgm;
778 lua_pushlightuserdata(L, (void *) &this_is_not_a_cat);
779 lua_gettable(L, LUA_REGISTRYINDEX);
780 pgm = lua_touserdata(L, -1);
781 lua_pop(L, 1);
782 return pgm;
783}
784
871/* Instruction definitions */ 785/* Instruction definitions */
872 786
873/** 787/**
@@ -935,20 +849,33 @@ _buffer_instruction_parse_run(lua_State *L,
935 return ok; 849 return ok;
936} 850}
937 851
938static Eina_Bool 852static int
939_buffer_instruction_prepare(Evas_Filter_Program *pgm EINA_UNUSED, 853_lua_buffer_new(lua_State *L)
940 Evas_Filter_Instruction *instr)
941{ 854{
942 EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE); 855 // Reuse old "buffer" instruction code
943 EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE); 856 Evas_Filter_Program *pgm = _lua_program_get(L);
944 EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcmp(instr->name, "buffer"), EINA_FALSE); 857 Evas_Filter_Instruction *instr;
945 858
859 instr = _instruction_new(_lua_buffer_meta);
946 instr->type = EVAS_FILTER_MODE_BUFFER; 860 instr->type = EVAS_FILTER_MODE_BUFFER;
947 instr->parse_run = _buffer_instruction_parse_run; 861 instr->parse_run = _buffer_instruction_parse_run;
948 _instruction_param_seq_add(instr, "type", VT_STRING, "rgba"); 862 _instruction_param_seq_add(instr, "type", VT_STRING, "rgba");
949 _instruction_param_seq_add(instr, "src", VT_BUFFER, NULL); 863 _instruction_param_seq_add(instr, "src", VT_BUFFER, NULL);
950 864
951 return EINA_TRUE; 865 // drop "buffer" metatable
866 _lua_implicit_metatable_drop(L, _lua_buffer_meta);
867
868 if (!_lua_instruction_run(L, instr))
869 {
870 _instruction_del(instr);
871 return luaL_error(L, "buffer instanciation failed");
872 }
873 else
874 {
875 pgm->instructions = eina_inlist_append(pgm->instructions, EINA_INLIST_GET(instr));
876 }
877
878 return instr->return_count;
952} 879}
953 880
954static int 881static int
@@ -1329,9 +1256,10 @@ _lua_curve_points_func(lua_State *L, int i, Evas_Filter_Program *pgm EINA_UNUSED
1329 case LUA_TFUNCTION: 1256 case LUA_TFUNCTION:
1330 for (k = 0; k < 256; k++) 1257 for (k = 0; k < 256; k++)
1331 { 1258 {
1259 lua_getglobal(L, _lua_errfunc_name);
1332 lua_pushvalue(L, i); 1260 lua_pushvalue(L, i);
1333 lua_pushinteger(L, k); 1261 lua_pushinteger(L, k);
1334 if (!lua_pcall(L, 1, 1, 0)) 1262 if (!lua_pcall(L, 1, 1, -3))
1335 { 1263 {
1336 if (!lua_isnumber(L, -1)) 1264 if (!lua_isnumber(L, -1))
1337 { 1265 {
@@ -1932,17 +1860,21 @@ evas_filter_program_del(Evas_Filter_Program *pgm)
1932 free(pgm); 1860 free(pgm);
1933} 1861}
1934 1862
1935static const int this_is_not_a_cat = 42; 1863// [-1, +1, e] -- converts the top of the stack to a valid 'color' object
1936 1864static Eina_Bool
1937static Evas_Filter_Program * 1865_lua_convert_color(lua_State *L)
1938_lua_program_get(lua_State *L) 1866{
1939{ 1867 int top = lua_gettop(L);
1940 Evas_Filter_Program *pgm; 1868 lua_getglobal(L, _lua_errfunc_name); //+1
1941 lua_pushlightuserdata(L, (void *) &this_is_not_a_cat); 1869 lua_getglobal(L, _lua_color_meta); //+1 (mt)
1942 lua_gettable(L, LUA_REGISTRYINDEX); 1870 lua_getfield(L, -1, "__call"); //+1 (func)
1943 pgm = lua_touserdata(L, -1); 1871 lua_pushvalue(L, -2); //+1 (mt)
1944 lua_pop(L, 1); 1872 lua_pushvalue(L, top); //+1 (argument)
1945 return pgm; 1873 if (lua_pcall(L, 2, 1, top + 1) != 0)
1874 return EINA_FALSE;
1875 lua_insert(L, top);
1876 lua_settop(L, top);
1877 return EINA_TRUE;
1946} 1878}
1947 1879
1948static Eina_Bool 1880static Eina_Bool
@@ -1954,10 +1886,12 @@ _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
1954 if (param->set) 1886 if (param->set)
1955 { 1887 {
1956 ERR("Parameter %s has already been set", param->name); 1888 ERR("Parameter %s has already been set", param->name);
1957 luaL_error(L, "Parameter %s has already been set", param->name); 1889 return luaL_error(L, "Parameter %s has already been set", param->name);
1958 return 0;
1959 } 1890 }
1960 1891
1892 if (i < 0)
1893 i = lua_gettop(L) + i + 1;
1894
1961 switch (param->type) 1895 switch (param->type)
1962 { 1896 {
1963 case VT_BOOL: 1897 case VT_BOOL:
@@ -1992,35 +1926,45 @@ _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
1992 param->value.s = strdup(lua_tostring(L, i)); 1926 param->value.s = strdup(lua_tostring(L, i));
1993 break; 1927 break;
1994 case VT_COLOR: 1928 case VT_COLOR:
1995 if ((lua_isnumber(L, i)) || (lua_type(L, i) == LUA_TSTRING)) 1929 {
1996 { 1930 // Auto convert values to a color() if they aren't one already
1997 int A, R, G, B; 1931 int cid = 0, pop = 0, A, R, G, B;
1998 DATA32 color; 1932 if (lua_istable(L, i))
1999 1933 {
2000 if (lua_isnumber(L, i)) 1934 luaL_getmetatable(L, _lua_color_meta);
2001 color = (DATA32) lua_tonumber(L, i); 1935 lua_getmetatable(L, i);
2002 else 1936 if (!lua_isnil(L, -1) && lua_equal(L, -2, -1))
2003 { 1937 {
2004 if (!_color_parse(lua_tostring(L, i), &color)) 1938 // this is a color already
2005 goto fail; 1939 cid = i;
2006 } 1940 }
2007 1941 lua_pop(L, 2);
2008 A = A_VAL(&color); 1942 }
2009 R = R_VAL(&color); 1943 if (!cid)
2010 G = G_VAL(&color); 1944 {
2011 B = B_VAL(&color); 1945 lua_pushvalue(L, i); //+1 (arg)
2012 if (!A && (R || G || B)) A = 0xFF; 1946 if (!_lua_convert_color(L)) //-1/+1
2013 if ((A < R) || (A < G) || (A < B)) 1947 {
2014 { 1948 ERR("Failed to convert color: %s", lua_tostring(L, -1));
2015 ERR("Argument '%s' of function '%s' is not a valid premultiplied RGBA value!", 1949 goto fail;
2016 param->name, instr->name); 1950 }
2017 evas_color_argb_premul(A, &R, &G, &B); 1951 cid = lua_gettop(L);
2018 //goto fail; 1952 pop = 1;
2019 } 1953 }
2020 param->value.c = ARGB_JOIN(A, R, G, B); 1954 if (!lua_istable(L, cid))
2021 } 1955 goto fail;
2022 else 1956 lua_getfield(L, cid, "a");
2023 goto fail; 1957 A = lua_tointeger(L, -1);
1958 lua_getfield(L, cid, "r");
1959 R = lua_tointeger(L, -1);
1960 lua_getfield(L, cid, "g");
1961 G = lua_tointeger(L, -1);
1962 lua_getfield(L, cid, "b");
1963 B = lua_tointeger(L, -1);
1964 lua_pop(L, pop + 4);
1965 evas_color_argb_premul(A, &R, &G, &B);
1966 param->value.c = ARGB_JOIN(A, R, G, B);
1967 }
2024 break; 1968 break;
2025 case VT_BUFFER: 1969 case VT_BUFFER:
2026 { 1970 {
@@ -2051,13 +1995,15 @@ _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
2051 goto fail; 1995 goto fail;
2052 } 1996 }
2053 1997
1998 if (i != lua_gettop(L))
1999 ERR("something is wrong");
2000
2054 param->set = EINA_TRUE; 2001 param->set = EINA_TRUE;
2055 return EINA_TRUE; 2002 return EINA_TRUE;
2056 2003
2057fail: 2004fail:
2058 ERR("Invalid value for parameter %s", param->name); 2005 ERR("Invalid value for parameter %s", param->name);
2059 luaL_error(L, "Invalid value for parameter %s", param->name); 2006 return luaL_error(L, "Invalid value for parameter %s", param->name);
2060 return EINA_FALSE;
2061} 2007}
2062 2008
2063static Instruction_Param * 2009static Instruction_Param *
@@ -2089,7 +2035,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
2089 if (eina_inlist_count(instr->params) < argc) 2035 if (eina_inlist_count(instr->params) < argc)
2090 { 2036 {
2091 ERR("Too many arguments passed to the instruction %s", instr->name); 2037 ERR("Too many arguments passed to the instruction %s", instr->name);
2092 goto fail; 2038 return EINA_FALSE;
2093 } 2039 }
2094 2040
2095 if (lua_istable(L, 1)) 2041 if (lua_istable(L, 1))
@@ -2097,7 +2043,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
2097 if (argc > 1) 2043 if (argc > 1)
2098 { 2044 {
2099 ERR("Too many arguments passed to the instruction %s (in table mode)", instr->name); 2045 ERR("Too many arguments passed to the instruction %s (in table mode)", instr->name);
2100 goto fail; 2046 return EINA_FALSE;
2101 } 2047 }
2102 2048
2103 lua_pushnil(L); 2049 lua_pushnil(L);
@@ -2110,7 +2056,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
2110 if (!param) 2056 if (!param)
2111 { 2057 {
2112 ERR("Parameter %s does not exist", name); 2058 ERR("Parameter %s does not exist", name);
2113 goto fail; 2059 return EINA_FALSE;
2114 } 2060 }
2115 } 2061 }
2116 else if (lua_isnumber(L, -2)) 2062 else if (lua_isnumber(L, -2))
@@ -2120,24 +2066,24 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
2120 if (!param) 2066 if (!param)
2121 { 2067 {
2122 ERR("Too many parameters for the function %s", instr->name); 2068 ERR("Too many parameters for the function %s", instr->name);
2123 goto fail; 2069 return EINA_FALSE;
2124 } 2070 }
2125 2071
2126 if (!param->allow_seq) 2072 if (!param->allow_seq)
2127 { 2073 {
2128 ERR("The parameter %s must be referred to by name in function %s", 2074 ERR("The parameter %s must be referred to by name in function %s",
2129 param->name, instr->name); 2075 param->name, instr->name);
2130 goto fail; 2076 return EINA_FALSE;
2131 } 2077 }
2132 } 2078 }
2133 else 2079 else
2134 { 2080 {
2135 ERR("Invalid type for the parameter key in function %s", instr->name); 2081 ERR("Invalid type for the parameter key in function %s", instr->name);
2136 goto fail; 2082 return EINA_FALSE;
2137 } 2083 }
2138 2084
2139 if (!_lua_parameter_parse(pgm, L, instr, param, -1)) 2085 if (!_lua_parameter_parse(pgm, L, instr, param, -1))
2140 goto fail; 2086 return EINA_FALSE;
2141 lua_pop(L, 1); 2087 lua_pop(L, 1);
2142 } 2088 }
2143 } 2089 }
@@ -2147,7 +2093,7 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
2147 { 2093 {
2148 if ((++i) > argc) break; 2094 if ((++i) > argc) break;
2149 if (!_lua_parameter_parse(pgm, L, instr, param, i)) 2095 if (!_lua_parameter_parse(pgm, L, instr, param, i))
2150 goto fail; 2096 return EINA_FALSE;
2151 } 2097 }
2152 } 2098 }
2153 2099
@@ -2161,11 +2107,6 @@ _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
2161 } 2107 }
2162 2108
2163 return EINA_TRUE; 2109 return EINA_TRUE;
2164
2165fail:
2166 ERR("Invalid parameters for instruction %s", instr->name);
2167 luaL_error(L, "Invalid parameters for instruction %s", instr->name);
2168 return EINA_FALSE;
2169} 2110}
2170 2111
2171static int 2112static int
@@ -2174,18 +2115,14 @@ _lua_generic_function(lua_State *L, const char *name,
2174{ 2115{
2175 Evas_Filter_Program *pgm = _lua_program_get(L); 2116 Evas_Filter_Program *pgm = _lua_program_get(L);
2176 Evas_Filter_Instruction *instr; 2117 Evas_Filter_Instruction *instr;
2177 Eina_Bool ok;
2178 2118
2179 instr = _instruction_new(name); 2119 instr = _instruction_new(name);
2180 prepare(pgm, instr); 2120 prepare(pgm, instr);
2181 ok = _lua_instruction_run(L, instr);
2182 2121
2183 if (!ok) 2122 if (!_lua_instruction_run(L, instr))
2184 { 2123 {
2185 ERR("Instruction parsing failed");
2186 _instruction_del(instr); 2124 _instruction_del(instr);
2187 lua_error(L); 2125 return luaL_error(L, "Instruction parsing failed");
2188 return 0;
2189 } 2126 }
2190 else 2127 else
2191 { 2128 {
@@ -2212,33 +2149,14 @@ _lua_print(lua_State *L)
2212 2149
2213 for (i = 1; i <= nargs; i++) 2150 for (i = 1; i <= nargs; i++)
2214 { 2151 {
2215 if (lua_isstring(L, i)) 2152 const char *str;
2216 eina_strbuf_append(s, lua_tostring(L, i)); 2153 lua_getglobal(L, _lua_errfunc_name);
2217 else if (lua_isnumber(L, i)) 2154 lua_getglobal(L, "tostring"); //+1
2218 { 2155 lua_pushvalue(L, i); //+1
2219 double d = lua_tonumber(L, i); 2156 lua_pcall(L, 1, 1, -3); //-2/+1
2220 2157 str = lua_tostring(L, -1);
2221 if (fabs(d - floor(d)) < 0.000001) 2158 eina_strbuf_append(s, str ? str : "(nil)");
2222 eina_strbuf_append_printf(s, "%d", (int) d); 2159 lua_pop(L, 2);
2223 else
2224 eina_strbuf_append_printf(s, "%f", d);
2225 }
2226 else if (luaL_checkudata(L, i, _lua_buffer_meta))
2227 {
2228 Buffer *buf, **pbuf;
2229 pbuf = lua_touserdata(L, i);
2230 buf = pbuf ? *pbuf : NULL;
2231 if (!buf)
2232 eina_strbuf_append(s, "Buffer[null]");
2233 else
2234 eina_strbuf_append_printf(s, "Buffer[#%d %dx%d %s%s%s]",
2235 buf->cid, buf->w, buf->h,
2236 buf->alpha ? "alpha" : "rgba",
2237 buf->proxy ? " src: " : "",
2238 buf->proxy ? buf->proxy : "");
2239 }
2240 else
2241 eina_strbuf_append(s, "<>");
2242 eina_strbuf_append_char(s, ' '); 2160 eina_strbuf_append_char(s, ' ');
2243 } 2161 }
2244 2162
@@ -2264,7 +2182,6 @@ _lua_##name(lua_State *L) \
2264 lua_pushcfunction(L, _lua_##name); \ 2182 lua_pushcfunction(L, _lua_##name); \
2265 lua_setglobal(L, #name); 2183 lua_setglobal(L, #name);
2266 2184
2267LUA_GENERIC_FUNCTION(buffer)
2268LUA_GENERIC_FUNCTION(blend) 2185LUA_GENERIC_FUNCTION(blend)
2269LUA_GENERIC_FUNCTION(blur) 2186LUA_GENERIC_FUNCTION(blur)
2270LUA_GENERIC_FUNCTION(bump) 2187LUA_GENERIC_FUNCTION(bump)
@@ -2276,21 +2193,98 @@ LUA_GENERIC_FUNCTION(mask)
2276LUA_GENERIC_FUNCTION(padding_set) 2193LUA_GENERIC_FUNCTION(padding_set)
2277LUA_GENERIC_FUNCTION(transform) 2194LUA_GENERIC_FUNCTION(transform)
2278 2195
2279static const luaL_Reg buffer_methods[] = { 2196static const luaL_Reg _lua_buffer_metamethods[] = {
2280 { "width", _lua_buffer_width }, 2197 { "__call", _lua_buffer_new },
2281 { "height", _lua_buffer_height },
2282 { "type", _lua_buffer_type },
2283 { "name", _lua_buffer_name },
2284 { "source", _lua_buffer_source },
2285 { NULL, NULL }
2286};
2287
2288static const luaL_Reg buffer_meta[] = {
2289 { "__tostring", _lua_buffer_tostring }, 2198 { "__tostring", _lua_buffer_tostring },
2290 { "__index", _lua_buffer_index }, 2199 { "__index", _lua_buffer_index },
2291 { NULL, NULL } 2200 { NULL, NULL }
2292}; 2201};
2293 2202
2203static char *_lua_color_code = NULL;
2204
2205static inline void
2206_lua_import_path_get(char *path, size_t len, const char *name)
2207{
2208 const char *pfx = _evas_module_datadir_get();
2209 struct stat st;
2210 size_t r;
2211
2212//#ifdef FILTERS_DEBUG
2213 // This is a hack to fetch the most recent file from source
2214 if (stat(path, &st) == -1)
2215 {
2216 char *sep = evas_file_path_join("", "");
2217 char *src = strdup(__FILE__);
2218 char *slash = strrchr(src, *sep);
2219 if (slash)
2220 {
2221 *slash = '\0';
2222 if (*src == '/')
2223 r = snprintf(path, len - 1, "%s/lua/%s.lua", src, name);
2224 else // abs_srcdir is unknown here
2225 r = snprintf(path, len - 1, "%s/src/%s/lua/%s.lua", PACKAGE_BUILD_DIR, src, name);
2226 if (r >= len) path[len - 1] = '\0';
2227 }
2228 free(sep);
2229 free(src);
2230 if (!stat(path, &st)) return;
2231 }
2232//#endif
2233
2234 r = snprintf(path, len - 1, "%s/filters/lua/%s.lua", pfx ? pfx : ".", name);
2235 if (r >= len) path[len - 1] = '\0';
2236}
2237
2238static Eina_Bool
2239_lua_import_class(lua_State *L, const char *name, char **code)
2240{
2241 // Load code from file
2242 if (!*code)
2243 {
2244 char path[PATH_MAX];
2245 Eina_File *f;
2246 void *map;
2247 size_t sz;
2248
2249 _lua_import_path_get(path, PATH_MAX, name);
2250 f = eina_file_open(path, EINA_FALSE);
2251 if (!f) return EINA_FALSE;
2252 sz = eina_file_size_get(f);
2253 *code = malloc(sz);
2254 if (!*code) return EINA_FALSE;
2255 map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
2256 if (!map) return EINA_FALSE;
2257 memcpy(*code, map, sz);
2258 eina_file_map_free(f, map);
2259 eina_file_close(f);
2260 }
2261
2262 if (!luaL_dostring(L, *code)) //+1
2263 {
2264 lua_getglobal(L, _lua_errfunc_name); //+1
2265 lua_pushliteral(L, _lua_register_func); //+1
2266 lua_rawget(L, -3); //-1/+1
2267 if (lua_isfunction(L, -1))
2268 {
2269 lua_getglobal(L, "_G"); //+1
2270 if (lua_pcall(L, 1, 0, -3) != 0) //-2
2271 {
2272 ERR("Failed to register globals for '%s': %s", name, lua_tostring(L, -1));
2273 lua_pop(L, 1);
2274 }
2275 }
2276 else lua_pop(L, 1);
2277 lua_pop(L, 1); // -1 (errfunc)
2278 lua_setglobal(L, name); //-1
2279 }
2280 else
2281 {
2282 ERR("Lua class '%s' could not be loaded: %s", name, lua_tostring(L, -1));
2283 return EINA_FALSE;
2284 }
2285 return EINA_TRUE;
2286}
2287
2294static void 2288static void
2295_filter_program_buffers_set(Evas_Filter_Program *pgm) 2289_filter_program_buffers_set(Evas_Filter_Program *pgm)
2296{ 2290{
@@ -2311,6 +2305,27 @@ _filter_program_buffers_set(Evas_Filter_Program *pgm)
2311 } 2305 }
2312} 2306}
2313 2307
2308static inline void
2309_lua_class_create(lua_State *L, const char *name,
2310 const luaL_Reg *meta, const luaL_Reg *methods)
2311{
2312 luaL_newmetatable(L, name);
2313 luaL_register(L, NULL, meta);
2314 lua_pushliteral(L, "__metatable");
2315 lua_pushvalue(L, -2);
2316 lua_rawset(L, -3);
2317 if (methods)
2318 {
2319 lua_pushliteral(L, _lua_methods_table);
2320 lua_newtable(L);
2321 luaL_register(L, NULL, methods);
2322 lua_rawset(L, -3);
2323 }
2324 lua_pushvalue(L, -1);
2325 lua_setmetatable(L, -2);
2326 lua_setglobal(L, name);
2327}
2328
2314static lua_State * 2329static lua_State *
2315_lua_state_create(Evas_Filter_Program *pgm) 2330_lua_state_create(Evas_Filter_Program *pgm)
2316{ 2331{
@@ -2327,19 +2342,24 @@ _lua_state_create(Evas_Filter_Program *pgm)
2327 luaopen_table(L); 2342 luaopen_table(L);
2328 luaopen_string(L); 2343 luaopen_string(L);
2329 luaopen_math(L); 2344 luaopen_math(L);
2345 luaopen_debug(L);
2346 lua_settop(L, 0);
2330 2347
2331 // Implement print 2348 // Implement print
2332 lua_getglobal(L, "_G"); 2349 lua_getglobal(L, "_G");
2333 luaL_register(L, NULL, printlib); 2350 luaL_register(L, NULL, printlib);
2334 lua_pop(L, 1); 2351 lua_pop(L, 1);
2335 2352
2353 // Add backtrace error function
2354 lua_pushcfunction(L, _lua_backtrace);
2355 lua_setglobal(L, _lua_errfunc_name);
2356
2336 // Store program 2357 // Store program
2337 lua_pushlightuserdata(L, (void *) &this_is_not_a_cat); 2358 lua_pushlightuserdata(L, (void *) &this_is_not_a_cat);
2338 lua_pushlightuserdata(L, pgm); 2359 lua_pushlightuserdata(L, pgm);
2339 lua_settable(L, LUA_REGISTRYINDEX); 2360 lua_settable(L, LUA_REGISTRYINDEX);
2340 2361
2341 // Register functions 2362 // Register functions
2342 PUSH_LUA_FUNCTION(buffer)
2343 PUSH_LUA_FUNCTION(blend) 2363 PUSH_LUA_FUNCTION(blend)
2344 PUSH_LUA_FUNCTION(blur) 2364 PUSH_LUA_FUNCTION(blur)
2345 PUSH_LUA_FUNCTION(bump) 2365 PUSH_LUA_FUNCTION(bump)
@@ -2351,13 +2371,6 @@ _lua_state_create(Evas_Filter_Program *pgm)
2351 PUSH_LUA_FUNCTION(padding_set) 2371 PUSH_LUA_FUNCTION(padding_set)
2352 PUSH_LUA_FUNCTION(transform) 2372 PUSH_LUA_FUNCTION(transform)
2353 2373
2354 // Register special variables
2355 for (unsigned k = 0; k < (sizeof(color_map) / sizeof(color_map[0])); k++)
2356 {
2357 lua_pushnumber(L, color_map[k].value);
2358 lua_setglobal(L, color_map[k].name);
2359 }
2360
2361 for (unsigned k = 0; k < (sizeof(fill_modes) / sizeof(fill_modes[0])); k++) 2374 for (unsigned k = 0; k < (sizeof(fill_modes) / sizeof(fill_modes[0])); k++)
2362 { 2375 {
2363 if (strcmp("repeat", fill_modes[k].name)) 2376 if (strcmp("repeat", fill_modes[k].name))
@@ -2391,18 +2404,40 @@ _lua_state_create(Evas_Filter_Program *pgm)
2391 lua_setglobal(L, booleans[k].name); 2404 lua_setglobal(L, booleans[k].name);
2392 } 2405 }
2393 2406
2394 // Register buffer meta stuff 2407 // Create buffer class based on userdata
2395 luaL_openlib(L, _lua_buffer_meta, buffer_methods, 0); 2408 _lua_class_create(L, _lua_buffer_meta, _lua_buffer_metamethods, NULL);
2396 luaL_newmetatable(L, _lua_buffer_meta); 2409
2397 luaL_openlib(L, NULL, buffer_meta, 0); 2410 // Load color class
2398 lua_pushliteral(L, "__metatable"); 2411 if (!_lua_import_class(L, _lua_color_meta, &_lua_color_code))
2399 lua_pushvalue(L, -3); 2412 ERR("Could not load color class!");
2400 lua_rawset(L, -3);
2401 lua_pop(L, 1);
2402 2413
2403 return L; 2414 return L;
2404} 2415}
2405 2416
2417static int
2418_lua_backtrace(lua_State *L)
2419{
2420 if (!lua_isstring(L, 1)) /* 'message' not a string? */
2421 return 1; /* keep it intact */
2422 ERR("Lua error: %s", lua_tolstring(L, 1, NULL));
2423 lua_getfield(L, LUA_GLOBALSINDEX, "debug");
2424 if (!lua_istable(L, -1))
2425 {
2426 lua_pop(L, 1);
2427 return 1;
2428 }
2429 lua_getfield(L, -1, "traceback");
2430 if (!lua_isfunction(L, -1))
2431 {
2432 lua_pop(L, 2);
2433 return 1;
2434 }
2435 lua_pushvalue(L, 1); /* pass error message */
2436 lua_pushinteger(L, 2); /* skip this function and traceback */
2437 lua_call(L, 2, 1); /* call debug.traceback */
2438 return 1;
2439}
2440
2406#ifdef FILTERS_LEGACY_COMPAT 2441#ifdef FILTERS_LEGACY_COMPAT
2407// This function is here to avoid breaking the ABI too much. 2442// This function is here to avoid breaking the ABI too much.
2408// It should not stay here long, only until all client apps have changed the filters' code to Lua. 2443// 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)
2545 * } 2580 * }
2546 */ 2581 */
2547 2582
2548#define JOINC(k) ARGB_JOIN(pgm->state.k.a, pgm->state.k.r, pgm->state.k.g, pgm->state.k.b) 2583#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; \
2584 evas_color_argb_unpremul(A, &R, &G, &B); d = ARGB_JOIN(A, R, G, B); d; })
2549#define SETFIELD(name, val) do { lua_pushnumber(L, val); lua_setfield(L, -2, name); } while(0) 2585#define SETFIELD(name, val) do { lua_pushnumber(L, val); lua_setfield(L, -2, name); } while(0)
2586#define SETCOLOR(name, val) do { lua_pushnumber(L, val); _lua_convert_color(L); lua_setfield(L, -2, name); } while(0)
2550 2587
2551 // TODO: Mark program as dependent on some values so we can improve 2588 // TODO: Mark program as dependent on some values so we can improve
2552 // the changed flag (ie. re-run the filter only when required) 2589 // the changed flag (ie. re-run the filter only when required)
@@ -2555,7 +2592,7 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
2555 2592
2556 lua_newtable(L); // "state" 2593 lua_newtable(L); // "state"
2557 { 2594 {
2558 SETFIELD("color", JOINC(color)); 2595 SETCOLOR("color", JOINC(color));
2559 SETFIELD("scale", pgm->state.scale); 2596 SETFIELD("scale", pgm->state.scale);
2560 SETFIELD("pos", pgm->state.pos); 2597 SETFIELD("pos", pgm->state.pos);
2561 lua_newtable(L); // "cur" 2598 lua_newtable(L); // "cur"
@@ -2577,10 +2614,10 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
2577 } 2614 }
2578 lua_newtable(L); // "text" 2615 lua_newtable(L); // "text"
2579 { 2616 {
2580 SETFIELD("outline", JOINC(text.outline)); 2617 SETCOLOR("outline", JOINC(text.outline));
2581 SETFIELD("shadow", JOINC(text.shadow)); 2618 SETCOLOR("shadow", JOINC(text.shadow));
2582 SETFIELD("glow", JOINC(text.glow)); 2619 SETCOLOR("glow", JOINC(text.glow));
2583 SETFIELD("glow2", JOINC(text.glow2)); 2620 SETCOLOR("glow2", JOINC(text.glow2));
2584 lua_setfield(L, -2, "text"); 2621 lua_setfield(L, -2, "text");
2585 } 2622 }
2586 } 2623 }
@@ -2588,6 +2625,7 @@ _filter_program_state_set(Evas_Filter_Program *pgm)
2588 2625
2589#undef JOINC 2626#undef JOINC
2590#undef SETFIELD 2627#undef SETFIELD
2628#undef SETCOLOR
2591} 2629}
2592 2630
2593static void 2631static void
@@ -2656,8 +2694,9 @@ evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str)
2656 { 2694 {
2657 pgm->lua_func = luaL_ref(L, LUA_REGISTRYINDEX); 2695 pgm->lua_func = luaL_ref(L, LUA_REGISTRYINDEX);
2658 _filter_program_reset(pgm); 2696 _filter_program_reset(pgm);
2697 lua_getglobal(L, _lua_errfunc_name);
2659 lua_rawgeti(L, LUA_REGISTRYINDEX, pgm->lua_func); 2698 lua_rawgeti(L, LUA_REGISTRYINDEX, pgm->lua_func);
2660 ok = !lua_pcall(L, 0, LUA_MULTRET, 0); 2699 ok = !lua_pcall(L, 0, LUA_MULTRET, -2);
2661 } 2700 }
2662 2701
2663 if (!ok) 2702 if (!ok)
@@ -3382,8 +3421,9 @@ evas_filter_context_program_use(Evas_Filter_Context *ctx,
3382 { 3421 {
3383 pgm->changed = EINA_FALSE; 3422 pgm->changed = EINA_FALSE;
3384 _filter_program_reset(pgm); 3423 _filter_program_reset(pgm);
3424 lua_getglobal(pgm->L, _lua_errfunc_name);
3385 lua_rawgeti(pgm->L, LUA_REGISTRYINDEX, pgm->lua_func); 3425 lua_rawgeti(pgm->L, LUA_REGISTRYINDEX, pgm->lua_func);
3386 success = !lua_pcall(pgm->L, 0, LUA_MULTRET, 0); 3426 success = !lua_pcall(pgm->L, 0, LUA_MULTRET, -2);
3387 if (!success) 3427 if (!success)
3388 { 3428 {
3389 const char *msg = lua_tostring(pgm->L, -1); 3429 const char *msg = lua_tostring(pgm->L, -1);
@@ -3416,3 +3456,10 @@ end:
3416 if (dc) ENFN->context_free(ENDT, dc); 3456 if (dc) ENFN->context_free(ENDT, dc);
3417 return success; 3457 return success;
3418} 3458}
3459
3460void
3461evas_filter_parser_shutdown(void)
3462{
3463 free(_lua_color_code);
3464 _lua_color_code = NULL;
3465}
diff --git a/src/lib/evas/filters/evas_filter_private.h b/src/lib/evas/filters/evas_filter_private.h
index 002b2da..7a4ba85 100644
--- a/src/lib/evas/filters/evas_filter_private.h
+++ b/src/lib/evas/filters/evas_filter_private.h
@@ -268,4 +268,6 @@ Eina_Bool evas_filter_interpolate(DATA8* output /* 256 values */, int
268Evas_Filter_Command *_evas_filter_command_get(Evas_Filter_Context *ctx, int cmdid); 268Evas_Filter_Command *_evas_filter_command_get(Evas_Filter_Context *ctx, int cmdid);
269int evas_filter_smallest_pow2_larger_than(int val); 269int evas_filter_smallest_pow2_larger_than(int val);
270 270
271void evas_filter_parser_shutdown(void);
272
271#endif // EVAS_FILTER_PRIVATE_H 273#endif // EVAS_FILTER_PRIVATE_H
diff --git a/src/lib/evas/filters/lua/color.lua b/src/lib/evas/filters/lua/color.lua
new file mode 100644
index 0000000..3fb1e9b
--- /dev/null
+++ b/src/lib/evas/filters/lua/color.lua
@@ -0,0 +1,302 @@
1--[[
2A simple 'color' class for Evas filters.
3
4The default alpha value will be 255 unless specified,
5which means the default color is opaque black.
6
7r,g,b,a values range from 0 to 255 and are straight
8(ie. NOT pre-multiplied).
9--]]
10
11local __color, __inrange, __color_parse
12
13--[[Checks that a number is valid and in the range 0-255]]
14__inrange = function(a)
15 if ((not tonumber(a)) or (tonumber(a) < 0) or (tonumber(a) > 255)) then
16 return false
17 else
18 return true
19 end
20end
21
22--[[
23Parses a string of one of the formats:
24 1. "#RRGGBB"
25 2. "#RRGGBBAA"
26 3. "#RGB"
27 4. "#RGBA"
28 To the rgba values.
29Same as evas_common_format_color_parse, except we don't premultiply here.
30--]]
31__color_parse = function(str)
32 local r,g,b,a
33 if not str then return 0,0,0,0 end
34 if not string.match(str, "^#[%x]+$") then return 0,0,0,0 end
35 len = string.len(str)
36 if len == 7 then -- #rrggbb
37 r = tonumber(string.sub(str, 2, 3), 16)
38 g = tonumber(string.sub(str, 4, 5), 16)
39 b = tonumber(string.sub(str, 6, 7), 16)
40 a = 0xff
41 return r,g,b,a
42 end
43 if len == 9 then -- #rrggbbaa
44 r = tonumber(string.sub(str, 2, 3), 16)
45 g = tonumber(string.sub(str, 4, 5), 16)
46 b = tonumber(string.sub(str, 6, 7), 16)
47 a = tonumber(string.sub(str, 8, 9), 16)
48 return r,g,b,a
49 end
50 if len == 4 then -- #rgb
51 r = tonumber(string.sub(str, 2, 2), 16)
52 g = tonumber(string.sub(str, 3, 3), 16)
53 b = tonumber(string.sub(str, 4, 4), 16)
54 r = (r * 0x10) + r
55 g = (g * 0x10) + g
56 b = (b * 0x10) + b
57 a = 0xff
58 return r,g,b,a
59 end
60 if len == 5 then -- #rgba
61 r = tonumber(string.sub(str, 2, 2), 16)
62 g = tonumber(string.sub(str, 3, 3), 16)
63 b = tonumber(string.sub(str, 4, 4), 16)
64 a = tonumber(string.sub(str, 5, 5), 16)
65 r = (r * 0x10) + r
66 g = (g * 0x10) + g
67 b = (b * 0x10) + b
68 a = (a * 0x10) + a
69 return r,g,b,a
70 end
71 return 0,0,0,255
72end
73
74__color = {
75 __names = {
76 white = 0xFFFFFFFF,
77 black = 0xFF000000,
78 red = 0xFFFF0000,
79 green = 0xFF008000,
80 blue = 0xFF0000FF,
81 darkblue = 0xFF0000A0,
82 yellow = 0xFFFFFF00,
83 magenta = 0xFFFF00FF,
84 cyan = 0xFF00FFFF,
85 orange = 0xFFFFA500,
86 purple = 0xFF800080,
87 brown = 0xFFA52A2A,
88 maroon = 0xFF800000,
89 lime = 0xFF00FF00,
90 gray = 0xFF808080,
91 grey = 0xFF808080,
92 silver = 0xFFC0C0C0,
93 olive = 0xFF808000,
94 invisible = 0x00000000,
95 transparent = 0x00000000
96 },
97
98 __methods = {
99 --[[
100 Assign a value to a color object.
101
102 Accepted formats include:
103 - 'colorname' (eg. 'red')
104 - another color object
105 - {r,g,b} or {r,g,b,a}
106 - a single integer value from 0x00000000 to 0xFFFFFFFF (0xAARRGGBB)
107 - 3 or 4 arguments (c:set(r,g,b) or c:set(r,g,b,a))
108 - a string like "#aarrggbb"
109 --]]
110 set = function (self, A, B, C, D)
111 -- nil
112 if not A then
113 return self:set(0xFF000000)
114 end
115
116 -- name or #value or 0xvalue
117 if (type(A) == 'string') then
118 if string.sub(A, 1, 1) == "#" then
119 return self:set(__color_parse(A))
120 end
121 if string.sub(A, 1, 2) == "0x" then
122 return self:set(tonumber(A))
123 end
124 return self:set(__color.__names[A])
125 end
126
127 -- another color
128 if (getmetatable(A) == getmetatable(self)) then
129 self.r = math.floor(A.r)
130 self.g = math.floor(A.g)
131 self.b = math.floor(A.b)
132 self.a = math.floor(A.a)
133 return self
134 end
135
136 -- input {r,g,b} or {r,g,b,a}
137 if (type(A) == 'table') then
138 if ((not __inrange(A[1])) or (not __inrange(A[2])) or (not __inrange(A[3]))) then
139 error('Invalid color value: ' .. tostring(A[1]) .. " , " .. tostring(A[2]) .. " , " .. tostring(A[3]))
140 end
141 self.r = math.floor(A[1])
142 self.g = math.floor(A[2])
143 self.b = math.floor(A[3])
144 if (__inrange(A[4])) then self.a = math.floor(A[4]) else self.a = 255 end
145 return self
146 end
147
148 -- input single value 0xAARRGGBB
149 if ((B == nil) and (type(A) == 'number')) then
150 A = math.floor(A) -- % 0x100000000
151 if ((A < 0) or (A > 0xFFFFFFFF)) then
152 error('Invalid color value: ' .. string.format("0x%x", A))
153 end
154 self.a = math.floor(A / 0x1000000)
155 self.r = math.floor((A / 0x10000) % 0x100)
156 self.g = math.floor((A / 0x100) % 0x100)
157 self.b = math.floor(A % 0x100)
158 return self
159 end
160
161 -- simplest method (r,g,b[,a])
162 if ((not __inrange(A)) or (not __inrange(B)) or (not __inrange(C))) then
163 error('Invalid color value: ' .. tostring(A) .. " , " .. tostring(B) .. " , " .. tostring(C))
164 end
165 if (__inrange(D)) then self.a = math.floor(D) else self.a = 255 end
166 self.r = math.floor(A)
167 self.g = math.floor(B)
168 self.b = math.floor(C)
169 return self
170 end,
171
172 --[[
173 Multiply a color by a value (another color or an alpha value).
174 Returns a new value.
175 --]]
176 mul = function (self, A)
177 local C = __color(self)
178 if tonumber(A) ~= nil then
179 C.a = C.a * tonumber(A) / 255
180 else
181 A = __color(A)
182 C.r = C.r * A.r / 255
183 C.g = C.g * A.g / 255
184 C.b = C.b * A.b / 255
185 C.a = C.a * A.a / 255
186 end
187 return C
188 end,
189
190 --[[
191 Add a color to another.
192 Returns a new value.
193 --]]
194 add = function (self, A)
195 local C = __color(self)
196 A = __color(A)
197 C.a = math.min(C.a + A.a, 255)
198 C.r = math.min(C.r + A.r, 255)
199 C.g = math.min(C.g + A.g, 255)
200 C.b = math.min(C.b + A.b, 255)
201 return C
202 end,
203
204 --[[
205 Alpha blending function: A:blend(B) returns A.a*A.rgb + B.a*(255-A.a)*B.rgb
206 This blends A on top of B.
207 Returns a new value.
208 --]]
209 blend = function (self, A)
210 local C = __color(self)
211 A = __color(A)
212 C.r = ((C.a * C.r) / 255) + ((255 - C.a) * A.a) * A.r / (255 * 255);
213 C.g = ((C.a * C.g) / 255) + ((255 - C.a) * A.a) * A.g / (255 * 255);
214 C.b = ((C.a * C.b) / 255) + ((255 - C.a) * A.a) * A.b / (255 * 255);
215 C.a = C.a + ((255 - C.a) * A.a) / 255;
216 return C
217 end
218 },
219
220 __index = function (self, key)
221 methods = getmetatable(self).__methods
222 if (rawget(methods, key)) then return rawget(methods, key) end
223 error('Invalid index \'' .. tostring(key) .. '\' for a color')
224 end,
225
226 __tostring = function (self)
227 return string.format('#%02x%02x%02x%02x', self.r, self.g, self.b, self.a)
228 end,
229
230 __call = function (mt, ...)
231 local C = {}
232 setmetatable(C, mt)
233 return C:set(...)
234 end,
235
236 __mul = function (self, ...)
237 return __color(self):mul(...)
238 end,
239
240 __add = function (self, ...)
241 return __color(self):add(...)
242 end,
243
244 -- Register all global values into global env (_G)
245 __register = function (tbl)
246 for k, v in pairs(__color.__names) do
247 rawset(tbl, k, __color(v))
248 end
249 end,
250
251 -- Test case
252 __test = function ()
253 local A, B, C
254
255 C = __color()
256 assert(tostring(C) == '#000000ff')
257 C:set({0xFE, 0xAB, 0x12})
258 assert(tostring(C) == '#feab12ff')
259 C:set(0xFFFEAB99)
260 assert(tostring(C) == '#feab99ff')
261 C:set()
262 assert(tostring(C) == '#000000ff')
263 C:set(0xfe, 0xab, 0x12, 0xff)
264 assert(tostring(C) == '#feab12ff')
265 C = __color{0xfe, 0xab, 0x12}
266 assert(tostring(C) == '#feab12ff')
267 B = __color(C)
268 assert(tostring(B) == '#feab12ff')
269 B = B * 128
270 assert(tostring(B) == '#feab1280')
271 A = B * C
272 assert(tostring(A) == '#fd720180')
273 A = B + C
274 assert(tostring(A) == '#ffff24ff')
275 A = __color(0xFF012345):blend(0xFFFFFFFF)
276 assert(tostring(A) == '#012345ff')
277 A = __color(0x00012345):blend(0xFFFFFFFF)
278 assert(tostring(A) == '#ffffffff')
279 A = __color(0x80102030):blend(0xFFFFFFFF)
280 assert(tostring(A) == '#878f97ff') -- check this
281 A = __color(0x80102030):blend("transparent")
282 assert(tostring(A) == '#08101880')
283 A = __color("#ff0000ff") * 255
284 assert(tostring(A) == '#ff0000ff')
285 A = A * 0x80
286 assert(tostring(A) == '#ff000080')
287 assert(tostring(__color('#123')) == '#112233ff')
288 assert(tostring(__color('#1234')) == '#11223344')
289 assert(tostring(__color('#123456')) == '#123456ff')
290 assert(tostring(__color('#12345678')) == '#12345678')
291
292 __color.__register(_G)
293 assert(tostring(white) == '#ffffffff')
294 assert(tostring(red) == '#ff0000ff')
295
296 print('All color tests passed')
297 return true
298 end
299}
300setmetatable(__color, __color)
301if arg and arg[1] == "-t" then __color.__test() end
302return __color
diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h
index 163ed0e..215e996 100644
--- a/src/lib/evas/include/evas_private.h
+++ b/src/lib/evas/include/evas_private.h
@@ -1840,6 +1840,7 @@ void _evas_unwalk(Evas_Public_Data *e_pd);
1840// expose for use in engines 1840// expose for use in engines
1841EAPI int _evas_module_engine_inherit(Evas_Func *funcs, char *name); 1841EAPI int _evas_module_engine_inherit(Evas_Func *funcs, char *name);
1842EAPI const char *_evas_module_libdir_get(void); 1842EAPI const char *_evas_module_libdir_get(void);
1843const char *_evas_module_datadir_get(void);
1843 1844
1844Eina_Bool evas_render_mapped(Evas_Public_Data *e, Evas_Object *obj, 1845Eina_Bool evas_render_mapped(Evas_Public_Data *e, Evas_Object *obj,
1845 Evas_Object_Protected_Data *source_pd, 1846 Evas_Object_Protected_Data *source_pd,