1 #include "evas_filter_private.h"
2 
3 #include <stdarg.h>
4 
5 // Lua breaks API all the time
6 #ifdef ENABLE_LUA_OLD
7 // For 5.2 --> 5.1 compatibility
8 # define LUA_COMPAT_ALL
9 // For 5.3 --> 5.1 compatibility
10 # define LUA_COMPAT_5_1
11 #endif
12 
13 #include <lua.h>
14 #include <lualib.h>
15 #include <lauxlib.h>
16 
17 #define FILTERS_LEGACY_COMPAT
18 
19 #define EVAS_FILTER_MODE_GROW   (EVAS_FILTER_MODE_LAST+1)
20 #define EVAS_FILTER_MODE_BUFFER (EVAS_FILTER_MODE_LAST+2)
21 
22 #define INSTR_PARAM_CHECK(a) do { if (!(a)) { \
23    ERR("Argument %s can not be nil in %s!", #a, instr->name); return NULL; } \
24    } while (0)
25 
26 /* Note on the documentation:
27  * To keep it simple, I'm not using any fancy features, only <ul>/<li> lists
28  * and @a, @b, @c flags from Doxygen.
29  * Let's keep it that way.
30  *
31  * This is a REFERENCE documentation, not supposed to contain tons of examples,
32  * but each filter command should have one simple copy and pasteable example.
33  */
34 
35 /**
36   @page evasfiltersref Evas filters reference
37 
38   @warning A new online documentation is available on the Wiki under
39   <a href="https://www.enlightenment.org/docs/efl/advanced/eflgfxfilters">
40   EFL Graphics Filters</a>. The documentation below is mostly still valid
41   but incomplete. This page may be removed in the future.
42 
43   The Evas filters are a combination of filters used to apply specific effects
44   to an @ref Evas_Object "Evas Object". For the moment, these effects are
45   specific to the @ref Evas_Object_Text "Text" and @ref Evas_Object_Image
46   "Image Objects".
47 
48   The filters can be applied to an object using simple Lua scripts. A script
49   will contain a series of buffer declarations and filter commands to apply
50   to these buffers. The Lua programming language reference can be found
51   <a href="http://www.lua.org/manual/5.1/manual.html">here</a>.
52 
53   Basically, when applying an effect to a @ref Evas_Object_Text "Text Object",
54   an alpha-only @c input buffer is created, where the text is rendered, and
55   an RGBA @c output buffer is created, where the text with effects shall be
56   finally rendered.
57 
58   The script language being Lua, it respects the usual Lua syntax and concepts.
59   As these are simple filters, the scripts should be kept as small and simple
60   as possible.
61 
62   Note: Lua has been used since 1.10. The previous filters syntax is not
63         guaranteed to be compatible with 1.10 and newer versions.
64 
65   Here are the available commands:
66   <ul>
67     <li> @ref sec_syntax "Syntax" </li>
68     <li> @ref sec_buffers "Buffer management" </li>
69     <ul>
70       <li> @ref sec_buffers_cspace "Colorspaces" </li>
71       <li> @ref sec_buffers_auto "Automatic buffers" </li>
72       <li> @ref sec_buffers_cmd "@c buffer command" </li>
73     </ul>
74     <li> @ref sec_commands "Commands" </li>
75     <ul>
76       <li> @ref sec_commands_blend "@c blend command"</li>
77       <li> @ref sec_commands_blur "@c blur command"</li>
78       <li> @ref sec_commands_grow "@c grow command"</li>
79       <li> @ref sec_commands_curve "@c curve command"</li>
80       <li> @ref sec_commands_fill "@c fill command"</li>
81       <li> @ref sec_commands_mask "@c mask command"</li>
82       <li> @ref sec_commands_bump "@c bump command"</li>
83       <li> @ref sec_commands_displace "@c displace command"</li>
84       <li> @ref sec_commands_transform "@c transform command"</li>
85     </ul>
86   </ul>
87 
88   All the examples in this page can (should) be directly used in
89   @ref evas_obj_text_filter_program_set.
90 
91   Note that most of the text effects work better with larger font sizes (> 50px),
92   and so do the examples in this page (embedded devices in mind).
93  */
94 
95 /**
96   @page evasfiltersref
97   @section sec_syntax Syntax
98 
99   Here is a simple example illustrating the syntax:
100 
101   @verbinclude filter_example_1.lua
102 
103   This example will display a cyan and dark blue glow surrounding the
104   main text (its color depends on the object's theme).
105 
106   <center>
107   @image html filter_example_1.png
108   </center>
109 
110   The syntax is pretty simple and follows a small set of rules:
111   <ul>
112     <li>All dimensions are in pixels</li>
113     <li>The commands will be executed in sequential order</li>
114     <li>Most commands have default values</li>
115     <li>A command argument can either be set by name, or sequentially omitting the name. So that:<br>
116     @verbatim function (arg1, arg2, arg3) @endverbatim</li>
117     <li>is equivalent to:<br>
118     @verbatim function ({ arg1, arg2, arg2 }) @endverbatim</li>
119     <li>or even (considering opt1, opt2 and opt3 are the first 3 arguments):<br>
120     @verbatim function ({ opt1 = arg1, opt2 = arg2, opt3 = arg3 }) @endverbatim</li>
121     <li>and since this is Lua, we can also write it as:<br>
122     @verbatim function { arg1, opt3 = arg3, opt2 = arg2 } @endverbatim</li>
123     <li>Boolean values are @c true/@c false but 1/0 and special string values are also accepted: 'yes'/'no', 'enabled'/'disabled'</li>
124   </ul>
125 
126   <h3>Special keywords and their values</h3>
127 
128   Some options accept a certain set of values (like enums):
129   <ul>
130     <li>@c color</li>
131     @anchor evasfilters_color
132     <ul>
133       <li>Colors can be referred to by strings or integers:</li>
134       <li>An integer can refer to any RGB or ARGB values:
135           @c 0xRRGGBB or @c 0xAARRGGBB. If alpha is zero, the color
136           will be opaque (alpha = @c 0xFF), unless R=G=B=0 (invisible).
137           These colors are <b>not</b> premultiplied.
138       </li>
139       <li>Hexadecimal values: @c '\#RRGGBB', @c '\#RRGGBBAA', @c '\#RGB', @c '\#RGBA'</li>
140       <li>The following string values are also accepted:</li>
141       <tt><ul>
142         <li>'white' == '\#FFFFFF'</li>
143         <li>'black' == '\#000000'</li>
144         <li>'red' == '\#FF0000'</li>
145         <li>'green' == '\#008000'</li>
146         <li>'blue' == '\#0000FF'</li>
147         <li>'darkblue' == '\#0000A0'</li>
148         <li>'yellow' == '\#FFFF00'</li>
149         <li>'magenta' == '\#FF00FF'</li>
150         <li>'cyan' == '\#00FFFF'</li>
151         <li>'orange' == '\#FFA500'</li>
152         <li>'purple' == '\#800080'</li>
153         <li>'brown' == '\#A52A2A'</li>
154         <li>'maroon' == '\#800000'</li>
155         <li>'lime' == '\#00FF00'</li>
156         <li>'gray' == '\#808080'</li>
157         <li>'grey' == '\#808080'</li>
158         <li>'silver' == '\#C0C0C0'</li>
159         <li>'olive' == '\#808000'</li>
160         <li>'invisible', 'transparent' == '\#0000' -- (alpha is zero)</li>
161       </ul></tt>
162     </ul>
163     <li>@c fillmode</li>
164     @anchor evasfilter_fillmode
165     <tt><ul>
166       <li>'none'</li>
167       <li>'stretch_x'</li>
168       <li>'stretch_y'</li>
169       <li>'repeat_x'</li>
170       <li>'repeat_y'</li>
171       <li>'repeat_x_stretch_y', 'stretch_y_repeat_x'</li>
172       <li>'repeat_y_stretch_x', 'stretch_x_repeat_y'</li>
173       <li>'repeat', 'repeat_xy'</li>
174       <li>'stretch', 'stretch_xy'</li>
175     </ul></tt>
176   </ul>
177  */
178 
179 /**
180   @page evasfiltersref
181   @section sec_buffers Buffer management
182 
183   The Evas filters subsystem is based on the concept of using various
184   buffers as image layers and drawing or applying filters to these buffers.
185   Think of it as how image drawing tools like The Gimp can combine multiple
186   layers and apply operations on them.
187 
188   Most of the buffers are allocated automatically at runtime, depending on the
189   various inputs and commands used (eg. 2-D blur will require a temporary
190   intermediate buffer).
191 
192   @subsection sec_buffers_cspace Colorspaces and size
193 
194   The buffers' size will be automatically defined at runtime, based on the
195   content of the input and the series of operations to apply (eg. blur adds
196   some necessary margins).
197 
198   The buffers can be either ALPHA (1 color channel only) or RGBA (full color).
199   Some operations might require specifically an ALPHA buffer, some others RGBA.
200 
201   Most buffers will have the same size, except those specified by an external
202   source.
203 
204 
205   @subsection sec_buffers_auto Automatic buffers
206 
207   The two most important buffers, input and output, are statically defined and
208   always present when running a filter. input is an ALPHA buffer, containing
209   the @ref Evas_Object_Text "Text Object"'s rendered text, and output is the
210   final target on which to render as RGBA.
211 
212   Some operations, like 2-D blur might require temporary intermediate buffers,
213   that will be allocated automatically. Those buffers are internal only and
214   can't be used from the script.
215 
216   Finally, if a buffer is created using another Evas Object as source (see
217   @ref sec_buffers_cmd "buffer" for more details), its pixel data will be filled
218   by rendering the Evas Object into this buffer. This is how it will be
219   possible to load external images, textures and even animations into a buffer.
220 
221   @since 1.9
222  */
223 
224 static struct
225 {
226    const char *name;
227    Evas_Filter_Fill_Mode value;
228 } fill_modes[] =
229 {
230    { "none", EVAS_FILTER_FILL_MODE_NONE },
231    { "stretch_x", EVAS_FILTER_FILL_MODE_STRETCH_X },
232    { "stretch_y", EVAS_FILTER_FILL_MODE_STRETCH_Y },
233    { "repeat_x", EVAS_FILTER_FILL_MODE_REPEAT_X },
234    { "repeat_y", EVAS_FILTER_FILL_MODE_REPEAT_Y },
235    { "repeat_x_stretch_y", EVAS_FILTER_FILL_MODE_REPEAT_X_STRETCH_Y },
236    { "repeat_y_stretch_x", EVAS_FILTER_FILL_MODE_REPEAT_Y_STRETCH_X },
237    { "stretch_y_repeat_x", EVAS_FILTER_FILL_MODE_REPEAT_X_STRETCH_Y }, // alias
238    { "stretch_x_repeat_y", EVAS_FILTER_FILL_MODE_REPEAT_Y_STRETCH_X }, // alias
239    { "repeat", EVAS_FILTER_FILL_MODE_REPEAT_XY }, // alias
240    { "repeat_xy", EVAS_FILTER_FILL_MODE_REPEAT_XY },
241    { "stretch", EVAS_FILTER_FILL_MODE_STRETCH_XY }, // alias
242    { "stretch_xy", EVAS_FILTER_FILL_MODE_STRETCH_XY }
243 };
244 
245 static const char *_lua_buffer_meta = "buffer";
246 static const char *_lua_color_meta = "color";
247 #define _lua_methods_table "__methods"
248 #define _lua_register_func "__register"
249 #define _lua_errfunc_name "__backtrace"
250 
251 static Evas_Filter_Fill_Mode _fill_mode_get(Evas_Filter_Instruction *instr);
252 static Eina_Bool _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr);
253 static int _lua_backtrace(lua_State *L);
254 
255 typedef enum
256 {
257    VT_NONE,
258    VT_BOOL,
259    VT_INT,
260    VT_REAL,
261    VT_STRING,
262    VT_COLOR,
263    VT_BUFFER,
264    VT_SPECIAL
265 } Value_Type;
266 
267 typedef struct _Buffer
268 {
269    EINA_INLIST;
270    Eina_Stringshare *name;
271    Eina_Stringshare *proxy;
272    int cid; // Transient value
273    struct {
274       int l, r, t, b; // Used for padding calculation. Can change over time.
275    } pad;
276    int w, h;
277    Eina_Bool alpha : 1;
278    Eina_Bool manual : 1; // created by "buffer" instruction
279 } Buffer;
280 
281 typedef struct _Instruction_Param Instruction_Param;
282 struct _Instruction_Param
283 {
284    EINA_INLIST;
285    Eina_Stringshare *name;
286    Value_Type type;
287    union {
288       Eina_Bool b;
289       int i;
290       double f;
291       char *s;
292       unsigned int c;
293       Buffer *buf;
294       struct {
295          void *data;
296          Eina_Bool (*func)(lua_State *L, int i, Evas_Filter_Program *, Evas_Filter_Instruction *, Instruction_Param *);
297       } special;
298    } value;
299    Eina_Bool set : 1;
300    Eina_Bool allow_seq : 1;
301    Eina_Bool allow_any_string : 1;
302 };
303 
304 struct _Evas_Filter_Instruction
305 {
306    EINA_INLIST;
307    Eina_Stringshare *name;
308    int /*Evas_Filter_Mode*/ type;
309    Eina_Inlist /* Instruction_Param */ *params;
310    int return_count;
311    Eina_Bool (* parse_run) (lua_State *L, Evas_Filter_Program *, Evas_Filter_Instruction *);
312    struct
313    {
314       int (* update) (Evas_Filter_Program *, Evas_Filter_Instruction *, int *, int *, int *, int *);
315    } pad;
316    Eina_Bool valid : 1;
317 };
318 
319 struct _Evas_Filter_Program
320 {
321    Eina_Stringshare *name; // Optional for now
322    Eina_Hash /* const char * : Evas_Filter_Proxy_Binding */ *proxies;
323    Eina_Inlist /* Evas_Filter_Instruction */ *instructions;
324    Eina_Inlist /* Buffer */ *buffers;
325    struct {
326       // Note: padding can't be in the state as it's calculated after running Lua
327       Evas_Filter_Padding calculated, final;
328    } pad;
329    Efl_Canvas_Filter_State state;
330    Eina_Inlist *data; // Evas_Filter_Data_Binding
331    lua_State *L;
332    int       lua_func;
333    int       last_bufid;
334    Eina_Bool valid : 1;
335    Eina_Bool padding_calc : 1; // Padding has been calculated
336    Eina_Bool padding_set : 1; // Padding has been forced
337    Eina_Bool changed : 1; // State (w,h) changed, needs re-run of Lua
338    Eina_Bool input_alpha : 1;
339 };
340 
341 /* Instructions */
342 static Evas_Filter_Instruction *
_instruction_new(const char * name)343 _instruction_new(const char *name)
344 {
345    Evas_Filter_Instruction *instr;
346 
347    instr = calloc(1, sizeof(Evas_Filter_Instruction));
348    instr->name = eina_stringshare_add(name);
349 
350    return instr;
351 }
352 
353 static Eina_Bool
_instruction_param_addv(Evas_Filter_Instruction * instr,const char * name,Value_Type format,Eina_Bool sequential,va_list args)354 _instruction_param_addv(Evas_Filter_Instruction *instr, const char *name,
355                         Value_Type format, Eina_Bool sequential, va_list args)
356 {
357    Instruction_Param *param;
358    char *s;
359 
360    param = calloc(1, sizeof(Instruction_Param));
361    param->name = eina_stringshare_add(name);
362    param->type = format;
363    switch (format)
364      {
365       case VT_BOOL:
366         param->value.b = (va_arg(args, unsigned int) != 0);
367         break;
368       case VT_INT:
369         param->value.i = va_arg(args, int);
370         break;
371       case VT_REAL:
372         param->value.f = va_arg(args, double);
373         break;
374       case VT_STRING:
375         s = va_arg(args, char *);
376         param->value.s = s ? strdup(s) : NULL;
377         break;
378       case VT_BUFFER:
379         param->value.buf = va_arg(args, Buffer *);
380         break;
381       case VT_COLOR:
382         param->value.c = va_arg(args, DATA32);
383         break;
384       case VT_SPECIAL:
385         param->value.special.func = va_arg(args, typeof(param->value.special.func));
386         param->value.special.data = va_arg(args, void *);
387         break;
388       case VT_NONE:
389       default:
390         free(param);
391         return EINA_FALSE;
392      }
393    param->allow_seq = sequential;
394    instr->params = eina_inlist_append(instr->params, EINA_INLIST_GET(param));
395 
396    return EINA_TRUE;
397 }
398 
399 static Eina_Bool
_instruction_param_adda(Evas_Filter_Instruction * instr,const char * name,Value_Type format,int sequential,...)400 _instruction_param_adda(Evas_Filter_Instruction *instr, const char *name,
401                         Value_Type format, int sequential,
402                         /* default value */ ...)
403 {
404    Eina_Bool ok;
405    va_list args;
406 
407    va_start(args, sequential);
408    ok = _instruction_param_addv(instr, name, format, sequential, args);
409    va_end(args);
410 
411    return ok;
412 }
413 #define _instruction_param_seq_add(a,b,c,...) _instruction_param_adda((a),(b),(c),1,__VA_ARGS__)
414 #define _instruction_param_name_add(a,b,c,...) _instruction_param_adda((a),(b),(c),0,__VA_ARGS__)
415 
416 static void
_instruction_del(Evas_Filter_Instruction * instr)417 _instruction_del(Evas_Filter_Instruction *instr)
418 {
419    Instruction_Param *param;
420 
421    if (!instr) return;
422    EINA_INLIST_FREE(instr->params, param)
423      {
424         if (param->type == VT_STRING)
425           free(param->value.s);
426         else if (param->type == VT_SPECIAL)
427           free(param->value.special.data);
428         eina_stringshare_del(param->name);
429         instr->params = eina_inlist_remove(instr->params, EINA_INLIST_GET(param));
430         free(param);
431      }
432    eina_stringshare_del(instr->name);
433    free(instr);
434 }
435 
436 static Instruction_Param *
_instruction_param_get(Evas_Filter_Instruction * instr,const char * name)437 _instruction_param_get(Evas_Filter_Instruction *instr, const char *name)
438 {
439    Instruction_Param *param;
440 
441    EINA_INLIST_FOREACH(instr->params, param)
442      if (!strcasecmp(name, param->name))
443        return param;
444 
445    return NULL;
446 }
447 
448 static int
_instruction_param_geti(Evas_Filter_Instruction * instr,const char * name,Eina_Bool * isset)449 _instruction_param_geti(Evas_Filter_Instruction *instr, const char *name,
450                         Eina_Bool *isset)
451 {
452    Instruction_Param *param;
453 
454    EINA_INLIST_FOREACH(instr->params, param)
455      if (!strcasecmp(name, param->name))
456        {
457           if (isset) *isset = param->set;
458           return param->value.i;
459        }
460 
461    if (isset) *isset = EINA_FALSE;
462    return -1;
463 }
464 
465 static Eina_Bool
_instruction_param_getb(Evas_Filter_Instruction * instr,const char * name,Eina_Bool * isset)466 _instruction_param_getb(Evas_Filter_Instruction *instr, const char *name,
467                         Eina_Bool *isset)
468 {
469    Instruction_Param *param;
470 
471    EINA_INLIST_FOREACH(instr->params, param)
472      if (!strcasecmp(name, param->name))
473        {
474           if (isset) *isset = param->set;
475           return param->value.b;
476        }
477 
478    if (isset) *isset = EINA_FALSE;
479    return EINA_FALSE;
480 }
481 
482 static double
_instruction_param_getd(Evas_Filter_Instruction * instr,const char * name,Eina_Bool * isset)483 _instruction_param_getd(Evas_Filter_Instruction *instr, const char *name,
484                         Eina_Bool *isset)
485 {
486    Instruction_Param *param;
487 
488    EINA_INLIST_FOREACH(instr->params, param)
489      if (!strcasecmp(name, param->name))
490        {
491           if (isset) *isset = param->set;
492           return param->value.f;
493        }
494 
495    if (isset) *isset = EINA_FALSE;
496    return 0.0;
497 }
498 
499 static DATA32
_instruction_param_getc(Evas_Filter_Instruction * instr,const char * name,Eina_Bool * isset)500 _instruction_param_getc(Evas_Filter_Instruction *instr, const char *name,
501                         Eina_Bool *isset)
502 {
503    Instruction_Param *param;
504 
505    EINA_INLIST_FOREACH(instr->params, param)
506      if (!strcasecmp(name, param->name))
507        {
508           if (isset) *isset = param->set;
509           return param->value.c;
510        }
511 
512    if (isset) *isset = EINA_FALSE;
513    return 0;
514 }
515 
516 static void *
_instruction_param_getspecial(Evas_Filter_Instruction * instr,const char * name,Eina_Bool * isset)517 _instruction_param_getspecial(Evas_Filter_Instruction *instr, const char *name,
518                               Eina_Bool *isset)
519 {
520    Instruction_Param *param;
521 
522    EINA_INLIST_FOREACH(instr->params, param)
523      if (!strcasecmp(name, param->name))
524        {
525           if (isset) *isset = param->set;
526           return param->value.special.data;
527        }
528 
529    if (isset) *isset = EINA_FALSE;
530    return 0;
531 }
532 
533 static const char *
_instruction_param_gets(Evas_Filter_Instruction * instr,const char * name,Eina_Bool * isset)534 _instruction_param_gets(Evas_Filter_Instruction *instr, const char *name,
535                         Eina_Bool *isset)
536 {
537    Instruction_Param *param;
538 
539    EINA_INLIST_FOREACH(instr->params, param)
540      if (!strcasecmp(name, param->name))
541        {
542           if (isset) *isset = param->set;
543           return param->value.s;
544        }
545 
546    if (isset) *isset = EINA_FALSE;
547    return NULL;
548 }
549 
550 static Buffer *
_instruction_param_getbuf(Evas_Filter_Instruction * instr,const char * name,Eina_Bool * isset)551 _instruction_param_getbuf(Evas_Filter_Instruction *instr, const char *name,
552                           Eina_Bool *isset)
553 {
554    Instruction_Param *param;
555 
556    EINA_INLIST_FOREACH(instr->params, param)
557      if (!strcasecmp(name, param->name))
558        {
559           if (isset) *isset = param->set;
560           return param->value.buf;
561        }
562 
563    if (isset) *isset = EINA_FALSE;
564    return NULL;
565 }
566 
567 static Eina_Bool
_bool_parse(const char * str,Eina_Bool * b)568 _bool_parse(const char *str, Eina_Bool *b)
569 {
570    if (!str || !*str) return EINA_FALSE;
571    if (!strcmp(str, "1") ||
572        !strcasecmp(str, "yes") ||
573        !strcasecmp(str, "on") ||
574        !strcasecmp(str, "enable") ||
575        !strcasecmp(str, "enabled") ||
576        !strcasecmp(str, "true"))
577      {
578         if (b) *b = EINA_TRUE;
579         return EINA_TRUE;
580      }
581    else if (!strcmp(str, "0") ||
582             !strcasecmp(str, "no") ||
583             !strcasecmp(str, "off") ||
584             !strcasecmp(str, "disable") ||
585             !strcasecmp(str, "disabled") ||
586             !strcasecmp(str, "false"))
587      {
588         if (b) *b = EINA_FALSE;
589         return EINA_TRUE;
590      }
591    return EINA_FALSE;
592 }
593 
594 #define PARSE_ABORT() do {} while (0)
595 //#define PARSE_ABORT() abort()
596 
597 #define PARSE_CHECK(a) do { if (!(a)) { ERR("Parsing failed because '%s' is false at %s:%d", #a, __func__, __LINE__); PARSE_ABORT(); goto end; } } while (0)
598 
599 /* Buffers */
600 static Buffer *
_buffer_get(Evas_Filter_Program * pgm,const char * name)601 _buffer_get(Evas_Filter_Program *pgm, const char *name)
602 {
603    Buffer *buf;
604 
605    EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, NULL);
606    EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
607 
608    EINA_INLIST_FOREACH(pgm->buffers, buf)
609      {
610         if (!strcmp(buf->name, name))
611           return buf;
612         else if (buf->proxy && !strcmp(buf->proxy, name))
613           return buf;
614      }
615 
616    return NULL;
617 }
618 
619 static Eina_Bool
_lua_buffer_push(lua_State * L,Buffer * buf)620 _lua_buffer_push(lua_State *L, Buffer *buf)
621 {
622    Buffer **ptr;
623 
624    lua_getglobal(L, buf->name);//+1
625    ptr = lua_newuserdata(L, sizeof(Buffer *));//+1
626    *ptr = buf;
627    luaL_getmetatable(L, _lua_buffer_meta);//+1
628    lua_setmetatable(L, -2);//-1
629    lua_setglobal(L, buf->name);//-1
630    lua_pop(L, 1);
631 
632    return EINA_TRUE;
633 }
634 
635 // Begin of Lua metamethods and stuff
636 
637 static int
_lua_buffer_tostring(lua_State * L)638 _lua_buffer_tostring(lua_State *L)
639 {
640    Buffer *buf, **pbuf;
641    pbuf = lua_touserdata(L, 1);
642    buf = pbuf ? *pbuf : NULL;
643    if (!buf)
644      lua_pushstring(L, "nil");
645    else
646      lua_pushfstring(L, "Buffer[#%d %dx%d %s%s%s]", buf->cid, buf->w, buf->h,
647                      buf->alpha ? "alpha" : "rgba",
648                      buf->proxy ? " src: " : "", buf->proxy ? buf->proxy : "");
649    return 1;
650 }
651 
652 static int
_lua_buffer_index(lua_State * L)653 _lua_buffer_index(lua_State *L)
654 {
655    Buffer *buf, **pbuf;
656    const char *key;
657 
658    pbuf = lua_touserdata(L, 1);
659    buf = pbuf ? *pbuf : NULL;
660    if (!buf) return 0;
661 
662    key = lua_tostring(L, 2);
663    if (!key) return 0;
664 
665    if (!strcmp(key, "w") || !strcmp(key, "width"))
666      {
667         lua_pushinteger(L, buf->w);
668         return 1;
669      }
670    else if (!strcmp(key, "h") || !strcmp(key, "height"))
671      {
672         lua_pushinteger(L, buf->h);
673         return 1;
674      }
675    else if (!strcmp(key, "type"))
676      {
677         lua_pushstring(L, buf->alpha ? "alpha" : "rgba");
678         return 1;
679      }
680    else if (!strcmp(key, "alpha"))
681      {
682         lua_pushboolean(L, buf->alpha);
683         return 1;
684      }
685    else if (!strcmp(key, "rgba"))
686      {
687         lua_pushboolean(L, !buf->alpha);
688         return 1;
689      }
690    else if (!strcmp(key, "name"))
691      {
692         lua_pushstring(L, buf->name);
693         return 1;
694      }
695    else if (!strcmp(key, "source"))
696      {
697         if (!buf->proxy) return 0;
698         lua_pushstring(L, buf->proxy);
699         return 1;
700      }
701    else
702      return luaL_error(L, "Unknown index '%s' for a buffer", key);
703 
704    return 0;
705 }
706 
707 // remove metatable from first argument if this is a __call metafunction
708 static inline int
_lua_implicit_metatable_drop(lua_State * L,const char * name)709 _lua_implicit_metatable_drop(lua_State *L, const char *name)
710 {
711    int ret = 0;
712    if (lua_istable(L, 1) && lua_getmetatable(L, 1))
713      {
714         luaL_getmetatable(L, name);
715         if (lua_rawequal(L, -1, -2))
716           {
717              lua_remove(L, 1);
718              ret = 1;
719           }
720         lua_pop(L, 2);
721      }
722    return ret;
723 }
724 
725 // End of all lua metamethods and stuff
726 
727 static inline void
_buffer_name_format(char * name,Evas_Filter_Program * pgm,const char * src)728 _buffer_name_format(char *name /*[64]*/, Evas_Filter_Program *pgm, const char *src)
729 {
730    unsigned i;
731 
732    if (src)
733      {
734         // Cleanup name and avoid overriding existing globals
735         snprintf(name, 64, "__source_%s", src);
736         name[63] = '\0';
737         for (i = 0; name[i]; i++)
738           {
739              if (!isdigit(name[i]) && !isalpha(name[i]))
740                name[i] = '_';
741           }
742      }
743    else
744      {
745         sprintf(name, "__buffer_%02d", ++pgm->last_bufid);
746      }
747 }
748 
749 static Buffer *
_buffer_add(Evas_Filter_Program * pgm,const char * name,Eina_Bool alpha,const char * src,Eina_Bool manual)750 _buffer_add(Evas_Filter_Program *pgm, const char *name, Eina_Bool alpha,
751             const char *src, Eina_Bool manual)
752 {
753    Buffer *buf;
754 
755    buf = _buffer_get(pgm, name);
756    if (buf)
757      {
758         if (!src)
759           {
760              ERR("Buffer '%s' already exists", name);
761              return NULL;
762           }
763         else return buf;
764      }
765 
766    if (alpha && src)
767      {
768         ERR("Can not set proxy buffer as alpha!");
769         return NULL;
770      }
771 
772    buf = calloc(1, sizeof(Buffer));
773    if (!buf) return NULL;
774 
775    buf->manual = manual;
776    if (!name)
777      {
778         char bufname[64];
779         _buffer_name_format(bufname, pgm, src);
780         buf->name = eina_stringshare_add(bufname);
781      }
782    else
783      buf->name = eina_stringshare_add(name);
784    buf->proxy = eina_stringshare_add(src);
785    buf->alpha = alpha;
786    buf->w = pgm->state.w;
787    buf->h = pgm->state.h;
788 
789    pgm->buffers = eina_inlist_append(pgm->buffers, EINA_INLIST_GET(buf));
790    _lua_buffer_push(pgm->L, buf);
791 
792    return buf;
793 }
794 
795 static void
_buffer_del(Buffer * buf)796 _buffer_del(Buffer *buf)
797 {
798    if (!buf) return;
799    eina_stringshare_del(buf->name);
800    eina_stringshare_del(buf->proxy);
801    free(buf);
802 }
803 
804 static const int this_is_not_a_cat = 42;
805 
806 static Evas_Filter_Program *
_lua_program_get(lua_State * L)807 _lua_program_get(lua_State *L)
808 {
809    Evas_Filter_Program *pgm;
810    lua_pushlightuserdata(L, (void *) &this_is_not_a_cat);
811    lua_gettable(L, LUA_REGISTRYINDEX);
812    pgm = lua_touserdata(L, -1);
813    lua_pop(L, 1);
814    return pgm;
815 }
816 
817 /* Instruction definitions */
818 
819 /**
820   @page evasfiltersref
821 
822   @subsection sec_buffers_cmd Buffer command
823 
824   Create a new buffer.
825 
826   @verbatim
827   name1 = buffer()
828   name2 = buffer("alpha")
829   name3 = buffer("rgba")
830   name4 = buffer({ type = "rgba" })
831   name5 = buffer({ src = "partname" })
832   @endverbatim
833 
834   @param type   Buffer type: @c rgba (default) or @c alpha
835   @param src    An optional source. If set, @a type will be @c rgba.
836   @return A new buffer. This value must not be saved to a variable.
837 
838   This creates a new named buffer, specify its colorspace or source. Possible options:
839     @li @c alpha: Create an alpha-only buffer (1 channel, no color)
840     @li @c rgba: Create an RGBA buffer (4 channels, full color)
841     @li <tt>{src = "partname"}</tt>: Use another <tt>Evas Object</tt> as source for this
842       buffer's pixels. The name can either be an Edje part name or the one
843       specified in @c evas_obj_text_filter_source_set.
844 
845   If no option is given, an RGBA buffer will be created. All buffers have the
846   same size, unless they are based on an external source.
847 
848   @see evas_obj_text_filter_source_set
849 
850   @since 1.10
851  */
852 
853 static Eina_Bool
_buffer_instruction_parse_run(lua_State * L,Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)854 _buffer_instruction_parse_run(lua_State *L,
855                               Evas_Filter_Program *pgm,
856                               Evas_Filter_Instruction *instr)
857 {
858    char bufname[64] = {0};
859    const char *src, *type;
860    Eina_Bool alpha = EINA_FALSE;
861    Buffer *buf;
862 
863    EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
864    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
865 
866    // FIXME: Buffers are still referred to internally by name.
867    // This is pretty bad with the switch to Lua.
868 
869    type = _instruction_param_gets(instr, "type", NULL);
870    src = _instruction_param_gets(instr, "src", NULL);
871 
872    alpha = (type && !strcasecmp(type, "alpha"));
873 
874    if (src)
875      {
876         if (alpha) WRN("Proxy buffers can't be alpha. Disarding alpha flag.");
877         alpha = EINA_FALSE;
878      }
879 
880    _buffer_name_format(bufname, pgm, src);
881    buf = _buffer_add(pgm, bufname, alpha, src, EINA_TRUE);
882    if (!buf) return EINA_FALSE;
883 
884    lua_getglobal(L, bufname);
885    instr->return_count = 1;
886 
887    return EINA_TRUE;
888 }
889 
890 static int
_lua_buffer_new(lua_State * L)891 _lua_buffer_new(lua_State *L)
892 {
893    // Reuse old "buffer" instruction code
894    Evas_Filter_Program *pgm = _lua_program_get(L);
895    Evas_Filter_Instruction *instr;
896 
897    instr = _instruction_new(_lua_buffer_meta);
898    instr->type = EVAS_FILTER_MODE_BUFFER;
899    instr->parse_run = _buffer_instruction_parse_run;
900    _instruction_param_seq_add(instr, "type", VT_STRING, "rgba");
901    _instruction_param_seq_add(instr, "src", VT_STRING, NULL);
902 
903    // drop "buffer" metatable
904    _lua_implicit_metatable_drop(L, _lua_buffer_meta);
905 
906    if (!_lua_instruction_run(L, instr))
907      {
908         _instruction_del(instr);
909         return luaL_error(L, "buffer instantiation failed");
910      }
911    else
912      {
913         pgm->instructions = eina_inlist_append(pgm->instructions, EINA_INLIST_GET(instr));
914      }
915 
916    return instr->return_count;
917 }
918 
919 static int
_blend_padding_update(Evas_Filter_Program * pgm EINA_UNUSED,Evas_Filter_Instruction * instr,int * padl,int * padr,int * padt,int * padb)920 _blend_padding_update(Evas_Filter_Program *pgm EINA_UNUSED,
921                       Evas_Filter_Instruction *instr,
922                       int *padl, int *padr, int *padt, int *padb)
923 {
924    Evas_Filter_Fill_Mode fillmode;
925    Buffer *src, *dst;
926    int ox, oy, l = 0, r = 0, t = 0, b = 0;
927 
928    ox = _instruction_param_geti(instr, "ox", NULL);
929    oy = _instruction_param_geti(instr, "oy", NULL);
930 
931    src = _instruction_param_getbuf(instr, "src", NULL);
932    dst = _instruction_param_getbuf(instr, "dst", NULL);
933    EINA_SAFETY_ON_NULL_RETURN_VAL(src, 0);
934    EINA_SAFETY_ON_NULL_RETURN_VAL(dst, 0);
935 
936    fillmode = _fill_mode_get(instr);
937    if (fillmode & (EVAS_FILTER_FILL_MODE_STRETCH_X | EVAS_FILTER_FILL_MODE_REPEAT_X)) ox = 0;
938    if (fillmode & (EVAS_FILTER_FILL_MODE_STRETCH_Y | EVAS_FILTER_FILL_MODE_REPEAT_Y)) oy = 0;
939 
940    if (ox < 0) l = (-ox) + src->pad.l;
941    else r = ox + src->pad.r;
942 
943    if (oy < 0) t = (-oy) + src->pad.t;
944    else b = oy + src->pad.b;
945 
946    if (dst->pad.l < l) dst->pad.l = l;
947    if (dst->pad.r < r) dst->pad.r = r;
948    if (dst->pad.t < t) dst->pad.t = t;
949    if (dst->pad.b < b) dst->pad.b = b;
950 
951    if (padl) *padl = l;
952    if (padr) *padr = r;
953    if (padt) *padt = t;
954    if (padb) *padb = b;
955 
956    return 0;
957 }
958 
959 /**
960   @page evasfiltersref
961   @section sec_commands Filter commands
962   @page evasfiltersref
963 
964   This section will present the various filter instructions, their syntax
965   and their effects.
966  */
967 
968 /**
969   @page evasfiltersref
970 
971   @subsection sec_commands_blend Blend
972 
973   Blend a buffer onto another. This is the simplest filter, as it just
974   renders one buffer on another, potentially using a color, an
975   offset and fill options.
976 
977   @verbatim
978   blend ({ src = input, dst = output, ox = 0, oy = 0, color = 'white', fillmode = 'none' })
979   @endverbatim
980 
981   @param src Source buffer to blend.
982   @param dst Destination buffer for blending.
983   @param ox  X offset. Moves the buffer to the right (ox > 0) or to the left (ox < 0) by N pixels.
984   @param oy  Y offset. Moves the buffer to the bottom (oy > 0) or to the top (oy < 0) by N pixels.
985   @param color A color to use for alpha to RGBA conversion. See @ref evasfilters_color "colors". <br>
986                  If the input is an alpha buffer and the output is RGBA, this will
987                  draw the buffer in this color. If both buffers are RGBA, this will
988                  have no effect.
989   @param fillmode Map the input onto the whole surface of the output by stretching or
990                   repeating it. See @ref evasfilter_fillmode "fillmodes".
991   @param alphaonly If true, this means all RGBA->Alpha conversions discard the
992                    RGB components entirely, and only use the Alpha channel.
993                    False by default, which means RGB is used as Grey color level.
994 
995   If @a src is an alpha buffer and @a dst is an RGBA buffer, then the @a color option should be set.
996 
997   @verbinclude filter_blend.lua
998 
999   <center>
1000   @image html filter_blend.png
1001   </center>
1002 
1003   @since 1.9
1004  */
1005 
1006 static Eina_Bool
_blend_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1007 _blend_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1008 {
1009    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1010    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1011    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "blend"), EINA_FALSE);
1012 
1013    instr->type = EVAS_FILTER_MODE_BLEND;
1014    instr->pad.update = _blend_padding_update;
1015    _instruction_param_seq_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1016    _instruction_param_seq_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1017    _instruction_param_seq_add(instr, "ox", VT_INT, 0);
1018    _instruction_param_seq_add(instr, "oy", VT_INT, 0);
1019    _instruction_param_name_add(instr, "color", VT_COLOR, 0xFFFFFFFF);
1020    _instruction_param_name_add(instr, "fillmode", VT_STRING, "none");
1021    _instruction_param_name_add(instr, "alphaonly", VT_BOOL, EINA_FALSE);
1022 
1023    return EINA_TRUE;
1024 }
1025 
1026 static int
_blur_padding_update(Evas_Filter_Program * pgm EINA_UNUSED,Evas_Filter_Instruction * instr,int * padl,int * padr,int * padt,int * padb)1027 _blur_padding_update(Evas_Filter_Program *pgm EINA_UNUSED,
1028                      Evas_Filter_Instruction *instr,
1029                      int *padl, int *padr, int *padt, int *padb)
1030 {
1031    Eina_Bool yset = EINA_FALSE;
1032    int rx, ry, ox, oy, l, r, t, b, count;
1033    const char *typestr;
1034    Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT;
1035    Buffer *src, *dst;
1036 
1037    rx = _instruction_param_geti(instr, "rx", NULL);
1038    ry = _instruction_param_geti(instr, "ry", &yset);
1039    ox = _instruction_param_geti(instr, "ox", NULL);
1040    oy = _instruction_param_geti(instr, "oy", NULL);
1041    count = _instruction_param_geti(instr, "count", NULL);
1042    typestr = _instruction_param_gets(instr, "type", NULL);
1043 
1044    src = _instruction_param_getbuf(instr, "src", NULL);
1045    dst = _instruction_param_getbuf(instr, "dst", NULL);
1046    EINA_SAFETY_ON_NULL_RETURN_VAL(src, 0);
1047    EINA_SAFETY_ON_NULL_RETURN_VAL(dst, 0);
1048 
1049    if (typestr && !strcasecmp(typestr, "box"))
1050      type = EVAS_FILTER_BLUR_BOX;
1051 
1052    if (!yset) ry = rx;
1053    if (rx < 0) rx = 0;
1054    if (ry < 0) ry = 0;
1055 
1056    if (type == EVAS_FILTER_BLUR_BOX)
1057      {
1058         if (count < 1) count = 1;
1059         if (count > 6) count = 3;
1060      }
1061    else
1062      count = 1;
1063 
1064    rx *= count;
1065    ry *= count;
1066 
1067    l = rx + src->pad.l + ((ox < 0) ? (-ox) : 0);
1068    r = rx + src->pad.r + ((ox > 0) ? ox : 0);
1069    t = ry + src->pad.t + ((oy < 0) ? (-oy) : 0);
1070    b = ry + src->pad.b + ((oy > 0) ? oy : 0);
1071 
1072    if (dst->pad.l < l) dst->pad.l = l;
1073    if (dst->pad.r < r) dst->pad.r = r;
1074    if (dst->pad.t < t) dst->pad.t = t;
1075    if (dst->pad.b < b) dst->pad.b = b;
1076 
1077    if (padl) *padl = l;
1078    if (padr) *padr = r;
1079    if (padt) *padt = t;
1080    if (padb) *padb = b;
1081 
1082    return 0;
1083 }
1084 
1085 /**
1086   @page evasfiltersref
1087 
1088   @subsection sec_commands_blur Blur
1089 
1090   Apply blur effect on a buffer (box or gaussian).
1091 
1092   @verbatim
1093   blur ({ rx = 3, ry = nil, type = 'default', ox = 0, oy = 0, color = 'white', src = input, dst = output })
1094   @endverbatim
1095 
1096   @param rx    X radius. Specifies the radius of the blurring kernel (X direction).
1097   @param ry    Y radius. Specifies the radius of the blurring kernel (Y direction). If -1 is used, then @a ry = @a rx.
1098   @param type  Blur type to apply. One of @c default, @c box or @c gaussian. See below for details about @c default.
1099   @param ox    X offset. Moves the buffer to the right (@a ox > 0) or to the left (@a ox < 0) by N pixels.
1100   @param oy    Y offset. Moves the buffer to the bottom (@a oy > 0) or to the top (@a oy < 0) by N pixels.
1101   @param color A color to use for alpha to RGBA conversion. See @ref evasfilters_color "colors". <br>
1102                  If the input is an alpha buffer and the output is RGBA, this will
1103                  draw the buffer in this color.
1104   @param src   Source buffer to blur.
1105   @param dst   Destination buffer for blending.
1106   @param count Number of times to repeat the blur. Only valid with @c box blur. Valid range is: 1 to 6.
1107 
1108   The blur type @c default is <b>recommended in all situations</b> as it will select the smoothest
1109   and fastest operation possible depending on the kernel size. Instead of running a real
1110   gaussian blur, 2 or 3 box blurs may be chained to produce a similar effect at a much
1111   higher speed. The value @a count can be set to a value from 1 to 6 if blur type @c box
1112   has been specified.
1113 
1114   The speedups of @c box over @c gaussian are of orders of 4x to more than 20x faster.
1115 
1116   If @a src is an alpha buffer and @a dst is an RGBA buffer, then the color option should be set.
1117 
1118   @a ox and @a oy can be used to move the blurry output by a few pixels, like a drop shadow. Example:
1119   @verbinclude filter_blur.lua
1120 
1121   <center>
1122   @image html filter_blur.png
1123   </center>
1124 
1125   @since 1.9
1126  */
1127 
1128 static Eina_Bool
_blur_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1129 _blur_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1130 {
1131    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1132    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1133    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "blur"), EINA_FALSE);
1134 
1135    instr->type = EVAS_FILTER_MODE_BLUR;
1136    instr->pad.update = _blur_padding_update;
1137    _instruction_param_seq_add(instr, "rx", VT_INT, 3);
1138    _instruction_param_seq_add(instr, "ry", VT_INT, -1);
1139    _instruction_param_seq_add(instr, "type", VT_STRING, "default");
1140    _instruction_param_seq_add(instr, "ox", VT_INT, 0);
1141    _instruction_param_seq_add(instr, "oy", VT_INT, 0);
1142    _instruction_param_name_add(instr, "color", VT_COLOR, 0xFFFFFFFF);
1143    _instruction_param_name_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1144    _instruction_param_name_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1145    _instruction_param_name_add(instr, "count", VT_INT, 0);
1146    _instruction_param_name_add(instr, "alphaonly", VT_BOOL, EINA_FALSE);
1147 
1148    return EINA_TRUE;
1149 }
1150 
1151 /**
1152   @page evasfiltersref
1153 
1154   @subsection sec_commands_bump Bump
1155 
1156   Apply a light effect (ambient light, specular reflection and shadows) based on a bump map.
1157 
1158   This can be used to give a relief effect on the object.
1159 
1160   @verbatim
1161   bump ({ map, azimuth = 135.0, elevation = 45.0, depth = 8.0, specular = 0.0,
1162           color = 'white', compensate = false, src = input, dst = output,
1163           black = 'black', white = 'white', fillmode = 'repeat' })
1164   @endverbatim
1165 
1166   @param map        An alpha buffer treated like a Z map for the light effect (bump map). Must be specified.
1167   @param azimuth    The angle between the light vector and the X axis in the XY plane (Z = 0). 135.0 means 45 degrees from the top-left. Counter-clockwise notation.
1168   @param elevation  The angle between the light vector and the Z axis. 45.0 means 45 degrees to the screen's plane. Ranges from 0 to 90 only.
1169   @param depth      The depth of the object in an arbitrary unit. More depth means the shadows will be stronger. Default is 8.0.
1170   @param specular   An arbitrary unit for the specular light effect. Default is 0.0, but a common value would be 40.0.
1171   @param color      The main color of the object if src is an alpha buffer. This represents the light's normal color. See @ref evasfilters_color "colors".
1172   @param compensate If set to true, compensate for whitening or darkening on flat surfaces. Default is false but it is recommended if specular light is wanted.
1173   @param src        Source buffer. This should be an alpha buffer.
1174   @param dst        Destination buffer. This should be an RGBA buffer (although alpha is supported). Must be of the same size as @a src.
1175   @param black      The shadows' color. Usually this will be black (@c #000).
1176   @param white      The specular light's color. Usually this will be white (@c \#FFF).
1177   @param fillmode   This specifies how to handle @a map when its dimensions don't match those of @a src and @a dst. Default is to @c repeat. See @ref evasfilter_fillmode "fillmodes".
1178 
1179   @note As of 2014/02/11, the ALPHA to RGBA support is of much better quality than ALPHA only, but @b very slow. RGBA sources are not supported yet.
1180 
1181   Here is a full example of a very simple bevel effect:
1182   @verbinclude filter_bump.lua
1183 
1184   <center>
1185   @image html filter_bump.png
1186   </center>
1187 
1188   @since 1.9
1189  */
1190 
1191 static Eina_Bool
_bump_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1192 _bump_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1193 {
1194    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1195    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1196    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "bump"), EINA_FALSE);
1197 
1198    instr->type = EVAS_FILTER_MODE_BUMP;
1199    _instruction_param_seq_add(instr, "map", VT_BUFFER, NULL);
1200    _instruction_param_seq_add(instr, "azimuth", VT_REAL, 135.0);
1201    _instruction_param_seq_add(instr, "elevation", VT_REAL, 45.0);
1202    _instruction_param_seq_add(instr, "depth", VT_REAL, 8.0);
1203    _instruction_param_seq_add(instr, "specular", VT_REAL, 0.0);
1204    _instruction_param_name_add(instr, "color", VT_COLOR, 0xFFFFFFFF);
1205    _instruction_param_name_add(instr, "compensate", VT_BOOL, EINA_FALSE);
1206    _instruction_param_name_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1207    _instruction_param_name_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1208    _instruction_param_name_add(instr, "black", VT_COLOR, 0xFF000000);
1209    _instruction_param_name_add(instr, "white", VT_COLOR, 0xFFFFFFFF);
1210    _instruction_param_name_add(instr, "fillmode", VT_STRING, "repeat");
1211 
1212    return EINA_TRUE;
1213 }
1214 
1215 static Eina_Bool
_lua_curve_points_func(lua_State * L,int i,Evas_Filter_Program * pgm EINA_UNUSED,Evas_Filter_Instruction * instr,Instruction_Param * param)1216 _lua_curve_points_func(lua_State *L, int i, Evas_Filter_Program *pgm EINA_UNUSED,
1217                        Evas_Filter_Instruction *instr, Instruction_Param *param)
1218 {
1219    int values[256];
1220    char *token, *copy = NULL;
1221    const char *points_str;
1222    lua_Number n;
1223    int k;
1224 
1225    switch (lua_type(L, i))
1226      {
1227       case LUA_TTABLE:
1228         // FIXME: indices start from 0 here. Lua prefers starting with 1.
1229         for (k = 0; k < 256; k++)
1230           {
1231              lua_rawgeti(L, i, k);
1232              if (lua_isnil(L, -1))
1233                {
1234                   lua_pop(L, 1);
1235                   values[k] = -1;
1236                }
1237              else if (lua_isnumber(L, -1))
1238                {
1239                   n = lua_tonumber(L, -1);
1240                   if ((n < -1) || (n > 255))
1241                     {
1242                        WRN("Value out of range in argument '%s' of function '%s' (got %d, expected 0-255)",
1243                            param->name, instr->name, (int) n);
1244                        if (n < -1) n = 0;
1245                        if (n > 255) n = 255;
1246                     }
1247                   lua_pop(L, 1);
1248                   values[k] = (int) n;
1249                }
1250              else
1251                {
1252                   lua_pop(L, 1);
1253                   ERR("Invalid value type '%s' (expected number) in table for argument '%s' of function '%s'",
1254                       lua_typename(L, -1), param->name, instr->name);
1255                   return EINA_FALSE;
1256                }
1257           }
1258         break;
1259 
1260       case LUA_TSTRING:
1261         for (k = 0; k < 256; k++)
1262           values[k] = -1;
1263         points_str = lua_tostring(L, i);
1264         copy = strdup(points_str);
1265         if (!copy) return EINA_FALSE;
1266         token = strtok(copy, "-");
1267         if (!token)
1268           {
1269              ERR("Invalid string format for argument '%s' of function '%s'",
1270                  param->name, instr->name);
1271              free(copy);
1272              return EINA_FALSE;
1273           }
1274         while (token)
1275           {
1276              int x, y, r, minx = 0;
1277              r = sscanf(token, "%i:%i", &x, &y);
1278              if ((r != 2) || (x < minx) || (x >= 256))
1279                {
1280                   ERR("Invalid string format for argument '%s' of function '%s'",
1281                       param->name, instr->name);
1282                   free(copy);
1283                   return EINA_FALSE;
1284                }
1285              minx = x + 1;
1286              if ((y < -1) || (y > 255))
1287                {
1288                   WRN("Value out of range in argument '%s' of function '%s' (got %d, expected 0-255)",
1289                       param->name, instr->name, y);
1290                   if (y < -1) y = 0;
1291                   if (y > 255) y = 255;
1292                }
1293              values[x] = y;
1294              token = strtok(NULL, "-");
1295           }
1296         free(copy);
1297         break;
1298 
1299       case LUA_TFUNCTION:
1300         for (k = 0; k < 256; k++)
1301           {
1302              lua_getglobal(L, _lua_errfunc_name);
1303              lua_pushvalue(L, i);
1304              lua_pushinteger(L, k);
1305              if (!lua_pcall(L, 1, 1, -3))
1306                {
1307                   if (!lua_isnumber(L, -1))
1308                     {
1309                        ERR("Function returned an invalid type '%s' (expected number) "
1310                            "in argument '%s' of function '%s'",
1311                            lua_typename(L, -1), param->name, instr->name);
1312                        return EINA_FALSE;
1313                     }
1314                   n = lua_tonumber(L, -1);
1315                   if ((n < -1) || (n > 255))
1316                     {
1317                        WRN("Value out of range in argument '%s' of function '%s' (got %d, expected 0-255)",
1318                            param->name, instr->name, (int) n);
1319                        if (n < -1) n = 0;
1320                        if (n > 255) n = 255;
1321                     }
1322                   lua_pop(L, 2);
1323                   values[k] = (int) n;
1324                }
1325              else
1326                {
1327                   ERR("Failed to call function for argument '%s' of function '%s': %s",
1328                       param->name, instr->name, lua_tostring(L, -1));
1329                   return EINA_FALSE;
1330                }
1331           }
1332         break;
1333 
1334       default:
1335         ERR("Invalid type '%s' for argument '%s' of function '%s'",
1336             lua_typename(L, i), param->name, instr->name);
1337         return EINA_FALSE;
1338      }
1339 
1340    free(param->value.special.data);
1341    param->value.special.data = malloc(sizeof(values));
1342    if (!param->value.special.data) return EINA_FALSE;
1343    memcpy(param->value.special.data, values, sizeof(values));
1344 
1345    return EINA_TRUE;
1346 }
1347 
1348 /**
1349   @page evasfiltersref
1350 
1351   @subsection sec_commands_curve Curve
1352 
1353   Apply a color curve to a specific channel in a buffer.
1354 
1355   @verbatim
1356   curve ({ points, interpolation = 'linear', channel = 'rgb', src = input, dst = output })
1357   @endverbatim
1358 
1359   Modify the colors of a buffer. This applies a color curve y = f(x) to every pixel.
1360 
1361   @param points        The color curve to apply. See below for the syntax.
1362   @param interpolation How to interpolate between points. One of @c linear (y = ax + b) or @c none (y = Yk).
1363   @param channel       Target channel for the color modification. One of @c R(ed), @c G(reen), @c B(lue), @c A(lpha), @c RGB and @c RGBA. If @a src is an alpha buffer, this parameter will be ignored.
1364   @param src           Source buffer.
1365   @param dst           Destination buffer, must be of same dimensions and color space as @a src.
1366 
1367   The @a points argument contains a list of (X,Y) points in the range 0..255,
1368   describing a function <tt>f(x) = y</tt> to apply to all pixel values.
1369 
1370   The syntax of this @a points string is <tt>'x1:y1 - x2:y2 - x3:y3 - ... - xn:yn'</tt>
1371   (remember that all spaces are discarded).
1372   The points @c xn are in @a increasing order: <tt>x1 < x2 < x3 < ... < xn</tt>,
1373   and all values @c xn or @c yn are within the range 0..255.
1374 
1375   The identity curve is then described as <tt>'0:0-255:255'</tt>, with linear interpolation:
1376   @verbatim
1377   curve ({ points = '0:0 - 255:255', interpolation = linear })
1378   @endverbatim
1379   If ignored, y(x = 0) is 0 and y(x = 255) is 255.
1380 
1381   The following example will generate a 4px thick stroke around text letters:
1382   @verbinclude filter_curve.lua
1383 
1384   <center>
1385   @image html filter_curve.png
1386   </center>
1387 
1388   The curve command can be used to alter the output of a blur operation.
1389 
1390   @since 1.9
1391  */
1392 
1393 static Eina_Bool
_curve_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1394 _curve_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1395 {
1396    Instruction_Param *param;
1397    Eina_Inlist *last = NULL;
1398 
1399    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1400    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1401    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "curve"), EINA_FALSE);
1402 
1403    instr->type = EVAS_FILTER_MODE_CURVE;
1404 
1405    // TODO: Allow passing an array of 256 values as points.
1406    // It could be easily computed from another function in the script.
1407    _instruction_param_seq_add(instr, "points", VT_SPECIAL, _lua_curve_points_func, NULL);
1408    if (instr->params)
1409      {
1410         last = instr->params->last;
1411         if (last)
1412           {
1413              param = EINA_INLIST_CONTAINER_GET(last, Instruction_Param);
1414              param->allow_any_string = EINA_TRUE;
1415           }
1416      }
1417 
1418    _instruction_param_seq_add(instr, "interpolation", VT_STRING, "linear");
1419    _instruction_param_seq_add(instr, "channel", VT_STRING, "rgb");
1420    _instruction_param_name_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1421    _instruction_param_name_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1422 
1423    return EINA_TRUE;
1424 }
1425 
1426 static int
_displace_padding_update(Evas_Filter_Program * pgm EINA_UNUSED,Evas_Filter_Instruction * instr,int * padl,int * padr,int * padt,int * padb)1427 _displace_padding_update(Evas_Filter_Program *pgm EINA_UNUSED,
1428                          Evas_Filter_Instruction *instr,
1429                          int *padl, int *padr, int *padt, int *padb)
1430 {
1431    int intensity = 0;
1432    int l, r, t, b;
1433    Buffer *src, *dst;
1434 
1435    intensity = _instruction_param_geti(instr, "intensity", NULL);
1436    src = _instruction_param_getbuf(instr, "src", NULL);
1437    dst = _instruction_param_getbuf(instr, "dst", NULL);
1438    EINA_SAFETY_ON_NULL_RETURN_VAL(src, 0);
1439    EINA_SAFETY_ON_NULL_RETURN_VAL(dst, 0);
1440 
1441    l = intensity + src->pad.l;
1442    r = intensity + src->pad.r;
1443    t = intensity + src->pad.t;
1444    b = intensity + src->pad.b;
1445 
1446    if (dst->pad.l < l) dst->pad.l = l;
1447    if (dst->pad.r < r) dst->pad.r = r;
1448    if (dst->pad.t < t) dst->pad.t = t;
1449    if (dst->pad.b < b) dst->pad.b = b;
1450 
1451    if (padl) *padl = l;
1452    if (padr) *padr = r;
1453    if (padt) *padt = t;
1454    if (padb) *padb = b;
1455 
1456    return 0;
1457 }
1458 
1459 /**
1460   @page evasfiltersref
1461 
1462   @subsection sec_commands_displace Displace
1463 
1464   Apply a displacement map on a buffer.
1465 
1466   @verbatim
1467   displace ({ map, intensity = 10, flags = 0, src = input, dst = output, fillmode = 'repeat' })
1468   @endverbatim
1469 
1470   @param map       An RGBA buffer containing a displacement map. See below for more details.
1471   @param intensity Maximum distance for the displacement.
1472                    This means 0 and 255 will represent a displacement of @c intensity pixels.
1473   @param flags     One of @c default, @c nearest, @c smooth, @c nearest_stretch or @c smooth_stretch.
1474                    This defines how pixels should be treated when going out of the @a src image bounds.
1475                    @c default is equivalent to @c smooth_stretch.
1476   @param src       Source buffer
1477   @param dst       Destination buffer. Must be of same color format and size as @a src.
1478   @param fillmode  Defines how to handle cases where the map has a different size from @a src and @a dst.
1479                    It should be a combination of @c stretch or @c repeat: @c none is not supported.
1480                    See @ref evasfilter_fillmode "fillmodes".
1481 
1482   <h3>Displacement map</h3>
1483 
1484   The @a map buffer is an RGBA image containing displacement and alpha values.
1485   Its size can be different from @c src or @c dst.
1486 
1487   The @b red channel is used for X displacements while the @b green channel is
1488   used for Y displacements. All subpixel values are in the range 0..255.
1489   A value of 128 means 0 displacement, lower means displace to the top/left
1490   and higher than 128 displace to the bottom/right.
1491 
1492   If <tt>signed char</tt> is used instead of <tt>unsigned char</tt> to represent
1493   these R and G values, then < 0 means displace top/left while > 0 means bottom/right.
1494 
1495   The @c alpha channel is used as an alpha multiplier for blending.
1496 
1497   Considering <tt>I(x, y)</tt> represents the pixel at position (x, y) in the
1498   image I, then here is how the displacement is applied to @a dst:
1499   @verbatim
1500   D = map (x, y)
1501   dst (x, y) = D.alpha * src (x + (D.red - 128) * intensity / 128, y + (D.green - 128) * intensity / 128) / 255 + (255 - D.alpha) * dst (x, y) / 255
1502   @endverbatim
1503   Of course, the real algorithm takes into account interpolation between pixels as well.
1504 
1505   @since 1.9
1506  */
1507 
1508 static Eina_Bool
_displace_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1509 _displace_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1510 {
1511    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1512    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1513    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "displace"), EINA_FALSE);
1514 
1515    instr->type = EVAS_FILTER_MODE_DISPLACE;
1516    instr->pad.update = _displace_padding_update;
1517    _instruction_param_seq_add(instr, "map", VT_BUFFER, NULL);
1518    _instruction_param_seq_add(instr, "intensity", VT_INT, 10);
1519    _instruction_param_seq_add(instr, "flags", VT_STRING, "default");
1520    _instruction_param_name_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1521    _instruction_param_name_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1522    _instruction_param_name_add(instr, "fillmode", VT_STRING, "repeat");
1523 
1524    return EINA_TRUE;
1525 }
1526 
1527 /**
1528   @page evasfiltersref
1529 
1530   @subsection sec_commands_fill Fill
1531 
1532   Fill a buffer with a specific color.
1533   Not blending, can be used to clear a buffer.
1534 
1535   @verbatim
1536   fill ({ dst = output, color = 'transparent', l = 0, r = 0, t = 0, b = 0 })
1537   @endverbatim
1538 
1539   @param dst       Target buffer to fill with @a color.
1540   @param color     The color used to fill the buffer. All pixels within the fill area will be reset to this value. See @ref evasfilters_color "colors".
1541   @param l         Left padding: skip @a l pixels from the left border of the buffer
1542   @param r         Right padding: skip @a r pixels from the right border of the buffer
1543   @param t         Top padding: skip @a t pixels from the top border of the buffer
1544   @param b         Bottom padding: skip @a b pixels from the bottom border of the buffer
1545 
1546   This function should generally not be used, except for:
1547   <ul>
1548     <li>@a Testing an effect over a specific background color</li>
1549     <li>Clearing out a buffer with either white or transparent color</li>
1550   </ul>
1551 
1552   @since 1.9
1553  */
1554 
1555 static Eina_Bool
_fill_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1556 _fill_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1557 {
1558    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1559    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1560    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "fill"), EINA_FALSE);
1561 
1562    instr->type = EVAS_FILTER_MODE_FILL;
1563    _instruction_param_seq_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1564    _instruction_param_seq_add(instr, "color", VT_COLOR, 0x0);
1565    _instruction_param_seq_add(instr, "l", VT_INT, 0);
1566    _instruction_param_seq_add(instr, "r", VT_INT, 0);
1567    _instruction_param_seq_add(instr, "t", VT_INT, 0);
1568    _instruction_param_seq_add(instr, "b", VT_INT, 0);
1569 
1570    return EINA_TRUE;
1571 }
1572 
1573 static int
_grow_padding_update(Evas_Filter_Program * pgm EINA_UNUSED,Evas_Filter_Instruction * instr,int * padl,int * padr,int * padt,int * padb)1574 _grow_padding_update(Evas_Filter_Program *pgm EINA_UNUSED,
1575                      Evas_Filter_Instruction *instr,
1576                      int *padl, int *padr, int *padt, int *padb)
1577 {
1578    Buffer *src, *dst;
1579    int l, r, t, b;
1580    int radius;
1581 
1582    radius = _instruction_param_geti(instr, "radius", NULL);
1583    src = _instruction_param_getbuf(instr, "src", NULL);
1584    dst = _instruction_param_getbuf(instr, "dst", NULL);
1585    EINA_SAFETY_ON_NULL_RETURN_VAL(src, 0);
1586    EINA_SAFETY_ON_NULL_RETURN_VAL(dst, 0);
1587 
1588    if (radius < 0) radius = 0;
1589 
1590    l = radius + src->pad.l;
1591    r = radius + src->pad.r;
1592    t = radius + src->pad.t;
1593    b = radius + src->pad.b;
1594 
1595    if (padl) *padl = l;
1596    if (padr) *padr = r;
1597    if (padt) *padt = t;
1598    if (padb) *padb = b;
1599 
1600    if (dst->pad.l < l) dst->pad.l = l;
1601    if (dst->pad.r < r) dst->pad.r = r;
1602    if (dst->pad.t < t) dst->pad.t = t;
1603    if (dst->pad.b < b) dst->pad.b = b;
1604 
1605    return 0;
1606 }
1607 
1608 /**
1609   @page evasfiltersref
1610 
1611   @subsection sec_commands_grow Grow
1612 
1613   Grow or shrink a buffer's contents. This is not a zoom effect.
1614 
1615   @verbatim
1616   grow ({ radius, smooth = true, src = input, dst = output })
1617   @endverbatim
1618 
1619   @param radius  The radius of the grow kernel.
1620                  If a negative value is specified, the contents will shrink rather than grow.
1621   @param smooth  If @c true, use a smooth transitions between black and white (smooth blur and smoother curve).
1622   @param src     Source buffer to blur.
1623   @param dst     Destination buffer for blending. This must be of same size and colorspace as @a src.
1624 
1625   Example:
1626   @verbinclude filter_grow.lua
1627 
1628   This will first grow the letters in the buffer @c input by a few pixels, and
1629   then draw this buffer in black in the background.
1630 
1631   <center>
1632   @image html filter_grow.png
1633   </center>
1634 
1635   @since 1.9
1636  */
1637 
1638 static Eina_Bool
_grow_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1639 _grow_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1640 {
1641    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1642    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1643    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "grow"), EINA_FALSE);
1644 
1645    instr->type = EVAS_FILTER_MODE_GROW;
1646    instr->pad.update = _grow_padding_update;
1647    _instruction_param_seq_add(instr, "radius", VT_INT, 0);
1648    _instruction_param_name_add(instr, "smooth", VT_BOOL, EINA_TRUE);
1649    _instruction_param_name_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1650    _instruction_param_name_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1651    _instruction_param_name_add(instr, "alphaonly", VT_BOOL, EINA_FALSE);
1652 
1653    return EINA_TRUE;
1654 }
1655 
1656 /**
1657   @page evasfiltersref
1658 
1659   @subsection sec_commands_mask Mask
1660 
1661   Blend two input buffers into a third (target).
1662 
1663   @verbatim
1664   mask ({ mask, src = input, dst = output, color = 'white', fillmode = 'repeat' })
1665   @endverbatim
1666 
1667   @param mask     A mask or texture to blend with the input @a src into the target @a dst.
1668   @param src      Source buffer. This can also be thought of a mask if @a src is alpha and @a mask is RGBA.
1669   @param dst      Destination buffer for blending. This must be of same size and colorspace as @a src.
1670   @param color    A color to use for alpha to RGBA conversion for the blend operations. White means no change.
1671                   See @ref evasfilters_color "colors". This will have no effect on RGBA sources.
1672   @param fillmode Defines whether to stretch or repeat the @a mask if its size that of @p src.
1673                   Should be set when masking with external textures. Default is repeat. See @ref evasfilter_fillmode "fillmodes".
1674 
1675   Note that @a src and @a mask are interchangeable, if they have the same dimensions.
1676 
1677   Example:
1678   @verbinclude filter_mask.lua
1679 
1680   This will create an inner shadow effect.
1681 
1682   <center>
1683   @image html filter_mask.png
1684   </center>
1685 
1686   @since 1.9
1687  */
1688 
1689 static Eina_Bool
_mask_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1690 _mask_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1691 {
1692    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1693    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1694    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "mask"), EINA_FALSE);
1695 
1696    instr->type = EVAS_FILTER_MODE_MASK;
1697    _instruction_param_seq_add(instr, "mask", VT_BUFFER, NULL);
1698    _instruction_param_seq_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1699    _instruction_param_seq_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1700    _instruction_param_name_add(instr, "color", VT_COLOR, 0xFFFFFFFF);
1701    _instruction_param_name_add(instr, "fillmode", VT_STRING, "repeat");
1702 
1703    return EINA_TRUE;
1704 }
1705 
1706 static int
_transform_padding_update(Evas_Filter_Program * pgm EINA_UNUSED,Evas_Filter_Instruction * instr,int * padl,int * padr,int * padt,int * padb)1707 _transform_padding_update(Evas_Filter_Program *pgm EINA_UNUSED,
1708                           Evas_Filter_Instruction *instr,
1709                           int *padl, int *padr, int *padt, int *padb)
1710 {
1711    Buffer *dst;
1712    int ox, oy, l = 0, r = 0, t = 0, b = 0;
1713 
1714    //ox = _instruction_param_geti(instr, "ox", NULL);
1715    ox = 0;
1716    oy = _instruction_param_geti(instr, "oy", NULL);
1717    dst = _instruction_param_getbuf(instr, "dst", NULL);
1718    EINA_SAFETY_ON_NULL_RETURN_VAL(dst, 0);
1719 
1720    //if (ox < 0) l = (-ox) * 2;
1721    //else r = ox * 2;
1722    r = ox * 2;
1723 
1724    if (oy < 0) t = (-oy) * 2;
1725    else b = oy * 2;
1726 
1727    if (dst->pad.l < l) dst->pad.l = l;
1728    if (dst->pad.r < r) dst->pad.r = r;
1729    if (dst->pad.t < t) dst->pad.t = t;
1730    if (dst->pad.b < b) dst->pad.b = b;
1731 
1732    if (padl) *padl = l;
1733    if (padr) *padr = r;
1734    if (padt) *padt = t;
1735    if (padb) *padb = b;
1736 
1737    return 0;
1738 }
1739 
1740 /**
1741   @page evasfiltersref
1742 
1743   @subsection sec_commands_transform Transform
1744 
1745   Apply a geometrical transformation to a buffer.
1746 
1747   Right now, only <b>vertical flip</b> is implemented and available.
1748   This operation does not blend and assumes the destination buffer is empty.
1749 
1750   @verbatim
1751   transform ({ dst, op = 'vflip', src = input, oy = 0 })
1752   @endverbatim
1753 
1754   @param dst      Destination buffer. Must be of the same colorspace as @a src. Must be specified.
1755   @param op       Must be @c 'vflip'. There is no other operation yet.
1756   @param src      Source buffer to transform.
1757   @param oy       Y offset.
1758 
1759   Example:
1760   @verbinclude filter_transform.lua
1761 
1762   This will create a mirrored text effect, for a font of 50px.
1763 
1764   <center>
1765   @image html filter_transform.png
1766   </center>
1767 
1768   @note Because of the meaning of @a oy, this effect probably needs to be
1769         customized for a single font size (FIXME).
1770 
1771   @since 1.9
1772  */
1773 
1774 static Eina_Bool
_transform_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1775 _transform_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1776 {
1777    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1778    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1779    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "transform"), EINA_FALSE);
1780 
1781    instr->type = EVAS_FILTER_MODE_TRANSFORM;
1782    instr->pad.update = _transform_padding_update;
1783    _instruction_param_seq_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1784    _instruction_param_seq_add(instr, "op", VT_STRING, "vflip");
1785    _instruction_param_seq_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1786    //_instruction_param_name_add(instr, "ox", VT_INT, 0);
1787    _instruction_param_name_add(instr, "oy", VT_INT, 0);
1788 
1789    return EINA_TRUE;
1790 }
1791 
1792 /**
1793   @page evasfiltersref
1794   Remove color information from buffer's contents and leave only grayscale
1795   TODO: write down more information
1796  */
1797 
1798 static Eina_Bool
_grayscale_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1799 _grayscale_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1800 {
1801    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1802    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1803    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "grayscale"), EINA_FALSE);
1804 
1805    instr->type = EVAS_FILTER_MODE_GRAYSCALE;
1806    _instruction_param_seq_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1807    _instruction_param_seq_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1808 
1809    return EINA_TRUE;
1810 }
1811 
1812 /**
1813   @page evasfiltersref
1814   Apply inverse color
1815   TODO: write down more information
1816  */
1817 
1818 static Eina_Bool
_inverse_color_instruction_prepare(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr)1819 _inverse_color_instruction_prepare(Evas_Filter_Program *pgm, Evas_Filter_Instruction *instr)
1820 {
1821    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1822    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1823    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "inverse_color"), EINA_FALSE);
1824 
1825    instr->type = EVAS_FILTER_MODE_INVERSE_COLOR;
1826    _instruction_param_seq_add(instr, "src", VT_BUFFER, _buffer_get(pgm, "input"));
1827    _instruction_param_seq_add(instr, "dst", VT_BUFFER, _buffer_get(pgm, "output"));
1828 
1829    return EINA_TRUE;
1830 }
1831 
1832 static int
_padding_set_padding_update(Evas_Filter_Program * pgm,Evas_Filter_Instruction * instr,int * padl,int * padr,int * padt,int * padb)1833 _padding_set_padding_update(Evas_Filter_Program *pgm,
1834                             Evas_Filter_Instruction *instr,
1835                             int *padl, int *padr, int *padt, int *padb)
1836 {
1837    int l = 0, r = 0, t = 0, b = 0;
1838    Eina_Bool lset = EINA_FALSE;
1839    Eina_Bool rset = EINA_FALSE;
1840    Eina_Bool tset = EINA_FALSE;
1841    Eina_Bool bset = EINA_FALSE;
1842 
1843    l = _instruction_param_geti(instr, "l", &lset);
1844    r = _instruction_param_geti(instr, "r", &rset);
1845    t = _instruction_param_geti(instr, "t", &tset);
1846    b = _instruction_param_geti(instr, "b", &bset);
1847 
1848    if (!lset && !rset && !bset && !tset)
1849      INF("padding_set() called without specifying any of l,r,t,b resets to 0");
1850 
1851    if (l < 0 || r < 0 || t < 0 || b < 0)
1852      {
1853         WRN("invalid padding values in padding_set(%d, %d, %d, %d), resets to 0", l, r, t, b);
1854         l = r = t = b = 0;
1855      }
1856 
1857    if (!rset) r = l;
1858    if (!tset) t = r;
1859    if (!bset) b = t;
1860 
1861    if (padl) *padl = l;
1862    if (padr) *padr = r;
1863    if (padt) *padt = t;
1864    if (padb) *padb = b;
1865    pgm->padding_set = EINA_TRUE;
1866 
1867    return 0;
1868 }
1869 
1870 /**
1871   @page evasfiltersref
1872 
1873   @subsection sec_commands_padding_set Padding_Set
1874 
1875   Forcily set a specific padding for this filter.
1876 
1877   @verbatim
1878   padding_set ({ l, r = [l], t = [r], b = [t] })
1879   @endverbatim
1880 
1881   @param l        Padding on the left side in pixels.
1882   @param r        Padding on the right side in pixels. If unset, defaults to @a l.
1883   @param t        Padding on the top in pixels. If unset, defaults to @a r.
1884   @param b        Padding on the bottom in pixels. If unset, defaults to @a t.
1885 
1886   All values must be >= 0. When filtering 'filled' images, some values may be too high
1887   and would result in completely hiding the image.
1888 
1889   It is not possible to set only one of those without forcing the others as well.
1890   A common use case will be when changing a blur size during an animation, or
1891   when applying a mask that will hide most of the (blurred) text.
1892 
1893   Example (the @c fill command is used for illustration purposes):
1894   @verbinclude filter_padding.lua
1895 
1896   This will set the left, right, top and bottom paddings to their respective values,
1897   and some effects may look like they've been "clipped" out.
1898 
1899   <center>
1900   @image html filter_padding.png
1901   </center>
1902 
1903   @since 1.10
1904  */
1905 
1906 static Eina_Bool
_padding_set_instruction_prepare(Evas_Filter_Program * pgm EINA_UNUSED,Evas_Filter_Instruction * instr)1907 _padding_set_instruction_prepare(Evas_Filter_Program *pgm EINA_UNUSED,
1908                                  Evas_Filter_Instruction *instr)
1909 {
1910    EINA_SAFETY_ON_NULL_RETURN_VAL(instr, EINA_FALSE);
1911    EINA_SAFETY_ON_NULL_RETURN_VAL(instr->name, EINA_FALSE);
1912    EINA_SAFETY_ON_FALSE_RETURN_VAL(!strcasecmp(instr->name, "padding_set"), EINA_FALSE);
1913 
1914    instr->type = EVAS_FILTER_MODE_PADDING_SET;
1915    instr->pad.update = _padding_set_padding_update;
1916    _instruction_param_seq_add(instr, "l", VT_INT, 0);
1917    _instruction_param_seq_add(instr, "r", VT_INT, 0);
1918    _instruction_param_seq_add(instr, "t", VT_INT, 0);
1919    _instruction_param_seq_add(instr, "b", VT_INT, 0);
1920 
1921    return EINA_TRUE;
1922 }
1923 
1924 /* Evas_Filter_Parser entry points */
1925 
1926 #undef PARSE_CHECK
1927 #define PARSE_CHECK(a) do { if (!(a)) { ERR("Parsing failed because '%s' is false at %s:%d", #a, __func__, __LINE__); PARSE_ABORT(); goto end; } } while (0)
1928 
1929 EAPI void
evas_filter_program_del(Evas_Filter_Program * pgm)1930 evas_filter_program_del(Evas_Filter_Program *pgm)
1931 {
1932    Evas_Filter_Instruction *instr;
1933    Buffer *buf;
1934 
1935    if (!pgm) return;
1936 
1937    if (pgm->L)
1938      lua_close(pgm->L);
1939 
1940    EINA_INLIST_FREE(pgm->buffers, buf)
1941      {
1942         pgm->buffers = eina_inlist_remove(pgm->buffers, EINA_INLIST_GET(buf));
1943         _buffer_del(buf);
1944      }
1945 
1946    EINA_INLIST_FREE(pgm->instructions, instr)
1947      {
1948         pgm->instructions = eina_inlist_remove(pgm->instructions, EINA_INLIST_GET(instr));
1949         _instruction_del(instr);
1950      }
1951 
1952    eina_stringshare_del(pgm->name);
1953    free(pgm);
1954 }
1955 
1956 // [-1, +1, e] -- converts the top of the stack to a valid 'color' object
1957 static Eina_Bool
_lua_convert_color(lua_State * L)1958 _lua_convert_color(lua_State *L)
1959 {
1960    int top = lua_gettop(L);
1961    lua_getglobal(L, _lua_errfunc_name); //+1
1962    lua_getglobal(L, _lua_color_meta); //+1 (mt)
1963    lua_getfield(L, -1, "__call"); //+1 (func)
1964    lua_pushvalue(L, -2); //+1 (mt)
1965    lua_pushvalue(L, top); //+1 (argument)
1966    if (lua_pcall(L, 2, 1, top + 1) != 0)
1967      {
1968         ERR("Failed to call metamethod __call: %s", lua_tostring(L, -1));
1969         lua_settop(L, top);
1970         return EINA_FALSE;
1971      }
1972    lua_insert(L, top);
1973    lua_settop(L, top);
1974    return EINA_TRUE;
1975 }
1976 
1977 static Eina_Bool
_lua_parameter_parse(Evas_Filter_Program * pgm,lua_State * L,Evas_Filter_Instruction * instr,Instruction_Param * param,int i)1978 _lua_parameter_parse(Evas_Filter_Program *pgm, lua_State *L,
1979                      Evas_Filter_Instruction *instr,
1980                      Instruction_Param *param, int i)
1981 {
1982    if (!param) return EINA_FALSE;
1983    if (param->set)
1984      {
1985         ERR("Parameter %s has already been set", param->name);
1986         return luaL_error(L, "Parameter %s has already been set", param->name);
1987      }
1988 
1989    if (i < 0)
1990      i = lua_gettop(L) + i + 1;
1991 
1992    switch (param->type)
1993      {
1994       case VT_BOOL:
1995         if (lua_type(L, i) == LUA_TSTRING)
1996           {
1997              Eina_Bool ok = EINA_FALSE;
1998              const char *str = lua_tostring(L, i);
1999              Eina_Bool val = _bool_parse(str, &ok);
2000              if (!ok)
2001                goto fail;
2002              param->value.b = val;
2003           }
2004         else if (lua_isboolean(L, i) || lua_isnumber(L, i))
2005           param->value.b = lua_toboolean(L, i);
2006         else
2007           goto fail;
2008         break;
2009       case VT_INT:
2010         if (!lua_isnumber(L, i))
2011           goto fail;
2012         param->value.i = lua_tointeger(L, i);
2013         break;
2014       case VT_REAL:
2015         if (!lua_isnumber(L, i))
2016           goto fail;
2017         param->value.f = lua_tonumber(L, i);
2018         break;
2019       case VT_STRING:
2020         if (lua_type(L, i) != LUA_TSTRING)
2021           goto fail;
2022         free(param->value.s);
2023         param->value.s = strdup(lua_tostring(L, i));
2024         break;
2025       case VT_COLOR:
2026         {
2027            // Auto convert values to a color() if they aren't one already
2028            int cid = 0, pop = 0, A, R, G, B;
2029            if (lua_istable(L, i))
2030              {
2031                 luaL_getmetatable(L, _lua_color_meta);
2032                 lua_getmetatable(L, i);
2033                 if (!lua_isnil(L, -1) && lua_rawequal(L, -2, -1))
2034                   {
2035                      // this is a color already
2036                      cid = i;
2037                   }
2038                 lua_pop(L, 2);
2039              }
2040            if (!cid)
2041              {
2042                 lua_pushvalue(L, i); //+1 (arg)
2043                 if (!_lua_convert_color(L)) //-1/+1
2044                   {
2045                      ERR("Failed to convert color: %s", lua_tostring(L, -1));
2046                      goto fail;
2047                   }
2048                 cid = lua_gettop(L);
2049                 pop = 1;
2050              }
2051            if (!lua_istable(L, cid))
2052              goto fail;
2053            lua_getfield(L, cid, "a");
2054            A = lua_tointeger(L, -1);
2055            lua_getfield(L, cid, "r");
2056            R = lua_tointeger(L, -1);
2057            lua_getfield(L, cid, "g");
2058            G = lua_tointeger(L, -1);
2059            lua_getfield(L, cid, "b");
2060            B = lua_tointeger(L, -1);
2061            lua_pop(L, pop + 4);
2062            evas_color_argb_premul(A, &R, &G, &B);
2063            param->value.c = ARGB_JOIN(A, R, G, B);
2064         }
2065         break;
2066       case VT_BUFFER:
2067         {
2068            if (lua_type(L, i) == LUA_TSTRING)
2069              {
2070                 param->value.buf = _buffer_get(pgm, lua_tostring(L, i));
2071                 if (!param->value.buf)
2072                   goto fail;
2073              }
2074            else
2075              {
2076                 Buffer **pbuf;
2077                 luaL_checkudata(L, i, _lua_buffer_meta);
2078                 pbuf = lua_touserdata(L, i);
2079                 param->value.buf = pbuf ? *pbuf : NULL;
2080              }
2081            break;
2082         }
2083       case VT_SPECIAL:
2084         if (!param->value.special.func ||
2085             !param->value.special.func(L, i, pgm, instr, param))
2086           goto fail;
2087         break;
2088       case VT_NONE:
2089       default:
2090         // This should not happen
2091         CRI("Invalid function declaration");
2092         goto fail;
2093      }
2094 
2095    if (i != lua_gettop(L))
2096      ERR("something is wrong");
2097 
2098    param->set = EINA_TRUE;
2099    return EINA_TRUE;
2100 
2101 fail:
2102    ERR("Invalid value for parameter %s", param->name);
2103    return luaL_error(L, "Invalid value for parameter %s", param->name);
2104 }
2105 
2106 static Instruction_Param *
_parameter_get_by_id(Evas_Filter_Instruction * instr,int id)2107 _parameter_get_by_id(Evas_Filter_Instruction *instr, int id)
2108 {
2109    Instruction_Param *param;
2110    int i = 0;
2111 
2112    if (id < 0)
2113      return NULL;
2114 
2115    EINA_INLIST_FOREACH(instr->params, param)
2116      if (id == (i++))
2117        return param;
2118 
2119    return NULL;
2120 }
2121 
2122 static Eina_Bool
_lua_instruction_run(lua_State * L,Evas_Filter_Instruction * instr)2123 _lua_instruction_run(lua_State *L, Evas_Filter_Instruction *instr)
2124 {
2125    const unsigned int argc = lua_gettop(L);
2126    Evas_Filter_Program *pgm = _lua_program_get(L);
2127    Instruction_Param *param;
2128    unsigned int i = 0;
2129 
2130    if (!instr) return EINA_FALSE;
2131 
2132    if (eina_inlist_count(instr->params) < argc)
2133      {
2134         ERR("Too many arguments passed to the instruction %s", instr->name);
2135         return EINA_FALSE;
2136      }
2137 
2138    if (lua_istable(L, 1))
2139      {
2140         if (argc > 1)
2141           {
2142              ERR("Too many arguments passed to the instruction %s (in table mode)", instr->name);
2143              return EINA_FALSE;
2144           }
2145 
2146         lua_pushnil(L);
2147         while (lua_next(L, 1))
2148           {
2149              if (!lua_isnumber(L, -2) && (lua_type(L, -2) == LUA_TSTRING))
2150                {
2151                   const char *name = lua_tostring(L, -2);
2152                   param = _instruction_param_get(instr, name);
2153                   if (!param)
2154                     {
2155                        ERR("Parameter %s does not exist", name);
2156                        return EINA_FALSE;
2157                     }
2158                }
2159              else if (lua_isnumber(L, -2))
2160                {
2161                   int idx = (int) lua_tonumber(L, -2);
2162                   param = _parameter_get_by_id(instr, idx - 1);
2163                   if (!param)
2164                     {
2165                        ERR("Too many parameters for the function %s", instr->name);
2166                        return EINA_FALSE;
2167                     }
2168 
2169                   if (!param->allow_seq)
2170                     {
2171                        ERR("The parameter %s must be referred to by name in function %s",
2172                            param->name, instr->name);
2173                        return EINA_FALSE;
2174                     }
2175                }
2176              else
2177                {
2178                   ERR("Invalid type for the parameter key in function %s", instr->name);
2179                   return EINA_FALSE;
2180                }
2181 
2182              if (!_lua_parameter_parse(pgm, L, instr, param, -1))
2183                return EINA_FALSE;
2184              lua_pop(L, 1);
2185           }
2186      }
2187    else
2188      {
2189         EINA_INLIST_FOREACH(instr->params, param)
2190           {
2191              if ((++i) > argc) break;
2192              if (!_lua_parameter_parse(pgm, L, instr, param, i))
2193                return EINA_FALSE;
2194           }
2195      }
2196 
2197    if (instr->parse_run)
2198      {
2199         if (!instr->parse_run(L, pgm, instr))
2200           {
2201              ERR("Failed to run instruction '%s'", instr->name);
2202              return EINA_FALSE;
2203           }
2204      }
2205 
2206    return EINA_TRUE;
2207 }
2208 
2209 static int
_lua_generic_function(lua_State * L,const char * name,Eina_Bool (* prepare)(Evas_Filter_Program * pgm,Evas_Filter_Instruction *))2210 _lua_generic_function(lua_State *L, const char *name,
2211                       Eina_Bool (* prepare) (Evas_Filter_Program *pgm, Evas_Filter_Instruction *))
2212 {
2213    Evas_Filter_Program *pgm = _lua_program_get(L);
2214    Evas_Filter_Instruction *instr;
2215 
2216    instr = _instruction_new(name);
2217    prepare(pgm, instr);
2218 
2219    if (!_lua_instruction_run(L, instr))
2220      {
2221         _instruction_del(instr);
2222         return luaL_error(L, "Instruction parsing failed");
2223      }
2224    else
2225      {
2226         pgm->instructions = eina_inlist_append(pgm->instructions, EINA_INLIST_GET(instr));
2227      }
2228 
2229    return instr->return_count;
2230 }
2231 
2232 static int
_lua_print(lua_State * L)2233 _lua_print(lua_State *L)
2234 {
2235    Eina_Strbuf *s;
2236    int nargs = lua_gettop(L);
2237    int i;
2238 
2239    if (nargs < 1)
2240      {
2241         INF("(nothing)");
2242         return 0;
2243      }
2244 
2245    s = eina_strbuf_new();
2246 
2247    for (i = 1; i <= nargs; i++)
2248      {
2249         const char *str;
2250         lua_getglobal(L, _lua_errfunc_name);
2251         lua_getglobal(L, "tostring"); //+1
2252         lua_pushvalue(L, i); //+1
2253         if (lua_pcall(L, 1, 1, -3) == 0) //-2/+1
2254           str = lua_tostring(L, -1);
2255         else
2256           {
2257              ERR("tostring() failed inside print(): %s", lua_tostring(L, -1));
2258              str = "(invalid)";
2259           }
2260         eina_strbuf_append(s, str ? str : "(nil)");
2261         lua_pop(L, 2);
2262         eina_strbuf_append_char(s, ' ');
2263      }
2264 
2265    INF("%s", eina_strbuf_string_get(s));
2266    eina_strbuf_free(s);
2267 
2268    return 0;
2269 }
2270 
2271 #define LUA_GENERIC_FUNCTION(name) \
2272 static int \
2273 _lua_##name(lua_State *L) \
2274 { \
2275    return _lua_generic_function(L, #name, _##name##_instruction_prepare); \
2276 }
2277 
2278 #define PUSH_LUA_FUNCTION(name) \
2279    lua_pushcfunction(L, _lua_##name); \
2280    lua_setglobal(L, #name);
2281 
2282 LUA_GENERIC_FUNCTION(blend)
2283 LUA_GENERIC_FUNCTION(blur)
2284 LUA_GENERIC_FUNCTION(bump)
2285 LUA_GENERIC_FUNCTION(curve)
2286 LUA_GENERIC_FUNCTION(displace)
2287 LUA_GENERIC_FUNCTION(fill)
2288 LUA_GENERIC_FUNCTION(grow)
2289 LUA_GENERIC_FUNCTION(mask)
2290 LUA_GENERIC_FUNCTION(padding_set)
2291 LUA_GENERIC_FUNCTION(transform)
2292 LUA_GENERIC_FUNCTION(grayscale)
2293 LUA_GENERIC_FUNCTION(inverse_color)
2294 
2295 static const luaL_Reg _lua_buffer_metamethods[] = {
2296    { "__call", _lua_buffer_new },
2297    { "__tostring", _lua_buffer_tostring },
2298    { "__index", _lua_buffer_index },
2299    { NULL, NULL }
2300 };
2301 
2302 static char *_lua_color_code = NULL;
2303 
2304 static inline void
_lua_import_path_get(char * path,size_t len,const char * name)2305 _lua_import_path_get(char *path, size_t len, const char *name)
2306 {
2307    const char *pfx = NULL;
2308    /* a hack for in-tree runs, can point this to src/lib/evas */
2309    if (getenv("EFL_RUN_IN_TREE"))
2310      pfx = getenv("EFL_EVAS_FILTER_LUA_PREFIX");
2311    /* the real path not for in-tree runs */
2312    if (!pfx)
2313      pfx = _evas_module_datadir_get();
2314    size_t r = 0;
2315 
2316 #ifdef FILTERS_DEBUG
2317    // This is a hack to fetch the most recent file from source
2318    char *sep = evas_file_path_join("", "");
2319    char *src = strdup(__FILE__);
2320    struct stat st;
2321    if (sep && src)
2322      {
2323         char *slash = strrchr(src, *sep);
2324         if (slash)
2325           {
2326              *slash = '\0';
2327              if (*src == '/')
2328                r = snprintf(path, len - 1, "%s/lua/%s.lua", src, name);
2329              else // abs_srcdir is unknown here
2330                r = snprintf(path, len - 1, "%s/src/%s/lua/%s.lua", PACKAGE_BUILD_DIR, src, name);
2331              if (r >= len) path[len - 1] = '\0';
2332           }
2333      }
2334    free(sep);
2335    free(src);
2336    if (r && !stat(path, &st)) return;
2337 #endif
2338 
2339    r = snprintf(path, len - 1, "%s/filters/lua/%s.lua", pfx ? pfx : ".", name);
2340    if (r >= len) path[len - 1] = '\0';
2341 }
2342 
2343 static Eina_Bool
_lua_import_class(lua_State * L,const char * name,char ** code)2344 _lua_import_class(lua_State *L, const char *name, char **code)
2345 {
2346    // Load code from file
2347    if (!*code)
2348      {
2349         char path[PATH_MAX];
2350         Eina_File *f;
2351         void *map;
2352         size_t sz;
2353 
2354         _lua_import_path_get(path, PATH_MAX, name);
2355         f = eina_file_open(path, EINA_FALSE);
2356         if (!f) return EINA_FALSE;
2357         sz = eina_file_size_get(f);
2358         *code = malloc(sz + 1);
2359         if (!*code) return EINA_FALSE;
2360         map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
2361         if (!map) return EINA_FALSE;
2362         memcpy(*code, map, sz);
2363         (*code)[sz] = '\0';
2364         eina_file_map_free(f, map);
2365         eina_file_close(f);
2366      }
2367 
2368    if (!luaL_dostring(L, *code)) //+1
2369      {
2370         lua_getglobal(L, _lua_errfunc_name); //+1
2371         lua_pushliteral(L, _lua_register_func); //+1
2372         lua_rawget(L, -3); //-1/+1
2373         if (lua_isfunction(L, -1))
2374           {
2375              if (lua_pcall(L, 0, 0, -2) != 0) //-1
2376                {
2377                   ERR("Failed to register globals for '%s': %s", name, lua_tostring(L, -1));
2378                   lua_pop(L, 1);
2379                }
2380           }
2381         else lua_pop(L, 1);
2382         lua_pop(L, 1); // -1 (errfunc)
2383         lua_setglobal(L, name); //-1
2384      }
2385    else
2386      {
2387         ERR("Lua class '%s' could not be loaded: %s", name, lua_tostring(L, -1));
2388         return EINA_FALSE;
2389      }
2390    return EINA_TRUE;
2391 }
2392 
2393 static void
_filter_program_buffers_set(Evas_Filter_Program * pgm)2394 _filter_program_buffers_set(Evas_Filter_Program *pgm)
2395 {
2396    // Standard buffers
2397    _buffer_add(pgm, "input", pgm->input_alpha, NULL, EINA_FALSE);
2398    _buffer_add(pgm, "output", EINA_FALSE, NULL, EINA_FALSE);
2399 
2400    // Register proxies
2401    if (pgm->proxies)
2402      {
2403         Eina_Iterator *it = eina_hash_iterator_tuple_new(pgm->proxies);
2404         Eina_Hash_Tuple *tup;
2405 
2406         EINA_ITERATOR_FOREACH(it, tup)
2407           {
2408              const char *source = tup->key;
2409              char name[64];
2410              Buffer *buf;
2411 
2412              _buffer_name_format(name, pgm, source);
2413              buf = _buffer_add(pgm, name, EINA_FALSE, source, EINA_FALSE);
2414              if (buf)
2415                {
2416                   Evas_Filter_Proxy_Binding *bind = tup->data;
2417                   Evas_Object_Protected_Data *obj;
2418 
2419                   obj = efl_data_scope_get(bind->eo_source, EFL_CANVAS_OBJECT_CLASS);
2420                   buf->w = obj->cur->geometry.w;
2421                   buf->h = obj->cur->geometry.h;
2422                }
2423           }
2424 
2425         eina_iterator_free(it);
2426      }
2427 }
2428 
2429 static inline void
_lua_class_create(lua_State * L,const char * name,const luaL_Reg * meta,const luaL_Reg * methods)2430 _lua_class_create(lua_State *L, const char *name,
2431                   const luaL_Reg *meta, const luaL_Reg *methods)
2432 {
2433    luaL_newmetatable(L, name);
2434    luaL_register(L, NULL, meta);
2435    lua_pushliteral(L, "__metatable");
2436    lua_pushvalue(L, -2);
2437    lua_rawset(L, -3);
2438    if (methods)
2439      {
2440         lua_pushliteral(L, _lua_methods_table);
2441         lua_newtable(L);
2442         luaL_register(L, NULL, methods);
2443         lua_rawset(L, -3);
2444      }
2445    lua_pushvalue(L, -1);
2446    lua_setmetatable(L, -2);
2447    lua_setglobal(L, name);
2448 }
2449 
2450 #if LUA_VERSION_NUM < 502
2451 // From LuaJIT/src/lib_init.c
2452 // Prevent loading package, IO and OS libs (mini-sandbox)
2453 static const luaL_Reg lj_lib_load[] = {
2454   { "",                 luaopen_base },
2455   //{ LUA_LOADLIBNAME,    luaopen_package },
2456   { LUA_TABLIBNAME,     luaopen_table },
2457   //{ LUA_IOLIBNAME,      luaopen_io },
2458   //{ LUA_OSLIBNAME,      luaopen_os },
2459   { LUA_STRLIBNAME,     luaopen_string },
2460   { LUA_MATHLIBNAME,    luaopen_math },
2461   { LUA_DBLIBNAME,      luaopen_debug },
2462 #ifdef LUA_BITLIBNAME
2463   { LUA_BITLIBNAME,     luaopen_bit },
2464 #endif
2465 #ifdef LUA_JITLIBNAME
2466   { LUA_JITLIBNAME,     luaopen_jit },
2467 #endif
2468   { NULL,               NULL }
2469 };
2470 
2471 static void
_luaL_openlibs(lua_State * L)2472 _luaL_openlibs(lua_State *L)
2473 {
2474   const luaL_Reg *lib;
2475   for (lib = lj_lib_load; lib->func; lib++) {
2476     lua_pushcfunction(L, lib->func);
2477     lua_pushstring(L, lib->name);
2478     lua_call(L, 1, 0);
2479   }
2480 }
2481 #endif
2482 
2483 static lua_State *
_lua_state_create(Evas_Filter_Program * pgm)2484 _lua_state_create(Evas_Filter_Program *pgm)
2485 {
2486    lua_State *L;
2487 
2488    pgm->L = L = luaL_newstate();
2489    if (!L)
2490      {
2491         ERR("Could not create a new Lua state");
2492         return NULL;
2493      }
2494 
2495 #if LUA_VERSION_NUM >= 502
2496    luaL_requiref(L, "",       luaopen_base, 1);
2497    luaL_requiref(L, "table",  luaopen_table, 1);
2498    luaL_requiref(L, "string", luaopen_string, 1);
2499    luaL_requiref(L, "math",   luaopen_math, 1);
2500    luaL_requiref(L, "debug",  luaopen_debug, 1);
2501 #else
2502    _luaL_openlibs(L);
2503 #endif
2504    lua_settop(L, 0);
2505 
2506    // Implement print
2507    lua_pushcfunction(L, _lua_print);
2508    lua_setglobal(L, "print");
2509 
2510    // Add backtrace error function
2511    lua_pushcfunction(L, _lua_backtrace);
2512    lua_setglobal(L, _lua_errfunc_name);
2513 
2514    // Store program
2515    lua_pushlightuserdata(L, (void *) &this_is_not_a_cat);
2516    lua_pushlightuserdata(L, pgm);
2517    lua_settable(L, LUA_REGISTRYINDEX);
2518 
2519    // Register functions
2520    PUSH_LUA_FUNCTION(blend)
2521    PUSH_LUA_FUNCTION(blur)
2522    PUSH_LUA_FUNCTION(bump)
2523    PUSH_LUA_FUNCTION(curve)
2524    PUSH_LUA_FUNCTION(displace)
2525    PUSH_LUA_FUNCTION(fill)
2526    PUSH_LUA_FUNCTION(grow)
2527    PUSH_LUA_FUNCTION(mask)
2528    PUSH_LUA_FUNCTION(padding_set)
2529    PUSH_LUA_FUNCTION(transform)
2530    PUSH_LUA_FUNCTION(grayscale)
2531    PUSH_LUA_FUNCTION(inverse_color)
2532 
2533    for (unsigned k = 0; k < (sizeof(fill_modes) / sizeof(fill_modes[0])); k++)
2534      {
2535         if (strcmp("repeat", fill_modes[k].name))
2536           {
2537              lua_pushstring(L, fill_modes[k].name);
2538              lua_setglobal(L, fill_modes[k].name);
2539           }
2540      }
2541 
2542    lua_pushstring(L, "rgba");
2543    lua_setglobal(L, "rgba");
2544 
2545    lua_pushstring(L, "alpha");
2546    lua_setglobal(L, "alpha");
2547 
2548    static const struct { Eina_Bool b; const char *name; } booleans[] =
2549    {
2550       { EINA_TRUE, "on" },
2551       { EINA_TRUE, "yes" },
2552       { EINA_TRUE, "enable" },
2553       { EINA_TRUE, "enabled" },
2554       { EINA_FALSE, "off" },
2555       { EINA_FALSE, "no" },
2556       { EINA_FALSE, "disable" },
2557       { EINA_FALSE, "disabled" }
2558    };
2559 
2560    for (unsigned k = 0; k < (sizeof(booleans) / sizeof(booleans[0])); k++)
2561      {
2562         lua_pushnumber(L, booleans[k].b);
2563         lua_setglobal(L, booleans[k].name);
2564      }
2565 
2566    // Create buffer class based on userdata
2567    _lua_class_create(L, _lua_buffer_meta, _lua_buffer_metamethods, NULL);
2568 
2569    // Load color class
2570    if (!_lua_import_class(L, _lua_color_meta, &_lua_color_code))
2571      ERR("Could not load color class!");
2572 
2573    return L;
2574 }
2575 
2576 static int
_lua_backtrace(lua_State * L)2577 _lua_backtrace(lua_State *L)
2578 {
2579    if (!lua_isstring(L, 1))  /* 'message' not a string? */
2580      return 1;  /* keep it intact */
2581    ERR("Lua error: %s", lua_tolstring(L, 1, NULL));
2582    lua_getglobal(L, "debug");
2583    if (!lua_istable(L, -1))
2584      {
2585         lua_pop(L, 1);
2586         return 1;
2587      }
2588    lua_getfield(L, -1, "traceback");
2589    if (!lua_isfunction(L, -1))
2590      {
2591         lua_pop(L, 2);
2592         return 1;
2593      }
2594    lua_pushvalue(L, 1);  /* pass error message */
2595    lua_pushinteger(L, 2);  /* skip this function and traceback */
2596    lua_call(L, 2, 1);  /* call debug.traceback */
2597    return 1;
2598 }
2599 
2600 #ifdef FILTERS_LEGACY_COMPAT
2601 // This function is here to avoid breaking the ABI too much.
2602 // It should not stay here long, only until all client apps have changed the filters' code to Lua.
2603 static char *
_legacy_strdup(const char * str)2604 _legacy_strdup(const char *str)
2605 {
2606    static Eina_Strbuf *dst = NULL;
2607 
2608    if (!dst) dst = eina_strbuf_new();
2609    for (const char *ptr = str; ptr && *ptr; ptr++)
2610      {
2611         if (ptr[0] == '/' && ptr[1] == '/')
2612           {
2613              // Comments
2614              ptr = strchr(ptr, '\n');
2615              if (!ptr) break;
2616           }
2617         else if (ptr[0] == '/' && ptr[1] == '*')
2618           {
2619              /* Comments */
2620              ptr = strstr(ptr + 2, "*/");
2621              if (!ptr) break;
2622              ptr++;
2623           }
2624         else if (*ptr == '(')
2625           eina_strbuf_append_char(dst, '{');
2626         else if (*ptr == ')')
2627           eina_strbuf_append_char(dst, '}');
2628         else if (*ptr == '#')
2629           {
2630              // Colors: #RGBA becomes "#RGBA"
2631              ptr++;
2632              eina_strbuf_append_length(dst, "\"#", 2);
2633              while (*ptr && *ptr != ',' && *ptr != ')')
2634                eina_strbuf_append_char(dst, *ptr++);
2635              eina_strbuf_append_char(dst, '"');
2636              ptr--;
2637           }
2638         else if (!strncasecmp("buffer", ptr, 6))
2639           {
2640              // Buffers: "buffer : a (rgba)" into "local a = buffer (rgba)"
2641              ptr = strchr(ptr, ':');
2642              if (!ptr) break;
2643              eina_strbuf_append(dst, "local ");
2644              for (ptr++; ptr && *ptr; ptr++)
2645                {
2646                   if (*ptr != '(')
2647                     eina_strbuf_append_char(dst, *ptr);
2648                   else
2649                     {
2650                        eina_strbuf_append(dst, " = buffer{");
2651                        break;
2652                     }
2653                }
2654           }
2655         else if (!strncasecmp("points", ptr, 6))
2656           {
2657              // Color curves: points = 0:0 - 255:255 becomes points = "0:0-255:255"
2658              ptr = strchr(ptr, '=');
2659              if (!ptr) break;
2660              ptr++;
2661              eina_strbuf_append(dst, "points = \"");
2662              while (*ptr && *ptr != ',' && *ptr != ')')
2663                {
2664                   if (isspace(*ptr))
2665                     {
2666                        ptr++;
2667                        continue;
2668                     }
2669                   eina_strbuf_append_char(dst, *ptr++);
2670                }
2671              eina_strbuf_append_char(dst, '"');
2672              ptr--;
2673           }
2674         else if (!strncasecmp("curve", ptr, 5))
2675           {
2676              // Color curves: curve (0:0 - 255:255, becomes curve { points = "0:0-255:255",
2677              const char *end = strchr(ptr, ')');
2678              const char *points = strstr(ptr, "points");
2679              if (!end || (points > end)) break;
2680              if (!points)
2681                {
2682                   while (*ptr != '(') ptr++;
2683                   ptr++;
2684                   eina_strbuf_append(dst, "curve { points = \"");
2685                   while (*ptr && *ptr != ',' && *ptr != ')')
2686                     {
2687                        if (isspace(*ptr))
2688                          {
2689                             ptr++;
2690                             continue;
2691                          }
2692                        eina_strbuf_append_char(dst, *ptr++);
2693                     }
2694                   eina_strbuf_append_char(dst, '"');
2695                   ptr--;
2696                }
2697              else
2698                {
2699                   eina_strbuf_append_length(dst, "curve", 5);
2700                   ptr += 4;
2701                }
2702           }
2703         else if (!strncasecmp("repeat", ptr, 6))
2704           {
2705              // repeat is a Lua keyword, replace all occurences by "repeat_xy"
2706              if (ptr[-1] != '_' && ptr[6] != '_')
2707                {
2708                   eina_strbuf_append(dst, "\"repeat_xy\"");
2709                   ptr += 5;
2710                }
2711              else
2712                eina_strbuf_append_char(dst, *ptr);
2713           }
2714         else
2715           eina_strbuf_append_char(dst, *ptr);
2716      }
2717 
2718    return eina_strbuf_string_steal(dst);
2719 }
2720 #endif
2721 
2722 static Eina_Bool
_filter_program_state_set(Evas_Filter_Program * pgm)2723 _filter_program_state_set(Evas_Filter_Program *pgm)
2724 {
2725    lua_State *L = pgm->L;
2726 
2727    // TODO:
2728    // text properties: colors, font size, ascent/descent, style (enum)
2729 
2730    /* State is defined as follow:
2731     * state = {
2732     *   text = {
2733     *     outline = COL
2734     *     shadow = COL
2735     *     glow = COL
2736     *     glow2 = COL
2737     *   }
2738     *   color = COL
2739     * }
2740     */
2741 
2742 #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; \
2743    evas_color_argb_unpremul(A, &R, &G, &B); d = ARGB_JOIN(A, R, G, B); d; })
2744 #define SETFIELD(name, val) do { lua_pushnumber(L, val); lua_setfield(L, -2, name); } while(0)
2745 #define SETCOLOR(name, val) do { lua_pushnumber(L, val); _lua_convert_color(L); lua_setfield(L, -2, name); } while(0)
2746 
2747    // TODO: Mark program as dependent on some values so we can improve
2748    // the changed flag (ie. re-run the filter only when required)
2749    // eg. edje state_val changed but it is not used by the filter --> no redraw
2750    // --> this needs a metatable with __index
2751 
2752    lua_newtable(L); // "state"
2753    {
2754       SETCOLOR("color", JOINC(color));
2755       SETFIELD("scale", pgm->state.scale);
2756       SETFIELD("pos", pgm->state.pos);
2757       lua_newtable(L); // "cur"
2758       {
2759          SETFIELD("value", pgm->state.cur.value);
2760          lua_pushstring(L, pgm->state.cur.name);
2761          lua_setfield(L, -2, "name");
2762          lua_setfield(L, -2, "cur");
2763       }
2764       if (pgm->state.next.name)
2765         {
2766            lua_newtable(L); // "next"
2767            {
2768               SETFIELD("value", pgm->state.next.value);
2769               lua_pushstring(L, pgm->state.next.name);
2770               lua_setfield(L, -2, "name");
2771            }
2772            lua_setfield(L, -2, "next");
2773         }
2774       lua_newtable(L); // "text"
2775       {
2776          SETCOLOR("outline", JOINC(text.outline));
2777          SETCOLOR("shadow",  JOINC(text.shadow));
2778          SETCOLOR("glow",    JOINC(text.glow));
2779          SETCOLOR("glow2",   JOINC(text.glow2));
2780          lua_setfield(L, -2, "text");
2781       }
2782    }
2783    lua_setglobal(L, "state");
2784 
2785    /* now push all extra data */
2786    if (pgm->data)
2787      {
2788         Evas_Filter_Data_Binding *db;
2789         EINA_INLIST_FOREACH(pgm->data, db)
2790           {
2791              if (db->value)
2792                {
2793                   if (db->execute)
2794                     {
2795                        char *buf = alloca(strlen(db->name) + strlen(db->value) + 4);
2796                        if (!buf) return EINA_FALSE;
2797                        sprintf(buf, "%s = %s", db->name, db->value);
2798                        if (luaL_dostring(L, buf) != 0)
2799                          {
2800                             ERR("Failed to run value: %s", lua_tostring(L, -1));
2801                             return EINA_FALSE;
2802                          }
2803                     }
2804                   else
2805                     {
2806                        lua_pushstring(L, db->value);
2807                        lua_setglobal(L, db->name);
2808                     }
2809                }
2810              else
2811                {
2812                   lua_pushnil(L);
2813                   lua_setglobal(L, db->name);
2814                }
2815           }
2816      }
2817 
2818    return EINA_TRUE;
2819 
2820 #undef JOINC
2821 #undef SETFIELD
2822 #undef SETCOLOR
2823 }
2824 
2825 static Eina_Bool
_filter_program_reset(Evas_Filter_Program * pgm)2826 _filter_program_reset(Evas_Filter_Program *pgm)
2827 {
2828    Evas_Filter_Instruction *instr;
2829    lua_State *L = pgm->L;
2830    Eina_Inlist *il;
2831    Buffer *buf;
2832 
2833    // Clear out commands
2834    EINA_INLIST_FREE(pgm->instructions, instr)
2835      {
2836         pgm->instructions = eina_inlist_remove(pgm->instructions, EINA_INLIST_GET(instr));
2837         _instruction_del(instr);
2838      }
2839 
2840    // Clear out buffers
2841    EINA_INLIST_FOREACH_SAFE(pgm->buffers, il, buf)
2842      {
2843         lua_pushnil(L);
2844         lua_setglobal(L, buf->name);
2845         pgm->buffers = eina_inlist_remove(pgm->buffers, EINA_INLIST_GET(buf));
2846         _buffer_del(buf);
2847      }
2848 
2849    // Re-create buffers
2850    _filter_program_buffers_set(pgm);
2851 
2852    // Reset state table
2853    return _filter_program_state_set(pgm);
2854 }
2855 
2856 /** Parse a style program */
2857 
2858 EAPI Eina_Bool
evas_filter_program_parse(Evas_Filter_Program * pgm,const char * str)2859 evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str)
2860 {
2861    lua_State *L;
2862    Eina_Bool ok;
2863 
2864    EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
2865    EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
2866    EINA_SAFETY_ON_FALSE_RETURN_VAL(*str != 0, EINA_FALSE);
2867 
2868    L = _lua_state_create(pgm);
2869    if (!L) return EINA_FALSE;
2870 
2871    ok = !luaL_loadstring(L, str);
2872    if (!ok)
2873      {
2874         ERR("Failed to load Lua program: %s", lua_tostring(L, -1));
2875      }
2876 
2877 #ifdef FILTERS_LEGACY_COMPAT
2878    if (!ok)
2879      {
2880         char *code = _legacy_strdup(str);
2881         DBG("Fallback to transformed legacy code:\n%s", code);
2882         ok = !luaL_loadstring(L, code);
2883         free(code);
2884      }
2885 #endif
2886 
2887    if (ok)
2888      {
2889         pgm->lua_func = luaL_ref(L, LUA_REGISTRYINDEX);
2890         ok =_filter_program_reset(pgm);
2891         if (ok)
2892           {
2893              lua_getglobal(L, _lua_errfunc_name);
2894              lua_rawgeti(L, LUA_REGISTRYINDEX, pgm->lua_func);
2895              ok = !lua_pcall(L, 0, LUA_MULTRET, -2);
2896           }
2897      }
2898 
2899    if (!ok)
2900      {
2901         const char *msg = lua_tostring(L, -1);
2902         ERR("Lua parsing failed: %s", msg);
2903         lua_close(L);
2904         pgm->L = NULL;
2905      }
2906    else if (!pgm->instructions)
2907      {
2908         ERR("No instructions found in Lua script");
2909         lua_close(L);
2910         ok = EINA_FALSE;
2911         pgm->L = NULL;
2912      }
2913    pgm->valid = ok;
2914    pgm->padding_calc = EINA_FALSE;
2915    pgm->changed = EINA_FALSE;
2916 
2917    return ok;
2918 }
2919 
2920 /** Run a program, must be already loaded */
2921 
2922 static Eina_Bool
_buffers_update(Evas_Filter_Context * ctx,Evas_Filter_Program * pgm)2923 _buffers_update(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm)
2924 {
2925    Evas_Filter_Proxy_Binding *pb;
2926    Buffer *buf;
2927    int w, h, id;
2928 
2929    EINA_INLIST_FOREACH(pgm->buffers, buf)
2930      {
2931         if (buf->proxy)
2932           {
2933              pb = eina_hash_find(pgm->proxies, buf->proxy);
2934              if (!pb) return EINA_FALSE;
2935 
2936              ctx->has_proxies = EINA_TRUE;
2937              id = evas_filter_buffer_proxy_new(ctx, pb, &w, &h);
2938              if (id < 0) return EINA_FALSE;
2939 
2940              buf->cid = id;
2941              buf->w = w;
2942              buf->h = h;
2943 
2944              XDBG("Created proxy buffer #%d %dx%d %s '%s'", buf->cid,
2945                   w, h, buf->alpha ? "alpha" : "rgba", buf->name);
2946           }
2947         else
2948           {
2949              w = pgm->state.w;
2950              h = pgm->state.h;
2951 
2952              id = evas_filter_buffer_empty_new(ctx, w, h, buf->alpha);
2953              if (id < 0) return EINA_FALSE;
2954 
2955              buf->cid = id;
2956              buf->w = w;
2957              buf->h = h;
2958 
2959              XDBG("Created context buffer #%d %dx%d %s '%s'", buf->cid,
2960                   w, h, buf->alpha ? "alpha" : "rgba", buf->name);
2961           }
2962      }
2963 
2964    return EINA_TRUE;
2965 }
2966 
2967 /** Evaluate required padding to correctly apply an effect */
2968 
2969 EAPI Eina_Bool
evas_filter_program_padding_get(Evas_Filter_Program * pgm,Evas_Filter_Padding * out_final,Evas_Filter_Padding * out_calculated)2970 evas_filter_program_padding_get(Evas_Filter_Program *pgm,
2971                                 Evas_Filter_Padding *out_final,
2972                                 Evas_Filter_Padding *out_calculated)
2973 {
2974    Evas_Filter_Instruction *instr;
2975    int pl = 0, pr = 0, pt = 0, pb = 0;
2976    int maxl = 0, maxr = 0, maxt = 0, maxb = 0;
2977    int setl = 0, setr = 0, sett = 0, setb = 0;
2978    Eina_Bool was_set = EINA_FALSE;
2979    Buffer *buf;
2980 
2981    EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
2982 
2983    if (pgm->padding_calc)
2984      {
2985         if (out_final) *out_final = pgm->pad.final;
2986         if (out_calculated) *out_calculated = pgm->pad.calculated;
2987         return EINA_TRUE;
2988      }
2989 
2990    // Reset all paddings
2991    EINA_INLIST_FOREACH(pgm->buffers, buf)
2992      buf->pad.l = buf->pad.r = buf->pad.t = buf->pad.b = 0;
2993 
2994    // Accumulate paddings
2995    EINA_INLIST_FOREACH(pgm->instructions, instr)
2996      {
2997         if (instr->type == EVAS_FILTER_MODE_PADDING_SET)
2998           {
2999              instr->pad.update(pgm, instr, &setl, &setr, &sett, &setb);
3000              was_set = EINA_TRUE;
3001           }
3002         else if (instr->pad.update)
3003           {
3004              instr->pad.update(pgm, instr, &pl, &pr, &pt, &pb);
3005              if (pl > maxl) maxl = pl;
3006              if (pr > maxr) maxr = pr;
3007              if (pt > maxt) maxt = pt;
3008              if (pb > maxb) maxb = pb;
3009           }
3010      }
3011 
3012    pgm->pad.calculated.l = maxl;
3013    pgm->pad.calculated.r = maxr;
3014    pgm->pad.calculated.t = maxt;
3015    pgm->pad.calculated.b = maxb;
3016    if (!was_set)
3017      pgm->pad.final = pgm->pad.calculated;
3018    else
3019      {
3020         pgm->pad.final.l = setl;
3021         pgm->pad.final.r = setr;
3022         pgm->pad.final.t = sett;
3023         pgm->pad.final.b = setb;
3024      }
3025    pgm->padding_calc = EINA_TRUE;
3026 
3027    if (out_final) *out_final = pgm->pad.final;
3028    if (out_calculated) *out_calculated = pgm->pad.calculated;
3029 
3030    return EINA_TRUE;
3031 }
3032 
3033 /** Create an empty filter program for style parsing */
3034 
3035 EAPI Evas_Filter_Program *
evas_filter_program_new(const char * name,Eina_Bool input_alpha)3036 evas_filter_program_new(const char *name, Eina_Bool input_alpha)
3037 {
3038    Evas_Filter_Program *pgm;
3039 
3040    pgm = calloc(1, sizeof(Evas_Filter_Program));
3041    if (!pgm) return NULL;
3042    pgm->name = eina_stringshare_add(name);
3043    pgm->input_alpha = input_alpha;
3044    pgm->state = (Efl_Canvas_Filter_State) EFL_CANVAS_FILTER_STATE_DEFAULT;
3045 
3046    return pgm;
3047 }
3048 
3049 EAPI Eina_Bool
evas_filter_program_state_set(Evas_Filter_Program * pgm,const Efl_Canvas_Filter_State * state)3050 evas_filter_program_state_set(Evas_Filter_Program *pgm,
3051                               const Efl_Canvas_Filter_State *state)
3052 {
3053    EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
3054    EINA_SAFETY_ON_NULL_RETURN_VAL(state, EINA_FALSE);
3055 
3056    if (memcmp(&pgm->state, state, sizeof(Efl_Canvas_Filter_State)) != 0)
3057      {
3058         pgm->changed = EINA_TRUE;
3059         memcpy(&pgm->state, state, sizeof(Efl_Canvas_Filter_State));
3060      }
3061 
3062    if (pgm->changed)
3063      pgm->padding_calc = EINA_FALSE;
3064 
3065    return pgm->changed;
3066 }
3067 
3068 /** Bind objects for proxy rendering */
3069 EAPI void
evas_filter_program_source_set_all(Evas_Filter_Program * pgm,Eina_Hash * proxies)3070 evas_filter_program_source_set_all(Evas_Filter_Program *pgm,
3071                                    Eina_Hash *proxies)
3072 {
3073    if (!pgm) return;
3074    pgm->proxies = proxies;
3075 }
3076 
3077 void
evas_filter_program_data_set_all(Evas_Filter_Program * pgm,Eina_Inlist * data)3078 evas_filter_program_data_set_all(Evas_Filter_Program *pgm, Eina_Inlist *data)
3079 {
3080    if (!pgm) return;
3081    pgm->data = data;
3082 }
3083 
3084 /** Glue with Evas' filters */
3085 
3086 #define CA(color) ((color >> 24) & 0xFF)
3087 #define CR(color) ((color >> 16) & 0xFF)
3088 #define CG(color) ((color >> 8) & 0xFF)
3089 #define CB(color) ((color) & 0xFF)
3090 
3091 #define SETCOLOR(c) do { ENFN->context_color_get(ENC, dc, &R, &G, &B, &A); \
3092    ENFN->context_color_set(ENC, dc, CR(c), CG(c), CB(c), CA(c)); } while (0)
3093 #define RESETCOLOR() do { ENFN->context_color_set(ENC, dc, R, G, B, A); } while (0)
3094 
3095 #define SETCLIP(l, r, t, b) int _l = 0, _r = 0, _t = 0, _b = 0; \
3096    do { ENFN->context_clip_get(ENC, dc, &_l, &_r, &_t, &_b); \
3097    ENFN->context_clip_set(ENC, dc, l, r, t, b); } while (0)
3098 #define RESETCLIP() do { ENFN->context_clip_set(ENC, dc, _l, _r, _t, _b); } while (0)
3099 
3100 static Evas_Filter_Fill_Mode
_fill_mode_get(Evas_Filter_Instruction * instr)3101 _fill_mode_get(Evas_Filter_Instruction *instr)
3102 {
3103    const char *fill;
3104    unsigned k;
3105 
3106    if (!instr) return EVAS_FILTER_FILL_MODE_NONE;
3107    fill = _instruction_param_gets(instr, "fillmode", NULL);
3108    if (!fill) return EVAS_FILTER_FILL_MODE_NONE;
3109 
3110    for (k = 0; k < sizeof(fill_modes) / sizeof(fill_modes[0]); k++)
3111      {
3112         if (!strcasecmp(fill_modes[k].name, fill))
3113           return fill_modes[k].value;
3114      }
3115 
3116    return EVAS_FILTER_FILL_MODE_NONE;
3117 }
3118 
3119 static Evas_Filter_Command *
_instr2cmd_blend(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3120 _instr2cmd_blend(Evas_Filter_Context *ctx,
3121                  Evas_Filter_Instruction *instr, void *dc)
3122 {
3123    Eina_Bool isset = EINA_FALSE;
3124    Evas_Filter_Command *cmd;
3125    DATA32 color;
3126    Buffer *src, *dst;
3127    Evas_Filter_Fill_Mode fillmode;
3128    int ox, oy, A, R, G, B;
3129    Eina_Bool alphaonly;
3130 
3131    ox = _instruction_param_geti(instr, "ox", NULL);
3132    oy = _instruction_param_geti(instr, "oy", NULL);
3133    color = _instruction_param_getc(instr, "color", &isset);
3134    fillmode = _fill_mode_get(instr);
3135    src = _instruction_param_getbuf(instr, "src", NULL);
3136    dst = _instruction_param_getbuf(instr, "dst", NULL);
3137    alphaonly = _instruction_param_getb(instr, "alphaonly", NULL);
3138    INSTR_PARAM_CHECK(src);
3139    INSTR_PARAM_CHECK(dst);
3140 
3141    if (isset) SETCOLOR(color);
3142    cmd = evas_filter_command_blend_add(ctx, dc, src->cid, dst->cid,
3143                                        ox, oy, fillmode, alphaonly);
3144    if (isset) RESETCOLOR();
3145 
3146    return cmd;
3147 }
3148 
3149 static Evas_Filter_Command *
_instr2cmd_blur(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3150 _instr2cmd_blur(Evas_Filter_Context *ctx,
3151                 Evas_Filter_Instruction *instr, void *dc)
3152 {
3153    Eina_Bool colorset = EINA_FALSE, yset = EINA_FALSE, cntset = EINA_FALSE;
3154    Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT;
3155    Evas_Filter_Command *cmd;
3156    const char *typestr;
3157    DATA32 color;
3158    Buffer *src, *dst;
3159    int ox, oy, rx, ry, A, R, G, B, count;
3160    Eina_Bool alphaonly;
3161 
3162    ox = _instruction_param_geti(instr, "ox", NULL);
3163    oy = _instruction_param_geti(instr, "oy", NULL);
3164    rx = _instruction_param_geti(instr, "rx", NULL);
3165    ry = _instruction_param_geti(instr, "ry", &yset);
3166    color = _instruction_param_getc(instr, "color", &colorset);
3167    typestr = _instruction_param_gets(instr, "type", NULL);
3168    count = _instruction_param_geti(instr, "count", &cntset);
3169    src = _instruction_param_getbuf(instr, "src", NULL);
3170    dst = _instruction_param_getbuf(instr, "dst", NULL);
3171    alphaonly = _instruction_param_getb(instr, "alphaonly", NULL);
3172    INSTR_PARAM_CHECK(src);
3173    INSTR_PARAM_CHECK(dst);
3174 
3175    if (typestr)
3176      {
3177         if (!strcasecmp(typestr, "gaussian"))
3178           type = EVAS_FILTER_BLUR_GAUSSIAN;
3179         else if (!strcasecmp(typestr, "box"))
3180           type = EVAS_FILTER_BLUR_BOX;
3181         else if (!strcasecmp(typestr, "default"))
3182           type = EVAS_FILTER_BLUR_DEFAULT;
3183         else
3184           ERR("Unknown blur type '%s'. Using default blur.", typestr);
3185      }
3186 
3187    if (type == EVAS_FILTER_BLUR_BOX)
3188      {
3189         if (count < 1) count = 1;
3190         if (count > 6)
3191           {
3192              WRN("Box blur count should be below 6, defaults to 3.");
3193              count = 3;
3194           }
3195      }
3196    else
3197      {
3198         if (cntset) WRN("Blur count can only be used with BOX blur.");
3199         count = 1;
3200      }
3201 
3202    if (!yset) ry = rx;
3203    if (colorset) SETCOLOR(color);
3204    cmd = evas_filter_command_blur_add(ctx, dc, src->cid, dst->cid, type,
3205                                       rx, ry, ox, oy, count, alphaonly);
3206    if (colorset) RESETCOLOR();
3207 
3208    return cmd;
3209 }
3210 
3211 static Evas_Filter_Command *
_instr2cmd_bump(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3212 _instr2cmd_bump(Evas_Filter_Context *ctx,
3213                 Evas_Filter_Instruction *instr, void *dc)
3214 {
3215    Evas_Filter_Bump_Flags flags = EVAS_FILTER_BUMP_NORMAL;
3216    Evas_Filter_Fill_Mode fillmode;
3217    DATA32 color, black, white;
3218    Buffer *src, *dst, *map;
3219    double azimuth, elevation, depth, specular;
3220    int compensate;
3221 
3222    color = _instruction_param_getc(instr, "color", NULL);
3223    white = _instruction_param_getc(instr, "white", NULL);
3224    black = _instruction_param_getc(instr, "black", NULL);
3225    azimuth = _instruction_param_getd(instr, "azimuth", NULL);
3226    elevation = _instruction_param_getd(instr, "elevation", NULL);
3227    depth = _instruction_param_getd(instr, "depth", NULL);
3228    specular = _instruction_param_getd(instr, "specular", NULL);
3229    compensate = _instruction_param_geti(instr, "compensate", NULL);
3230    fillmode = _fill_mode_get(instr);
3231    if (compensate) flags |= EVAS_FILTER_BUMP_COMPENSATE;
3232 
3233    src = _instruction_param_getbuf(instr, "src", NULL);
3234    dst = _instruction_param_getbuf(instr, "dst", NULL);
3235    map = _instruction_param_getbuf(instr, "map", NULL);
3236    INSTR_PARAM_CHECK(src);
3237    INSTR_PARAM_CHECK(dst);
3238    INSTR_PARAM_CHECK(map);
3239 
3240    return evas_filter_command_bump_map_add(ctx, dc, src->cid, map->cid, dst->cid,
3241                                            azimuth, elevation, depth, specular,
3242                                            black, color, white, flags,
3243                                            fillmode);
3244 }
3245 
3246 static Evas_Filter_Command *
_instr2cmd_displace(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3247 _instr2cmd_displace(Evas_Filter_Context *ctx,
3248                     Evas_Filter_Instruction *instr, void *dc)
3249 {
3250    Evas_Filter_Fill_Mode fillmode;
3251    Evas_Filter_Displacement_Flags flags =
3252          EVAS_FILTER_DISPLACE_STRETCH | EVAS_FILTER_DISPLACE_LINEAR;
3253    const char *flagsstr;
3254    Buffer *src, *dst, *map;
3255    int intensity;
3256    Eina_Bool isset = EINA_FALSE;
3257 
3258    src = _instruction_param_getbuf(instr, "src", NULL);
3259    dst = _instruction_param_getbuf(instr, "dst", NULL);
3260    map = _instruction_param_getbuf(instr, "map", NULL);
3261    intensity = _instruction_param_geti(instr, "intensity", NULL);
3262    flagsstr = _instruction_param_gets(instr, "flags", &isset);
3263    fillmode = _fill_mode_get(instr);
3264    INSTR_PARAM_CHECK(src);
3265    INSTR_PARAM_CHECK(dst);
3266    INSTR_PARAM_CHECK(map);
3267 
3268    if (!flagsstr) flagsstr = "default";
3269    if (!strcasecmp(flagsstr, "nearest"))
3270      flags = EVAS_FILTER_DISPLACE_NEAREST;
3271    else if (!strcasecmp(flagsstr, "smooth"))
3272      flags = EVAS_FILTER_DISPLACE_LINEAR;
3273    else if (!strcasecmp(flagsstr, "nearest_stretch"))
3274      flags = EVAS_FILTER_DISPLACE_NEAREST | EVAS_FILTER_DISPLACE_STRETCH;
3275    else if (!strcasecmp(flagsstr, "default") || !strcasecmp(flagsstr, "smooth_stretch"))
3276      flags = EVAS_FILTER_DISPLACE_STRETCH | EVAS_FILTER_DISPLACE_LINEAR;
3277    else if (isset)
3278      WRN("Invalid flags '%s' in displace operation. Using default instead", flagsstr);
3279 
3280    return evas_filter_command_displacement_map_add(ctx, dc, src->cid, dst->cid,
3281                                                    map->cid, flags, intensity,
3282                                                    fillmode);
3283 }
3284 
3285 static Evas_Filter_Command *
_instr2cmd_fill(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3286 _instr2cmd_fill(Evas_Filter_Context *ctx,
3287                 Evas_Filter_Instruction *instr, void *dc)
3288 {
3289    Buffer *dst;
3290    int R, G, B, A, l, r, t, b;
3291    Evas_Filter_Command *cmd;
3292    DATA32 color;
3293 
3294    dst = _instruction_param_getbuf(instr, "dst", NULL);
3295    color = _instruction_param_getc(instr, "color", NULL);
3296    l = _instruction_param_geti(instr, "l", NULL);
3297    r = _instruction_param_geti(instr, "r", NULL);
3298    t = _instruction_param_geti(instr, "t", NULL);
3299    b = _instruction_param_geti(instr, "b", NULL);
3300    INSTR_PARAM_CHECK(dst);
3301 
3302    SETCOLOR(color);
3303    cmd = evas_filter_command_fill_add(ctx, dc, dst->cid);
3304    RESETCOLOR();
3305    if (!cmd) return NULL;
3306 
3307    cmd->draw.clip.l = l;
3308    cmd->draw.clip.r = r;
3309    cmd->draw.clip.t = t;
3310    cmd->draw.clip.b = b;
3311    cmd->draw.clip_mode_lrtb = EINA_TRUE;
3312    cmd->draw.rop = EFL_GFX_RENDER_OP_COPY;
3313 
3314    return cmd;
3315 }
3316 
3317 static Evas_Filter_Command *
_instr2cmd_grow(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3318 _instr2cmd_grow(Evas_Filter_Context *ctx,
3319                 Evas_Filter_Instruction *instr, void *dc)
3320 {
3321    Evas_Filter_Command *cmd;
3322    Buffer *src, *dst;
3323    Eina_Bool smooth;
3324    Eina_Bool alphaonly;
3325    int radius;
3326 
3327    src = _instruction_param_getbuf(instr, "src", NULL);
3328    dst = _instruction_param_getbuf(instr, "dst", NULL);
3329    radius = _instruction_param_geti(instr, "radius", NULL);
3330    smooth = _instruction_param_getb(instr, "smooth", NULL);
3331    alphaonly = _instruction_param_getb(instr, "alphaonly", NULL);
3332    INSTR_PARAM_CHECK(src);
3333    INSTR_PARAM_CHECK(dst);
3334 
3335    cmd = evas_filter_command_grow_add(ctx, dc, src->cid, dst->cid, radius, smooth, alphaonly);
3336    if (cmd) cmd->draw.need_temp_buffer = EINA_TRUE;
3337 
3338    return cmd;
3339 }
3340 
3341 static Evas_Filter_Command *
_instr2cmd_mask(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3342 _instr2cmd_mask(Evas_Filter_Context *ctx,
3343                 Evas_Filter_Instruction *instr, void *dc)
3344 {
3345    Evas_Filter_Fill_Mode fillmode;
3346    Evas_Filter_Command *cmd;
3347    Buffer *src, *dst, *mask;
3348    DATA32 color;
3349    int R, G, B, A;
3350 
3351    src = _instruction_param_getbuf(instr, "src", NULL);
3352    dst = _instruction_param_getbuf(instr, "dst", NULL);
3353    mask = _instruction_param_getbuf(instr, "mask", NULL);
3354    color = _instruction_param_getc(instr, "color", NULL);
3355    fillmode = _fill_mode_get(instr);
3356    INSTR_PARAM_CHECK(src);
3357    INSTR_PARAM_CHECK(dst);
3358    INSTR_PARAM_CHECK(mask);
3359 
3360    SETCOLOR(color);
3361    cmd = evas_filter_command_mask_add(ctx, dc, src->cid, mask->cid, dst->cid, fillmode);
3362    RESETCOLOR();
3363    if (!cmd) return NULL;
3364 
3365    if (!src->alpha && !mask->alpha && !dst->alpha && !ctx->gl)
3366      cmd->draw.need_temp_buffer = EINA_TRUE;
3367 
3368    return cmd;
3369 }
3370 
3371 static Evas_Filter_Command *
_instr2cmd_curve(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3372 _instr2cmd_curve(Evas_Filter_Context *ctx,
3373                  Evas_Filter_Instruction *instr, void *dc)
3374 {
3375    Evas_Filter_Interpolation_Mode mode = EVAS_FILTER_INTERPOLATION_MODE_LINEAR;
3376    Evas_Filter_Channel channel = EVAS_FILTER_CHANNEL_RGB;
3377    const char *interpolation, *channel_name;
3378    Buffer *src, *dst;
3379    DATA8 values[256];
3380    int *points;
3381 
3382    src = _instruction_param_getbuf(instr, "src", NULL);
3383    dst = _instruction_param_getbuf(instr, "dst", NULL);
3384    points = _instruction_param_getspecial(instr, "points", NULL);
3385    interpolation = _instruction_param_gets(instr, "interpolation", NULL);
3386    channel_name = _instruction_param_gets(instr, "channel", NULL);
3387    INSTR_PARAM_CHECK(points);
3388    INSTR_PARAM_CHECK(src);
3389    INSTR_PARAM_CHECK(dst);
3390 
3391    if (channel_name)
3392      {
3393         if (tolower(*channel_name) == 'r')
3394           {
3395              if (!strcasecmp(channel_name, "rgb"))
3396                channel = EVAS_FILTER_CHANNEL_RGB;
3397              else
3398                channel = EVAS_FILTER_CHANNEL_RED;
3399           }
3400         else if (tolower(*channel_name) == 'g')
3401           channel = EVAS_FILTER_CHANNEL_GREEN;
3402         else if (tolower(*channel_name) == 'b')
3403           channel = EVAS_FILTER_CHANNEL_BLUE;
3404         else if (tolower(*channel_name) == 'a')
3405           channel = EVAS_FILTER_CHANNEL_ALPHA;
3406      }
3407 
3408    if (interpolation && !strcasecmp(interpolation, "none"))
3409      mode = EVAS_FILTER_INTERPOLATION_MODE_NONE;
3410 
3411    if (!evas_filter_interpolate(values, points, mode))
3412      {
3413         int x;
3414         ERR("Failed to parse the interpolation chain");
3415         for (x = 0; x < 256; x++)
3416           values[x] = x;
3417      }
3418 
3419    return evas_filter_command_curve_add(ctx, dc, src->cid, dst->cid, values, channel);
3420 }
3421 
3422 static Evas_Filter_Command *
_instr2cmd_transform(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3423 _instr2cmd_transform(Evas_Filter_Context *ctx,
3424                      Evas_Filter_Instruction *instr, void *dc)
3425 {
3426    Evas_Filter_Transform_Flags flags;
3427    const char *op;
3428    Buffer *src, *dst;
3429    int ox = 0, oy;
3430 
3431    op = _instruction_param_gets(instr, "op", NULL);
3432    src = _instruction_param_getbuf(instr, "src", NULL);
3433    dst = _instruction_param_getbuf(instr, "dst", NULL);
3434    // ox = _instruction_param_geti(instr, "ox", NULL);
3435    oy = _instruction_param_geti(instr, "oy", NULL);
3436    INSTR_PARAM_CHECK(src);
3437    INSTR_PARAM_CHECK(dst);
3438 
3439    if (op && !strcasecmp(op, "vflip"))
3440      flags = EVAS_FILTER_TRANSFORM_VFLIP;
3441    else
3442      {
3443         ERR("Invalid transform '%s'", op);
3444         return NULL;
3445      }
3446 
3447    return evas_filter_command_transform_add(ctx, dc, src->cid, dst->cid, flags, ox, oy);
3448 }
3449 
3450 static Evas_Filter_Command *
_instr2cmd_grayscale(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3451 _instr2cmd_grayscale(Evas_Filter_Context *ctx,
3452                      Evas_Filter_Instruction *instr, void *dc)
3453 {
3454    Buffer *src, *dst;
3455 
3456    src = _instruction_param_getbuf(instr, "src", NULL);
3457    dst = _instruction_param_getbuf(instr, "dst", NULL);
3458    INSTR_PARAM_CHECK(src);
3459    INSTR_PARAM_CHECK(dst);
3460 
3461    return evas_filter_command_grayscale_add(ctx, dc, src->cid, dst->cid);
3462 }
3463 
3464 static Evas_Filter_Command *
_instr2cmd_inverse_color(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3465 _instr2cmd_inverse_color(Evas_Filter_Context *ctx,
3466                          Evas_Filter_Instruction *instr, void *dc)
3467 {
3468    Buffer *src, *dst;
3469 
3470    src = _instruction_param_getbuf(instr, "src", NULL);
3471    dst = _instruction_param_getbuf(instr, "dst", NULL);
3472    INSTR_PARAM_CHECK(src);
3473    INSTR_PARAM_CHECK(dst);
3474 
3475    return evas_filter_command_inverse_color_add(ctx, dc, src->cid, dst->cid);
3476 }
3477 
3478 static Eina_Bool
_command_from_instruction(Evas_Filter_Context * ctx,Evas_Filter_Instruction * instr,void * dc)3479 _command_from_instruction(Evas_Filter_Context *ctx,
3480                           Evas_Filter_Instruction *instr, void *dc)
3481 {
3482    Evas_Filter_Command * (* instr2cmd) (Evas_Filter_Context *, Evas_Filter_Instruction *, void *);
3483    Evas_Filter_Command *cmd;
3484 
3485    switch (instr->type)
3486      {
3487       case EVAS_FILTER_MODE_BLEND:
3488         instr2cmd = _instr2cmd_blend;
3489         break;
3490       case EVAS_FILTER_MODE_BLUR:
3491         instr2cmd = _instr2cmd_blur;
3492         break;
3493       case EVAS_FILTER_MODE_BUMP:
3494         instr2cmd = _instr2cmd_bump;
3495         break;
3496       case EVAS_FILTER_MODE_DISPLACE:
3497         instr2cmd = _instr2cmd_displace;
3498         break;
3499       case EVAS_FILTER_MODE_FILL:
3500         instr2cmd = _instr2cmd_fill;
3501         break;
3502       case EVAS_FILTER_MODE_GROW:
3503         instr2cmd = _instr2cmd_grow;
3504         break;
3505       case EVAS_FILTER_MODE_MASK:
3506         instr2cmd = _instr2cmd_mask;
3507         break;
3508       case EVAS_FILTER_MODE_CURVE:
3509         instr2cmd = _instr2cmd_curve;
3510         break;
3511       case EVAS_FILTER_MODE_TRANSFORM:
3512         instr2cmd = _instr2cmd_transform;
3513         break;
3514       case EVAS_FILTER_MODE_GRAYSCALE:
3515         instr2cmd = _instr2cmd_grayscale;
3516         break;
3517       case EVAS_FILTER_MODE_INVERSE_COLOR:
3518         instr2cmd = _instr2cmd_inverse_color;
3519         break;
3520       case EVAS_FILTER_MODE_PADDING_SET:
3521       case EVAS_FILTER_MODE_BUFFER:
3522         return EINA_TRUE;
3523       default:
3524         CRI("Invalid instruction type: %d", instr->type);
3525         return EINA_FALSE;
3526      }
3527 
3528    cmd = instr2cmd(ctx, instr, dc);
3529    if (!cmd) return EINA_FALSE;
3530 
3531    if (cmd->output)
3532      cmd->output->is_render = EINA_TRUE;
3533 
3534    return EINA_TRUE;
3535 }
3536 
3537 #ifdef FILTERS_DEBUG
3538 static void
_instruction_dump(Evas_Filter_Instruction * instr)3539 _instruction_dump(Evas_Filter_Instruction *instr)
3540 {
3541    Eina_Strbuf *str;
3542    const char *comma = "";
3543    Instruction_Param *param;
3544 
3545    if (!instr) return;
3546 
3547    str = eina_strbuf_new();
3548    eina_strbuf_append(str, instr->name);
3549    eina_strbuf_append(str, "({ ");
3550    EINA_INLIST_FOREACH(instr->params, param)
3551      {
3552         switch (param->type)
3553           {
3554            case VT_BOOL:
3555            case VT_INT:
3556              eina_strbuf_append_printf(str, "%s%s = %d", comma, param->name, param->value.i);
3557              break;
3558            case VT_COLOR:
3559              eina_strbuf_append_printf(str, "%s%s = 0x%08x", comma, param->name, param->value.c);
3560              break;
3561            case VT_REAL:
3562              eina_strbuf_append_printf(str, "%s%s = %f", comma, param->name, param->value.f);
3563              break;
3564            case VT_STRING:
3565              if (param->value.s)
3566                eina_strbuf_append_printf(str, "%s%s = \"%s\"", comma, param->name, param->value.s);
3567              else
3568                eina_strbuf_append_printf(str, "%s%s = nil", comma, param->name);
3569              break;
3570            case VT_BUFFER:
3571              if (param->value.buf)
3572                {
3573                   Buffer *buf = param->value.buf;
3574                   eina_strbuf_append_printf(str, "%s%s = Buffer[#%d %dx%d %s%s%s]",
3575                                             comma, param->name,
3576                                             buf->cid, buf->w, buf->h,
3577                                             buf->alpha ? "alpha" : "rgba",
3578                                             buf->proxy ? " src: " : "",
3579                                             buf->proxy ? buf->proxy : "");
3580                }
3581              else
3582                eina_strbuf_append_printf(str, "%s%s = nil", comma, param->name);
3583              break;
3584            case VT_NONE:
3585            default:
3586              eina_strbuf_append_printf(str, "%s%s = <INVALID>", comma, param->name);
3587              break;
3588           }
3589 
3590         comma = ", ";
3591      }
3592    eina_strbuf_append(str, "})");
3593    XDBG("%s", eina_strbuf_string_get(str));
3594    eina_strbuf_free(str);
3595 }
3596 #else
3597 # define _instruction_dump(a) do {} while(0)
3598 #endif
3599 
3600 Eina_Bool
evas_filter_context_program_use(void * engine,void * output,Evas_Filter_Context * ctx,Evas_Filter_Program * pgm,Eina_Bool reuse,int object_x,int object_y)3601 evas_filter_context_program_use(void *engine, void *output,
3602                                 Evas_Filter_Context *ctx,
3603                                 Evas_Filter_Program *pgm,
3604                                 Eina_Bool reuse, int object_x, int object_y)
3605 {
3606    Evas_Filter_Instruction *instr;
3607    Eina_Bool success = EINA_FALSE;
3608    void *dc = NULL;
3609 
3610    EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, EINA_FALSE);
3611    EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
3612    EINA_SAFETY_ON_FALSE_RETURN_VAL(pgm->valid, EINA_FALSE);
3613 
3614    XDBG("Using program '%s' for context %p", pgm->name, ctx);
3615 
3616    if (reuse) _evas_filter_context_program_reuse(engine, output, ctx);
3617 
3618    // Copy current state (size, edje state val, color class, etc...)
3619    ctx->w = pgm->state.w;
3620    ctx->h = pgm->state.h;
3621    ctx->x = object_x;
3622    ctx->y = object_y;
3623 
3624    // Create empty context with all required buffers
3625    evas_filter_context_clear(ctx, reuse);
3626 
3627    if (pgm->changed)
3628      {
3629         pgm->changed = EINA_FALSE;
3630         _filter_program_reset(pgm);
3631         lua_getglobal(pgm->L, _lua_errfunc_name);
3632         lua_rawgeti(pgm->L, LUA_REGISTRYINDEX, pgm->lua_func);
3633         success = !lua_pcall(pgm->L, 0, LUA_MULTRET, -2);
3634         if (!success)
3635           {
3636              const char *msg = lua_tostring(pgm->L, -1);
3637              ERR("Lua execution failed: %s", msg);
3638              goto end;
3639           }
3640      }
3641 
3642    // Create or update all buffers
3643    if (!_buffers_update(ctx, pgm)) goto end;
3644 
3645    // Compute and save padding info
3646    evas_filter_program_padding_get(pgm, &ctx->pad.final, &ctx->pad.calculated);
3647 
3648    dc = ENFN->context_new(engine);
3649    ENFN->context_color_set(engine, dc, 255, 255, 255, 255);
3650 
3651    // Apply all commands
3652    EINA_INLIST_FOREACH(pgm->instructions, instr)
3653      {
3654         _instruction_dump(instr);
3655         if (!_command_from_instruction(ctx, instr, dc))
3656           goto end;
3657      }
3658 
3659    success = EINA_TRUE;
3660    pgm->changed = EINA_FALSE;
3661 
3662 end:
3663    if (!success) evas_filter_context_clear(ctx, EINA_FALSE);
3664    if (dc) ENFN->context_free(engine, dc);
3665    return success;
3666 }
3667 
3668 void
evas_filter_parser_shutdown(void)3669 evas_filter_parser_shutdown(void)
3670 {
3671    free(_lua_color_code);
3672    _lua_color_code = NULL;
3673 }
3674