2013-12-09 03:20:33 -08:00
# include <stdarg.h>
2014-04-11 01:10:52 -07:00
# include <lua.h>
# include <lualib.h>
# include <lauxlib.h>
2015-06-03 03:59:11 -07:00
# include "evas_filter_private.h"
2014-04-11 01:10:52 -07:00
# if LUA_VERSION_NUM == 502
# define LUA52 1
# endif
2014-06-10 18:00:44 -07:00
# define FILTERS_LEGACY_COMPAT
2014-04-15 20:20:09 -07:00
2014-01-01 22:57:44 -08:00
# define EVAS_FILTER_MODE_GROW (EVAS_FILTER_MODE_LAST+1)
2014-04-11 01:10:52 -07:00
# define EVAS_FILTER_MODE_BUFFER (EVAS_FILTER_MODE_LAST+2)
2015-05-26 03:37:21 -07:00
# define INSTR_PARAM_CHECK(a) do { if (!(a)) { \
ERR ( " Argument %s can not be nil in %s! " , # a , instr - > name ) ; return - 1 ; } \
} while ( 0 )
2014-02-10 22:56:31 -08:00
/* Note on the documentation:
* To keep it simple , I ' m not using any fancy features , only < ul > / < li > lists
* and @ a , @ b , @ c flags from Doxygen .
* Let ' s keep it that way .
*
* This is a REFERENCE documentation , not supposed to contain tons of examples ,
* but each filter command should have one simple copy and pasteable example .
*/
/**
@ page evasfiltersref Evas filters reference
The Evas filters are a combination of filters used to apply specific effects
to an @ ref Evas_Object " Evas Object " . For the moment , these effects are
specific to the @ ref Evas_Object_Text " Text Objects " .
2014-05-08 21:53:04 -07:00
The filters can be applied to an object using simple Lua scripts . A script
will contain a series of buffer declarations and filter commands to apply
to these buffers . The Lua programming language reference can be found
< a href = " http://www.lua.org/manual/5.1/manual.html " > here < / a > .
2014-02-10 22:56:31 -08:00
Basically , when applying an effect to a @ ref Evas_Object_Text " Text Object " ,
an alpha - only @ c input buffer is created , where the text is rendered , and
an RGBA @ c output buffer is created , where the text with effects shall be
finally rendered .
2014-05-08 21:53:04 -07:00
The script language being Lua , it respects the usual Lua syntax and concepts .
As these are simple filters , the scripts should be kept as small and simple
as possible .
Note : Lua has been used since 1.10 . The previous filters syntax is not
garanteed to be compatible with 1.10 and newer versions .
2014-02-10 22:56:31 -08:00
Here are the available commands :
< ul >
< li > @ ref sec_syntax " Syntax " < / li >
< li > @ ref sec_buffers " Buffer management " < / li >
< ul >
< li > @ ref sec_buffers_cspace " Colorspaces " < / li >
< li > @ ref sec_buffers_auto " Automatic buffers " < / li >
2014-05-08 21:53:04 -07:00
< li > @ ref sec_buffers_cmd " @c buffer command " < / li >
2014-02-10 22:56:31 -08:00
< / ul >
< li > @ ref sec_commands " Commands " < / li >
< ul >
2014-05-08 21:53:04 -07:00
< li > @ ref sec_commands_blend " @c blend command " < / li >
< li > @ ref sec_commands_blur " @c blur command " < / li >
< li > @ ref sec_commands_grow " @c grow command " < / li >
< li > @ ref sec_commands_curve " @c curve command " < / li >
< li > @ ref sec_commands_fill " @c fill command " < / li >
< li > @ ref sec_commands_mask " @c mask command " < / li >
< li > @ ref sec_commands_bump " @c bump command " < / li >
< li > @ ref sec_commands_displace " @c displace command " < / li >
< li > @ ref sec_commands_transform " @c transform command " < / li >
2014-02-10 22:56:31 -08:00
< / ul >
< / ul >
All the examples in this page can ( should ) be directly used in
@ ref evas_obj_text_filter_program_set .
Note that most of the text effects work better with larger font sizes ( > 50 px ) ,
2014-05-08 21:53:04 -07:00
and so do the examples in this page ( embedded devices in mind ) .
2014-02-10 22:56:31 -08:00
*/
/**
@ page evasfiltersref
@ section sec_syntax Syntax
Here is a simple example illustrating the syntax :
2014-05-08 21:53:04 -07:00
@ verbinclude filter_example_1 . lua
2014-02-10 22:56:31 -08:00
This example will display a cyan and dark blue glow surrounding the
main text ( its color depends on the object ' s theme ) .
2014-02-12 22:28:46 -08:00
< center >
@ image html filter_example_1 . png
< / center >
2014-02-10 22:56:31 -08:00
The syntax is pretty simple and follows a small set of rules :
< ul >
< li > All dimensions are in pixels < / li >
< li > The commands will be executed in sequential order < / li >
< li > Most commands have default values < / li >
2014-05-08 21:53:04 -07:00
< li > A command argument can either be set by name , or sequentially omitting the name . So that : < br >
@ verbatim function ( arg1 , arg2 , arg3 ) @ endverbatim < / li >
< li > is equivalent to : < br >
@ verbatim function ( { arg1 , arg2 , arg2 } ) @ endverbatim < / li >
< li > or even ( considering opt1 , opt2 and opt3 are the first 3 arguments ) : < br >
@ verbatim function ( { opt1 = arg1 , opt2 = arg2 , opt3 = arg3 } ) @ endverbatim < / li >
< li > and since this is Lua , we can also write it as : < br >
@ verbatim function { arg1 , opt3 = arg3 , opt2 = arg2 } @ endverbatim < / li >
< li > Boolean values are @ c true / @ c false but 1 / 0 and special string values are also accepted : ' yes ' / ' no ' , ' enabled ' / ' disabled ' < / li >
2014-02-10 22:56:31 -08:00
< / ul >
< h3 > Special keywords and their values < / h3 >
Some options accept a certain set of values ( like enums ) :
< ul >
2014-05-08 21:53:04 -07:00
< li > @ c color < / li >
2014-02-10 22:56:31 -08:00
@ anchor evasfilters_color
< ul >
2014-05-08 21:53:04 -07:00
< li > Colors can be referred to by strings or integers : < / li >
< li > An integer can refer to any RGB or ARGB values :
@ c 0 xRRGGBB or @ c 0xAA RRGGBB . If alpha is zero , the color
will be opaque ( alpha = @ c 0xFF ) , unless R = G = B = 0 ( invisible ) .
These colors are < b > not < / b > premultiplied .
< / li >
< li > Hexademical values : @ c ' # RRGGBB ' , @ c ' # RRGGBBAA ' , @ c ' # RGB ' , @ c ' # RGBA ' < / li >
< li > The following string values are also accepted : < / li >
< tt > < ul >
< li > ' white ' = = ' # FFFFFF ' < / li >
< li > ' black ' = = ' # 000000 ' < / li >
< li > ' red ' = = ' # FF0000 ' < / li >
< li > ' green ' = = ' # 00 8000 ' < / li >
< li > ' blue ' = = ' # 0000FF ' < / li >
< li > ' darkblue ' = = ' # 0000 A0 ' < / li >
< li > ' yellow ' = = ' # FFFF00 ' < / li >
< li > ' magenta ' = = ' # FF00FF ' < / li >
< li > ' cyan ' = = ' # 00FF FF ' < / li >
< li > ' orange ' = = ' # FFA500 ' < / li >
< li > ' purple ' = = ' # 800080 ' < / li >
< li > ' brown ' = = ' # A52A2A ' < / li >
< li > ' maroon ' = = ' # 800000 ' < / li >
< li > ' lime ' = = ' # 00FF 00 ' < / li >
< li > ' gray ' = = ' # 808080 ' < / li >
< li > ' grey ' = = ' # 808080 ' < / li >
< li > ' silver ' = = ' # C0C0C0 ' < / li >
< li > ' olive ' = = ' # 808000 ' < / li >
< li > ' invisible ' , ' transparent ' = = ' # 0000 ' - - ( alpha is zero ) < / li >
< / ul > < / tt >
2014-02-10 22:56:31 -08:00
< / ul >
2014-05-08 21:53:04 -07:00
< li > @ c fillmode < / li >
2014-02-17 02:49:48 -08:00
@ anchor evasfilter_fillmode
2014-05-08 21:53:04 -07:00
< tt > < ul >
< li > ' none ' < / li >
< li > ' stretch_x ' < / li >
< li > ' stretch_y ' < / li >
< li > ' repeat_x ' < / li >
< li > ' repeat_y ' < / li >
< li > ' repeat_x_stretch_y ' , ' stretch_y_repeat_x ' < / li >
< li > ' repeat_y_stretch_x ' , ' stretch_x_repeat_y ' < / li >
< li > ' repeat ' , ' repeat_xy ' < / li >
< li > ' stretch ' , ' stretch_xy ' < / li >
< / ul > < / tt >
2014-02-10 22:56:31 -08:00
< / ul >
*/
/**
@ page evasfiltersref
@ section sec_buffers Buffer management
The Evas filters subsystem is based on the concept of using various
buffers as image layers and drawing or applying filters to these buffers .
2014-05-08 21:53:04 -07:00
Think of it as how image drawing tools like The Gimp can combine multiple
layers and apply operations on them .
2014-02-10 22:56:31 -08:00
Most of the buffers are allocated automatically at runtime , depending on the
various inputs and commands used ( eg . 2 - D blur will require a temporary
intermediate buffer ) .
@ subsection sec_buffers_cspace Colorspaces and size
The buffers ' size will be automatically defined at runtime , based on the
content of the input and the series of operations to apply ( eg . blur adds
some necessary margins ) .
The buffers can be either ALPHA ( 1 color channel only ) or RGBA ( full color ) .
Some operations might require specifically an ALPHA buffer , some others RGBA .
Most buffers will have the same size , except those specified by an external
source .
@ subsection sec_buffers_auto Automatic buffers
The two most important buffers , input and output , are statically defined and
always present when running a filter . input is an ALPHA buffer , containing
the @ ref Evas_Object_Text " Text Object " ' s rendered text , and output is the
final target on which to render as RGBA .
Some operations , like 2 - D blur might require temporary intermediate buffers ,
that will be allocated automatically . Those buffers are internal only and
can ' t be used from the script .
Finally , if a buffer is created using another Evas Object as source ( see
@ ref sec_buffers_cmd " buffer " for more details ) , its pixel data will be filled
by rendering the Evas Object into this buffer . This is how it will be
possible to load external images , textures and even animations into a buffer .
@ since 1.9
*/
2013-12-30 23:01:06 -08:00
static struct
{
const char * name ;
Evas_Filter_Fill_Mode value ;
} fill_modes [ ] =
{
{ " none " , EVAS_FILTER_FILL_MODE_NONE } ,
{ " stretch_x " , EVAS_FILTER_FILL_MODE_STRETCH_X } ,
{ " stretch_y " , EVAS_FILTER_FILL_MODE_STRETCH_Y } ,
{ " repeat_x " , EVAS_FILTER_FILL_MODE_REPEAT_X } ,
{ " repeat_y " , EVAS_FILTER_FILL_MODE_REPEAT_Y } ,
{ " repeat_x_stretch_y " , EVAS_FILTER_FILL_MODE_REPEAT_X_STRETCH_Y } ,
{ " repeat_y_stretch_x " , EVAS_FILTER_FILL_MODE_REPEAT_Y_STRETCH_X } ,
2014-01-22 23:54:50 -08:00
{ " stretch_y_repeat_x " , EVAS_FILTER_FILL_MODE_REPEAT_X_STRETCH_Y } , // alias
{ " stretch_x_repeat_y " , EVAS_FILTER_FILL_MODE_REPEAT_Y_STRETCH_X } , // alias
2013-12-30 23:01:06 -08:00
{ " repeat " , EVAS_FILTER_FILL_MODE_REPEAT_XY } , // alias
{ " repeat_xy " , EVAS_FILTER_FILL_MODE_REPEAT_XY } ,
{ " stretch " , EVAS_FILTER_FILL_MODE_STRETCH_XY } , // alias
{ " stretch_xy " , EVAS_FILTER_FILL_MODE_STRETCH_XY }
} ;
2015-06-04 03:42:38 -07:00
static const char * _lua_buffer_meta = " buffer " ;
static const char * _lua_color_meta = " color " ;
# define _lua_methods_table "__methods"
# define _lua_register_func "__register"
# define _lua_errfunc_name "__backtrace"
2015-05-18 05:04:29 -07:00
2014-03-24 20:27:21 -07:00
static Evas_Filter_Fill_Mode _fill_mode_get ( Evas_Filter_Instruction * instr ) ;
2015-06-04 03:42:38 -07:00
static Eina_Bool _lua_instruction_run ( lua_State * L , Evas_Filter_Instruction * instr ) ;
static int _lua_backtrace ( lua_State * L ) ;
2014-03-24 20:27:21 -07:00
2013-12-09 03:20:33 -08:00
typedef enum
{
VT_NONE ,
VT_BOOL ,
VT_INT ,
VT_REAL ,
VT_STRING ,
VT_COLOR ,
2015-05-27 22:37:10 -07:00
VT_BUFFER ,
VT_SPECIAL
2013-12-09 03:20:33 -08:00
} Value_Type ;
typedef struct _Buffer
{
EINA_INLIST ;
Eina_Stringshare * name ;
Eina_Stringshare * proxy ;
int cid ; // Transient value
2013-12-12 23:21:59 -08:00
struct {
int l , r , t , b ; // Used for padding calculation. Can change over time.
} pad ;
2015-05-18 01:35:49 -07:00
int w , h ;
2013-12-09 03:20:33 -08:00
Eina_Bool alpha : 1 ;
2015-05-26 03:37:21 -07:00
Eina_Bool manual : 1 ; // created by "buffer" instruction
2013-12-09 03:20:33 -08:00
} Buffer ;
2015-05-27 22:37:10 -07:00
typedef struct _Instruction_Param Instruction_Param ;
struct _Instruction_Param
2013-12-09 03:20:33 -08:00
{
EINA_INLIST ;
Eina_Stringshare * name ;
Value_Type type ;
2015-05-18 05:04:29 -07:00
union {
Eina_Bool b ;
int i ;
double f ;
char * s ;
unsigned int c ;
Buffer * buf ;
2015-05-27 22:37:10 -07:00
struct {
void * data ;
Eina_Bool ( * func ) ( lua_State * L , int i , Evas_Filter_Program * , Evas_Filter_Instruction * , Instruction_Param * ) ;
} special ;
2015-05-18 05:04:29 -07:00
} value ;
2013-12-09 03:20:33 -08:00
Eina_Bool set : 1 ;
Eina_Bool allow_seq : 1 ;
2014-01-01 22:57:44 -08:00
Eina_Bool allow_any_string : 1 ;
2015-05-27 22:37:10 -07:00
} ;
2013-12-09 03:20:33 -08:00
struct _Evas_Filter_Instruction
{
EINA_INLIST ;
Eina_Stringshare * name ;
2014-04-11 01:10:52 -07:00
int /*Evas_Filter_Mode*/ type ;
2013-12-09 03:20:33 -08:00
Eina_Inlist /* Instruction_Param */ * params ;
2014-04-11 01:10:52 -07:00
int return_count ;
Eina_Bool ( * parse_run ) ( lua_State * L , Evas_Filter_Program * , Evas_Filter_Instruction * ) ;
2013-12-09 03:20:33 -08:00
struct
{
2015-05-26 03:37:21 -07:00
int ( * update ) ( Evas_Filter_Program * , Evas_Filter_Instruction * , int * , int * , int * , int * ) ;
2013-12-09 03:20:33 -08:00
} pad ;
Eina_Bool valid : 1 ;
} ;
2015-05-26 03:37:21 -07:00
struct _Evas_Filter_Program_State
{
struct {
struct { int a , r , g , b ; } outline ;
struct { int a , r , g , b ; } shadow ;
struct { int a , r , g , b ; } glow ;
struct { int a , r , g , b ; } glow2 ;
} text ;
2015-05-28 01:59:59 -07:00
struct {
int a , r , g , b ;
} color ;
struct {
const char * name ;
double value ;
} cur ;
struct {
const char * name ;
double value ;
} next ;
2015-05-26 03:37:21 -07:00
int w , h ;
2015-05-27 23:59:10 -07:00
double scale ;
2015-05-28 01:59:59 -07:00
double pos ;
2015-05-26 03:37:21 -07:00
} ;
2013-12-09 03:20:33 -08:00
struct _Evas_Filter_Program
{
Eina_Stringshare * name ; // Optional for now
2014-02-05 03:09:05 -08:00
Eina_Hash /* const char * : Evas_Filter_Proxy_Binding */ * proxies ;
2013-12-09 03:20:33 -08:00
Eina_Inlist /* Evas_Filter_Instruction */ * instructions ;
Eina_Inlist /* Buffer */ * buffers ;
2014-03-20 19:52:52 -07:00
struct {
2015-05-26 03:37:21 -07:00
// Note: padding can't be in the state as it's calculated after running Lua
2014-03-20 19:52:52 -07:00
int l , r , t , b ;
} pad ;
2015-05-26 03:37:21 -07:00
Evas_Filter_Program_State state ;
2015-06-23 00:40:51 -07:00
Eina_Inlist * data ; // Evas_Filter_Data_Binding
2015-05-18 01:35:49 -07:00
lua_State * L ;
2015-05-26 00:12:00 -07:00
int lua_func ;
2015-05-26 03:37:21 -07:00
int last_bufid ;
2013-12-09 03:20:33 -08:00
Eina_Bool valid : 1 ;
2014-03-20 19:52:52 -07:00
Eina_Bool padding_calc : 1 ; // Padding has been calculated
Eina_Bool padding_set : 1 ; // Padding has been forced
2015-05-18 01:35:49 -07:00
Eina_Bool changed : 1 ; // State (w,h) changed, needs re-run of Lua
2015-05-18 05:04:29 -07:00
Eina_Bool input_alpha : 1 ;
2013-12-09 03:20:33 -08:00
} ;
/* Instructions */
static Evas_Filter_Instruction *
_instruction_new ( const char * name )
{
Evas_Filter_Instruction * instr ;
instr = calloc ( 1 , sizeof ( Evas_Filter_Instruction ) ) ;
instr - > name = eina_stringshare_add ( name ) ;
return instr ;
}
static Eina_Bool
_instruction_param_addv ( Evas_Filter_Instruction * instr , const char * name ,
2013-12-11 02:35:24 -08:00
Value_Type format , Eina_Bool sequential , va_list args )
2013-12-09 03:20:33 -08:00
{
Instruction_Param * param ;
2015-05-18 05:04:29 -07:00
char * s ;
2013-12-09 03:20:33 -08:00
2015-05-18 05:04:29 -07:00
param = calloc ( 1 , sizeof ( Instruction_Param ) ) ;
param - > name = eina_stringshare_add ( name ) ;
param - > type = format ;
2013-12-09 03:20:33 -08:00
switch ( format )
{
case VT_BOOL :
2015-05-18 05:04:29 -07:00
param - > value . b = ( va_arg ( args , unsigned int ) ! = 0 ) ;
break ;
2013-12-09 03:20:33 -08:00
case VT_INT :
2015-05-18 05:04:29 -07:00
param - > value . i = va_arg ( args , int ) ;
2013-12-09 03:20:33 -08:00
break ;
case VT_REAL :
2015-05-18 05:04:29 -07:00
param - > value . f = va_arg ( args , double ) ;
2013-12-09 03:20:33 -08:00
break ;
case VT_STRING :
2015-05-18 05:04:29 -07:00
s = va_arg ( args , char * ) ;
param - > value . s = s ? strdup ( s ) : NULL ;
break ;
2013-12-09 03:20:33 -08:00
case VT_BUFFER :
2015-05-18 05:04:29 -07:00
param - > value . buf = va_arg ( args , Buffer * ) ;
2013-12-09 03:20:33 -08:00
break ;
case VT_COLOR :
2015-05-18 05:04:29 -07:00
param - > value . c = va_arg ( args , DATA32 ) ;
2013-12-09 03:20:33 -08:00
break ;
2015-05-27 22:37:10 -07:00
case VT_SPECIAL :
param - > value . special . func = va_arg ( args , typeof ( param - > value . special . func ) ) ;
param - > value . special . data = va_arg ( args , void * ) ;
break ;
2013-12-09 03:20:33 -08:00
case VT_NONE :
default :
2015-07-24 09:51:42 -07:00
free ( param ) ;
2013-12-09 03:20:33 -08:00
return EINA_FALSE ;
}
param - > allow_seq = sequential ;
instr - > params = eina_inlist_append ( instr - > params , EINA_INLIST_GET ( param ) ) ;
return EINA_TRUE ;
}
static Eina_Bool
_instruction_param_adda ( Evas_Filter_Instruction * instr , const char * name ,
2013-12-11 02:35:24 -08:00
Value_Type format , Eina_Bool sequential ,
/* default value */ . . . )
2013-12-09 03:20:33 -08:00
{
Eina_Bool ok ;
va_list args ;
va_start ( args , sequential ) ;
ok = _instruction_param_addv ( instr , name , format , sequential , args ) ;
va_end ( args ) ;
return ok ;
}
2015-05-27 22:37:10 -07:00
# define _instruction_param_seq_add(a,b,c,...) _instruction_param_adda((a),(b),(c),1,__VA_ARGS__)
# define _instruction_param_name_add(a,b,c,...) _instruction_param_adda((a),(b),(c),0,__VA_ARGS__)
2013-12-09 03:20:33 -08:00
static void
_instruction_del ( Evas_Filter_Instruction * instr )
{
Instruction_Param * param ;
if ( ! instr ) return ;
EINA_INLIST_FREE ( instr - > params , param )
{
2015-05-18 05:04:29 -07:00
if ( param - > type = = VT_STRING )
free ( param - > value . s ) ;
2015-05-27 22:37:10 -07:00
else if ( param - > type = = VT_SPECIAL )
free ( param - > value . special . data ) ;
2013-12-09 03:20:33 -08:00
eina_stringshare_del ( param - > name ) ;
instr - > params = eina_inlist_remove ( instr - > params , EINA_INLIST_GET ( param ) ) ;
free ( param ) ;
}
eina_stringshare_del ( instr - > name ) ;
free ( instr ) ;
}
2014-04-11 01:10:52 -07:00
static Instruction_Param *
_instruction_param_get ( Evas_Filter_Instruction * instr , const char * name )
{
Instruction_Param * param ;
EINA_INLIST_FOREACH ( instr - > params , param )
if ( ! strcasecmp ( name , param - > name ) )
return param ;
return NULL ;
}
2013-12-09 03:20:33 -08:00
static int
_instruction_param_geti ( Evas_Filter_Instruction * instr , const char * name ,
Eina_Bool * isset )
{
Instruction_Param * param ;
EINA_INLIST_FOREACH ( instr - > params , param )
2013-12-11 02:35:24 -08:00
if ( ! strcasecmp ( name , param - > name ) )
2013-12-09 03:20:33 -08:00
{
2015-05-18 05:04:29 -07:00
if ( isset ) * isset = param - > set ;
return param - > value . i ;
2013-12-09 03:20:33 -08:00
}
if ( isset ) * isset = EINA_FALSE ;
return - 1 ;
}
static double
_instruction_param_getd ( Evas_Filter_Instruction * instr , const char * name ,
Eina_Bool * isset )
{
Instruction_Param * param ;
EINA_INLIST_FOREACH ( instr - > params , param )
2013-12-11 02:35:24 -08:00
if ( ! strcasecmp ( name , param - > name ) )
2013-12-09 03:20:33 -08:00
{
2015-05-18 05:04:29 -07:00
if ( isset ) * isset = param - > set ;
return param - > value . f ;
2013-12-09 03:20:33 -08:00
}
if ( isset ) * isset = EINA_FALSE ;
return 0.0 ;
}
static DATA32
_instruction_param_getc ( Evas_Filter_Instruction * instr , const char * name ,
Eina_Bool * isset )
{
Instruction_Param * param ;
EINA_INLIST_FOREACH ( instr - > params , param )
2013-12-11 02:35:24 -08:00
if ( ! strcasecmp ( name , param - > name ) )
2013-12-09 03:20:33 -08:00
{
2015-05-18 05:04:29 -07:00
if ( isset ) * isset = param - > set ;
return param - > value . c ;
2013-12-09 03:20:33 -08:00
}
if ( isset ) * isset = EINA_FALSE ;
return 0 ;
}
2015-05-27 22:37:10 -07:00
static void *
_instruction_param_getspecial ( Evas_Filter_Instruction * instr , const char * name ,
Eina_Bool * isset )
{
Instruction_Param * param ;
EINA_INLIST_FOREACH ( instr - > params , param )
if ( ! strcasecmp ( name , param - > name ) )
{
if ( isset ) * isset = param - > set ;
return param - > value . special . data ;
}
if ( isset ) * isset = EINA_FALSE ;
return 0 ;
}
2013-12-09 03:20:33 -08:00
static const char *
_instruction_param_gets ( Evas_Filter_Instruction * instr , const char * name ,
Eina_Bool * isset )
{
Instruction_Param * param ;
EINA_INLIST_FOREACH ( instr - > params , param )
2013-12-11 02:35:24 -08:00
if ( ! strcasecmp ( name , param - > name ) )
2013-12-09 03:20:33 -08:00
{
2015-05-18 05:04:29 -07:00
if ( isset ) * isset = param - > set ;
return param - > value . s ;
}
if ( isset ) * isset = EINA_FALSE ;
return NULL ;
}
static Buffer *
_instruction_param_getbuf ( Evas_Filter_Instruction * instr , const char * name ,
Eina_Bool * isset )
{
Instruction_Param * param ;
EINA_INLIST_FOREACH ( instr - > params , param )
if ( ! strcasecmp ( name , param - > name ) )
{
if ( isset ) * isset = param - > set ;
return param - > value . buf ;
2013-12-09 03:20:33 -08:00
}
if ( isset ) * isset = EINA_FALSE ;
return NULL ;
}
static Eina_Bool
_bool_parse ( const char * str , Eina_Bool * b )
{
if ( ! str | | ! * str ) return EINA_FALSE ;
if ( ! strcmp ( str , " 1 " ) | |
! strcasecmp ( str , " yes " ) | |
! strcasecmp ( str , " on " ) | |
! strcasecmp ( str , " enable " ) | |
! strcasecmp ( str , " enabled " ) | |
! strcasecmp ( str , " true " ) )
{
if ( b ) * b = EINA_TRUE ;
return EINA_TRUE ;
}
else if ( ! strcmp ( str , " 0 " ) | |
! strcasecmp ( str , " no " ) | |
! strcasecmp ( str , " off " ) | |
! strcasecmp ( str , " disable " ) | |
! strcasecmp ( str , " disabled " ) | |
! strcasecmp ( str , " false " ) )
{
if ( b ) * b = EINA_FALSE ;
return EINA_TRUE ;
}
return EINA_FALSE ;
}
# define PARSE_ABORT() do {} while (0)
//#define PARSE_ABORT() abort()
# define PARSE_CHECK(a) do { if (!(a)) { ERR("Parsing failed because '%s' is false at %s:%d", #a, __FUNCTION__, __LINE__); PARSE_ABORT(); goto end; } } while (0)
/* Buffers */
static Buffer *
_buffer_get ( Evas_Filter_Program * pgm , const char * name )
{
Buffer * buf ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( pgm , NULL ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( name , NULL ) ;
EINA_INLIST_FOREACH ( pgm - > buffers , buf )
2015-06-24 22:43:05 -07:00
{
if ( ! strcmp ( buf - > name , name ) )
return buf ;
else if ( buf - > proxy & & ! strcmp ( buf - > proxy , name ) )
return buf ;
}
2013-12-09 03:20:33 -08:00
return NULL ;
}
static Eina_Bool
2015-05-18 05:04:29 -07:00
_lua_buffer_push ( lua_State * L , Buffer * buf )
{
Buffer * * ptr ;
2015-06-04 03:42:38 -07:00
lua_getglobal ( L , buf - > name ) ; //+1
ptr = lua_newuserdata ( L , sizeof ( Buffer * * ) ) ; //+1
2015-05-26 03:37:21 -07:00
* ptr = buf ;
2015-06-04 03:42:38 -07:00
luaL_getmetatable ( L , _lua_buffer_meta ) ; //+1
lua_setmetatable ( L , - 2 ) ; //-1
lua_setglobal ( L , buf - > name ) ; //-1
lua_pop ( L , 1 ) ;
2015-05-18 05:04:29 -07:00
return EINA_TRUE ;
}
2015-06-04 03:42:38 -07:00
// Begin of Lua metamethods and stuff
2015-05-18 05:04:29 -07:00
static int
_lua_buffer_tostring ( lua_State * L )
{
Buffer * buf , * * pbuf ;
pbuf = lua_touserdata ( L , 1 ) ;
buf = pbuf ? * pbuf : NULL ;
if ( ! buf )
lua_pushstring ( L , " nil " ) ;
else
lua_pushfstring ( L , " Buffer[#%d %dx%d %s%s%s] " , buf - > cid , buf - > w , buf - > h ,
buf - > alpha ? " alpha " : " rgba " ,
buf - > proxy ? " src: " : " " , buf - > proxy ? buf - > proxy : " " ) ;
return 1 ;
}
2015-05-27 18:12:18 -07:00
static int
_lua_buffer_index ( lua_State * L )
{
Buffer * buf , * * pbuf ;
const char * key ;
pbuf = lua_touserdata ( L , 1 ) ;
buf = pbuf ? * pbuf : NULL ;
if ( ! buf ) return 0 ;
key = lua_tostring ( L , 2 ) ;
if ( ! key ) return 0 ;
2015-06-04 03:42:38 -07:00
if ( ! strcmp ( key , " w " ) | | ! strcmp ( key , " width " ) )
2015-05-27 18:12:18 -07:00
{
lua_pushinteger ( L , buf - > w ) ;
return 1 ;
}
2015-06-04 03:42:38 -07:00
else if ( ! strcmp ( key , " h " ) | | ! strcmp ( key , " height " ) )
2015-05-27 18:12:18 -07:00
{
lua_pushinteger ( L , buf - > h ) ;
return 1 ;
}
else if ( ! strcmp ( key , " type " ) )
{
lua_pushstring ( L , buf - > alpha ? " alpha " : " rgba " ) ;
return 1 ;
}
else if ( ! strcmp ( key , " alpha " ) )
{
lua_pushboolean ( L , buf - > alpha ) ;
return 1 ;
}
else if ( ! strcmp ( key , " rgba " ) )
{
lua_pushboolean ( L , ! buf - > alpha ) ;
return 1 ;
}
else if ( ! strcmp ( key , " name " ) )
{
lua_pushstring ( L , buf - > name ) ;
return 1 ;
}
else if ( ! strcmp ( key , " source " ) )
{
if ( ! buf - > proxy ) return 0 ;
lua_pushstring ( L , buf - > proxy ) ;
return 1 ;
}
else
2015-06-04 03:42:38 -07:00
return luaL_error ( L , " Unknown index '%s' for a buffer " , key ) ;
2015-05-27 18:12:18 -07:00
2015-06-04 03:42:38 -07:00
return 0 ;
2015-05-18 05:04:29 -07:00
}
2015-06-04 03:42:38 -07:00
// remove metatable from first argument if this is a __call metafunction
static inline int
_lua_implicit_metatable_drop ( lua_State * L , const char * name )
2015-05-18 05:04:29 -07:00
{
2015-06-04 03:42:38 -07:00
int ret = 0 ;
if ( lua_istable ( L , 1 ) & & lua_getmetatable ( L , 1 ) )
{
luaL_getmetatable ( L , name ) ;
if ( lua_equal ( L , - 1 , - 2 ) )
{
lua_remove ( L , 1 ) ;
ret = 1 ;
}
lua_pop ( L , 2 ) ;
}
return ret ;
2015-05-18 05:04:29 -07:00
}
2015-06-04 03:42:38 -07:00
// End of all lua metamethods and stuff
2015-05-18 05:04:29 -07:00
static Buffer *
2013-12-09 03:20:33 -08:00
_buffer_add ( Evas_Filter_Program * pgm , const char * name , Eina_Bool alpha ,
2015-05-26 03:37:21 -07:00
const char * src , Eina_Bool manual )
2013-12-09 03:20:33 -08:00
{
Buffer * buf ;
if ( _buffer_get ( pgm , name ) )
{
ERR ( " Buffer '%s' already exists " , name ) ;
2015-05-18 05:04:29 -07:00
return NULL ;
2013-12-09 03:20:33 -08:00
}
if ( alpha & & src )
{
ERR ( " Can not set proxy buffer as alpha! " ) ;
2015-05-18 05:04:29 -07:00
return NULL ;
2013-12-09 03:20:33 -08:00
}
buf = calloc ( 1 , sizeof ( Buffer ) ) ;
2015-05-18 05:04:29 -07:00
if ( ! buf ) return NULL ;
2013-12-09 03:20:33 -08:00
2015-05-26 03:37:21 -07:00
buf - > manual = manual ;
if ( ! name )
{
char bufname [ 32 ] ;
snprintf ( bufname , sizeof ( bufname ) , " __buffer%02d " , + + pgm - > last_bufid ) ;
buf - > name = eina_stringshare_add ( bufname ) ;
}
else
buf - > name = eina_stringshare_add ( name ) ;
2013-12-09 03:20:33 -08:00
buf - > proxy = eina_stringshare_add ( src ) ;
buf - > alpha = alpha ;
2015-05-26 03:37:21 -07:00
buf - > w = pgm - > state . w ;
buf - > h = pgm - > state . h ;
2013-12-09 03:20:33 -08:00
pgm - > buffers = eina_inlist_append ( pgm - > buffers , EINA_INLIST_GET ( buf ) ) ;
2015-05-18 05:04:29 -07:00
_lua_buffer_push ( pgm - > L , buf ) ;
2013-12-09 03:20:33 -08:00
2015-05-18 05:04:29 -07:00
return buf ;
2013-12-09 03:20:33 -08:00
}
static void
_buffer_del ( Buffer * buf )
{
if ( ! buf ) return ;
eina_stringshare_del ( buf - > name ) ;
eina_stringshare_del ( buf - > proxy ) ;
free ( buf ) ;
}
2015-06-04 03:42:38 -07:00
static const int this_is_not_a_cat = 42 ;
static Evas_Filter_Program *
_lua_program_get ( lua_State * L )
{
Evas_Filter_Program * pgm ;
lua_pushlightuserdata ( L , ( void * ) & this_is_not_a_cat ) ;
lua_gettable ( L , LUA_REGISTRYINDEX ) ;
pgm = lua_touserdata ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
return pgm ;
}
2013-12-09 03:20:33 -08:00
/* Instruction definitions */
2014-04-11 01:10:52 -07:00
/**
@ page evasfiltersref
@ subsection sec_buffers_cmd Buffer command
Create a new buffer .
2014-05-08 21:53:04 -07:00
@ verbatim
name1 = buffer ( )
name2 = buffer ( " alpha " )
name3 = buffer ( " rgba " )
name4 = buffer ( { type = " rgba " } )
name5 = buffer ( { src = " partname " } )
@ endverbatim
2014-04-11 01:10:52 -07:00
@ param type Buffer type : @ c rgba ( default ) or @ c alpha
@ param src An optional source . If set , @ a type will be @ c rgba .
@ return A new buffer . This value must not be saved to a variable .
This creates a new named buffer , specify its colorspace or source . Possible options :
@ li @ c alpha : Create an alpha - only buffer ( 1 channel , no color )
@ li @ c rgba : Create an RGBA buffer ( 4 channels , full color )
@ li < tt > { src = " partname " } < / tt > : Use another < tt > Evas Object < / tt > as source for this
buffer ' s pixels . The name can either be an Edje part name or the one
specified in @ c evas_obj_text_filter_source_set .
If no option is given , an RGBA buffer will be created . All buffers have the
same size , unless they are based on an external source .
@ see evas_obj_text_filter_source_set
@ since 1.10
*/
static Eina_Bool
_buffer_instruction_parse_run ( lua_State * L ,
Evas_Filter_Program * pgm ,
Evas_Filter_Instruction * instr )
{
char bufname [ 32 ] = { 0 } ;
const char * src , * rgba ;
Eina_Bool ok , alpha = EINA_FALSE ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( pgm , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
// FIXME: Buffers are still referred to internally by name.
// This is pretty bad with the switch to Lua.
rgba = _instruction_param_gets ( instr , " type " , NULL ) ;
src = _instruction_param_gets ( instr , " src " , NULL ) ;
alpha = ( rgba & & ! strcasecmp ( rgba , " alpha " ) ) ;
2015-05-26 03:37:21 -07:00
snprintf ( bufname , sizeof ( bufname ) , " __buffer%02d " , + + pgm - > last_bufid ) ;
ok = ( _buffer_add ( pgm , bufname , alpha , src , EINA_TRUE ) ! = NULL ) ;
2014-04-11 01:10:52 -07:00
if ( ! ok ) return EINA_FALSE ;
2015-05-18 05:04:29 -07:00
lua_getglobal ( L , bufname ) ;
2014-04-11 01:10:52 -07:00
instr - > return_count = 1 ;
return ok ;
}
2015-06-04 03:42:38 -07:00
static int
_lua_buffer_new ( lua_State * L )
2014-04-11 01:10:52 -07:00
{
2015-06-04 03:42:38 -07:00
// Reuse old "buffer" instruction code
Evas_Filter_Program * pgm = _lua_program_get ( L ) ;
Evas_Filter_Instruction * instr ;
2014-04-11 01:10:52 -07:00
2015-06-04 03:42:38 -07:00
instr = _instruction_new ( _lua_buffer_meta ) ;
2014-04-11 01:10:52 -07:00
instr - > type = EVAS_FILTER_MODE_BUFFER ;
instr - > parse_run = _buffer_instruction_parse_run ;
2015-05-18 05:04:29 -07:00
_instruction_param_seq_add ( instr , " type " , VT_STRING , " rgba " ) ;
2015-06-15 22:50:43 -07:00
_instruction_param_seq_add ( instr , " src " , VT_STRING , NULL ) ;
2014-04-11 01:10:52 -07:00
2015-06-04 03:42:38 -07:00
// drop "buffer" metatable
_lua_implicit_metatable_drop ( L , _lua_buffer_meta ) ;
if ( ! _lua_instruction_run ( L , instr ) )
{
_instruction_del ( instr ) ;
return luaL_error ( L , " buffer instanciation failed " ) ;
}
else
{
pgm - > instructions = eina_inlist_append ( pgm - > instructions , EINA_INLIST_GET ( instr ) ) ;
}
return instr - > return_count ;
2014-04-11 01:10:52 -07:00
}
2015-05-26 03:37:21 -07:00
static int
_blend_padding_update ( Evas_Filter_Program * pgm EINA_UNUSED ,
Evas_Filter_Instruction * instr ,
2014-01-07 01:38:22 -08:00
int * padl , int * padr , int * padt , int * padb )
{
2014-03-24 20:27:21 -07:00
Evas_Filter_Fill_Mode fillmode ;
2015-05-26 03:37:21 -07:00
Buffer * src , * dst ;
2014-01-07 01:38:22 -08:00
int ox , oy , l = 0 , r = 0 , t = 0 , b = 0 ;
ox = _instruction_param_geti ( instr , " ox " , NULL ) ;
oy = _instruction_param_geti ( instr , " oy " , NULL ) ;
2015-05-26 03:37:21 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2014-01-07 01:38:22 -08:00
2014-03-24 20:27:21 -07:00
fillmode = _fill_mode_get ( instr ) ;
if ( fillmode & ( EVAS_FILTER_FILL_MODE_STRETCH_X | EVAS_FILTER_FILL_MODE_REPEAT_X ) ) ox = 0 ;
if ( fillmode & ( EVAS_FILTER_FILL_MODE_STRETCH_Y | EVAS_FILTER_FILL_MODE_REPEAT_Y ) ) oy = 0 ;
2015-05-26 03:37:21 -07:00
if ( ox < 0 ) l = ( - ox ) + src - > pad . l ;
else r = ox + src - > pad . r ;
2014-01-07 01:38:22 -08:00
2015-05-26 03:37:21 -07:00
if ( oy < 0 ) t = ( - oy ) + src - > pad . t ;
else b = oy + src - > pad . b ;
2014-01-07 01:38:22 -08:00
2015-05-26 03:37:21 -07:00
if ( dst - > pad . l < l ) dst - > pad . l = l ;
if ( dst - > pad . r < r ) dst - > pad . r = r ;
if ( dst - > pad . t < t ) dst - > pad . t = t ;
if ( dst - > pad . b < b ) dst - > pad . b = b ;
2014-01-07 01:38:22 -08:00
if ( padl ) * padl = l ;
if ( padr ) * padr = r ;
if ( padt ) * padt = t ;
if ( padb ) * padb = b ;
2015-05-26 03:37:21 -07:00
return 0 ;
2014-01-07 01:38:22 -08:00
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ section sec_commands Filter commands
@ page evasfiltersref
This section will present the various filter instructions , their syntax
and their effects .
*/
/**
@ page evasfiltersref
@ subsection sec_commands_blend Blend
Blend a buffer onto another . This is the simplest filter , as it just
renders one buffer on another , potentially using a color , an
offset and fill options .
2014-05-08 21:53:04 -07:00
@ verbatim
blend ( { src = input , dst = output , ox = 0 , oy = 0 , color = ' white ' , fillmode = ' none ' } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param src Source buffer to blend .
@ param dst Destination buffer for blending .
@ param ox X offset . Moves the buffer to the right ( ox > 0 ) or to the left ( ox < 0 ) by N pixels .
@ param oy Y offset . Moves the buffer to the bottom ( oy > 0 ) or to the top ( oy < 0 ) by N pixels .
2014-02-19 02:37:19 -08:00
@ param color A color to use for alpha to RGBA conversion . See @ ref evasfilters_color " colors " . < br >
2014-02-10 22:56:31 -08:00
If the input is an alpha buffer and the output is RGBA , this will
2014-02-19 02:37:19 -08:00
draw the buffer in this color . If both buffers are RGBA , this will
have no effect .
2014-02-17 02:49:48 -08:00
@ param fillmode Map the input onto the whole surface of the output by stretching or
repeating it . See @ ref evasfilter_fillmode " fillmodes " .
2014-02-10 22:56:31 -08:00
If @ a src is an alpha buffer and @ a dst is an RGBA buffer , then the @ a color option should be set .
2014-05-08 21:53:04 -07:00
@ verbinclude filter_blend . lua
2014-02-12 22:10:57 -08:00
< center >
@ image html filter_blend . png
< / center >
2014-02-10 22:56:31 -08:00
@ since 1.9
*/
2013-12-09 03:20:33 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_blend_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-09 03:20:33 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
2013-12-11 02:35:24 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " blend " ) , EINA_FALSE ) ;
2013-12-09 03:20:33 -08:00
instr - > type = EVAS_FILTER_MODE_BLEND ;
2014-01-07 01:38:22 -08:00
instr - > pad . update = _blend_padding_update ;
2015-05-18 05:04:29 -07:00
_instruction_param_seq_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
_instruction_param_seq_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2013-12-09 03:20:33 -08:00
_instruction_param_seq_add ( instr , " ox " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " oy " , VT_INT , 0 ) ;
_instruction_param_name_add ( instr , " color " , VT_COLOR , 0xFFFFFFFF ) ;
2013-12-31 00:51:09 -08:00
_instruction_param_name_add ( instr , " fillmode " , VT_STRING , " none " ) ;
2013-12-09 03:20:33 -08:00
return EINA_TRUE ;
}
2015-05-26 03:37:21 -07:00
static int
_blur_padding_update ( Evas_Filter_Program * pgm EINA_UNUSED ,
Evas_Filter_Instruction * instr ,
2013-12-12 23:21:59 -08:00
int * padl , int * padr , int * padt , int * padb )
2013-12-09 03:20:33 -08:00
{
2014-03-10 20:18:21 -07:00
Eina_Bool yset = EINA_FALSE ;
2014-03-11 02:21:46 -07:00
int rx , ry , ox , oy , l , r , t , b , count ;
2015-05-26 03:37:21 -07:00
const char * typestr ;
2014-03-11 02:21:46 -07:00
Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT ;
2015-05-26 03:37:21 -07:00
Buffer * src , * dst ;
2013-12-09 03:20:33 -08:00
rx = _instruction_param_geti ( instr , " rx " , NULL ) ;
ry = _instruction_param_geti ( instr , " ry " , & yset ) ;
2014-01-02 01:04:06 -08:00
ox = _instruction_param_geti ( instr , " ox " , NULL ) ;
oy = _instruction_param_geti ( instr , " oy " , NULL ) ;
2014-03-11 02:21:46 -07:00
count = _instruction_param_geti ( instr , " count " , NULL ) ;
typestr = _instruction_param_gets ( instr , " type " , NULL ) ;
2015-05-26 03:37:21 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2014-03-11 02:21:46 -07:00
if ( typestr & & ! strcasecmp ( typestr , " box " ) )
type = EVAS_FILTER_BLUR_BOX ;
2013-12-12 23:21:59 -08:00
2014-02-18 00:01:54 -08:00
if ( ! yset ) ry = rx ;
if ( rx < 0 ) rx = 0 ;
if ( ry < 0 ) ry = 0 ;
2014-03-11 02:21:46 -07:00
if ( type = = EVAS_FILTER_BLUR_BOX )
{
if ( count < 1 ) count = 1 ;
if ( count > 6 ) count = 3 ;
}
else
count = 1 ;
rx * = count ;
ry * = count ;
2015-05-26 03:37:21 -07:00
l = rx + src - > pad . l + ( ( ox < 0 ) ? ( - ox ) : 0 ) ;
r = rx + src - > pad . r + ( ( ox > 0 ) ? ox : 0 ) ;
t = ry + src - > pad . t + ( ( oy < 0 ) ? ( - oy ) : 0 ) ;
b = ry + src - > pad . b + ( ( oy > 0 ) ? oy : 0 ) ;
2014-02-18 00:01:54 -08:00
2015-05-26 03:37:21 -07:00
if ( dst - > pad . l < l ) dst - > pad . l = l ;
if ( dst - > pad . r < r ) dst - > pad . r = r ;
if ( dst - > pad . t < t ) dst - > pad . t = t ;
if ( dst - > pad . b < b ) dst - > pad . b = b ;
2014-02-18 00:01:54 -08:00
if ( padl ) * padl = l ;
if ( padr ) * padr = r ;
if ( padt ) * padt = t ;
if ( padb ) * padb = b ;
2015-05-26 03:37:21 -07:00
return 0 ;
2013-12-09 03:20:33 -08:00
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_blur Blur
Apply blur effect on a buffer ( box or gaussian ) .
2014-05-08 21:53:04 -07:00
@ verbatim
blur ( { rx = 3 , ry = nil , type = ' default ' , ox = 0 , oy = 0 , color = ' white ' , src = input , dst = output } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param rx X radius . Specifies the radius of the blurring kernel ( X direction ) .
@ param ry Y radius . Specifies the radius of the blurring kernel ( Y direction ) . If - 1 is used , then @ a ry = @ a rx .
2014-03-11 02:21:46 -07:00
@ param type Blur type to apply . One of @ c default , @ c box or @ c gaussian . See below for details about @ c default .
2014-02-10 22:56:31 -08:00
@ param ox X offset . Moves the buffer to the right ( @ a ox > 0 ) or to the left ( @ a ox < 0 ) by N pixels .
@ param oy Y offset . Moves the buffer to the bottom ( @ a oy > 0 ) or to the top ( @ a oy < 0 ) by N pixels .
2014-02-19 02:37:19 -08:00
@ param color A color to use for alpha to RGBA conversion . See @ ref evasfilters_color " colors " . < br >
2014-02-10 22:56:31 -08:00
If the input is an alpha buffer and the output is RGBA , this will
draw the buffer in this color .
@ param src Source buffer to blur .
@ param dst Destination buffer for blending .
2014-03-11 02:21:46 -07:00
@ param count Number of times to repeat the blur . Only valid with @ c box blur . Valid range is : 1 to 6.
The blur type @ c default is < b > recommended in all situations < / b > as it will select the smoothest
and fastest operation possible depending on the kernel size . Instead of running a real
gaussian blur , 2 or 3 box blurs may be chained to produce a similar effect at a much
higher speed . The value @ a count can be set to a value from 1 to 6 if blur type @ c box
has been specified .
The speedups of @ c box over @ c gaussian are of orders of 4 x to more than 20 x faster .
2014-02-10 22:56:31 -08:00
If @ a src is an alpha buffer and @ a dst is an RGBA buffer , then the color option should be set .
@ a ox and @ a oy can be used to move the blurry output by a few pixels , like a drop shadow . Example :
2014-05-08 21:53:04 -07:00
@ verbinclude filter_blur . lua
2014-02-10 22:56:31 -08:00
2014-02-12 22:10:57 -08:00
< center >
@ image html filter_blur . png
< / center >
2014-02-10 22:56:31 -08:00
@ since 1.9
*/
2013-12-09 03:20:33 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_blur_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-09 03:20:33 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
2013-12-11 02:35:24 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " blur " ) , EINA_FALSE ) ;
2013-12-09 03:20:33 -08:00
instr - > type = EVAS_FILTER_MODE_BLUR ;
instr - > pad . update = _blur_padding_update ;
_instruction_param_seq_add ( instr , " rx " , VT_INT , 3 ) ;
_instruction_param_seq_add ( instr , " ry " , VT_INT , - 1 ) ;
_instruction_param_seq_add ( instr , " type " , VT_STRING , " default " ) ;
_instruction_param_seq_add ( instr , " ox " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " oy " , VT_INT , 0 ) ;
_instruction_param_name_add ( instr , " color " , VT_COLOR , 0xFFFFFFFF ) ;
2015-05-18 05:04:29 -07:00
_instruction_param_name_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
_instruction_param_name_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2014-03-11 02:21:46 -07:00
_instruction_param_name_add ( instr , " count " , VT_INT , 0 ) ;
2013-12-09 03:20:33 -08:00
return EINA_TRUE ;
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_bump Bump
Apply a light effect ( ambient light , specular reflection and shadows ) based on a bump map .
This can be used to give a relief effect on the object .
2014-05-08 21:53:04 -07:00
@ verbatim
bump ( { map , azimuth = 135.0 , elevation = 45.0 , depth = 8.0 , specular = 0.0 ,
color = ' white ' , compensate = false , src = input , dst = output ,
black = ' black ' , white = ' white ' , fillmode = ' repeat ' } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param map An alpha buffer treated like a Z map for the light effect ( bump map ) . Must be specified .
@ 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 .
@ 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 .
@ param depth The depth of the object in an arbitrary unit . More depth means the shadows will be stronger . Default is 8.0 .
@ param specular An arbitrary unit for the specular light effect . Default is 0.0 , but a common value would be 40.0 .
@ 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 " .
@ 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 .
@ param src Source buffer . This should be an alpha buffer .
@ param dst Destination buffer . This should be an RGBA buffer ( although alpha is supported ) . Must be of the same size as @ a src .
@ param black The shadows ' color . Usually this will be black ( @ c # 000 ) .
@ param white The specular light ' s color . Usually this will be white ( @ c # FFF ) .
2014-02-17 02:49:48 -08:00
@ 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 " .
2014-02-10 22:56:31 -08:00
@ 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 .
2014-02-23 18:18:10 -08:00
Here is a full example of a very simple bevel effect :
2014-05-08 21:53:04 -07:00
@ verbinclude filter_bump . lua
2014-02-10 22:56:31 -08:00
2014-02-12 22:10:57 -08:00
< center >
@ image html filter_bump . png
< / center >
2014-02-10 22:56:31 -08:00
@ since 1.9
*/
2013-12-09 03:20:33 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_bump_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-09 03:20:33 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
2013-12-11 02:35:24 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " bump " ) , EINA_FALSE ) ;
2013-12-09 03:20:33 -08:00
instr - > type = EVAS_FILTER_MODE_BUMP ;
_instruction_param_seq_add ( instr , " map " , VT_BUFFER , NULL ) ;
_instruction_param_seq_add ( instr , " azimuth " , VT_REAL , 135.0 ) ;
_instruction_param_seq_add ( instr , " elevation " , VT_REAL , 45.0 ) ;
_instruction_param_seq_add ( instr , " depth " , VT_REAL , 8.0 ) ;
_instruction_param_seq_add ( instr , " specular " , VT_REAL , 0.0 ) ;
_instruction_param_name_add ( instr , " color " , VT_COLOR , 0xFFFFFFFF ) ;
_instruction_param_name_add ( instr , " compensate " , VT_BOOL , EINA_FALSE ) ;
2015-05-18 05:04:29 -07:00
_instruction_param_name_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
_instruction_param_name_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2013-12-09 03:20:33 -08:00
_instruction_param_name_add ( instr , " black " , VT_COLOR , 0xFF000000 ) ;
_instruction_param_name_add ( instr , " white " , VT_COLOR , 0xFFFFFFFF ) ;
2013-12-31 00:51:09 -08:00
_instruction_param_name_add ( instr , " fillmode " , VT_STRING , " repeat " ) ;
2013-12-09 03:20:33 -08:00
return EINA_TRUE ;
}
2015-05-27 22:37:10 -07:00
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 )
{
int values [ 256 ] ;
char * token , * copy = NULL ;
const char * points_str ;
lua_Number n ;
int k ;
switch ( lua_type ( L , i ) )
{
case LUA_TTABLE :
// FIXME: indices start from 0 here. Lua prefers starting with 1.
for ( k = 0 ; k < 256 ; k + + )
{
lua_rawgeti ( L , i , k ) ;
if ( lua_isnil ( L , - 1 ) )
{
lua_pop ( L , 1 ) ;
values [ k ] = - 1 ;
}
else if ( lua_isnumber ( L , - 1 ) )
{
n = lua_tonumber ( L , - 1 ) ;
if ( ( n < - 1 ) | | ( n > 255 ) )
{
WRN ( " Value out of range in argument '%s' of function '%s' (got %d, expected 0-255) " ,
param - > name , instr - > name , ( int ) n ) ;
if ( n < - 1 ) n = 0 ;
if ( n > 255 ) n = 255 ;
}
lua_pop ( L , 1 ) ;
values [ k ] = ( int ) n ;
}
else
{
lua_pop ( L , 1 ) ;
ERR ( " Invalid value type '%s' (expected number) in table for argument '%s' of function '%s' " ,
lua_typename ( L , - 1 ) , param - > name , instr - > name ) ;
return EINA_FALSE ;
}
}
break ;
case LUA_TSTRING :
for ( k = 0 ; k < 256 ; k + + )
values [ k ] = - 1 ;
points_str = lua_tostring ( L , i ) ;
copy = strdup ( points_str ) ;
if ( ! copy ) return EINA_FALSE ;
token = strtok ( copy , " - " ) ;
if ( ! token )
{
ERR ( " Invalid string format for argument '%s' of function '%s' " ,
param - > name , instr - > name ) ;
free ( copy ) ;
return EINA_FALSE ;
}
while ( token )
{
int x , y , r , minx = 0 ;
r = sscanf ( token , " %i:%i " , & x , & y ) ;
if ( ( r ! = 2 ) | | ( x < minx ) | | ( x > = 256 ) )
{
ERR ( " Invalid string format for argument '%s' of function '%s' " ,
param - > name , instr - > name ) ;
free ( copy ) ;
return EINA_FALSE ;
}
minx = x + 1 ;
if ( ( y < - 1 ) | | ( y > 255 ) )
{
WRN ( " Value out of range in argument '%s' of function '%s' (got %d, expected 0-255) " ,
param - > name , instr - > name , y ) ;
if ( y < - 1 ) y = 0 ;
if ( y > 255 ) y = 255 ;
}
values [ x ] = y ;
token = strtok ( NULL , " - " ) ;
}
free ( copy ) ;
break ;
case LUA_TFUNCTION :
for ( k = 0 ; k < 256 ; k + + )
{
2015-06-04 03:42:38 -07:00
lua_getglobal ( L , _lua_errfunc_name ) ;
2015-05-27 22:37:10 -07:00
lua_pushvalue ( L , i ) ;
lua_pushinteger ( L , k ) ;
2015-06-04 03:42:38 -07:00
if ( ! lua_pcall ( L , 1 , 1 , - 3 ) )
2015-05-27 22:37:10 -07:00
{
if ( ! lua_isnumber ( L , - 1 ) )
{
ERR ( " Function returned an invalid type '%s' (expected number) "
" in argument '%s' of function '%s' " ,
lua_typename ( L , - 1 ) , param - > name , instr - > name ) ;
return EINA_FALSE ;
}
n = lua_tonumber ( L , - 1 ) ;
if ( ( n < - 1 ) | | ( n > 255 ) )
{
WRN ( " Value out of range in argument '%s' of function '%s' (got %d, expected 0-255) " ,
param - > name , instr - > name , ( int ) n ) ;
if ( n < - 1 ) n = 0 ;
if ( n > 255 ) n = 255 ;
}
2015-07-14 22:09:49 -07:00
lua_pop ( L , 2 ) ;
2015-05-27 22:37:10 -07:00
values [ k ] = ( int ) n ;
}
else
{
ERR ( " Failed to call function for argument '%s' of function '%s': %s " ,
param - > name , instr - > name , lua_tostring ( L , - 1 ) ) ;
return EINA_FALSE ;
}
}
break ;
default :
ERR ( " Invalid type '%s' for argument '%s' of function '%s' " ,
lua_typename ( L , i ) , param - > name , instr - > name ) ;
return EINA_FALSE ;
}
free ( param - > value . special . data ) ;
param - > value . special . data = malloc ( sizeof ( values ) ) ;
if ( ! param - > value . special . data ) return EINA_FALSE ;
memcpy ( param - > value . special . data , values , sizeof ( values ) ) ;
return EINA_TRUE ;
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_curve Curve
Apply a color curve to a specific channel in a buffer .
2014-05-08 21:53:04 -07:00
@ verbatim
curve ( { points , interpolation = ' linear ' , channel = ' rgb ' , src = input , dst = output } )
@ endverbatim
2014-02-10 22:56:31 -08:00
Modify the colors of a buffer . This applies a color curve y = f ( x ) to every pixel .
@ param points The color curve to apply . See below for the syntax .
@ param interpolation How to interpolate between points . One of @ c linear ( y = ax + b ) or @ c none ( y = Yk ) .
@ 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 .
@ param src Source buffer .
@ param dst Destination buffer , must be of same dimensions and color space as @ a src .
The @ a points argument contains a list of ( X , Y ) points in the range 0. .255 ,
describing a function < tt > f ( x ) = y < / tt > to apply to all pixel values .
2014-05-08 21:53:04 -07:00
The syntax of this @ a points string is < tt > ' x1 : y1 - x2 : y2 - x3 : y3 - . . . - xn : yn ' < / tt >
2014-02-10 22:56:31 -08:00
( remember that all spaces are discarded ) .
The points @ c xn are in @ a increasing order : < tt > x1 < x2 < x3 < . . . < xn < / tt > ,
and all values @ c xn or @ c yn are within the range 0. .255 .
2014-05-08 21:53:04 -07:00
The identity curve is then described as < tt > ' 0 : 0 - 255 : 255 ' < / tt > , with linear interpolation :
@ verbatim
curve ( { points = ' 0 : 0 - 255 : 255 ' , interpolation = linear } )
@ endverbatim
2014-02-10 22:56:31 -08:00
If ignored , y ( x = 0 ) is 0 and y ( x = 255 ) is 255.
The following example will generate a 4 px thick stroke around text letters :
2014-05-08 21:53:04 -07:00
@ verbinclude filter_curve . lua
2014-02-10 22:56:31 -08:00
2014-02-12 22:10:57 -08:00
< center >
@ image html filter_curve . png
< / center >
2014-02-10 22:56:31 -08:00
The curve command can be used to alter the output of a blur operation .
@ since 1.9
*/
2013-12-09 03:20:33 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_curve_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-09 03:20:33 -08:00
{
2014-01-01 22:57:44 -08:00
Instruction_Param * param ;
2013-12-09 03:20:33 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
2013-12-11 02:35:24 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " curve " ) , EINA_FALSE ) ;
2013-12-09 03:20:33 -08:00
2014-01-01 22:57:44 -08:00
instr - > type = EVAS_FILTER_MODE_CURVE ;
2014-05-08 21:53:04 -07:00
// TODO: Allow passing an array of 256 values as points.
// It could be easily computed from another function in the script.
2015-05-27 22:37:10 -07:00
_instruction_param_seq_add ( instr , " points " , VT_SPECIAL , _lua_curve_points_func , NULL ) ;
2014-01-01 22:57:44 -08:00
param = EINA_INLIST_CONTAINER_GET ( eina_inlist_last ( instr - > params ) , Instruction_Param ) ;
param - > allow_any_string = EINA_TRUE ;
_instruction_param_seq_add ( instr , " interpolation " , VT_STRING , " linear " ) ;
_instruction_param_seq_add ( instr , " channel " , VT_STRING , " rgb " ) ;
2015-05-18 05:04:29 -07:00
_instruction_param_name_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
_instruction_param_name_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2014-01-01 22:57:44 -08:00
2014-02-13 19:18:58 -08:00
return EINA_TRUE ;
2013-12-09 03:20:33 -08:00
}
2015-05-26 03:37:21 -07:00
static int
_displace_padding_update ( Evas_Filter_Program * pgm EINA_UNUSED ,
2013-12-12 23:21:59 -08:00
Evas_Filter_Instruction * instr ,
int * padl , int * padr , int * padt , int * padb )
2013-12-09 03:20:33 -08:00
{
int intensity = 0 ;
2013-12-12 23:21:59 -08:00
int l , r , t , b ;
2015-05-26 03:37:21 -07:00
Buffer * src , * dst ;
2013-12-09 03:20:33 -08:00
intensity = _instruction_param_geti ( instr , " intensity " , NULL ) ;
2015-05-26 03:37:21 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2013-12-12 23:21:59 -08:00
2015-05-26 03:37:21 -07:00
l = intensity + src - > pad . l ;
r = intensity + src - > pad . r ;
t = intensity + src - > pad . t ;
b = intensity + src - > pad . b ;
2013-12-12 23:21:59 -08:00
2015-05-26 03:37:21 -07:00
if ( dst - > pad . l < l ) dst - > pad . l = l ;
if ( dst - > pad . r < r ) dst - > pad . r = r ;
if ( dst - > pad . t < t ) dst - > pad . t = t ;
if ( dst - > pad . b < b ) dst - > pad . b = b ;
2013-12-12 23:21:59 -08:00
if ( padl ) * padl = l ;
if ( padr ) * padr = r ;
if ( padt ) * padt = t ;
if ( padb ) * padb = b ;
2015-05-26 03:37:21 -07:00
return 0 ;
2013-12-09 03:20:33 -08:00
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_displace Displace
Apply a displacement map on a buffer .
2014-05-08 21:53:04 -07:00
@ verbatim
displace ( { map , intensity = 10 , flags = 0 , src = input , dst = output , fillmode = ' repeat ' } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param map An RGBA buffer containing a displacement map . See below for more details .
@ param intensity Maximum distance for the displacement .
This means 0 and 255 will represent a displacement of @ c intensity pixels .
@ param flags One of @ c default , @ c nearest , @ c smooth , @ c nearest_stretch or @ c smooth_stretch .
This defines how pixels should be treated when going out of the @ a src image bounds .
@ c default is equivalent to @ c smooth_stretch .
@ param src Source buffer
@ param dst Destination buffer . Must be of same color format and size as @ a src .
2014-02-17 03:23:07 -08:00
@ param fillmode Defines how to handle cases where the map has a different size from @ a src and @ a dst .
It should be a combination of @ c stretch or @ c repeat : @ c none is not supported .
See @ ref evasfilter_fillmode " fillmodes " .
2014-02-10 22:56:31 -08:00
< h3 > Displacement map < / h3 >
The @ a map buffer is an RGBA image containing displacement and alpha values .
Its size can be different from @ c src or @ c dst .
The @ b red channel is used for X displacements while the @ b green channel is
used for Y displacements . All subpixel values are in the range 0. .255 .
A value of 128 means 0 displacement , lower means displace to the top / left
and higher than 128 displace to the bottom / right .
If < tt > signed char < / tt > is used instead of < tt > unsigned char < / tt > to represent
these R and G values , then < 0 means displace top / left while > 0 means bottom / right .
The @ c alpha channel is used as an alpha multiplier for blending .
Considering < tt > I ( x , y ) < / tt > represents the pixel at position ( x , y ) in the
image I , then here is how the displacement is applied to @ a dst :
2014-05-08 21:53:04 -07:00
@ verbatim
D = map ( x , y )
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
@ endverbatim
2014-02-10 22:56:31 -08:00
Of course , the real algorithm takes into account interpolation between pixels as well .
@ since 1.9
*/
2013-12-09 03:20:33 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_displace_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-09 03:20:33 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
2013-12-11 02:35:24 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " displace " ) , EINA_FALSE ) ;
2013-12-09 03:20:33 -08:00
instr - > type = EVAS_FILTER_MODE_DISPLACE ;
instr - > pad . update = _displace_padding_update ;
_instruction_param_seq_add ( instr , " map " , VT_BUFFER , NULL ) ;
_instruction_param_seq_add ( instr , " intensity " , VT_INT , 10 ) ;
2014-02-11 19:42:47 -08:00
_instruction_param_seq_add ( instr , " flags " , VT_STRING , " default " ) ;
2015-05-18 05:04:29 -07:00
_instruction_param_name_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
_instruction_param_name_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2013-12-31 00:51:09 -08:00
_instruction_param_name_add ( instr , " fillmode " , VT_STRING , " repeat " ) ;
2013-12-09 03:20:33 -08:00
return EINA_TRUE ;
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_fill Fill
Fill a buffer with a specific color .
Not blending , can be used to clear a buffer .
2014-05-08 21:53:04 -07:00
@ verbatim
fill ( { dst = output , color = ' transparent ' , l = 0 , r = 0 , t = 0 , b = 0 } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param dst Target buffer to fill with @ a color .
@ 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 " .
@ param l Left padding : skip @ a l pixels from the left border of the buffer
@ param r Right padding : skip @ a r pixels from the right border of the buffer
@ param t Top padding : skip @ a t pixels from the top border of the buffer
@ param b Bottom padding : skip @ a b pixels from the bottom border of the buffer
This function should generally not be used , except for :
< ul >
< li > @ a Testing an effect over a specific background color < / li >
< li > Clearing out a buffer with either white or transparent color < / li >
< / ul >
@ since 1.9
*/
2013-12-12 00:46:46 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_fill_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-12 00:46:46 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " fill " ) , EINA_FALSE ) ;
2014-01-01 22:57:44 -08:00
instr - > type = EVAS_FILTER_MODE_FILL ;
2015-05-18 05:04:29 -07:00
_instruction_param_seq_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2013-12-12 00:46:46 -08:00
_instruction_param_seq_add ( instr , " color " , VT_COLOR , 0x0 ) ;
2014-01-02 01:44:01 -08:00
_instruction_param_seq_add ( instr , " l " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " r " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " t " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " b " , VT_INT , 0 ) ;
2013-12-12 00:46:46 -08:00
return EINA_TRUE ;
}
2015-05-26 03:37:21 -07:00
static int
_grow_padding_update ( Evas_Filter_Program * pgm EINA_UNUSED ,
Evas_Filter_Instruction * instr ,
2013-12-12 23:21:59 -08:00
int * padl , int * padr , int * padt , int * padb )
2013-12-09 03:20:33 -08:00
{
2015-05-26 03:37:21 -07:00
Buffer * src , * dst ;
2013-12-12 23:21:59 -08:00
int l , r , t , b ;
int radius ;
2013-12-09 03:20:33 -08:00
radius = _instruction_param_geti ( instr , " radius " , NULL ) ;
2015-05-26 03:37:21 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2013-12-12 23:21:59 -08:00
2013-12-09 03:20:33 -08:00
if ( radius < 0 ) radius = 0 ;
2015-05-26 03:37:21 -07:00
l = radius + src - > pad . l ;
r = radius + src - > pad . r ;
t = radius + src - > pad . t ;
b = radius + src - > pad . b ;
2013-12-12 23:21:59 -08:00
if ( padl ) * padl = l ;
if ( padr ) * padr = r ;
if ( padt ) * padt = t ;
if ( padb ) * padb = b ;
2013-12-09 03:20:33 -08:00
2015-05-26 03:37:21 -07:00
if ( dst - > pad . l < l ) dst - > pad . l = l ;
if ( dst - > pad . r < r ) dst - > pad . r = r ;
if ( dst - > pad . t < t ) dst - > pad . t = t ;
if ( dst - > pad . b < b ) dst - > pad . b = b ;
return 0 ;
2013-12-09 03:20:33 -08:00
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_grow Grow
Grow or shrink a buffer ' s contents . This is not a zoom effect .
2014-05-08 21:53:04 -07:00
@ verbatim
grow ( { radius , smooth = true , src = input , dst = output } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param radius The radius of the grow kernel .
If a negative value is specified , the contents will shrink rather than grow .
@ param smooth If @ c true , use a smooth transitions between black and white ( smooth blur and smoother curve ) .
@ param src Source buffer to blur .
@ param dst Destination buffer for blending . This must be of same size and colorspace as @ a src .
Example :
2014-05-08 21:53:04 -07:00
@ verbinclude filter_grow . lua
2014-02-13 00:26:33 -08:00
2014-02-23 18:18:10 -08:00
This will first grow the letters in the buffer @ c input by a few pixels , and
then draw this buffer in black in the background .
2014-02-10 22:56:31 -08:00
2014-02-12 22:10:57 -08:00
< center >
@ image html filter_grow . png
< / center >
2014-02-10 22:56:31 -08:00
@ since 1.9
*/
2013-12-09 03:20:33 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_grow_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-09 03:20:33 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
2013-12-11 02:35:24 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " grow " ) , EINA_FALSE ) ;
2013-12-09 03:20:33 -08:00
instr - > type = EVAS_FILTER_MODE_GROW ;
instr - > pad . update = _grow_padding_update ;
_instruction_param_seq_add ( instr , " radius " , VT_INT , 0 ) ;
_instruction_param_name_add ( instr , " smooth " , VT_BOOL , EINA_TRUE ) ;
2015-05-18 05:04:29 -07:00
_instruction_param_name_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
_instruction_param_name_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2013-12-09 03:20:33 -08:00
return EINA_TRUE ;
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_mask Mask
2014-02-19 02:37:19 -08:00
Blend two input buffers into a third ( target ) .
2014-02-10 22:56:31 -08:00
2014-05-08 21:53:04 -07:00
@ verbatim
mask ( { mask , src = input , dst = output , color = ' white ' , fillmode = ' repeat ' } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param mask A mask or texture to blend with the input @ a src into the target @ a dst .
@ param src Source buffer . This can also be thought of a mask if @ a src is alpha and @ a mask is RGBA .
@ param dst Destination buffer for blending . This must be of same size and colorspace as @ a src .
2014-02-19 02:37:19 -08:00
@ param color A color to use for alpha to RGBA conversion for the blend operations . White means no change .
See @ ref evasfilters_color " colors " . This will have no effect on RGBA sources .
2014-03-24 23:19:21 -07:00
@ param fillmode Defines whether to stretch or repeat the @ a mask if its size that of @ src .
Should be set when masking with external textures . Default is repeat . See @ ref evasfilter_fillmode " fillmodes " .
2014-02-10 22:56:31 -08:00
Note that @ a src and @ a mask are interchangeable , if they have the same dimensions .
Example :
2014-05-08 21:53:04 -07:00
@ verbinclude filter_mask . lua
2014-02-13 00:26:33 -08:00
2014-02-23 18:18:10 -08:00
This will create an inner shadow effect .
2014-02-10 22:56:31 -08:00
2014-02-12 22:10:57 -08:00
< center >
@ image html filter_mask . png
< / center >
2014-02-10 22:56:31 -08:00
@ since 1.9
*/
2013-12-09 03:20:33 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_mask_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2013-12-09 03:20:33 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
2013-12-11 02:35:24 -08:00
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " mask " ) , EINA_FALSE ) ;
2013-12-09 03:20:33 -08:00
instr - > type = EVAS_FILTER_MODE_MASK ;
_instruction_param_seq_add ( instr , " mask " , VT_BUFFER , NULL ) ;
2015-05-18 05:04:29 -07:00
_instruction_param_seq_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
_instruction_param_seq_add ( instr , " dst " , VT_BUFFER , _buffer_get ( pgm , " output " ) ) ;
2013-12-09 03:20:33 -08:00
_instruction_param_name_add ( instr , " color " , VT_COLOR , 0xFFFFFFFF ) ;
2014-03-24 23:19:21 -07:00
_instruction_param_name_add ( instr , " fillmode " , VT_STRING , " repeat " ) ;
2013-12-09 03:20:33 -08:00
return EINA_TRUE ;
}
2015-05-26 03:37:21 -07:00
static int
_transform_padding_update ( Evas_Filter_Program * pgm EINA_UNUSED ,
2014-01-07 01:38:22 -08:00
Evas_Filter_Instruction * instr ,
int * padl , int * padr , int * padt , int * padb )
{
2015-05-26 03:37:21 -07:00
Buffer * dst ;
2014-01-07 01:38:22 -08:00
int ox , oy , l = 0 , r = 0 , t = 0 , b = 0 ;
//ox = _instruction_param_geti(instr, "ox", NULL);
ox = 0 ;
oy = _instruction_param_geti ( instr , " oy " , NULL ) ;
2015-05-26 03:37:21 -07:00
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
INSTR_PARAM_CHECK ( dst ) ;
2014-01-07 01:38:22 -08:00
if ( ox < 0 ) l = ( - ox ) * 2 ;
else r = ox * 2 ;
if ( oy < 0 ) t = ( - oy ) * 2 ;
else b = oy * 2 ;
2015-05-26 03:37:21 -07:00
if ( dst - > pad . l < l ) dst - > pad . l = l ;
if ( dst - > pad . r < r ) dst - > pad . r = r ;
if ( dst - > pad . t < t ) dst - > pad . t = t ;
if ( dst - > pad . b < b ) dst - > pad . b = b ;
2014-01-07 01:38:22 -08:00
if ( padl ) * padl = l ;
if ( padr ) * padr = r ;
if ( padt ) * padt = t ;
if ( padb ) * padb = b ;
2015-05-26 03:37:21 -07:00
return 0 ;
2014-01-07 01:38:22 -08:00
}
2014-02-10 22:56:31 -08:00
/**
@ page evasfiltersref
@ subsection sec_commands_transform Transform
Apply a geometrical transformation to a buffer .
Right now , only < b > vertical flip < / b > is implemented and available .
2014-02-19 02:48:44 -08:00
This operation does not blend and assumes the destination buffer is empty .
2014-02-10 22:56:31 -08:00
2014-05-08 21:53:04 -07:00
@ verbatim
transform ( { dst , op = ' vflip ' , src = input , oy = 0 } )
@ endverbatim
2014-02-10 22:56:31 -08:00
@ param dst Destination buffer . Must be of the same colorspace as @ a src . Must be specified .
2014-05-08 21:53:04 -07:00
@ param op Must be @ c ' vflip ' . There is no other operation yet .
2014-02-10 22:56:31 -08:00
@ param src Source buffer to transform .
@ param oy Y offset .
Example :
2014-05-08 21:53:04 -07:00
@ verbinclude filter_transform . lua
2014-02-13 00:26:33 -08:00
2014-02-10 22:56:31 -08:00
This will create a mirrored text effect , for a font of 50 px .
2014-02-12 22:10:57 -08:00
< center >
@ image html filter_transform . png
< / center >
2014-02-10 22:56:31 -08:00
@ note Because of the meaning of @ a oy , this effect probably needs to be
customized for a single font size ( FIXME ) .
@ since 1.9
*/
2014-01-07 01:38:22 -08:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_transform_instruction_prepare ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * instr )
2014-01-07 01:38:22 -08:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " transform " ) , EINA_FALSE ) ;
instr - > type = EVAS_FILTER_MODE_TRANSFORM ;
instr - > pad . update = _transform_padding_update ;
2014-02-11 22:58:06 -08:00
_instruction_param_seq_add ( instr , " dst " , VT_BUFFER , NULL ) ;
2014-01-07 01:38:22 -08:00
_instruction_param_seq_add ( instr , " op " , VT_STRING , " vflip " ) ;
2015-05-18 05:04:29 -07:00
_instruction_param_seq_add ( instr , " src " , VT_BUFFER , _buffer_get ( pgm , " input " ) ) ;
2014-01-07 01:38:22 -08:00
//_instruction_param_name_add(instr, "ox", VT_INT, 0);
_instruction_param_name_add ( instr , " oy " , VT_INT , 0 ) ;
return EINA_TRUE ;
}
2015-05-26 03:37:21 -07:00
static int
2014-03-20 19:52:52 -07:00
_padding_set_padding_update ( Evas_Filter_Program * pgm ,
Evas_Filter_Instruction * instr ,
int * padl , int * padr , int * padt , int * padb )
{
int l = 0 , r = 0 , t = 0 , b = 0 ;
Eina_Bool lset = EINA_FALSE ;
Eina_Bool rset = EINA_FALSE ;
Eina_Bool tset = EINA_FALSE ;
Eina_Bool bset = EINA_FALSE ;
l = _instruction_param_geti ( instr , " l " , & lset ) ;
r = _instruction_param_geti ( instr , " r " , & rset ) ;
t = _instruction_param_geti ( instr , " t " , & tset ) ;
b = _instruction_param_geti ( instr , " b " , & bset ) ;
if ( ! lset & & ! rset & & ! bset & & ! tset )
2015-06-09 05:29:13 -07:00
INF ( " padding_set() called without specifying any of l,r,t,b resets to 0 " ) ;
2014-03-20 19:52:52 -07:00
if ( l < 0 | | r < 0 | | t < 0 | | b < 0 )
{
WRN ( " invalid padding values in padding_set(%d, %d, %d, %d), resets to 0 " , l , r , t , b ) ;
l = r = t = b = 0 ;
}
if ( ! rset ) r = l ;
if ( ! tset ) t = r ;
if ( ! bset ) b = t ;
if ( padl ) * padl = l ;
if ( padr ) * padr = r ;
if ( padt ) * padt = t ;
if ( padb ) * padb = b ;
pgm - > padding_set = EINA_TRUE ;
2015-05-26 03:37:21 -07:00
return 0 ;
2014-03-20 19:52:52 -07:00
}
/**
@ page evasfiltersref
@ subsection sec_commands_padding_set Padding_Set
Forcily set a specific padding for this filter .
2014-05-08 21:53:04 -07:00
@ verbatim
padding_set ( { l , r = [ l ] , t = [ r ] , b = [ t ] } )
@ endverbatim
2014-03-20 19:52:52 -07:00
@ param l Padding on the left side in pixels .
@ param r Padding on the right side in pixels . If unset , defaults to @ a l .
@ param t Padding on the top in pixels . If unset , defaults to @ a r .
@ param b Padding on the bottom in pixels . If unset , defaults to @ a t .
All values must be > = 0. When filtering ' filled ' images , some values may be too high
and would result in completely hiding the image .
It is not possible to set only one of those without forcing the others as well .
A common use case will be when changing a blur size during an animation , or
when applying a mask that will hide most of the ( blurred ) text .
2014-05-08 22:22:59 -07:00
Example ( the @ c fill command is used for illustration purposes ) :
@ verbinclude filter_padding . lua
This will set the left , right , top and bottom paddings to their respective values ,
and some effects may look like they ' ve been " clipped " out .
< center >
@ image html filter_padding . png
< / center >
2014-03-20 19:52:52 -07:00
@ since 1.10
*/
static Eina_Bool
2015-05-18 05:04:29 -07:00
_padding_set_instruction_prepare ( Evas_Filter_Program * pgm EINA_UNUSED ,
Evas_Filter_Instruction * instr )
2014-03-20 19:52:52 -07:00
{
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( instr - > name , EINA_FALSE ) ;
EINA_SAFETY_ON_FALSE_RETURN_VAL ( ! strcasecmp ( instr - > name , " padding_set " ) , EINA_FALSE ) ;
instr - > type = EVAS_FILTER_MODE_PADDING_SET ;
instr - > pad . update = _padding_set_padding_update ;
_instruction_param_seq_add ( instr , " l " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " r " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " t " , VT_INT , 0 ) ;
_instruction_param_seq_add ( instr , " b " , VT_INT , 0 ) ;
return EINA_TRUE ;
}
2013-12-09 03:20:33 -08:00
/* Evas_Filter_Parser entry points */
# undef PARSE_CHECK
# define PARSE_CHECK(a) do { if (!(a)) { ERR("Parsing failed because '%s' is false at %s:%d", #a, __FUNCTION__, __LINE__); PARSE_ABORT(); goto end; } } while (0)
2014-02-17 19:02:45 -08:00
EAPI void
2013-12-09 03:20:33 -08:00
evas_filter_program_del ( Evas_Filter_Program * pgm )
{
Evas_Filter_Instruction * instr ;
Buffer * buf ;
if ( ! pgm ) return ;
2015-05-18 01:35:49 -07:00
if ( pgm - > L )
lua_close ( pgm - > L ) ;
2013-12-09 03:20:33 -08:00
EINA_INLIST_FREE ( pgm - > buffers , buf )
{
pgm - > buffers = eina_inlist_remove ( pgm - > buffers , EINA_INLIST_GET ( buf ) ) ;
_buffer_del ( buf ) ;
}
EINA_INLIST_FREE ( pgm - > instructions , instr )
{
pgm - > instructions = eina_inlist_remove ( pgm - > instructions , EINA_INLIST_GET ( instr ) ) ;
_instruction_del ( instr ) ;
}
eina_stringshare_del ( pgm - > name ) ;
free ( pgm ) ;
}
2015-06-04 03:42:38 -07:00
// [-1, +1, e] -- converts the top of the stack to a valid 'color' object
static Eina_Bool
_lua_convert_color ( lua_State * L )
{
int top = lua_gettop ( L ) ;
lua_getglobal ( L , _lua_errfunc_name ) ; //+1
lua_getglobal ( L , _lua_color_meta ) ; //+1 (mt)
lua_getfield ( L , - 1 , " __call " ) ; //+1 (func)
lua_pushvalue ( L , - 2 ) ; //+1 (mt)
lua_pushvalue ( L , top ) ; //+1 (argument)
if ( lua_pcall ( L , 2 , 1 , top + 1 ) ! = 0 )
return EINA_FALSE ;
lua_insert ( L , top ) ;
lua_settop ( L , top ) ;
return EINA_TRUE ;
2014-04-11 01:10:52 -07:00
}
2014-04-29 22:48:16 -07:00
static Eina_Bool
2015-05-18 05:04:29 -07:00
_lua_parameter_parse ( Evas_Filter_Program * pgm , lua_State * L ,
2015-05-26 03:37:21 -07:00
Evas_Filter_Instruction * instr ,
2015-05-18 05:04:29 -07:00
Instruction_Param * param , int i )
2014-04-11 01:10:52 -07:00
{
2014-05-14 01:45:20 -07:00
if ( ! param ) return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
if ( param - > set )
{
ERR ( " Parameter %s has already been set " , param - > name ) ;
2015-06-04 03:42:38 -07:00
return luaL_error ( L , " Parameter %s has already been set " , param - > name ) ;
2014-04-11 01:10:52 -07:00
}
2015-06-04 03:42:38 -07:00
if ( i < 0 )
i = lua_gettop ( L ) + i + 1 ;
2014-04-11 01:10:52 -07:00
switch ( param - > type )
{
case VT_BOOL :
if ( lua_type ( L , i ) = = LUA_TSTRING )
{
2015-05-18 05:04:29 -07:00
Eina_Bool ok = EINA_FALSE ;
2014-04-11 01:10:52 -07:00
const char * str = lua_tostring ( L , i ) ;
Eina_Bool val = _bool_parse ( str , & ok ) ;
2015-05-18 05:04:29 -07:00
if ( ! ok )
goto fail ;
param - > value . b = val ;
2014-04-11 01:10:52 -07:00
}
else if ( lua_isboolean ( L , i ) | | lua_isnumber ( L , i ) )
2015-05-18 05:04:29 -07:00
param - > value . b = lua_toboolean ( L , i ) ;
else
goto fail ;
2014-04-11 01:10:52 -07:00
break ;
case VT_INT :
2015-05-18 05:04:29 -07:00
if ( ! lua_isnumber ( L , i ) )
goto fail ;
param - > value . i = lua_tointeger ( L , i ) ;
2014-04-11 01:10:52 -07:00
break ;
case VT_REAL :
2015-05-18 05:04:29 -07:00
if ( ! lua_isnumber ( L , i ) )
goto fail ;
param - > value . f = lua_tonumber ( L , i ) ;
2014-04-11 01:10:52 -07:00
break ;
case VT_STRING :
2015-05-18 05:04:29 -07:00
if ( lua_type ( L , i ) ! = LUA_TSTRING )
goto fail ;
free ( param - > value . s ) ;
param - > value . s = strdup ( lua_tostring ( L , i ) ) ;
2014-04-11 01:10:52 -07:00
break ;
case VT_COLOR :
2015-06-04 03:42:38 -07:00
{
// Auto convert values to a color() if they aren't one already
int cid = 0 , pop = 0 , A , R , G , B ;
if ( lua_istable ( L , i ) )
{
luaL_getmetatable ( L , _lua_color_meta ) ;
lua_getmetatable ( L , i ) ;
if ( ! lua_isnil ( L , - 1 ) & & lua_equal ( L , - 2 , - 1 ) )
{
// this is a color already
cid = i ;
}
lua_pop ( L , 2 ) ;
}
if ( ! cid )
{
lua_pushvalue ( L , i ) ; //+1 (arg)
if ( ! _lua_convert_color ( L ) ) //-1/+1
{
ERR ( " Failed to convert color: %s " , lua_tostring ( L , - 1 ) ) ;
goto fail ;
}
cid = lua_gettop ( L ) ;
pop = 1 ;
}
if ( ! lua_istable ( L , cid ) )
goto fail ;
lua_getfield ( L , cid , " a " ) ;
A = lua_tointeger ( L , - 1 ) ;
lua_getfield ( L , cid , " r " ) ;
R = lua_tointeger ( L , - 1 ) ;
lua_getfield ( L , cid , " g " ) ;
G = lua_tointeger ( L , - 1 ) ;
lua_getfield ( L , cid , " b " ) ;
B = lua_tointeger ( L , - 1 ) ;
lua_pop ( L , pop + 4 ) ;
evas_color_argb_premul ( A , & R , & G , & B ) ;
param - > value . c = ARGB_JOIN ( A , R , G , B ) ;
}
2014-04-11 01:10:52 -07:00
break ;
case VT_BUFFER :
2015-05-18 05:04:29 -07:00
{
if ( lua_type ( L , i ) = = LUA_TSTRING )
{
param - > value . buf = _buffer_get ( pgm , lua_tostring ( L , i ) ) ;
if ( ! param - > value . buf )
goto fail ;
}
else
{
Buffer * * pbuf ;
luaL_checkudata ( L , i , _lua_buffer_meta ) ;
pbuf = lua_touserdata ( L , i ) ;
param - > value . buf = pbuf ? * pbuf : NULL ;
}
break ;
}
2015-05-27 22:37:10 -07:00
case VT_SPECIAL :
if ( ! param - > value . special . func | |
! param - > value . special . func ( L , i , pgm , instr , param ) )
goto fail ;
break ;
2014-04-11 01:10:52 -07:00
case VT_NONE :
default :
// This should not happen
CRI ( " Invalid function declaration " ) ;
goto fail ;
}
2015-06-04 03:42:38 -07:00
if ( i ! = lua_gettop ( L ) )
ERR ( " something is wrong " ) ;
2014-04-11 01:10:52 -07:00
param - > set = EINA_TRUE ;
2014-04-29 22:48:16 -07:00
return EINA_TRUE ;
2014-04-11 01:10:52 -07:00
fail :
ERR ( " Invalid value for parameter %s " , param - > name ) ;
2015-06-04 03:42:38 -07:00
return luaL_error ( L , " Invalid value for parameter %s " , param - > name ) ;
2014-04-11 01:10:52 -07:00
}
2014-09-18 00:11:46 -07:00
static Instruction_Param *
2015-05-18 01:35:49 -07:00
_parameter_get_by_id ( Evas_Filter_Instruction * instr , int id )
2014-09-18 00:11:46 -07:00
{
Instruction_Param * param ;
int i = 0 ;
if ( id < 0 )
return NULL ;
EINA_INLIST_FOREACH ( instr - > params , param )
if ( id = = ( i + + ) )
return param ;
return NULL ;
}
2014-04-11 01:10:52 -07:00
static Eina_Bool
_lua_instruction_run ( lua_State * L , Evas_Filter_Instruction * instr )
{
const unsigned int argc = lua_gettop ( L ) ;
Evas_Filter_Program * pgm = _lua_program_get ( L ) ;
Instruction_Param * param ;
unsigned int i = 0 ;
2014-05-14 01:45:20 -07:00
if ( ! instr ) return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
if ( eina_inlist_count ( instr - > params ) < argc )
{
ERR ( " Too many arguments passed to the instruction %s " , instr - > name ) ;
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
}
if ( lua_istable ( L , 1 ) )
{
if ( argc > 1 )
{
ERR ( " Too many arguments passed to the instruction %s (in table mode) " , instr - > name ) ;
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
}
2014-09-18 00:11:46 -07:00
lua_pushnil ( L ) ;
2014-04-11 01:10:52 -07:00
while ( lua_next ( L , 1 ) )
{
if ( ! lua_isnumber ( L , - 2 ) & & ( lua_type ( L , - 2 ) = = LUA_TSTRING ) )
{
const char * name = lua_tostring ( L , - 2 ) ;
param = _instruction_param_get ( instr , name ) ;
if ( ! param )
{
ERR ( " Parameter %s does not exist " , name ) ;
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
}
}
2014-09-18 00:11:46 -07:00
else if ( lua_isnumber ( L , - 2 ) )
2014-04-11 01:10:52 -07:00
{
2014-09-18 00:11:46 -07:00
int idx = ( int ) lua_tonumber ( L , - 2 ) ;
2015-05-18 01:35:49 -07:00
param = _parameter_get_by_id ( instr , idx - 1 ) ;
2014-09-18 00:11:46 -07:00
if ( ! param )
{
ERR ( " Too many parameters for the function %s " , instr - > name ) ;
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-09-18 00:11:46 -07:00
}
if ( ! param - > allow_seq )
{
ERR ( " The parameter %s must be referred to by name in function %s " ,
param - > name , instr - > name ) ;
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-09-18 00:11:46 -07:00
}
2014-04-11 01:10:52 -07:00
}
2014-09-18 00:11:46 -07:00
else
2014-04-11 01:10:52 -07:00
{
2014-09-18 00:11:46 -07:00
ERR ( " Invalid type for the parameter key in function %s " , instr - > name ) ;
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
}
2015-05-26 03:37:21 -07:00
if ( ! _lua_parameter_parse ( pgm , L , instr , param , - 1 ) )
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
lua_pop ( L , 1 ) ;
}
}
else
{
EINA_INLIST_FOREACH ( instr - > params , param )
{
2014-04-29 22:48:16 -07:00
if ( ( + + i ) > argc ) break ;
2015-05-26 03:37:21 -07:00
if ( ! _lua_parameter_parse ( pgm , L , instr , param , i ) )
2015-06-04 03:42:38 -07:00
return EINA_FALSE ;
2014-04-11 01:10:52 -07:00
}
}
if ( instr - > parse_run )
{
if ( ! instr - > parse_run ( L , pgm , instr ) )
{
ERR ( " Failed to run instruction '%s' " , instr - > name ) ;
return EINA_FALSE ;
}
}
return EINA_TRUE ;
}
static int
_lua_generic_function ( lua_State * L , const char * name ,
2015-05-18 05:04:29 -07:00
Eina_Bool ( * prepare ) ( Evas_Filter_Program * pgm , Evas_Filter_Instruction * ) )
2014-04-11 01:10:52 -07:00
{
Evas_Filter_Program * pgm = _lua_program_get ( L ) ;
Evas_Filter_Instruction * instr ;
instr = _instruction_new ( name ) ;
2015-05-18 05:04:29 -07:00
prepare ( pgm , instr ) ;
2014-04-11 01:10:52 -07:00
2015-06-04 03:42:38 -07:00
if ( ! _lua_instruction_run ( L , instr ) )
2014-04-11 01:10:52 -07:00
{
_instruction_del ( instr ) ;
2015-06-04 03:42:38 -07:00
return luaL_error ( L , " Instruction parsing failed " ) ;
2014-04-11 01:10:52 -07:00
}
else
{
pgm - > instructions = eina_inlist_append ( pgm - > instructions , EINA_INLIST_GET ( instr ) ) ;
}
return instr - > return_count ;
}
2015-05-18 02:24:16 -07:00
static int
_lua_print ( lua_State * L )
{
Eina_Strbuf * s ;
int nargs = lua_gettop ( L ) ;
int i ;
if ( nargs < 1 )
{
2015-06-09 05:29:13 -07:00
INF ( " (nothing) " ) ;
2015-05-18 02:24:16 -07:00
return 0 ;
}
s = eina_strbuf_new ( ) ;
for ( i = 1 ; i < = nargs ; i + + )
{
2015-06-04 03:42:38 -07:00
const char * str ;
lua_getglobal ( L , _lua_errfunc_name ) ;
lua_getglobal ( L , " tostring " ) ; //+1
lua_pushvalue ( L , i ) ; //+1
lua_pcall ( L , 1 , 1 , - 3 ) ; //-2/+1
str = lua_tostring ( L , - 1 ) ;
eina_strbuf_append ( s , str ? str : " (nil) " ) ;
lua_pop ( L , 2 ) ;
2015-05-18 02:24:16 -07:00
eina_strbuf_append_char ( s , ' ' ) ;
}
2015-06-09 05:29:13 -07:00
INF ( " %s " , eina_strbuf_string_get ( s ) ) ;
2015-05-18 02:24:16 -07:00
eina_strbuf_free ( s ) ;
return 0 ;
}
static const struct luaL_Reg printlib [ ] = {
{ " print " , _lua_print } ,
{ NULL , NULL }
} ;
2014-04-11 01:10:52 -07:00
# define LUA_GENERIC_FUNCTION(name) \
static int \
_lua_ # # name ( lua_State * L ) \
{ \
return _lua_generic_function ( L , # name , _ # # name # # _instruction_prepare ) ; \
}
# define PUSH_LUA_FUNCTION(name) \
lua_pushcfunction ( L , _lua_ # # name ) ; \
lua_setglobal ( L , # name ) ;
LUA_GENERIC_FUNCTION ( blend )
LUA_GENERIC_FUNCTION ( blur )
LUA_GENERIC_FUNCTION ( bump )
LUA_GENERIC_FUNCTION ( curve )
LUA_GENERIC_FUNCTION ( displace )
LUA_GENERIC_FUNCTION ( fill )
LUA_GENERIC_FUNCTION ( grow )
LUA_GENERIC_FUNCTION ( mask )
LUA_GENERIC_FUNCTION ( padding_set )
LUA_GENERIC_FUNCTION ( transform )
2015-06-04 03:42:38 -07:00
static const luaL_Reg _lua_buffer_metamethods [ ] = {
{ " __call " , _lua_buffer_new } ,
2015-05-18 05:04:29 -07:00
{ " __tostring " , _lua_buffer_tostring } ,
2015-05-27 18:12:18 -07:00
{ " __index " , _lua_buffer_index } ,
2015-05-18 05:04:29 -07:00
{ NULL , NULL }
} ;
2015-06-04 03:42:38 -07:00
static char * _lua_color_code = NULL ;
static inline void
_lua_import_path_get ( char * path , size_t len , const char * name )
{
const char * pfx = _evas_module_datadir_get ( ) ;
size_t r ;
2015-07-27 19:27:08 -07:00
# ifdef FILTERS_DEBUG
struct stat st ;
2015-06-04 03:42:38 -07:00
// This is a hack to fetch the most recent file from source
if ( stat ( path , & st ) = = - 1 )
{
char * sep = evas_file_path_join ( " " , " " ) ;
char * src = strdup ( __FILE__ ) ;
char * slash = strrchr ( src , * sep ) ;
if ( slash )
{
* slash = ' \0 ' ;
if ( * src = = ' / ' )
r = snprintf ( path , len - 1 , " %s/lua/%s.lua " , src , name ) ;
else // abs_srcdir is unknown here
r = snprintf ( path , len - 1 , " %s/src/%s/lua/%s.lua " , PACKAGE_BUILD_DIR , src , name ) ;
if ( r > = len ) path [ len - 1 ] = ' \0 ' ;
}
free ( sep ) ;
free ( src ) ;
if ( ! stat ( path , & st ) ) return ;
}
2015-07-27 19:27:08 -07:00
# endif
2015-06-04 03:42:38 -07:00
r = snprintf ( path , len - 1 , " %s/filters/lua/%s.lua " , pfx ? pfx : " . " , name ) ;
if ( r > = len ) path [ len - 1 ] = ' \0 ' ;
}
static Eina_Bool
_lua_import_class ( lua_State * L , const char * name , char * * code )
{
// Load code from file
if ( ! * code )
{
char path [ PATH_MAX ] ;
Eina_File * f ;
void * map ;
size_t sz ;
_lua_import_path_get ( path , PATH_MAX , name ) ;
f = eina_file_open ( path , EINA_FALSE ) ;
if ( ! f ) return EINA_FALSE ;
sz = eina_file_size_get ( f ) ;
2015-06-09 05:29:13 -07:00
* code = malloc ( sz + 1 ) ;
2015-06-04 03:42:38 -07:00
if ( ! * code ) return EINA_FALSE ;
map = eina_file_map_all ( f , EINA_FILE_SEQUENTIAL ) ;
if ( ! map ) return EINA_FALSE ;
memcpy ( * code , map , sz ) ;
2015-06-09 05:29:13 -07:00
( * code ) [ sz ] = ' \0 ' ;
2015-06-04 03:42:38 -07:00
eina_file_map_free ( f , map ) ;
eina_file_close ( f ) ;
}
if ( ! luaL_dostring ( L , * code ) ) //+1
{
lua_getglobal ( L , _lua_errfunc_name ) ; //+1
lua_pushliteral ( L , _lua_register_func ) ; //+1
lua_rawget ( L , - 3 ) ; //-1/+1
if ( lua_isfunction ( L , - 1 ) )
{
lua_getglobal ( L , " _G " ) ; //+1
if ( lua_pcall ( L , 1 , 0 , - 3 ) ! = 0 ) //-2
{
ERR ( " Failed to register globals for '%s': %s " , name , lua_tostring ( L , - 1 ) ) ;
lua_pop ( L , 1 ) ;
}
}
else lua_pop ( L , 1 ) ;
lua_pop ( L , 1 ) ; // -1 (errfunc)
lua_setglobal ( L , name ) ; //-1
}
else
{
ERR ( " Lua class '%s' could not be loaded: %s " , name , lua_tostring ( L , - 1 ) ) ;
return EINA_FALSE ;
}
return EINA_TRUE ;
}
2015-05-26 03:37:21 -07:00
static void
_filter_program_buffers_set ( Evas_Filter_Program * pgm )
{
// Standard buffers
_buffer_add ( pgm , " input " , pgm - > input_alpha , NULL , EINA_FALSE ) ;
_buffer_add ( pgm , " output " , EINA_FALSE , NULL , EINA_FALSE ) ;
// Register proxies
if ( pgm - > proxies )
{
Eina_Iterator * it = eina_hash_iterator_key_new ( pgm - > proxies ) ;
const char * source ;
EINA_ITERATOR_FOREACH ( it , source )
2015-06-22 19:44:54 -07:00
{
// Cleanup name and avoid overriding existing globals
char name [ 64 ] ;
unsigned i ;
snprintf ( name , 64 , " __source_%s " , source ) ;
name [ 63 ] = ' \0 ' ;
for ( i = 0 ; name [ i ] ; i + + )
{
if ( ! isdigit ( name [ i ] ) & & ! isalpha ( name [ i ] ) )
name [ i ] = ' _ ' ;
}
_buffer_add ( pgm , name , EINA_FALSE , source , EINA_FALSE ) ;
}
2015-05-26 03:37:21 -07:00
eina_iterator_free ( it ) ;
}
}
2015-06-04 03:42:38 -07:00
static inline void
_lua_class_create ( lua_State * L , const char * name ,
const luaL_Reg * meta , const luaL_Reg * methods )
{
luaL_newmetatable ( L , name ) ;
luaL_register ( L , NULL , meta ) ;
lua_pushliteral ( L , " __metatable " ) ;
lua_pushvalue ( L , - 2 ) ;
lua_rawset ( L , - 3 ) ;
if ( methods )
{
lua_pushliteral ( L , _lua_methods_table ) ;
lua_newtable ( L ) ;
luaL_register ( L , NULL , methods ) ;
lua_rawset ( L , - 3 ) ;
}
lua_pushvalue ( L , - 1 ) ;
lua_setmetatable ( L , - 2 ) ;
lua_setglobal ( L , name ) ;
}
2014-04-11 01:10:52 -07:00
static lua_State *
_lua_state_create ( Evas_Filter_Program * pgm )
{
lua_State * L ;
2015-05-18 05:04:29 -07:00
pgm - > L = L = luaL_newstate ( ) ;
2014-04-11 01:10:52 -07:00
if ( ! L )
{
ERR ( " Could not create a new Lua state " ) ;
return NULL ;
}
luaopen_base ( L ) ;
luaopen_table ( L ) ;
luaopen_string ( L ) ;
luaopen_math ( L ) ;
2015-06-04 03:42:38 -07:00
luaopen_debug ( L ) ;
lua_settop ( L , 0 ) ;
2014-04-11 01:10:52 -07:00
2015-05-18 02:24:16 -07:00
// Implement print
lua_getglobal ( L , " _G " ) ;
luaL_register ( L , NULL , printlib ) ;
lua_pop ( L , 1 ) ;
2015-06-04 03:42:38 -07:00
// Add backtrace error function
lua_pushcfunction ( L , _lua_backtrace ) ;
lua_setglobal ( L , _lua_errfunc_name ) ;
2014-04-11 01:10:52 -07:00
// Store program
lua_pushlightuserdata ( L , ( void * ) & this_is_not_a_cat ) ;
lua_pushlightuserdata ( L , pgm ) ;
lua_settable ( L , LUA_REGISTRYINDEX ) ;
// Register functions
PUSH_LUA_FUNCTION ( blend )
PUSH_LUA_FUNCTION ( blur )
PUSH_LUA_FUNCTION ( bump )
PUSH_LUA_FUNCTION ( curve )
PUSH_LUA_FUNCTION ( displace )
PUSH_LUA_FUNCTION ( fill )
PUSH_LUA_FUNCTION ( grow )
PUSH_LUA_FUNCTION ( mask )
PUSH_LUA_FUNCTION ( padding_set )
PUSH_LUA_FUNCTION ( transform )
for ( unsigned k = 0 ; k < ( sizeof ( fill_modes ) / sizeof ( fill_modes [ 0 ] ) ) ; k + + )
{
if ( strcmp ( " repeat " , fill_modes [ k ] . name ) )
{
lua_pushstring ( L , fill_modes [ k ] . name ) ;
lua_setglobal ( L , fill_modes [ k ] . name ) ;
}
}
lua_pushstring ( L , " rgba " ) ;
lua_setglobal ( L , " rgba " ) ;
lua_pushstring ( L , " alpha " ) ;
lua_setglobal ( L , " alpha " ) ;
static const struct { Eina_Bool b ; const char * name ; } booleans [ ] =
{
{ EINA_TRUE , " on " } ,
{ EINA_TRUE , " yes " } ,
{ EINA_TRUE , " enable " } ,
{ EINA_TRUE , " enabled " } ,
{ EINA_FALSE , " off " } ,
{ EINA_FALSE , " no " } ,
2014-05-09 00:07:41 -07:00
{ EINA_FALSE , " disable " } ,
2014-04-11 01:10:52 -07:00
{ EINA_FALSE , " disabled " }
} ;
for ( unsigned k = 0 ; k < ( sizeof ( booleans ) / sizeof ( booleans [ 0 ] ) ) ; k + + )
{
lua_pushnumber ( L , booleans [ k ] . b ) ;
lua_setglobal ( L , booleans [ k ] . name ) ;
}
2015-06-04 03:42:38 -07:00
// Create buffer class based on userdata
_lua_class_create ( L , _lua_buffer_meta , _lua_buffer_metamethods , NULL ) ;
// Load color class
if ( ! _lua_import_class ( L , _lua_color_meta , & _lua_color_code ) )
ERR ( " Could not load color class! " ) ;
2014-05-09 00:07:41 -07:00
2014-04-11 01:10:52 -07:00
return L ;
}
2015-06-04 03:42:38 -07:00
static int
_lua_backtrace ( lua_State * L )
{
if ( ! lua_isstring ( L , 1 ) ) /* 'message' not a string? */
return 1 ; /* keep it intact */
ERR ( " Lua error: %s " , lua_tolstring ( L , 1 , NULL ) ) ;
lua_getfield ( L , LUA_GLOBALSINDEX , " debug " ) ;
if ( ! lua_istable ( L , - 1 ) )
{
lua_pop ( L , 1 ) ;
return 1 ;
}
lua_getfield ( L , - 1 , " traceback " ) ;
if ( ! lua_isfunction ( L , - 1 ) )
{
lua_pop ( L , 2 ) ;
return 1 ;
}
lua_pushvalue ( L , 1 ) ; /* pass error message */
lua_pushinteger ( L , 2 ) ; /* skip this function and traceback */
lua_call ( L , 2 , 1 ) ; /* call debug.traceback */
return 1 ;
}
2014-04-15 20:20:09 -07:00
# ifdef FILTERS_LEGACY_COMPAT
2014-04-11 01:10:52 -07:00
// This function is here to avoid breaking the ABI too much.
// It should not stay here long, only until all client apps have changed the filters' code to Lua.
static char *
_legacy_strdup ( const char * str )
{
2014-05-03 15:18:55 -07:00
static Eina_Strbuf * dst = NULL ;
2014-04-11 01:10:52 -07:00
2014-05-03 15:18:55 -07:00
if ( ! dst ) dst = eina_strbuf_new ( ) ;
2014-04-11 01:10:52 -07:00
for ( const char * ptr = str ; ptr & & * ptr ; ptr + + )
{
if ( ptr [ 0 ] = = ' / ' & & ptr [ 1 ] = = ' / ' )
2014-05-14 01:47:53 -07:00
{
// Comments
ptr = strchr ( ptr , ' \n ' ) ;
if ( ! ptr ) break ;
}
2014-04-11 01:10:52 -07:00
else if ( ptr [ 0 ] = = ' / ' & & ptr [ 1 ] = = ' * ' )
{
/* Comments */
ptr = strstr ( ptr + 2 , " */ " ) ;
2014-05-14 01:47:53 -07:00
if ( ! ptr ) break ;
ptr + + ;
2014-04-11 01:10:52 -07:00
}
else if ( * ptr = = ' ( ' )
eina_strbuf_append_char ( dst , ' { ' ) ;
else if ( * ptr = = ' ) ' )
eina_strbuf_append_char ( dst , ' } ' ) ;
else if ( * ptr = = ' # ' )
{
// Colors: #RGBA becomes "#RGBA"
ptr + + ;
eina_strbuf_append_length ( dst , " \" # " , 2 ) ;
while ( * ptr & & * ptr ! = ' , ' & & * ptr ! = ' ) ' )
eina_strbuf_append_char ( dst , * ptr + + ) ;
eina_strbuf_append_char ( dst , ' " ' ) ;
ptr - - ;
}
else if ( ! strncasecmp ( " buffer " , ptr , 6 ) )
{
// Buffers: "buffer : a (rgba)" into "local a = buffer (rgba)"
ptr = strchr ( ptr , ' : ' ) ;
if ( ! ptr ) break ;
eina_strbuf_append ( dst , " local " ) ;
for ( ptr + + ; ptr & & * ptr ; ptr + + )
{
if ( * ptr ! = ' ( ' )
eina_strbuf_append_char ( dst , * ptr ) ;
else
{
eina_strbuf_append ( dst , " = buffer{ " ) ;
break ;
}
}
}
else if ( ! strncasecmp ( " points " , ptr , 6 ) )
{
// Color curves: points = 0:0 - 255:255 becomes points = "0:0-255:255"
ptr = strchr ( ptr , ' = ' ) ;
if ( ! ptr ) break ;
ptr + + ;
eina_strbuf_append ( dst , " points = \" " ) ;
while ( * ptr & & * ptr ! = ' , ' & & * ptr ! = ' ) ' )
{
if ( isspace ( * ptr ) )
{
ptr + + ;
continue ;
}
eina_strbuf_append_char ( dst , * ptr + + ) ;
}
eina_strbuf_append_char ( dst , ' " ' ) ;
ptr - - ;
}
else if ( ! strncasecmp ( " curve " , ptr , 5 ) )
{
// Color curves: curve (0:0 - 255:255, becomes curve { points = "0:0-255:255",
const char * end = strchr ( ptr , ' ) ' ) ;
const char * points = strstr ( ptr , " points " ) ;
if ( ! end | | ( points > end ) ) break ;
if ( ! points )
{
while ( * ptr ! = ' ( ' ) ptr + + ;
ptr + + ;
eina_strbuf_append ( dst , " curve { points = \" " ) ;
while ( * ptr & & * ptr ! = ' , ' & & * ptr ! = ' ) ' )
{
if ( isspace ( * ptr ) )
{
ptr + + ;
continue ;
}
eina_strbuf_append_char ( dst , * ptr + + ) ;
}
eina_strbuf_append_char ( dst , ' " ' ) ;
ptr - - ;
}
2014-04-15 20:20:09 -07:00
else
{
eina_strbuf_append_length ( dst , " curve " , 5 ) ;
ptr + = 4 ;
}
2014-04-11 01:10:52 -07:00
}
else if ( ! strncasecmp ( " repeat " , ptr , 6 ) )
{
// repeat is a Lua keyword, replace all occurences by "repeat_xy"
if ( ptr [ - 1 ] ! = ' _ ' & & ptr [ 6 ] ! = ' _ ' )
{
eina_strbuf_append ( dst , " \" repeat_xy \" " ) ;
ptr + = 5 ;
}
else
eina_strbuf_append_char ( dst , * ptr ) ;
}
else
eina_strbuf_append_char ( dst , * ptr ) ;
}
return eina_strbuf_string_steal ( dst ) ;
}
2014-04-15 20:20:09 -07:00
# endif
2013-12-09 03:20:33 -08:00
2015-06-22 20:21:20 -07:00
static Eina_Bool
2015-05-26 03:37:21 -07:00
_filter_program_state_set ( Evas_Filter_Program * pgm )
{
lua_State * L = pgm - > L ;
// TODO:
// text properties: colors, font size, ascent/descent, style (enum)
/* State is defined as follow:
* state = {
* text = {
* outline = COL
* shadow = COL
* glow = COL
* glow2 = COL
* }
* color = COL
* }
*/
2015-06-04 03:42:38 -07:00
# define JOINC(k) (double) ({ DATA32 d; int A = pgm->state.k.a, R = pgm->state.k.r, G = pgm->state.k.g, B = pgm->state.k.b; \
evas_color_argb_unpremul ( A , & R , & G , & B ) ; d = ARGB_JOIN ( A , R , G , B ) ; d ; } )
2015-05-27 23:59:10 -07:00
# define SETFIELD(name, val) do { lua_pushnumber(L, val); lua_setfield(L, -2, name); } while(0)
2015-06-04 03:42:38 -07:00
# define SETCOLOR(name, val) do { lua_pushnumber(L, val); _lua_convert_color(L); lua_setfield(L, -2, name); } while(0)
2015-05-26 03:37:21 -07:00
2015-05-27 22:37:10 -07:00
// TODO: Mark program as dependent on some values so we can improve
// the changed flag (ie. re-run the filter only when required)
// eg. edje state_val changed but it is not used by the filter --> no redraw
// --> this needs a metatable with __index
2015-05-26 03:37:21 -07:00
lua_newtable ( L ) ; // "state"
{
2015-06-04 03:42:38 -07:00
SETCOLOR ( " color " , JOINC ( color ) ) ;
2015-05-27 23:59:10 -07:00
SETFIELD ( " scale " , pgm - > state . scale ) ;
2015-05-28 01:59:59 -07:00
SETFIELD ( " pos " , pgm - > state . pos ) ;
lua_newtable ( L ) ; // "cur"
{
SETFIELD ( " value " , pgm - > state . cur . value ) ;
lua_pushstring ( L , pgm - > state . cur . name ) ;
lua_setfield ( L , - 2 , " name " ) ;
lua_setfield ( L , - 2 , " cur " ) ;
}
2015-07-23 04:07:36 -07:00
if ( pgm - > state . next . name )
{
lua_newtable ( L ) ; // "next"
2015-05-28 01:59:59 -07:00
{
SETFIELD ( " value " , pgm - > state . next . value ) ;
lua_pushstring ( L , pgm - > state . next . name ) ;
lua_setfield ( L , - 2 , " name " ) ;
}
2015-07-23 04:07:36 -07:00
lua_setfield ( L , - 2 , " next " ) ;
}
2015-05-26 03:37:21 -07:00
lua_newtable ( L ) ; // "text"
{
2015-06-04 03:42:38 -07:00
SETCOLOR ( " outline " , JOINC ( text . outline ) ) ;
SETCOLOR ( " shadow " , JOINC ( text . shadow ) ) ;
SETCOLOR ( " glow " , JOINC ( text . glow ) ) ;
SETCOLOR ( " glow2 " , JOINC ( text . glow2 ) ) ;
2015-05-26 03:37:21 -07:00
lua_setfield ( L , - 2 , " text " ) ;
}
}
lua_setglobal ( L , " state " ) ;
2015-06-22 05:52:16 -07:00
/* now push all extra data */
if ( pgm - > data )
{
2015-06-23 00:40:51 -07:00
Evas_Filter_Data_Binding * db ;
EINA_INLIST_FOREACH ( pgm - > data , db )
2015-06-22 05:52:16 -07:00
{
2015-06-23 00:40:51 -07:00
if ( db - > value )
2015-06-22 19:44:54 -07:00
{
2015-06-23 00:40:51 -07:00
if ( db - > execute )
2015-06-22 19:44:54 -07:00
{
2015-06-23 00:40:51 -07:00
if ( luaL_dostring ( L , db - > value ) ! = 0 )
2015-06-22 20:21:20 -07:00
{
ERR ( " Failed to run value: %s " , lua_tostring ( L , - 1 ) ) ;
return EINA_FALSE ;
}
2015-06-22 19:44:54 -07:00
}
else
{
2015-06-23 00:40:51 -07:00
lua_pushstring ( L , db - > value ) ;
lua_setglobal ( L , db - > name ) ;
2015-06-22 19:44:54 -07:00
}
}
2015-06-22 05:52:16 -07:00
else
2015-06-22 19:44:54 -07:00
{
lua_pushnil ( L ) ;
2015-06-23 00:40:51 -07:00
lua_setglobal ( L , db - > name ) ;
2015-06-22 19:44:54 -07:00
}
2015-06-22 05:52:16 -07:00
}
}
2015-06-22 20:21:20 -07:00
return EINA_TRUE ;
2015-05-26 03:37:21 -07:00
# undef JOINC
# undef SETFIELD
2015-06-04 03:42:38 -07:00
# undef SETCOLOR
2015-05-26 03:37:21 -07:00
}
2015-06-22 20:21:20 -07:00
static Eina_Bool
2015-05-26 03:37:21 -07:00
_filter_program_reset ( Evas_Filter_Program * pgm )
{
Evas_Filter_Instruction * instr ;
lua_State * L = pgm - > L ;
Eina_Inlist * il ;
Buffer * buf ;
// Clear out commands
EINA_INLIST_FREE ( pgm - > instructions , instr )
{
pgm - > instructions = eina_inlist_remove ( pgm - > instructions , EINA_INLIST_GET ( instr ) ) ;
_instruction_del ( instr ) ;
}
// Clear out buffers
EINA_INLIST_FOREACH_SAFE ( pgm - > buffers , il , buf )
{
lua_pushnil ( L ) ;
lua_setglobal ( L , buf - > name ) ;
pgm - > buffers = eina_inlist_remove ( pgm - > buffers , EINA_INLIST_GET ( buf ) ) ;
_buffer_del ( buf ) ;
}
// Re-create buffers
_filter_program_buffers_set ( pgm ) ;
// Reset state table
2015-06-22 20:21:20 -07:00
return _filter_program_state_set ( pgm ) ;
2015-05-26 03:37:21 -07:00
}
2013-12-09 03:20:33 -08:00
/** Parse a style program */
2014-02-17 19:02:45 -08:00
EAPI Eina_Bool
2013-12-09 03:20:33 -08:00
evas_filter_program_parse ( Evas_Filter_Program * pgm , const char * str )
{
2014-04-11 01:10:52 -07:00
lua_State * L ;
Eina_Bool ok ;
2013-12-09 03:20:33 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL ( pgm , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( str , EINA_FALSE ) ;
EINA_SAFETY_ON_FALSE_RETURN_VAL ( * str ! = 0 , EINA_FALSE ) ;
2014-04-11 01:10:52 -07:00
L = _lua_state_create ( pgm ) ;
if ( ! L ) return EINA_FALSE ;
ok = ! luaL_loadstring ( L , str ) ;
2015-05-27 22:37:10 -07:00
if ( ! ok )
{
ERR ( " Failed to load Lua program: %s " , lua_tostring ( L , - 1 ) ) ;
}
2014-04-15 20:20:09 -07:00
# ifdef FILTERS_LEGACY_COMPAT
2014-04-11 01:10:52 -07:00
if ( ! ok )
{
char * code = _legacy_strdup ( str ) ;
2014-04-15 20:20:09 -07:00
DBG ( " Fallback to transformed legacy code: \n %s " , code ) ;
2014-04-11 01:10:52 -07:00
ok = ! luaL_loadstring ( L , code ) ;
free ( code ) ;
}
2014-04-15 20:20:09 -07:00
# endif
2014-06-10 18:00:44 -07:00
if ( ok )
2015-05-26 00:12:00 -07:00
{
pgm - > lua_func = luaL_ref ( L , LUA_REGISTRYINDEX ) ;
2015-06-22 20:21:20 -07:00
ok = _filter_program_reset ( pgm ) ;
if ( ok )
{
lua_getglobal ( L , _lua_errfunc_name ) ;
lua_rawgeti ( L , LUA_REGISTRYINDEX , pgm - > lua_func ) ;
ok = ! lua_pcall ( L , 0 , LUA_MULTRET , - 2 ) ;
}
2015-05-26 00:12:00 -07:00
}
2015-05-18 01:35:49 -07:00
2015-05-18 05:04:29 -07:00
if ( ! ok )
2014-06-10 18:00:44 -07:00
{
const char * msg = lua_tostring ( L , - 1 ) ;
ERR ( " Lua parsing failed: %s " , msg ) ;
2015-05-18 01:35:49 -07:00
lua_close ( L ) ;
2015-05-18 05:04:29 -07:00
pgm - > L = NULL ;
}
else if ( ! pgm - > instructions )
{
ERR ( " No instructions found in Lua script " ) ;
lua_close ( L ) ;
ok = EINA_FALSE ;
pgm - > L = NULL ;
2014-06-10 18:00:44 -07:00
}
2014-04-11 01:10:52 -07:00
pgm - > valid = ok ;
pgm - > padding_calc = EINA_FALSE ;
2015-05-26 03:37:21 -07:00
pgm - > changed = EINA_FALSE ;
2014-04-11 01:10:52 -07:00
return ok ;
2013-12-09 03:20:33 -08:00
}
2015-05-18 01:35:49 -07:00
/** Run a program, must be already loaded */
2015-05-26 00:12:00 -07:00
static void
_buffers_update ( Evas_Filter_Context * ctx , Evas_Filter_Program * pgm )
2015-05-18 01:35:49 -07:00
{
2015-05-26 00:12:00 -07:00
Evas_Object_Protected_Data * source ;
Evas_Filter_Proxy_Binding * pb ;
Evas_Filter_Buffer * fb ;
Buffer * buf ;
2015-05-18 01:35:49 -07:00
2015-05-26 00:12:00 -07:00
EINA_INLIST_FOREACH ( pgm - > buffers , buf )
2015-05-18 01:35:49 -07:00
{
2015-05-26 00:12:00 -07:00
if ( buf - > proxy )
{
pb = eina_hash_find ( pgm - > proxies , buf - > proxy ) ;
if ( ! pb ) continue ;
2015-05-18 01:35:49 -07:00
2015-05-26 00:12:00 -07:00
buf - > cid = evas_filter_buffer_empty_new ( ctx , buf - > alpha ) ;
fb = _filter_buffer_get ( ctx , buf - > cid ) ;
fb - > proxy = pb - > eo_proxy ;
fb - > source = pb - > eo_source ;
fb - > source_name = eina_stringshare_ref ( pb - > name ) ;
fb - > ctx - > has_proxies = EINA_TRUE ;
2015-05-18 01:35:49 -07:00
2015-05-26 00:12:00 -07:00
source = eo_data_scope_get ( fb - > source , EVAS_OBJECT_CLASS ) ;
if ( ( source - > cur - > geometry . w ! = buf - > w ) | |
( source - > cur - > geometry . h ! = buf - > h ) )
pgm - > changed = EINA_TRUE ;
buf - > w = fb - > w = source - > cur - > geometry . w ;
buf - > h = fb - > h = source - > cur - > geometry . h ;
}
else
{
2015-05-26 03:37:21 -07:00
if ( ( buf - > w ! = pgm - > state . w ) | | ( buf - > h ! = pgm - > state . h ) )
2015-05-26 00:12:00 -07:00
pgm - > changed = EINA_TRUE ;
buf - > cid = evas_filter_buffer_empty_new ( ctx , buf - > alpha ) ;
fb = _filter_buffer_get ( ctx , buf - > cid ) ;
2015-05-26 03:37:21 -07:00
fb - > w = buf - > w = pgm - > state . w ;
fb - > h = buf - > h = pgm - > state . h ;
2015-05-26 00:12:00 -07:00
}
2015-05-18 01:35:49 -07:00
}
}
2013-12-09 03:20:33 -08:00
/** Evaluate required padding to correctly apply an effect */
2014-02-17 19:02:45 -08:00
EAPI Eina_Bool
2013-12-09 03:20:33 -08:00
evas_filter_program_padding_get ( Evas_Filter_Program * pgm ,
int * l , int * r , int * t , int * b )
{
Evas_Filter_Instruction * instr ;
int pl = 0 , pr = 0 , pt = 0 , pb = 0 ;
2013-12-12 23:21:59 -08:00
int maxl = 0 , maxr = 0 , maxt = 0 , maxb = 0 ;
Buffer * buf ;
2013-12-09 03:20:33 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL ( pgm , EINA_FALSE ) ;
2014-03-20 19:52:52 -07:00
if ( pgm - > padding_calc | | pgm - > padding_set )
{
if ( l ) * l = pgm - > pad . l ;
if ( r ) * r = pgm - > pad . r ;
if ( t ) * t = pgm - > pad . t ;
if ( b ) * b = pgm - > pad . b ;
return EINA_TRUE ;
}
2013-12-12 23:21:59 -08:00
// Reset all paddings
EINA_INLIST_FOREACH ( pgm - > buffers , buf )
buf - > pad . l = buf - > pad . r = buf - > pad . t = buf - > pad . b = 0 ;
// Accumulate paddings
2013-12-09 03:20:33 -08:00
EINA_INLIST_FOREACH ( pgm - > instructions , instr )
2014-03-20 19:52:52 -07:00
{
if ( instr - > type = = EVAS_FILTER_MODE_PADDING_SET )
{
instr - > pad . update ( pgm , instr , & maxl , & maxr , & maxt , & maxb ) ;
break ;
}
else if ( instr - > pad . update )
{
instr - > pad . update ( pgm , instr , & pl , & pr , & pt , & pb ) ;
if ( pl > maxl ) maxl = pl ;
if ( pr > maxr ) maxr = pr ;
if ( pt > maxt ) maxt = pt ;
if ( pb > maxb ) maxb = pb ;
}
}
pgm - > pad . l = maxl ;
pgm - > pad . r = maxr ;
pgm - > pad . t = maxt ;
pgm - > pad . b = maxb ;
pgm - > padding_calc = EINA_TRUE ;
2013-12-09 03:20:33 -08:00
2013-12-12 23:21:59 -08:00
if ( l ) * l = maxl ;
if ( r ) * r = maxr ;
if ( t ) * t = maxt ;
if ( b ) * b = maxb ;
2013-12-09 03:20:33 -08:00
return EINA_TRUE ;
}
/** Create an empty filter program for style parsing */
2014-02-17 19:02:45 -08:00
EAPI Evas_Filter_Program *
2014-03-17 00:10:03 -07:00
evas_filter_program_new ( const char * name , Eina_Bool input_alpha )
2013-12-09 03:20:33 -08:00
{
Evas_Filter_Program * pgm ;
pgm = calloc ( 1 , sizeof ( Evas_Filter_Program ) ) ;
if ( ! pgm ) return NULL ;
pgm - > name = eina_stringshare_add ( name ) ;
2015-05-18 05:04:29 -07:00
pgm - > input_alpha = input_alpha ;
2015-05-26 03:37:21 -07:00
pgm - > state . color . r = 255 ;
pgm - > state . color . g = 255 ;
pgm - > state . color . b = 255 ;
pgm - > state . color . a = 255 ;
2015-05-27 23:59:10 -07:00
pgm - > state . scale = 1.0 ;
2013-12-09 03:20:33 -08:00
return pgm ;
}
2015-05-26 03:37:21 -07:00
EAPI Eina_Bool
evas_filter_program_state_set ( Evas_Filter_Program * pgm , Evas_Object * eo_obj ,
2015-05-28 01:59:59 -07:00
Evas_Object_Protected_Data * obj ,
const char * cur_state , double cur_val ,
const char * next_state , double next_val ,
double pos )
2015-05-18 01:35:49 -07:00
{
2015-05-26 03:37:21 -07:00
Evas_Filter_Program_State old_state ;
2015-05-18 01:35:49 -07:00
2015-05-26 03:37:21 -07:00
EINA_SAFETY_ON_NULL_RETURN_VAL ( pgm , EINA_FALSE ) ;
2015-05-18 01:35:49 -07:00
2015-05-26 03:37:21 -07:00
memcpy ( & old_state , & pgm - > state , sizeof ( Evas_Filter_Program_State ) ) ;
pgm - > state . w = obj - > cur - > geometry . w ;
pgm - > state . h = obj - > cur - > geometry . h ;
2015-05-27 23:59:10 -07:00
pgm - > state . scale = obj - > cur - > scale ;
2015-05-28 01:59:59 -07:00
pgm - > state . pos = pos ;
pgm - > state . cur . name = cur_state ;
pgm - > state . cur . value = cur_val ;
pgm - > state . next . name = next_state ;
pgm - > state . next . value = next_val ;
2015-05-26 03:37:21 -07:00
eo_do ( eo_obj ,
efl_gfx_color_get ( & pgm - > state . color . r ,
& pgm - > state . color . g ,
& pgm - > state . color . b ,
& pgm - > state . color . a ) ) ;
if ( eo_isa ( eo_obj , EVAS_TEXT_CLASS ) )
{
eo_do ( eo_obj ,
evas_obj_text_shadow_color_get ( & pgm - > state . text . shadow . r ,
& pgm - > state . text . shadow . g ,
& pgm - > state . text . shadow . b ,
& pgm - > state . text . shadow . a ) ,
evas_obj_text_outline_color_get ( & pgm - > state . text . outline . r ,
& pgm - > state . text . outline . g ,
& pgm - > state . text . outline . b ,
& pgm - > state . text . outline . a ) ,
evas_obj_text_glow_color_get ( & pgm - > state . text . glow . r ,
& pgm - > state . text . glow . g ,
& pgm - > state . text . glow . b ,
& pgm - > state . text . glow . a ) ,
evas_obj_text_glow2_color_get ( & pgm - > state . text . glow2 . r ,
& pgm - > state . text . glow2 . g ,
& pgm - > state . text . glow2 . b ,
& pgm - > state . text . glow2 . a ) ) ;
}
2015-05-18 01:35:49 -07:00
2015-05-26 03:37:21 -07:00
if ( memcmp ( & old_state , & pgm - > state , sizeof ( Evas_Filter_Program_State ) ) ! = 0 )
pgm - > changed = EINA_TRUE ;
if ( pgm - > changed )
pgm - > padding_calc = EINA_FALSE ;
return pgm - > changed ;
2015-05-18 01:35:49 -07:00
}
2014-02-05 03:09:05 -08:00
/** Bind objects for proxy rendering */
2014-02-17 19:02:45 -08:00
EAPI void
2014-02-04 18:40:10 -08:00
evas_filter_program_source_set_all ( Evas_Filter_Program * pgm ,
Eina_Hash * proxies )
{
2014-02-05 03:09:05 -08:00
if ( ! pgm ) return ;
pgm - > proxies = proxies ;
2013-12-09 03:20:33 -08:00
}
2015-06-22 05:52:16 -07:00
void
2015-06-23 00:40:51 -07:00
evas_filter_program_data_set_all ( Evas_Filter_Program * pgm , Eina_Inlist * data )
2015-06-22 05:52:16 -07:00
{
if ( ! pgm ) return ;
pgm - > data = data ;
}
2013-12-09 03:20:33 -08:00
/** Glue with Evas' filters */
# define CA(color) ((color >> 24) & 0xFF)
# define CR(color) ((color >> 16) & 0xFF)
# define CG(color) ((color >> 8) & 0xFF)
# define CB(color) ((color) & 0xFF)
# define SETCOLOR(c) do { ENFN->context_color_get(ENDT, dc, &R, &G, &B, &A); \
ENFN - > context_color_set ( ENDT , dc , CR ( c ) , CG ( c ) , CB ( c ) , CA ( c ) ) ; } while ( 0 )
# define RESETCOLOR() do { ENFN->context_color_set(ENDT, dc, R, G, B, A); } while (0)
2014-01-02 01:44:01 -08:00
# define SETCLIP(l, r, t, b) int _l = 0, _r = 0, _t = 0, _b = 0; \
do { ENFN - > context_clip_get ( ENDT , dc , & _l , & _r , & _t , & _b ) ; \
ENFN - > context_clip_set ( ENDT , dc , l , r , t , b ) ; } while ( 0 )
# define RESETCLIP() do { ENFN->context_clip_set(ENDT, dc, _l, _r, _t, _b); } while (0)
2013-12-30 23:01:06 -08:00
static Evas_Filter_Fill_Mode
_fill_mode_get ( Evas_Filter_Instruction * instr )
{
const char * fill ;
unsigned k ;
if ( ! instr ) return EVAS_FILTER_FILL_MODE_NONE ;
2013-12-31 00:51:09 -08:00
fill = _instruction_param_gets ( instr , " fillmode " , NULL ) ;
2014-04-11 01:10:52 -07:00
if ( ! fill ) return EVAS_FILTER_FILL_MODE_NONE ;
2013-12-30 23:01:06 -08:00
for ( k = 0 ; k < sizeof ( fill_modes ) / sizeof ( fill_modes [ 0 ] ) ; k + + )
{
if ( ! strcasecmp ( fill_modes [ k ] . name , fill ) )
return fill_modes [ k ] . value ;
}
return EVAS_FILTER_FILL_MODE_NONE ;
}
2013-12-09 03:20:33 -08:00
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_blend ( Evas_Filter_Context * ctx ,
2013-12-09 03:20:33 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
Eina_Bool isset = EINA_FALSE ;
DATA32 color ;
2015-05-18 05:04:29 -07:00
Buffer * src , * dst ;
2013-12-30 23:01:06 -08:00
Evas_Filter_Fill_Mode fillmode ;
2014-02-11 17:14:38 -08:00
int cmdid , ox , oy , A , R , G , B ;
2013-12-09 03:20:33 -08:00
ox = _instruction_param_geti ( instr , " ox " , NULL ) ;
oy = _instruction_param_geti ( instr , " oy " , NULL ) ;
color = _instruction_param_getc ( instr , " color " , & isset ) ;
2013-12-30 23:01:06 -08:00
fillmode = _fill_mode_get ( instr ) ;
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2013-12-09 03:20:33 -08:00
if ( isset ) SETCOLOR ( color ) ;
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_blend_add ( ctx , dc , src - > cid , dst - > cid , ox , oy ,
2013-12-31 00:51:09 -08:00
fillmode ) ;
2013-12-09 03:20:33 -08:00
if ( isset ) RESETCOLOR ( ) ;
2014-01-22 23:54:50 -08:00
if ( cmdid < 0 ) return cmdid ;
2013-12-09 03:20:33 -08:00
return cmdid ;
}
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_blur ( Evas_Filter_Context * ctx ,
2013-12-09 03:20:33 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
2014-03-11 02:21:46 -07:00
Eina_Bool colorset = EINA_FALSE , yset = EINA_FALSE , cntset = EINA_FALSE ;
2013-12-09 03:20:33 -08:00
Evas_Filter_Blur_Type type = EVAS_FILTER_BLUR_DEFAULT ;
2015-05-18 05:04:29 -07:00
const char * typestr ;
2013-12-09 03:20:33 -08:00
DATA32 color ;
2015-05-18 05:04:29 -07:00
Buffer * src , * dst ;
2014-03-11 02:21:46 -07:00
int cmdid , ox , oy , rx , ry , A , R , G , B , count ;
2013-12-09 03:20:33 -08:00
ox = _instruction_param_geti ( instr , " ox " , NULL ) ;
oy = _instruction_param_geti ( instr , " oy " , NULL ) ;
rx = _instruction_param_geti ( instr , " rx " , NULL ) ;
ry = _instruction_param_geti ( instr , " ry " , & yset ) ;
2014-03-11 02:21:46 -07:00
color = _instruction_param_getc ( instr , " color " , & colorset ) ;
2013-12-09 03:20:33 -08:00
typestr = _instruction_param_gets ( instr , " type " , NULL ) ;
2014-03-11 02:21:46 -07:00
count = _instruction_param_geti ( instr , " count " , & cntset ) ;
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2013-12-09 03:20:33 -08:00
if ( typestr )
{
if ( ! strcasecmp ( typestr , " gaussian " ) )
type = EVAS_FILTER_BLUR_GAUSSIAN ;
else if ( ! strcasecmp ( typestr , " box " ) )
type = EVAS_FILTER_BLUR_BOX ;
else if ( ! strcasecmp ( typestr , " default " ) )
type = EVAS_FILTER_BLUR_DEFAULT ;
else
ERR ( " Unknown blur type '%s'. Using default blur. " , typestr ) ;
}
2014-03-11 02:21:46 -07:00
if ( type = = EVAS_FILTER_BLUR_BOX )
{
if ( count < 1 ) count = 1 ;
if ( count > 6 )
{
WRN ( " Box blur count should be below 6, defaults to 3. " ) ;
count = 3 ;
}
}
else
{
if ( cntset ) WRN ( " Blur count can only be used with BOX blur. " ) ;
count = 1 ;
}
2013-12-09 03:20:33 -08:00
if ( ! yset ) ry = rx ;
2014-03-11 02:21:46 -07:00
if ( colorset ) SETCOLOR ( color ) ;
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_blur_add ( ctx , dc , src - > cid , dst - > cid , type ,
2014-03-11 02:21:46 -07:00
rx , ry , ox , oy , count ) ;
if ( colorset ) RESETCOLOR ( ) ;
2013-12-09 03:20:33 -08:00
return cmdid ;
}
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_bump ( Evas_Filter_Context * ctx ,
2013-12-11 02:35:24 -08:00
Evas_Filter_Instruction * instr , void * dc )
2013-12-09 03:20:33 -08:00
{
Evas_Filter_Bump_Flags flags = EVAS_FILTER_BUMP_NORMAL ;
2013-12-30 23:01:06 -08:00
Evas_Filter_Fill_Mode fillmode ;
2013-12-09 03:20:33 -08:00
DATA32 color , black , white ;
2015-05-18 05:04:29 -07:00
Buffer * src , * dst , * map ;
2013-12-09 03:20:33 -08:00
double azimuth , elevation , depth , specular ;
int cmdid , compensate ;
color = _instruction_param_getc ( instr , " color " , NULL ) ;
white = _instruction_param_getc ( instr , " white " , NULL ) ;
black = _instruction_param_getc ( instr , " black " , NULL ) ;
azimuth = _instruction_param_getd ( instr , " azimuth " , NULL ) ;
elevation = _instruction_param_getd ( instr , " elevation " , NULL ) ;
depth = _instruction_param_getd ( instr , " depth " , NULL ) ;
specular = _instruction_param_getd ( instr , " specular " , NULL ) ;
compensate = _instruction_param_geti ( instr , " compensate " , NULL ) ;
2013-12-30 23:01:06 -08:00
fillmode = _fill_mode_get ( instr ) ;
2013-12-09 03:20:33 -08:00
if ( compensate ) flags | = EVAS_FILTER_BUMP_COMPENSATE ;
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
map = _instruction_param_getbuf ( instr , " map " , NULL ) ;
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
INSTR_PARAM_CHECK ( map ) ;
2013-12-09 03:20:33 -08:00
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_bump_map_add ( ctx , dc , src - > cid , map - > cid , dst - > cid ,
2013-12-09 03:20:33 -08:00
azimuth , elevation , depth , specular ,
2013-12-31 00:51:09 -08:00
black , color , white , flags ,
fillmode ) ;
2013-12-09 03:20:33 -08:00
return cmdid ;
}
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_displace ( Evas_Filter_Context * ctx ,
2013-12-11 02:35:24 -08:00
Evas_Filter_Instruction * instr , void * dc )
2013-12-09 03:20:33 -08:00
{
2013-12-30 23:01:06 -08:00
Evas_Filter_Fill_Mode fillmode ;
2014-02-11 19:42:47 -08:00
Evas_Filter_Displacement_Flags flags =
EVAS_FILTER_DISPLACE_STRETCH | EVAS_FILTER_DISPLACE_LINEAR ;
2015-05-18 05:04:29 -07:00
const char * flagsstr ;
Buffer * src , * dst , * map ;
2014-02-11 19:42:47 -08:00
int cmdid , intensity ;
Eina_Bool isset = EINA_FALSE ;
2013-12-09 03:20:33 -08:00
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
map = _instruction_param_getbuf ( instr , " map " , NULL ) ;
2013-12-09 03:20:33 -08:00
intensity = _instruction_param_geti ( instr , " intensity " , NULL ) ;
2014-02-11 19:42:47 -08:00
flagsstr = _instruction_param_gets ( instr , " flags " , & isset ) ;
2013-12-30 23:01:06 -08:00
fillmode = _fill_mode_get ( instr ) ;
2015-05-18 05:04:29 -07:00
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
INSTR_PARAM_CHECK ( map ) ;
2013-12-09 03:20:33 -08:00
2014-02-11 19:42:47 -08:00
if ( ! flagsstr ) flagsstr = " default " ;
if ( ! strcasecmp ( flagsstr , " nearest " ) )
flags = EVAS_FILTER_DISPLACE_NEAREST ;
else if ( ! strcasecmp ( flagsstr , " smooth " ) )
flags = EVAS_FILTER_DISPLACE_LINEAR ;
else if ( ! strcasecmp ( flagsstr , " nearest_stretch " ) )
flags = EVAS_FILTER_DISPLACE_NEAREST | EVAS_FILTER_DISPLACE_STRETCH ;
else if ( ! strcasecmp ( flagsstr , " default " ) | | ! strcasecmp ( flagsstr , " smooth_stretch " ) )
flags = EVAS_FILTER_DISPLACE_STRETCH | EVAS_FILTER_DISPLACE_LINEAR ;
else if ( isset )
WRN ( " Invalid flags '%s' in displace operation. Using default instead " , flagsstr ) ;
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_displacement_map_add ( ctx , dc , src - > cid , dst - > cid ,
map - > cid , flags , intensity ,
2013-12-31 00:51:09 -08:00
fillmode ) ;
2013-12-09 03:20:33 -08:00
return cmdid ;
}
2013-12-12 00:46:46 -08:00
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_fill ( Evas_Filter_Context * ctx ,
2013-12-12 00:46:46 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
2015-05-18 05:04:29 -07:00
Buffer * dst ;
2014-01-02 01:44:01 -08:00
int R , G , B , A , l , r , t , b ;
Evas_Filter_Command * cmd ;
2014-02-13 19:26:41 -08:00
Eina_Inlist * il ;
2013-12-12 00:46:46 -08:00
DATA32 color ;
int cmdid ;
2015-05-18 05:04:29 -07:00
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
2013-12-12 00:46:46 -08:00
color = _instruction_param_getc ( instr , " color " , NULL ) ;
2014-01-02 01:44:01 -08:00
l = _instruction_param_geti ( instr , " l " , NULL ) ;
r = _instruction_param_geti ( instr , " r " , NULL ) ;
t = _instruction_param_geti ( instr , " t " , NULL ) ;
b = _instruction_param_geti ( instr , " b " , NULL ) ;
2015-05-18 05:04:29 -07:00
INSTR_PARAM_CHECK ( dst ) ;
2013-12-12 00:46:46 -08:00
2014-01-01 22:57:44 -08:00
SETCOLOR ( color ) ;
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_fill_add ( ctx , dc , dst - > cid ) ;
2014-01-01 22:57:44 -08:00
RESETCOLOR ( ) ;
2013-12-12 00:46:46 -08:00
2014-02-13 19:26:41 -08:00
if ( cmdid < 0 ) return - 1 ;
il = eina_inlist_last ( ctx - > commands ) ;
if ( ! il ) return - 1 ;
cmd = EINA_INLIST_CONTAINER_GET ( il , Evas_Filter_Command ) ;
2014-01-02 01:44:01 -08:00
cmd - > draw . clip . l = l ;
cmd - > draw . clip . r = r ;
cmd - > draw . clip . t = t ;
cmd - > draw . clip . b = b ;
cmd - > draw . clip_mode_lrtb = EINA_TRUE ;
2013-12-12 00:46:46 -08:00
return cmdid ;
}
2013-12-09 03:20:33 -08:00
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_grow ( Evas_Filter_Context * ctx ,
2013-12-09 03:20:33 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
2014-02-19 02:38:58 -08:00
Evas_Filter_Command * cmd ;
2015-05-18 05:04:29 -07:00
Buffer * src , * dst ;
2013-12-09 03:20:33 -08:00
Eina_Bool smooth ;
int cmdid , radius ;
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
2013-12-09 03:20:33 -08:00
radius = _instruction_param_geti ( instr , " radius " , NULL ) ;
smooth = _instruction_param_geti ( instr , " smooth " , NULL ) ;
2015-05-18 05:04:29 -07:00
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2013-12-09 03:20:33 -08:00
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_grow_add ( ctx , dc , src - > cid , dst - > cid ,
2013-12-09 03:20:33 -08:00
radius , smooth ) ;
2014-02-19 02:38:58 -08:00
cmd = _evas_filter_command_get ( ctx , cmdid ) ;
if ( cmd ) cmd - > draw . need_temp_buffer = EINA_TRUE ;
2013-12-09 03:20:33 -08:00
return cmdid ;
}
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_mask ( Evas_Filter_Context * ctx ,
2013-12-09 03:20:33 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
2013-12-30 23:01:06 -08:00
Evas_Filter_Fill_Mode fillmode ;
2015-05-18 05:04:29 -07:00
Buffer * src , * dst , * mask ;
2013-12-09 03:20:33 -08:00
DATA32 color ;
2014-02-11 17:14:38 -08:00
int R , G , B , A , cmdid ;
2013-12-09 03:20:33 -08:00
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
mask = _instruction_param_getbuf ( instr , " mask " , NULL ) ;
2013-12-09 03:20:33 -08:00
color = _instruction_param_getc ( instr , " color " , NULL ) ;
2013-12-30 23:01:06 -08:00
fillmode = _fill_mode_get ( instr ) ;
2015-05-18 05:04:29 -07:00
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
INSTR_PARAM_CHECK ( mask ) ;
2013-12-09 03:20:33 -08:00
2014-01-01 22:57:44 -08:00
SETCOLOR ( color ) ;
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_mask_add ( ctx , dc , src - > cid , mask - > cid , dst - > cid , fillmode ) ;
2014-01-01 22:57:44 -08:00
RESETCOLOR ( ) ;
2014-01-22 23:54:50 -08:00
if ( cmdid < 0 ) return cmdid ;
2015-05-18 05:04:29 -07:00
if ( ! src - > alpha & & ! mask - > alpha & & ! dst - > alpha )
2014-01-22 23:54:50 -08:00
{
Evas_Filter_Command * cmd ;
cmd = _evas_filter_command_get ( ctx , cmdid ) ;
cmd - > draw . need_temp_buffer = EINA_TRUE ;
}
2014-01-01 22:57:44 -08:00
return cmdid ;
}
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_curve ( Evas_Filter_Context * ctx ,
2014-01-01 22:57:44 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
Evas_Filter_Interpolation_Mode mode = EVAS_FILTER_INTERPOLATION_MODE_LINEAR ;
Evas_Filter_Channel channel = EVAS_FILTER_CHANNEL_RGB ;
2015-05-27 22:37:10 -07:00
const char * interpolation , * channel_name ;
2015-05-18 05:04:29 -07:00
Buffer * src , * dst ;
2015-05-27 22:37:10 -07:00
DATA8 values [ 256 ] ;
int * points ;
int cmdid ;
2014-01-01 22:57:44 -08:00
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
2015-05-27 22:37:10 -07:00
points = _instruction_param_getspecial ( instr , " points " , NULL ) ;
2014-01-01 22:57:44 -08:00
interpolation = _instruction_param_gets ( instr , " interpolation " , NULL ) ;
channel_name = _instruction_param_gets ( instr , " channel " , NULL ) ;
2015-05-27 22:37:10 -07:00
INSTR_PARAM_CHECK ( points ) ;
2015-05-18 05:04:29 -07:00
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2014-01-01 22:57:44 -08:00
if ( channel_name )
{
if ( tolower ( * channel_name ) = = ' r ' )
{
if ( ! strcasecmp ( channel_name , " rgb " ) )
channel = EVAS_FILTER_CHANNEL_RGB ;
else
channel = EVAS_FILTER_CHANNEL_RED ;
}
else if ( tolower ( * channel_name ) = = ' g ' )
channel = EVAS_FILTER_CHANNEL_GREEN ;
else if ( tolower ( * channel_name ) = = ' b ' )
channel = EVAS_FILTER_CHANNEL_BLUE ;
else if ( tolower ( * channel_name ) = = ' a ' )
channel = EVAS_FILTER_CHANNEL_ALPHA ;
}
2014-02-03 19:32:15 -08:00
if ( interpolation & & ! strcasecmp ( interpolation , " none " ) )
mode = EVAS_FILTER_INTERPOLATION_MODE_NONE ;
2014-01-01 22:57:44 -08:00
2015-05-27 22:37:10 -07:00
if ( ! evas_filter_interpolate ( values , points , mode ) )
2014-01-01 22:57:44 -08:00
{
int x ;
ERR ( " Failed to parse the interpolation chain " ) ;
for ( x = 0 ; x < 256 ; x + + )
values [ x ] = x ;
}
2015-05-18 05:04:29 -07:00
cmdid = evas_filter_command_curve_add ( ctx , dc , src - > cid , dst - > cid , values , channel ) ;
2013-12-09 03:20:33 -08:00
return cmdid ;
}
2014-01-07 01:38:22 -08:00
static int
2015-05-18 05:04:29 -07:00
_instr2cmd_transform ( Evas_Filter_Context * ctx ,
2014-01-07 01:38:22 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
Evas_Filter_Transform_Flags flags ;
2015-05-18 05:04:29 -07:00
const char * op ;
Buffer * src , * dst ;
2014-01-07 01:38:22 -08:00
int ox = 0 , oy ;
op = _instruction_param_gets ( instr , " op " , NULL ) ;
2015-05-18 05:04:29 -07:00
src = _instruction_param_getbuf ( instr , " src " , NULL ) ;
dst = _instruction_param_getbuf ( instr , " dst " , NULL ) ;
2014-01-07 01:38:22 -08:00
// ox = _instruction_param_geti(instr, "ox", NULL);
oy = _instruction_param_geti ( instr , " oy " , NULL ) ;
2015-05-18 05:04:29 -07:00
INSTR_PARAM_CHECK ( src ) ;
INSTR_PARAM_CHECK ( dst ) ;
2014-01-07 01:38:22 -08:00
if ( ! strcasecmp ( op , " vflip " ) )
flags = EVAS_FILTER_TRANSFORM_VFLIP ;
else
{
ERR ( " Invalid transform '%s' " , op ) ;
return - 1 ;
}
2015-05-18 05:04:29 -07:00
return evas_filter_command_transform_add ( ctx , dc , src - > cid , dst - > cid , flags , ox , oy ) ;
2014-01-07 01:38:22 -08:00
}
2013-12-09 03:20:33 -08:00
static int
2015-05-18 05:04:29 -07:00
_command_from_instruction ( Evas_Filter_Context * ctx ,
2013-12-09 03:20:33 -08:00
Evas_Filter_Instruction * instr , void * dc )
{
2015-05-18 05:04:29 -07:00
int ( * instr2cmd ) ( Evas_Filter_Context * , Evas_Filter_Instruction * , void * ) ;
2013-12-09 03:20:33 -08:00
switch ( instr - > type )
{
case EVAS_FILTER_MODE_BLEND :
instr2cmd = _instr2cmd_blend ;
break ;
case EVAS_FILTER_MODE_BLUR :
instr2cmd = _instr2cmd_blur ;
break ;
case EVAS_FILTER_MODE_BUMP :
instr2cmd = _instr2cmd_bump ;
break ;
case EVAS_FILTER_MODE_DISPLACE :
instr2cmd = _instr2cmd_displace ;
break ;
2013-12-12 00:46:46 -08:00
case EVAS_FILTER_MODE_FILL :
instr2cmd = _instr2cmd_fill ;
break ;
2013-12-09 03:20:33 -08:00
case EVAS_FILTER_MODE_GROW :
instr2cmd = _instr2cmd_grow ;
break ;
case EVAS_FILTER_MODE_MASK :
instr2cmd = _instr2cmd_mask ;
break ;
case EVAS_FILTER_MODE_CURVE :
instr2cmd = _instr2cmd_curve ;
break ;
2014-01-07 01:38:22 -08:00
case EVAS_FILTER_MODE_TRANSFORM :
instr2cmd = _instr2cmd_transform ;
break ;
2014-03-20 19:52:52 -07:00
case EVAS_FILTER_MODE_PADDING_SET :
2014-04-11 01:10:52 -07:00
case EVAS_FILTER_MODE_BUFFER :
2014-03-20 19:52:52 -07:00
return EINA_TRUE ;
2013-12-09 03:20:33 -08:00
default :
2013-12-29 22:43:52 -08:00
CRI ( " Invalid instruction type: %d " , instr - > type ) ;
2013-12-09 03:20:33 -08:00
return - 1 ;
}
2015-05-18 05:04:29 -07:00
return instr2cmd ( ctx , instr , dc ) ;
2013-12-09 03:20:33 -08:00
}
2014-04-11 01:10:52 -07:00
# ifdef FILTERS_DEBUG
static void
_instruction_dump ( Evas_Filter_Instruction * instr )
{
Eina_Strbuf * str ;
const char * comma = " " ;
Instruction_Param * param ;
if ( ! instr ) return ;
str = eina_strbuf_new ( ) ;
eina_strbuf_append ( str , instr - > name ) ;
eina_strbuf_append ( str , " ({ " ) ;
EINA_INLIST_FOREACH ( instr - > params , param )
{
switch ( param - > type )
{
case VT_BOOL :
case VT_INT :
2015-05-18 05:04:29 -07:00
eina_strbuf_append_printf ( str , " %s%s = %d " , comma , param - > name , param - > value . i ) ;
2014-04-11 01:10:52 -07:00
break ;
case VT_COLOR :
2015-05-18 05:04:29 -07:00
eina_strbuf_append_printf ( str , " %s%s = 0x%08x " , comma , param - > name , param - > value . c ) ;
2014-04-11 01:10:52 -07:00
break ;
case VT_REAL :
2015-05-18 05:04:29 -07:00
eina_strbuf_append_printf ( str , " %s%s = %f " , comma , param - > name , param - > value . f ) ;
2014-04-11 01:10:52 -07:00
break ;
case VT_STRING :
2015-05-18 05:04:29 -07:00
if ( param - > value . s )
eina_strbuf_append_printf ( str , " %s%s = \" %s \" " , comma , param - > name , param - > value . s ) ;
else
eina_strbuf_append_printf ( str , " %s%s = nil " , comma , param - > name ) ;
break ;
2014-04-11 01:10:52 -07:00
case VT_BUFFER :
2015-05-18 05:04:29 -07:00
if ( param - > value . buf )
{
Buffer * buf = param - > value . buf ;
eina_strbuf_append_printf ( str , " %s%s = Buffer[#%d %dx%d %s%s%s] " ,
comma , param - > name ,
buf - > cid , buf - > w , buf - > h ,
buf - > alpha ? " alpha " : " rgba " ,
buf - > proxy ? " src: " : " " ,
buf - > proxy ? buf - > proxy : " " ) ;
}
else
eina_strbuf_append_printf ( str , " %s%s = nil " , comma , param - > name ) ;
2014-04-11 01:10:52 -07:00
break ;
case VT_NONE :
default :
eina_strbuf_append_printf ( str , " %s%s = <INVALID> " , comma , param - > name ) ;
break ;
}
comma = " , " ;
}
eina_strbuf_append ( str , " }) " ) ;
2015-06-09 05:29:13 -07:00
XDBG ( " %s " , eina_strbuf_string_get ( str ) ) ;
2014-04-11 01:10:52 -07:00
eina_strbuf_free ( str ) ;
}
# else
# define _instruction_dump(a) do {} while(0)
# endif
2013-12-09 03:20:33 -08:00
Eina_Bool
2014-02-05 03:09:05 -08:00
evas_filter_context_program_use ( Evas_Filter_Context * ctx ,
2013-12-09 03:20:33 -08:00
Evas_Filter_Program * pgm )
{
Evas_Filter_Instruction * instr ;
Eina_Bool success = EINA_FALSE ;
void * dc = NULL ;
int cmdid ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( ctx , EINA_FALSE ) ;
EINA_SAFETY_ON_NULL_RETURN_VAL ( pgm , EINA_FALSE ) ;
EINA_SAFETY_ON_FALSE_RETURN_VAL ( pgm - > valid , EINA_FALSE ) ;
2015-06-09 05:29:13 -07:00
XDBG ( " Using program '%s' for context %p " , pgm - > name , ctx ) ;
2013-12-09 03:20:33 -08:00
2015-05-18 01:35:49 -07:00
// Copy current state (size, edje state val, color class, etc...)
2015-05-26 03:37:21 -07:00
ctx - > w = pgm - > state . w ;
ctx - > h = pgm - > state . h ;
2015-05-18 01:35:49 -07:00
2013-12-09 03:20:33 -08:00
// Create empty context with all required buffers
evas_filter_context_clear ( ctx ) ;
2014-02-05 03:09:05 -08:00
2015-05-26 00:12:00 -07:00
if ( pgm - > changed )
{
2015-05-26 03:37:21 -07:00
pgm - > changed = EINA_FALSE ;
_filter_program_reset ( pgm ) ;
2015-06-04 03:42:38 -07:00
lua_getglobal ( pgm - > L , _lua_errfunc_name ) ;
2015-05-26 00:12:00 -07:00
lua_rawgeti ( pgm - > L , LUA_REGISTRYINDEX , pgm - > lua_func ) ;
2015-06-04 03:42:38 -07:00
success = ! lua_pcall ( pgm - > L , 0 , LUA_MULTRET , - 2 ) ;
2015-05-26 00:12:00 -07:00
if ( ! success )
2015-05-18 01:35:49 -07:00
{
2015-05-26 00:12:00 -07:00
const char * msg = lua_tostring ( pgm - > L , - 1 ) ;
ERR ( " Lua execution failed: %s " , msg ) ;
goto end ;
2013-12-09 03:20:33 -08:00
}
}
2015-05-26 03:37:21 -07:00
_buffers_update ( ctx , pgm ) ;
2013-12-09 03:20:33 -08:00
2014-01-06 21:55:27 -08:00
// Compute and save padding info
evas_filter_program_padding_get ( pgm , & ctx - > padl , & ctx - > padr , & ctx - > padt , & ctx - > padb ) ;
2013-12-09 03:20:33 -08:00
dc = ENFN - > context_new ( ENDT ) ;
ENFN - > context_color_set ( ENDT , dc , 255 , 255 , 255 , 255 ) ;
// Apply all commands
EINA_INLIST_FOREACH ( pgm - > instructions , instr )
{
2014-04-11 01:10:52 -07:00
_instruction_dump ( instr ) ;
2015-05-18 05:04:29 -07:00
cmdid = _command_from_instruction ( ctx , instr , dc ) ;
2013-12-09 03:20:33 -08:00
if ( cmdid < = 0 )
goto end ;
}
success = EINA_TRUE ;
2015-05-26 00:12:00 -07:00
pgm - > changed = EINA_FALSE ;
2013-12-09 03:20:33 -08:00
end :
if ( ! success ) evas_filter_context_clear ( ctx ) ;
if ( dc ) ENFN - > context_free ( ENDT , dc ) ;
return success ;
}
2015-06-04 03:42:38 -07:00
void
evas_filter_parser_shutdown ( void )
{
free ( _lua_color_code ) ;
_lua_color_code = NULL ;
}