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