Evas filters: EO-ify the filters API

This creates the new interface
 Efl.Gfx.Filter

And the implementation is a mixin (evas_filter_mixin.c):
 Evas.Filter

All the filter rendering code has now been moved to this
new file. TODO: Merge image filtering.
This commit is contained in:
Jean-Philippe Andre 2015-06-17 16:26:30 +09:00
parent a18107309d
commit 64fd278c62
16 changed files with 796 additions and 601 deletions

View File

@ -111,7 +111,7 @@ main(int argc, char **argv)
evas_object_color_set(o, 255, 255, 255, 255);
evas_object_show(o);
eo_do(o, evas_obj_text_filter_program_set(filter));
eo_do(o, efl_gfx_filter_program_set(filter));
ecore_evas_manual_render(wpd.ee);
evas_object_geometry_get(o, NULL, NULL, &w, &h);

View File

@ -13,7 +13,9 @@ efl_eolian_files = \
lib/efl/interfaces/efl_gfx_gradient_base.eo \
lib/efl/interfaces/efl_gfx_gradient_linear.eo \
lib/efl/interfaces/efl_gfx_gradient_radial.eo \
lib/efl/interfaces/efl_model_base.eo
lib/efl/interfaces/efl_gfx_filter.eo \
lib/efl/interfaces/efl_model_base.eo \
$(NULL)
efl_eolian_files_h = $(efl_eolian_files:%.eo=%.eo.h)
efl_eolian_files_c = $(efl_eolian_files:%.eo=%.eo.c)

View File

@ -40,7 +40,9 @@ evas_eolian_files = \
lib/evas/canvas/efl_vg_root_node.eo \
lib/evas/canvas/efl_vg_gradient.eo \
lib/evas/canvas/efl_vg_gradient_radial.eo \
lib/evas/canvas/efl_vg_gradient_linear.eo
lib/evas/canvas/efl_vg_gradient_linear.eo \
lib/evas/canvas/evas_filter.eo \
$(NULL)
evas_eolian_type_files = \
lib/evas/canvas/evas_types.eot
@ -520,7 +522,9 @@ lib/evas/common/evas_op_sub/op_sub_pixel_mask_i386.c
### Evas filters
lib_evas_libevas_la_SOURCES += lib/evas/filters/evas_filter.c \
lib_evas_libevas_la_SOURCES += \
lib/evas/canvas/evas_filter_mixin.c \
lib/evas/filters/evas_filter.c \
lib/evas/filters/evas_filter_blend.c \
lib/evas/filters/evas_filter_blur.c \
lib/evas/filters/evas_filter_bump.c \

View File

@ -1603,7 +1603,7 @@ _edje_part_recalc_single_text(FLOAT_T sc EINA_UNUSED,
Edje_Part_Description_Text *chosen_desc,
Edje_Calc_Params *params,
int *minw, int *minh,
int *maxw, int *maxh, double pos)
int *maxw, int *maxh)
#define RECALC_SINGLE_TEXT_USING_APPLY 1
#if RECALC_SINGLE_TEXT_USING_APPLY
/*
@ -1634,7 +1634,7 @@ _edje_part_recalc_single_text(FLOAT_T sc EINA_UNUSED,
free(sfont);
params->type.text.size = size; /* XXX TODO used by further calcs, go inside recalc_apply? */
_edje_text_recalc_apply(ed, ep, params, chosen_desc, EINA_TRUE, pos);
_edje_text_recalc_apply(ed, ep, params, chosen_desc, EINA_TRUE);
if ((!chosen_desc) ||
((!chosen_desc->text.min_x) && (!chosen_desc->text.min_y) &&
@ -2406,6 +2406,7 @@ _edje_part_recalc_single_map(Edje *ed,
static inline const char *
_edje_filter_get(Edje *ed, Edje_Part_Description_Spec_Filter *filter)
{
if (!filter->code) return NULL;
if (EINA_UNLIKELY(!filter->checked_data))
{
Edje_String *st;
@ -2433,7 +2434,6 @@ _edje_part_recalc_single_filter(Edje *ed,
const char *src1, *src2, *part, *code;
Evas_Object *obj = ep->object;
Eina_List *li1, *li2;
Eina_Bool im = 0;
/* handle TEXT and IMAGE part types here */
if (ep->part->type == EDJE_PART_TYPE_TEXT)
@ -2446,19 +2446,6 @@ _edje_part_recalc_single_filter(Edje *ed,
prev_sources = ep->typedata.text->filter.sources;
filter_sources = edt->text.filter.sources;
}
#if 0
// old form
if (ep->typedata.text->filter.code)
filter = &ep->typedata.text->filter;
else
filter = &chosen_edt->text.filter;
if (ep->typedata.text->filter.sources != chosen_edt->text.filter.sources)
{
prev_sources = ep->typedata.text->filter.sources;
filter_sources = chosen_edt->text.filter.sources;
//ep->typedata.text->filter.sources = chosen_edt->text.filter.sources;
}
#endif
}
else if (ep->part->type == EDJE_PART_TYPE_IMAGE)
{
@ -2470,7 +2457,6 @@ _edje_part_recalc_single_filter(Edje *ed,
prev_sources = edi->image.filter.sources;
filter_sources = chosen_edi->image.filter.sources;
}
im = 1;
}
else
{
@ -2478,18 +2464,6 @@ _edje_part_recalc_single_filter(Edje *ed,
return;
}
// FIXME: Implement proper EO interface/mixin and remove this ugly thing
#define efl_gfx_filter_program_set(...) do { \
if (!im) evas_obj_text_filter_program_set(__VA_ARGS__); \
else evas_obj_text_filter_program_set(__VA_ARGS__); } while (0)
#define efl_gfx_filter_source_set(...) do { \
if (!im) evas_obj_text_filter_source_set(__VA_ARGS__); \
else evas_obj_image_filter_source_set(__VA_ARGS__); } while (0)
#define efl_gfx_filter_state_set(...) do { \
if (!im) evas_obj_text_filter_state_set(__VA_ARGS__); \
/* else evas_obj_image_filter_state_set(__VA_ARGS__); */ } while (0)
// End of pure ugliness
/* common code below */
code = _edje_filter_get(ed, filter);
if (!code)
@ -2724,7 +2698,7 @@ _edje_part_recalc_single(Edje *ed,
_edje_part_recalc_single_textblock(sc, ed, ep, (Edje_Part_Description_Text *)chosen_desc, params, &minw, &minh, &maxw, &maxh);
else if (ep->part->type == EDJE_PART_TYPE_TEXT)
{
_edje_part_recalc_single_text(sc, ed, ep, (Edje_Part_Description_Text*) desc, (Edje_Part_Description_Text*) chosen_desc, params, &minw, &minh, &maxw, &maxh, pos);
_edje_part_recalc_single_text(sc, ed, ep, (Edje_Part_Description_Text*) desc, (Edje_Part_Description_Text*) chosen_desc, params, &minw, &minh, &maxw, &maxh);
_edje_part_recalc_single_filter(ed, ep, desc, chosen_desc, pos);
}
@ -4522,7 +4496,7 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta
switch (ep->part->type)
{
case EDJE_PART_TYPE_TEXT:
_edje_text_recalc_apply(ed, ep, pf, (Edje_Part_Description_Text*) chosen_desc, EINA_FALSE, pos);
_edje_text_recalc_apply(ed, ep, pf, (Edje_Part_Description_Text*) chosen_desc, EINA_FALSE);
break;
case EDJE_PART_TYPE_PROXY:

View File

@ -2293,7 +2293,7 @@ void _edje_text_recalc_apply(Edje *ed,
Edje_Real_Part *ep,
Edje_Calc_Params *params,
Edje_Part_Description_Text *chosen_desc,
Eina_Bool calc_only, double state_val);
Eina_Bool calc_only);
Evas_Font_Size _edje_text_size_calc(Evas_Font_Size size, Edje_Text_Class *tc);
const char * _edje_text_class_font_get(Edje *ed,
Edje_Part_Description_Text *chosen_desc,

View File

@ -197,7 +197,7 @@ void
_edje_text_recalc_apply(Edje *ed, Edje_Real_Part *ep,
Edje_Calc_Params *params,
Edje_Part_Description_Text *chosen_desc,
Eina_Bool calc_only, double state_val)
Eina_Bool calc_only)
{
const char *text = NULL;
const char *font;

View File

@ -163,6 +163,7 @@ EAPI extern const Eo_Event_Description _EFL_GFX_PATH_CHANGED;
#include "interfaces/efl_gfx_gradient_base.eo.h"
#include "interfaces/efl_gfx_gradient_linear.eo.h"
#include "interfaces/efl_gfx_gradient_radial.eo.h"
#include "interfaces/efl_gfx_filter.eo.h"
#endif

View File

@ -0,0 +1,73 @@
interface Efl.Gfx.Filter
{
legacy_prefix: null;
/* @since 1.15 */
methods {
@property program {
set {
[[Set an evas filter program on this object.
Valid for Text and Image objects at the moment.
The argument passed to this function is a string
containing a valid Lua program based on the filters
API as described in the "Evas filters reference"
page.
Set to null to disable filtering.
]]
}
get {
[[Gets the code of the filter program set on this object.
May be null.
]]
}
values {
code: const(char)*; [[filter program source code]]
}
}
@property state {
set {
[[Set the current state of the filter (for use from Edje).]]
}
values {
cur_state: const(char)*;
cur_val: double(0.0);
next_state: const(char)*;
next_val: double(0.0);
pos: double(0.0);
}
}
@property padding {
get {
[[Gets the padding required to apply this filter.]]
}
values {
l: int;
r: int;
t: int;
b: int;
}
}
source_set {
[[Bind an object to use as a mask or texture with Evas Filters.
This will create automatically a new RGBA buffer containing
the source object's pixels (as it is rendered).
]]
params {
@in name: const(char)*; [[buffer name as used in the program]]
@in source: Efl.Gfx.Base*; [[object to use as a proxy source]]
}
}
source_get @const {
[[Retrieve which object is attached to this filter given its
buffer name.
]]
params {
@in name: const(char)*; [[buffer name as used in the program]]
@out source: Efl.Gfx.Base*; [[object used as a proxy source]]
}
}
}
}

View File

@ -20,6 +20,8 @@
#include "interfaces/efl_gfx_gradient_linear.eo.c"
#include "interfaces/efl_gfx_gradient_radial.eo.c"
#include "interfaces/efl_gfx_filter.eo.c"
EAPI const Eo_Event_Description _EFL_GFX_CHANGED =
EO_EVENT_DESCRIPTION("Graphics changed", "The visual representation of the object changed");

View File

@ -0,0 +1,66 @@
mixin Evas.Filter (Efl.Gfx.Filter)
{
// Evas internal implementation
legacy_prefix: null;
methods {
@property changed {
set {
[[Marks this filter as changed.]]
}
values {
val: bool;
}
}
@property invalid {
set {
[[Marks this filter as invalid.]]
}
values {
val: bool;
}
}
constructor {
[[Initialize the Evas.Filter mixin.
Should be called in a parent's class constructor.
]]
}
destructor {
[[Release all data held by this Evas.Filter.
This may include image buffers allocated by the Evas engine.
This should be called at the beginning of a parent's class destructor.
]]
}
input_render {
[[Called by Evas.Filter when the parent class must render the input.
;
]]
params {
filter: void*; [[Evas_Filter_Context]]
drawctx: void*;
l: int;
r: int;
t: int;
b: int;
do_async: bool;
}
}
dirty {
[[Called when the filter changes must trigger a redraw of the object.
Virtual, to be implemented in the parent class.
]]
}
}
implements {
Efl.Gfx.Filter.program.set;
Efl.Gfx.Filter.program.get;
Efl.Gfx.Filter.state.set;
Efl.Gfx.Filter.padding.get;
Efl.Gfx.Filter.source_set;
Efl.Gfx.Filter.source_get;
@virtual .input_render;
@virtual .dirty;
}
}

View File

@ -0,0 +1,512 @@
#include "evas_common_private.h"
#include "evas_private.h"
#include "../../lib/efl/interfaces/efl_gfx_filter.eo.h"
#include "evas_filter.eo.h"
#include "evas_filter.h"
#define MY_CLASS EVAS_FILTER_MIXIN
#define ENFN obj->layer->evas->engine.func
#define ENDT obj->layer->evas->engine.data.output
typedef struct _Evas_Filter_Data Evas_Filter_Data;
struct _Evas_Filter_Data
{
const Evas_Object_Filter_Data *data;
};
static void
_filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
{
Eo *eo_obj = data;
// Destroy context as we won't reuse it.
evas_filter_context_destroy(ctx);
// Redraw text with normal styles in case of failure
if (!success)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
ERR("Filter failed at runtime!");
eo_do(eo_obj,
evas_filter_invalid_set(EINA_TRUE);
evas_filter_dirty());
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
}
static void
_filter_source_hash_free_cb(void *data)
{
Evas_Filter_Proxy_Binding *pb = data;
Evas_Object_Protected_Data *proxy, *source;
Evas_Filter_Data *pd;
proxy = eo_data_scope_get(pb->eo_proxy, EVAS_OBJECT_CLASS);
source = eo_data_scope_get(pb->eo_source, EVAS_OBJECT_CLASS);
if (source)
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
Evas_Object_Proxy_Data, source_write)
source_write->proxies = eina_list_remove(source_write->proxies, pb->eo_proxy);
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
}
pd = eo_data_scope_get(pb->eo_proxy, MY_CLASS);
if (pd && proxy)
{
if (!eina_hash_population(pd->data->sources))
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, proxy->proxy,
Evas_Object_Proxy_Data, proxy_write)
proxy_write->is_proxy = EINA_FALSE;
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write)
}
}
eina_stringshare_del(pb->name);
free(pb);
}
Eina_Bool
evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *output, void *context, void *surface,
int x, int y, Eina_Bool do_async, Eina_Bool alpha)
{
Evas_Filter_Data *pd = eo_data_scope_get(eo_obj, MY_CLASS);
if (!pd->data->invalid && (pd->data->chain || pd->data->code))
{
int X, Y, W, H, l = 0, r = 0, t = 0, b = 0;
Evas_Filter_Context *filter;
void *drawctx;
Eina_Bool ok;
void *previous = pd->data->output;
Evas_Object_Filter_Data *fcow =
eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data));
/* NOTE: Filter rendering is now done ENTIRELY on CPU.
* So we rely on cache/cache2 to allocate a real image buffer,
* that we can draw to. The OpenGL texture will be created only
* after the rendering has been done, as we simply push the output
* image to GL.
*/
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
X = obj->cur->geometry.x;
Y = obj->cur->geometry.y;
// Prepare color multiplier
ENFN->context_color_set(output, context,
obj->cur->cache.clip.r,
obj->cur->cache.clip.g,
obj->cur->cache.clip.b,
obj->cur->cache.clip.a);
if (obj->cur->clipper)
ENFN->context_multiplier_set(output, context,
obj->cur->clipper->cur->cache.clip.r,
obj->cur->clipper->cur->cache.clip.g,
obj->cur->clipper->cur->cache.clip.b,
obj->cur->clipper->cur->cache.clip.a);
else
ENFN->context_multiplier_unset(output, context);
if (!fcow->chain)
{
Evas_Filter_Program *pgm;
pgm = evas_filter_program_new(obj->name ? obj->name : obj->type, alpha);
evas_filter_program_source_set_all(pgm, fcow->sources);
evas_filter_program_state_set(pgm, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
if (!evas_filter_program_parse(pgm, fcow->code))
{
ERR("Filter program parsing failed");
evas_filter_program_del(pgm);
fcow->invalid = EINA_TRUE;
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data),
fcow, EINA_TRUE);
return EINA_FALSE;
}
fcow->chain = pgm;
fcow->invalid = EINA_FALSE;
}
else if (previous && !fcow->changed)
{
Eina_Bool redraw;
redraw = evas_filter_program_state_set(fcow->chain, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
if (redraw)
DBG("Filter redraw by state change!");
// Scan proxies to find if any changed
if (!redraw && fcow->sources)
{
Evas_Filter_Proxy_Binding *pb;
Evas_Object_Protected_Data *source;
Eina_Iterator *iter;
iter = eina_hash_iterator_data_new(fcow->sources);
EINA_ITERATOR_FOREACH(iter, pb)
{
source = eo_data_scope_get(pb->eo_source, EVAS_OBJECT_CLASS);
if (source->changed)
{
redraw = EINA_TRUE;
break;
}
}
eina_iterator_free(iter);
}
if (!redraw)
{
// Render this image only
ENFN->image_draw(ENDT, context,
surface, previous,
0, 0, W, H, // src
X + x, Y + y, W, H, // dst
EINA_FALSE, // smooth
do_async);
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data),
fcow, EINA_TRUE);
return EINA_TRUE;
}
}
else
evas_filter_program_state_set(fcow->chain, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
filter = evas_filter_context_new(obj->layer->evas, do_async);
// Run script
ok = evas_filter_context_program_use(filter, fcow->chain);
if (!filter || !ok)
{
ERR("Parsing failed?");
evas_filter_context_destroy(filter);
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(pd->data),
fcow, EINA_TRUE);
return EINA_FALSE;
}
// Proxies
evas_filter_context_proxy_render_all(filter, eo_obj, EINA_FALSE);
// Draw Context
drawctx = ENFN->context_new(ENDT);
ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255);
// Allocate all buffers now
evas_filter_context_buffers_allocate_all(filter);
evas_filter_target_set(filter, context, surface, X + x, Y + y);
// Steal output and release previous
fcow->output = evas_filter_buffer_backing_steal(filter, EVAS_FILTER_BUFFER_OUTPUT_ID);
if (fcow->output != previous)
evas_filter_buffer_backing_release(filter, previous);
evas_filter_program_padding_get(fcow->chain, &l, &r, &t, &b);
eo_do(eo_obj, evas_filter_input_render(filter, drawctx, l, r, t, b, do_async));
#warning TODO: draw text into input buffer
#if 0
// Render text to input buffer
EINA_INLIST_FOREACH(EINA_INLIST_GET(pd->items), it)
if ((pd->font) && (it->text_props.len > 0))
{
evas_filter_font_draw(filter, drawctx, EVAS_FILTER_BUFFER_INPUT_ID, pd->font,
sl + it->x,
st + (int) pd->max_ascent,
&it->text_props,
do_async);
}
#endif
ENFN->context_free(ENDT, drawctx);
// Add post-run callback and run filter
evas_filter_context_post_run_callback_set(filter, _filter_cb, eo_obj);
ok = evas_filter_run(filter);
fcow->changed = EINA_FALSE;
if (!ok) fcow->invalid = EINA_TRUE;
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data **) &(pd->data), fcow, EINA_TRUE);
if (ok)
{
DBG("Effect rendering done.");
return EINA_TRUE;
}
else
{
ERR("Rendering failed.");
return EINA_FALSE;
}
}
return EINA_FALSE;
}
EOLIAN void
_evas_filter_efl_gfx_filter_program_set(Eo *eo_obj, Evas_Filter_Data *pd,
const char *code)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Filter_Program *pgm = NULL;
if (!pd) return;
if (pd->data->code == code) return;
if (pd->data->code && code && !strcmp(code, pd->data->code)) return;
evas_object_async_block(obj);
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
{
// Parse filter program
evas_filter_program_del(fcow->chain);
if (code)
{
pgm = evas_filter_program_new("Evas_Text", EINA_TRUE);
evas_filter_program_source_set_all(pgm, fcow->sources);
evas_filter_program_state_set(pgm, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
if (!evas_filter_program_parse(pgm, code))
{
ERR("Parsing failed!");
evas_filter_program_del(pgm);
pgm = NULL;
}
}
fcow->chain = pgm;
fcow->changed = EINA_TRUE;
fcow->invalid = (pgm == NULL);
eina_stringshare_replace(&fcow->code, code);
}
EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
// Update object
eo_do(eo_obj, evas_filter_dirty());
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
EOLIAN const char *
_evas_filter_efl_gfx_filter_program_get(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd)
{
return pd->data->code;
}
EOLIAN void
_evas_filter_efl_gfx_filter_source_set(Eo *eo_obj, Evas_Filter_Data *pd,
const char *name, Efl_Gfx_Base *eo_source)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Filter_Proxy_Binding *pb, *pb_old = NULL;
Evas_Object_Protected_Data *source = NULL;
Evas_Object_Filter_Data *fcow = NULL;
if (eo_source)
source = eo_data_scope_get(eo_source, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if (!name)
{
if (!eo_source || !pd->data->sources) return;
if (eina_hash_del_by_data(pd->data->sources, eo_source))
goto update;
return;
}
if (!source && !pd->data->sources)
return;
if (pd->data->sources)
{
pb_old = eina_hash_find(pd->data->sources, name);
if (pb_old && (pb_old->eo_source == eo_source)) return;
}
fcow = eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&pd->data);
if (!fcow->sources)
fcow->sources = eina_hash_string_small_new(EINA_FREE_CB(_filter_source_hash_free_cb));
else if (pb_old)
eina_hash_del(fcow->sources, name, pb_old);
if (!source)
{
pb_old = eina_hash_find(fcow->sources, name);
if (!pb_old)
{
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&pd->data, fcow, EINA_TRUE);
return;
}
eina_hash_del_by_key(fcow->sources, name);
goto update;
}
pb = calloc(1, sizeof(*pb));
pb->eo_proxy = eo_obj;
pb->eo_source = eo_source;
pb->name = eina_stringshare_add(name);
if (!eina_list_data_find(source->proxy->proxies, eo_obj))
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy, Evas_Object_Proxy_Data, source_write)
source_write->proxies = eina_list_append(source_write->proxies, eo_obj);
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
}
if (!obj->proxy->is_proxy)
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy, Evas_Object_Proxy_Data, proxy_write)
proxy_write->is_proxy = EINA_TRUE;
EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_write)
}
eina_hash_add(fcow->sources, pb->name, pb);
evas_filter_program_source_set_all(fcow->chain, fcow->sources);
// Update object
update:
if (fcow)
{
fcow->changed = EINA_TRUE;
fcow->invalid = EINA_FALSE;
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&pd->data, fcow, EINA_TRUE);
}
eo_do(eo_obj, evas_filter_dirty());
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
EOLIAN void
_evas_filter_efl_gfx_filter_source_get(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd,
const char *name, Efl_Gfx_Base **source)
{
if (!source) return;
*source = eina_hash_find(pd->data->sources, name);
}
EOLIAN void
_evas_filter_efl_gfx_filter_state_set(Eo *eo_obj, Evas_Filter_Data *pd,
const char *cur_state, double cur_val,
const char *next_state, double next_val,
double pos)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if ((cur_state != pd->data->state.cur.name) || (cur_val != pd->data->state.cur.value) ||
(next_state != pd->data->state.next.name) || (next_val != pd->data->state.next.value) ||
(pos != pd->data->state.pos))
{
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
{
fcow->changed = 1;
fcow->state.cur.name = cur_state;
fcow->state.cur.value = cur_val;
fcow->state.next.name = next_state;
fcow->state.next.value = next_val;
fcow->state.pos = pos;
if (pd->data->chain)
{
evas_filter_program_state_set(pd->data->chain, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
}
}
EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
// Mark as changed
eo_do(eo_obj, evas_filter_dirty());
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
}
EOLIAN void
_evas_filter_efl_gfx_filter_padding_get(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd,
int *l, int *r, int *t, int *b)
{
if (!pd->data->chain)
{
if (l) *l = 0;
if (r) *r = 0;
if (t) *t = 0;
if (b) *b = 0;
return;
}
evas_filter_program_padding_get(pd->data->chain, l, r, t, b);
}
EOLIAN void
_evas_filter_changed_set(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd, Eina_Bool val)
{
if ((evas_object_filter_cow_default != pd->data) && (pd->data->changed != val))
{
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
fcow->changed = val;
EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
}
}
EOLIAN void
_evas_filter_invalid_set(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd, Eina_Bool val)
{
if (pd->data->invalid != val)
{
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, pd->data, Evas_Object_Filter_Data, fcow)
fcow->invalid = val;
EINA_COW_WRITE_END(evas_object_filter_cow, pd->data, fcow);
}
}
EOLIAN void
_evas_filter_constructor(Eo *eo_obj EINA_UNUSED, Evas_Filter_Data *pd)
{
pd->data = eina_cow_alloc(evas_object_filter_cow);
}
EOLIAN void
_evas_filter_destructor(Eo *eo_obj, Evas_Filter_Data *pd)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
if (!pd->data) return;
if (evas_object_filter_cow_default == pd->data) return;
if (pd->data->output)
ENFN->image_free(ENDT, pd->data->output);
eina_hash_free(pd->data->sources);
evas_filter_program_del(pd->data->chain);
eina_stringshare_del(pd->data->code);
eina_cow_free(evas_object_filter_cow, (const Eina_Cow_Data **) &pd->data);
}
#include "evas_filter.eo.c"

View File

@ -718,7 +718,7 @@ _evas_object_eo_base_destructor(Eo *eo_obj, Evas_Object_Protected_Data *obj)
if (eo_isa(proxy, EVAS_IMAGE_CLASS))
evas_object_image_source_unset(proxy);
else if (eo_isa(proxy, EVAS_TEXT_CLASS))
eo_do(proxy, evas_obj_text_filter_source_set(NULL, eo_obj));
eo_do(proxy, efl_gfx_filter_source_set(NULL, eo_obj));
}
/* Eina_Cow has no way to know if we are going to really change something

View File

@ -1,5 +1,8 @@
#include "evas_common_private.h" /* Includes evas_bidi_utils stuff. */
#include "evas_private.h"
#include "../efl/interfaces/efl_gfx_filter.eo.h"
#include "evas_filter.eo.h"
#include "evas_filter.h"
#define MY_CLASS EVAS_TEXT_CLASS
@ -42,8 +45,6 @@ struct _Evas_Text_Data
Evas_Font_Size size;
Evas_Text_Style_Type style;
const Evas_Object_Filter_Data* filter; // cow
} cur, prev;
struct {
@ -66,6 +67,7 @@ struct _Evas_Text_Data
Evas_BiDi_Direction bidi_dir : 2;
char changed : 1;
char has_filter : 1;
};
struct _Evas_Object_Text_Item
@ -368,13 +370,11 @@ evas_object_text_add(Evas *e)
}
EOLIAN static Eo *
_evas_text_eo_base_constructor(Eo *eo_obj, Evas_Text_Data *o)
_evas_text_eo_base_constructor(Eo *eo_obj, Evas_Text_Data *o EINA_UNUSED)
{
eo_obj = eo_do_super_ret(eo_obj, MY_CLASS, eo_obj, eo_constructor());
evas_object_text_init(eo_obj);
o->cur.filter = eina_cow_alloc(evas_object_filter_cow);
return eo_obj;
}
@ -397,22 +397,9 @@ _evas_text_efl_text_properties_font_source_set(Eo *eo_obj, Evas_Text_Data *o, co
EOLIAN static const char*
_evas_text_efl_text_properties_font_source_get(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o)
{
return o->cur.source;
}
static inline void
_evas_text_filter_changed_set(Evas_Text_Data *o, Eina_Bool val)
{
if ((evas_object_filter_cow_default != o->cur.filter)
&& (o->cur.filter->changed != val))
{
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, o->cur.filter, Evas_Object_Filter_Data, fcow)
fcow->changed = val;
EINA_COW_WRITE_END(evas_object_filter_cow, o->cur.filter, fcow);
}
}
EOLIAN static void
_evas_text_efl_text_properties_font_set(Eo *eo_obj, Evas_Text_Data *o, const char *font, Evas_Font_Size size)
{
@ -479,7 +466,8 @@ _evas_text_efl_text_properties_font_set(Eo *eo_obj, Evas_Text_Data *o, const cha
_evas_object_text_items_clear(o);
_evas_object_text_recalc(eo_obj, o->cur.text);
o->changed = 1;
_evas_text_filter_changed_set(o, EINA_TRUE);
if (o->has_filter)
eo_do(eo_obj, evas_filter_changed_set(EINA_TRUE));
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
@ -665,6 +653,19 @@ _layout_text_item_trim(Evas_Object_Protected_Data *obj, Evas_Text_Data *o, Evas_
return EINA_TRUE;
}
static void
_evas_object_text_pad_get(Evas_Object *eo_obj, Evas_Text_Data *o, int *l, int *r, int *t, int *b)
{
if (l) *l = 0;
if (r) *r = 0;
if (t) *t = 0;
if (b) *b = 0;
if (!o->has_filter)
evas_text_style_pad_get(o->cur.style, l, r, t, b);
else
eo_do(eo_obj, efl_gfx_filter_padding_get(l, r, t, b));
}
/**
* @internal
* Populates o->items with the items of the text according to text
@ -767,10 +768,7 @@ _evas_object_text_layout(Evas_Object *eo_obj, Evas_Text_Data *o, Eina_Unicode *t
}
o->last_computed.advance_without_ellipsis = advance;
if (!o->cur.filter || !o->cur.filter->chain)
evas_text_style_pad_get(o->cur.style, &l, &r, NULL, NULL);
else
evas_filter_program_padding_get(o->cur.filter->chain, &l, &r, NULL, NULL);
_evas_object_text_pad_get(eo_obj, o, &l, &r, NULL, NULL);
/* Handle ellipsis */
if (pos && (o->cur.ellipsis >= 0.0) && (advance + l + r > obj->cur->geometry.w) && (obj->cur->geometry.w > 0))
@ -950,7 +948,8 @@ _evas_text_ellipsis_set(Eo *eo_obj, Evas_Text_Data *o, double ellipsis)
evas_object_async_block(obj);
o->cur.ellipsis = ellipsis;
o->changed = 1;
_evas_text_filter_changed_set(o, EINA_TRUE);
if (o->has_filter)
eo_do(eo_obj, evas_filter_changed_set(EINA_TRUE));
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
}
@ -1008,7 +1007,8 @@ _evas_text_efl_text_text_set(Eo *eo_obj, Evas_Text_Data *o, const char *_text)
if (o->cur.text != text) free(text);
o->changed = 1;
_evas_text_filter_changed_set(o, EINA_TRUE);
if (o->has_filter)
eo_do(eo_obj, evas_filter_changed_set(EINA_TRUE));
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
@ -1129,10 +1129,8 @@ _evas_text_char_pos_get(Eo *eo_obj, Evas_Text_Data *o, int pos, Evas_Coord *cx,
Eina_Bool int_ret = _evas_object_text_char_coords_get(eo_obj, o, (size_t) pos,
&x, &y, &w, &h);
if (!o->cur.filter || !o->cur.filter->chain)
evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
else
evas_filter_program_padding_get(o->cur.filter->chain, &l, &r, &t, &b);
_evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
y += o->max_ascent - t;
x -= l;
if (x < 0)
@ -1186,10 +1184,7 @@ _evas_text_char_coords_get(Eo *eo_obj, Evas_Text_Data *o, Evas_Coord x, Evas_Coo
int int_ret = _evas_object_text_char_at_coords(eo_obj, o, x, y - o->max_ascent,
&rx, &ry, &rw, &rh);
if (!o->cur.filter || !o->cur.filter->chain)
evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
else
evas_filter_program_padding_get(o->cur.filter->chain, &l, &r, &t, &b);
_evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
ry += o->max_ascent - t;
rx -= l;
if (rx < 0)
@ -1226,9 +1221,11 @@ _evas_text_style_set(Eo *eo_obj, Evas_Text_Data *o, Evas_Text_Style_Type style)
if (o->cur.style == style) return;
evas_object_async_block(obj);
evas_text_style_pad_get(o->cur.style, &pl, &pr, &pt, &pb);
_evas_object_text_pad_get(eo_obj, o, &pl, &pr, &pt, &pb);
//evas_text_style_pad_get(o->cur.style, &pl, &pr, &pt, &pb);
o->cur.style = style;
evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
_evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
//evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
if (o->items) w = obj->cur->geometry.w + (l - pl) + (r - pr);
h = obj->cur->geometry.h + (t - pt) + (b - pb);
@ -1345,18 +1342,9 @@ _evas_text_outline_color_get(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o, int *r,
}
EOLIAN static void
_evas_text_style_pad_get(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o, int *l, int *r, int *t, int *b)
_evas_text_style_pad_get(Eo *eo_obj, Evas_Text_Data *o, int *l, int *r, int *t, int *b)
{
int sl = 0, sr = 0, st = 0, sb = 0;
/* use temps to be certain we have initialized values */
if (!o->cur.filter || !o->cur.filter->chain)
evas_text_style_pad_get(o->cur.style, &sl, &sr, &st, &sb);
else
evas_filter_program_padding_get(o->cur.filter->chain, &sl, &sr, &st, &sb);
if (l) *l = sl;
if (r) *r = sr;
if (t) *t = st;
if (b) *b = sb;
_evas_object_text_pad_get(eo_obj, o, l, r, t, b);
}
EAPI int
@ -1539,6 +1527,8 @@ evas_object_text_init(Evas_Object *eo_obj)
#ifdef BIDI_SUPPORT
o->bidi_par_props = evas_bidi_paragraph_props_new();
#endif
eo_do(eo_obj, evas_filter_constructor());
}
EOLIAN static void
@ -1554,24 +1544,8 @@ evas_object_text_free(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj)
{
Evas_Text_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
/* free filter output */
if (evas_object_filter_cow_default != o->cur.filter)
{
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, o->cur.filter, Evas_Object_Filter_Data, fcow)
if (fcow->output)
ENFN->image_free(ENDT, fcow->output);
eina_hash_free(fcow->sources);
evas_filter_program_del(fcow->chain);
eina_stringshare_del(fcow->code);
fcow->output = NULL;
fcow->chain = NULL;
fcow->sources = NULL;
fcow->code = NULL;
EINA_COW_WRITE_END(evas_object_filter_cow, o->cur.filter, fcow);
eina_cow_free(evas_object_filter_cow, (const Eina_Cow_Data **) &o->cur.filter);
}
/* free obj */
eo_do(eo_obj, evas_filter_destructor());
_evas_object_text_items_clear(o);
if (o->cur.utf8_text) eina_stringshare_del(o->cur.utf8_text);
if (o->cur.font) eina_stringshare_del(o->cur.font);
@ -1605,34 +1579,34 @@ evas_font_draw_async_check(Evas_Object_Protected_Data *obj,
}
}
static void
_filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
/* ugly binding between evas_fitler_mixin.c and this object */
EOLIAN void
_evas_text_evas_filter_dirty(Eo *eo_obj, Evas_Text_Data *o)
{
Eo *eo_obj = data;
_evas_object_text_items_clear(o);
o->changed = 1;
_evas_object_text_recalc(eo_obj, o->cur.text);
}
// Destroy context as we won't reuse it.
evas_filter_context_destroy(ctx);
EOLIAN void
_evas_text_evas_filter_input_render(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o,
void *_filter, void *drawctx,
int l, int r, int t, int b, Eina_Bool do_async)
{
Evas_Filter_Context *filter = _filter;
Evas_Object_Text_Item *it;
(void) r; (void) b;
// Redraw text with normal styles in case of failure
if (!success)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Text_Data *o = (Evas_Text_Data *) obj->private_data;
ERR("Filter failed at runtime!");
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, o->cur.filter, Evas_Object_Filter_Data, fcow)
fcow->invalid = EINA_TRUE;
EINA_COW_WRITE_END(evas_object_filter_cow, o->cur.filter, fcow);
// Update object
_evas_object_text_items_clear(o);
o->changed = 1;
_evas_object_text_recalc(eo_obj, o->cur.text);
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
if ((o->font) && (it->text_props.len > 0))
{
evas_filter_font_draw(filter, drawctx, EVAS_FILTER_BUFFER_INPUT_ID, o->font,
l + it->x,
t + (int) o->max_ascent,
&it->text_props,
do_async);
}
}
static void
@ -1657,10 +1631,7 @@ evas_object_text_render(Evas_Object *eo_obj,
int shad_dst = 0, shad_sz = 0, dx = 0, dy = 0, haveshad = 0;
/* render object to surface with context, and offxet by x,y */
if (!o->cur.filter->chain)
evas_text_style_pad_get(o->cur.style, &sl, NULL, &st, NULL);
else
evas_filter_program_padding_get(o->cur.filter->chain, &sl, NULL, &st, NULL);
_evas_object_text_pad_get(eo_obj, o, &sl, NULL, &st, NULL);
ENFN->context_multiplier_unset(output, context);
ENFN->context_render_op_set(output, context, obj->cur->render_op);
/* FIXME: This clipping is just until we fix inset handling correctly. */
@ -1737,190 +1708,12 @@ evas_object_text_render(Evas_Object *eo_obj,
&it->text_props, \
do_async);
/* FIXME/WARNING
* The code below is EXPERIMENTAL, and not to be considered usable or even
* remotely similar to its final form. You've been warned :)
*/
if (!o->cur.filter->invalid && (o->cur.filter->chain || o->cur.filter->code))
if (o->has_filter)
{
int X, Y, W, H;
Evas_Filter_Context *filter;
const int inbuf = 1;
const int outbuf = 2;
void *filter_ctx;
Eina_Bool ok;
int ox = 0, oy = 0;
void *previous = o->cur.filter->output;
Evas_Object_Filter_Data *fcow =
eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&(o->cur.filter));
/* NOTE: Font effect rendering is now done ENTIRELY on CPU.
* So we rely on cache/cache2 to allocate a real image buffer,
* that we can draw to. The OpenGL texture will be created only
* after the rendering has been done, as we simply push the output
* image to GL.
*/
W = obj->cur->geometry.w;
H = obj->cur->geometry.h;
X = obj->cur->geometry.x;
Y = obj->cur->geometry.y;
// Prepare color multiplier
COLOR_ONLY_SET(obj, cur->cache, clip);
if (obj->cur->clipper)
ENFN->context_multiplier_set(output, context,
obj->cur->clipper->cur->cache.clip.r,
obj->cur->clipper->cur->cache.clip.g,
obj->cur->clipper->cur->cache.clip.b,
obj->cur->clipper->cur->cache.clip.a);
else
ENFN->context_multiplier_unset(output, context);
if (!fcow->chain)
{
Evas_Filter_Program *pgm;
pgm = evas_filter_program_new("Evas_Text", EINA_TRUE);
evas_filter_program_source_set_all(pgm, fcow->sources);
evas_filter_program_state_set(pgm, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
if (!evas_filter_program_parse(pgm, fcow->code))
{
ERR("Filter program parsing failed");
evas_filter_program_del(pgm);
fcow->invalid = EINA_TRUE;
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(o->cur.filter),
fcow, EINA_TRUE);
goto normal_render;
}
fcow->chain = pgm;
fcow->invalid = EINA_FALSE;
}
else if (previous && !fcow->changed)
{
Eina_Bool redraw;
redraw = evas_filter_program_state_set(fcow->chain, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
if (redraw)
DBG("Filter redraw by state change!");
// Scan proxies to find if any changed
if (!redraw && fcow->sources)
{
Evas_Filter_Proxy_Binding *pb;
Evas_Object_Protected_Data *source;
Eina_Iterator *iter;
iter = eina_hash_iterator_data_new(fcow->sources);
EINA_ITERATOR_FOREACH(iter, pb)
{
source = eo_data_scope_get(pb->eo_source, EVAS_OBJECT_CLASS);
if (source->changed)
{
redraw = EINA_TRUE;
break;
}
}
eina_iterator_free(iter);
}
if (!redraw)
{
// Render this image only
ENFN->image_draw(ENDT, context,
surface, previous,
0, 0, W, H, // src
X + x, Y + y, W, H, // dst
EINA_FALSE, // smooth
do_async);
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(o->cur.filter),
fcow, EINA_TRUE);
return;
}
}
else
evas_filter_program_state_set(fcow->chain, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
filter = evas_filter_context_new(obj->layer->evas, do_async);
// Run script
ok = evas_filter_context_program_use(filter, fcow->chain);
if (!filter || !ok)
{
ERR("Parsing failed?");
evas_filter_context_destroy(filter);
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(o->cur.filter),
fcow, EINA_TRUE);
goto normal_render;
}
// Proxies
evas_filter_context_proxy_render_all(filter, eo_obj, EINA_FALSE);
// Draw Context
filter_ctx = ENFN->context_new(ENDT);
ENFN->context_color_set(ENDT, filter_ctx, 255, 255, 255, 255);
// Allocate all buffers now
evas_filter_context_buffers_allocate_all(filter);
evas_filter_target_set(filter, context, surface, X + x, Y + y);
// Steal output and release previous
fcow->output = evas_filter_buffer_backing_steal(filter, outbuf);
if (fcow->output != previous)
evas_filter_buffer_backing_release(filter, previous);
// Render text to input buffer
EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it)
if ((o->font) && (it->text_props.len > 0))
{
evas_filter_font_draw(filter, filter_ctx, inbuf, o->font,
sl + ox + it->x,
st + oy + (int) o->max_ascent,
&it->text_props,
do_async);
}
ENFN->context_free(ENDT, filter_ctx);
// Add post-run callback and run filter
evas_filter_context_post_run_callback_set(filter, _filter_cb, eo_obj);
ok = evas_filter_run(filter);
fcow->changed = EINA_FALSE;
if (!ok) fcow->invalid = EINA_TRUE;
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&(o->cur.filter),
fcow, EINA_TRUE);
if (ok)
{
DBG("Effect rendering done.");
return;
}
else
{
ERR("Rendering failed");
goto normal_render;
}
if (evas_filter_object_render(eo_obj, obj, output, context, surface, x, y, do_async, EINA_TRUE))
return;
}
/* End of the EXPERIMENTAL code */
normal_render:
/* shadows */
switch (o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC)
{
@ -2279,7 +2072,8 @@ _evas_object_text_rehint(Evas_Object *eo_obj)
/* DO II */
_evas_object_text_recalc(eo_obj, o->cur.text);
o->changed = 1;
_evas_text_filter_changed_set(o, EINA_TRUE);
if (o->has_filter)
eo_do(eo_obj, evas_filter_changed_set(EINA_TRUE));
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
@ -2354,10 +2148,7 @@ _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text)
w = _evas_object_text_horiz_advance_without_ellipsis_get(o);
h = _evas_object_text_vert_advance_get(eo_obj, o);
if (!o->cur.filter->chain)
evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
else
evas_filter_program_padding_get(o->cur.filter->chain, &l, &r, &t, &b);
_evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
if (o->cur.ellipsis >= 0.0)
{
@ -2377,12 +2168,7 @@ _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text)
else
{
int t = 0, b = 0, l = 0, r = 0;
if (!o->cur.filter->chain)
evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b);
else
evas_filter_program_padding_get(o->cur.filter->chain, &l, &r, &t, &b);
_evas_object_text_pad_get(eo_obj, o, &l, &r, &t, &b);
eo_do_super(eo_obj, MY_CLASS,
efl_gfx_size_set(0, o->max_ascent + o->max_descent + t + b));
//// obj->cur->cache.geometry.validity = 0;
@ -2391,222 +2177,6 @@ _evas_object_text_recalc(Evas_Object *eo_obj, Eina_Unicode *text)
o->last_computed.h = obj->cur->geometry.h;
}
EOLIAN static void
_evas_text_filter_program_set(Eo *eo_obj, Evas_Text_Data *o, const char *arg)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Filter_Program *pgm = NULL;
if (!o) return;
if (o->cur.filter->code == arg) return;
if (o->cur.filter->code && arg && !strcmp(arg, o->cur.filter->code)) return;
evas_object_async_block(obj);
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, o->cur.filter, Evas_Object_Filter_Data, fcow)
{
// Parse filter program
evas_filter_program_del(fcow->chain);
if (arg)
{
pgm = evas_filter_program_new("Evas_Text", EINA_TRUE);
evas_filter_program_source_set_all(pgm, fcow->sources);
evas_filter_program_state_set(pgm, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
if (!evas_filter_program_parse(pgm, arg))
{
ERR("Parsing failed!");
evas_filter_program_del(pgm);
pgm = NULL;
}
}
fcow->chain = pgm;
fcow->changed = EINA_TRUE;
fcow->invalid = (pgm == NULL);
eina_stringshare_replace(&fcow->code, arg);
}
EINA_COW_WRITE_END(evas_object_filter_cow, o->cur.filter, fcow);
// Update object
_evas_object_text_items_clear(o);
o->changed = 1;
_evas_object_text_recalc(eo_obj, o->cur.text);
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
static void
_filter_source_hash_free_cb(void *data)
{
Evas_Filter_Proxy_Binding *pb = data;
Evas_Object_Protected_Data *proxy, *source;
Evas_Text_Data *o;
proxy = eo_data_scope_get(pb->eo_proxy, EVAS_OBJECT_CLASS);
source = eo_data_scope_get(pb->eo_source, EVAS_OBJECT_CLASS);
if (source)
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
Evas_Object_Proxy_Data, source_write)
source_write->proxies = eina_list_remove(source_write->proxies, pb->eo_proxy);
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
}
o = eo_data_scope_get(pb->eo_proxy, MY_CLASS);
if (o && proxy)
{
if (!eina_hash_population(o->cur.filter->sources))
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, proxy->proxy,
Evas_Object_Proxy_Data, proxy_write)
proxy_write->is_proxy = EINA_FALSE;
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write)
}
}
eina_stringshare_del(pb->name);
free(pb);
}
EOLIAN static void
_evas_text_filter_source_set(Eo *eo_obj, Evas_Text_Data *o, const char *name, Evas_Object *eo_source)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
Evas_Filter_Proxy_Binding *pb, *pb_old = NULL;
Evas_Object_Protected_Data *source = NULL;
Evas_Object_Filter_Data *fcow = NULL;
if (eo_source) source = eo_data_scope_get(eo_source, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if (!name)
{
if (!eo_source || !o->cur.filter->sources) return;
if (eina_hash_del_by_data(o->cur.filter->sources, eo_source))
goto update;
return;
}
if (!source && !o->cur.filter->sources)
return;
if (o->cur.filter->sources)
{
pb_old = eina_hash_find(o->cur.filter->sources, name);
if (pb_old && (pb_old->eo_source == eo_source)) return;
}
fcow = eina_cow_write(evas_object_filter_cow, (const Eina_Cow_Data**)&o->cur.filter);
if (!fcow->sources)
{
fcow->sources = eina_hash_string_small_new
(EINA_FREE_CB(_filter_source_hash_free_cb));
}
else if (pb_old)
eina_hash_del(fcow->sources, name, pb_old);
if (!source)
{
pb_old = eina_hash_find(fcow->sources, name);
if (!pb_old)
{
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&o->cur.filter,
fcow, EINA_TRUE);
return;
}
eina_hash_del_by_key(fcow->sources, name);
goto update;
}
pb = calloc(1, sizeof(*pb));
pb->eo_proxy = eo_obj;
pb->eo_source = eo_source;
pb->name = eina_stringshare_add(name);
if (!eina_list_data_find(source->proxy->proxies, eo_obj))
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy, Evas_Object_Proxy_Data, source_write)
source_write->proxies = eina_list_append(source_write->proxies, eo_obj);
EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, source_write)
}
if (!obj->proxy->is_proxy)
{
EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy, Evas_Object_Proxy_Data, proxy_write)
proxy_write->is_proxy = EINA_TRUE;
EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_write)
}
eina_hash_add(fcow->sources, pb->name, pb);
evas_filter_program_source_set_all(fcow->chain, fcow->sources);
// Update object
update:
if (fcow)
{
fcow->changed = EINA_TRUE;
fcow->invalid = EINA_FALSE;
eina_cow_done(evas_object_filter_cow, (const Eina_Cow_Data**)&o->cur.filter,
fcow, EINA_TRUE);
}
_evas_object_text_items_clear(o);
o->changed = 1;
_evas_object_text_recalc(eo_obj, o->cur.text);
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
EOLIAN static void
_evas_text_filter_state_set(Eo *eo_obj EINA_UNUSED, Evas_Text_Data *o,
const char *cur_state, double cur_val,
const char *next_state, double next_val, double pos)
{
Evas_Object_Protected_Data *obj = eo_data_scope_get(eo_obj, EVAS_OBJECT_CLASS);
evas_object_async_block(obj);
if ((cur_state != o->cur.filter->state.cur.name) || (cur_val != o->cur.filter->state.cur.value) ||
(next_state != o->cur.filter->state.next.name) || (next_val != o->cur.filter->state.next.value) ||
(pos != o->cur.filter->state.pos))
{
EINA_COW_WRITE_BEGIN(evas_object_filter_cow, o->cur.filter, Evas_Object_Filter_Data, fcow)
{
fcow->changed = 1;
fcow->state.cur.name = cur_state;
fcow->state.cur.value = cur_val;
fcow->state.next.name = next_state;
fcow->state.next.value = next_val;
fcow->state.pos = pos;
if (o->cur.filter->chain)
{
evas_filter_program_state_set(o->cur.filter->chain, eo_obj, obj,
fcow->state.cur.name, fcow->state.cur.value,
fcow->state.next.name, fcow->state.next.value,
fcow->state.pos);
}
}
EINA_COW_WRITE_END(evas_object_filter_cow, o->cur.filter, fcow);
// Mark as changed
_evas_object_text_items_clear(o);
o->changed = 1;
_evas_object_text_recalc(eo_obj, o->cur.text);
evas_object_change(eo_obj, obj);
evas_object_clip_dirty(eo_obj, obj);
evas_object_coords_recalc(eo_obj, obj);
evas_object_inform_call_resize(eo_obj);
}
}
EAPI void
evas_object_text_font_source_set(Eo *obj, const char *font_source)
{
@ -2646,4 +2216,43 @@ evas_object_text_text_get(const Eo *obj)
return eo_do_ret((Eo *) obj, ret, efl_text_get());
}
/* urgh. why are those needed? */
EOLIAN void
_evas_text_efl_gfx_filter_program_set(Eo *obj, Evas_Text_Data *pd EINA_UNUSED, const char *code)
{
pd->has_filter = (code != NULL);
eo_do_super(obj, MY_CLASS, efl_gfx_filter_program_set(code));
}
EOLIAN const char *
_evas_text_efl_gfx_filter_program_get(Eo *obj, Evas_Text_Data *pd EINA_UNUSED)
{
const char *code;
return eo_do_super_ret(obj, MY_CLASS, code, efl_gfx_filter_program_get());
}
EOLIAN void
_evas_text_efl_gfx_filter_source_set(Eo *obj, Evas_Text_Data *pd EINA_UNUSED, const char *name, Efl_Gfx_Base *source)
{
eo_do_super(obj, MY_CLASS, efl_gfx_filter_source_set(name, source));
}
EOLIAN void
_evas_text_efl_gfx_filter_source_get(Eo *obj, Evas_Text_Data *pd EINA_UNUSED, const char *name, Efl_Gfx_Base **source)
{
eo_do_super(obj, MY_CLASS, efl_gfx_filter_source_get(name, source));
}
EOLIAN void
_evas_text_efl_gfx_filter_state_set(Eo *obj, Evas_Text_Data *pd EINA_UNUSED,
const char *cur_state, double cur_val,
const char *next_state, double next_val, double pos)
{
eo_do_super(obj, MY_CLASS, efl_gfx_filter_state_set(cur_state, cur_val, next_state, next_val, pos));
}
#include "canvas/evas_text.eo.c"

View File

@ -1,4 +1,4 @@
class Evas.Text (Evas.Object, Efl.Text, Efl.Text_Properties)
class Evas.Text (Evas.Object, Efl.Text, Efl.Text_Properties, Evas.Filter)
{
legacy_prefix: evas_object_text;
eo_prefix: evas_obj_text;
@ -219,64 +219,6 @@ class Evas.Text (Evas.Object, Efl.Text, Efl.Text_Properties)
a: int; /*@ The alpha component of the given color. */
}
}
@property filter_program {
set {
/*@ Set an Evas filter program on this Text Object.
If the program fails to compile (syntax error, invalid
buffer name, etc...), the standard text effects will be
applied instead (SHADOW, etc...). switch back to the
standard text effects.
@since 1.9
@note EXPERIMENTAL FEATURE. This is an unstable API,
please use only for testing purposes.
@see @ref evasfiltersref "Evas filters reference"
*/
legacy: null;
}
values {
program: const(char)*; /*@ The program code, as defined
by the @ref evasfiltersref "Evas filters script language".
Pass NULL to remove the former program and switch back
to the standard text effect */
}
}
@property filter_source {
set {
/*@ Bind an object to use as a mask or texture with Evas Filters.
This will create automatically a new RGBA buffer containing
the source object's pixels (as it is rendered).
@since 1.9
@note EXPERIMENTAL FEATURE. This is an unstable API,
please use only for testing purposes.
@see @ref evasfiltersref "Evas filters reference" */
legacy: null;
}
values {
name: const(char)*; /*@ Object name as used in the program code */
eobj: Evas.Object *; /*@ Eo object to use through proxy rendering */
}
}
@property filter_state {
set {
/*@ Set the current state of the filter (for use from Edje)
@internal
@since 1.15
*/
legacy: null;
}
values {
cur_state: const(char)*;
cur_val: double(0.0);
next_state: const(char)*;
next_val: double(0.0);
animpos: double(0.0);
}
}
@property max_descent {
get {
return: Evas.Coord;
@ -384,5 +326,12 @@ class Evas.Text (Evas.Object, Efl.Text, Efl.Text_Properties)
Efl.Text_Properties.font.set;
Efl.Text_Properties.font_source.get;
Efl.Text_Properties.font_source.set;
Efl.Gfx.Filter.program.set;
Efl.Gfx.Filter.program.get;
Efl.Gfx.Filter.source_set;
Efl.Gfx.Filter.source_get;
Efl.Gfx.Filter.state.set;
Evas.Filter.dirty;
Evas.Filter.input_render;
}
}

View File

@ -1798,6 +1798,9 @@ void evas_model_set_from_torus_primitive(Evas_Canvas3D_Mesh *mesh, int frame, Ev
void evas_model_set_from_surface_primitive(Evas_Canvas3D_Mesh *mesh, int frame, Evas_Canvas3D_Surface_Func func, int precision, Evas_Vec2 tex_scale);
void evas_model_set_from_terrain_primitive(Evas_Canvas3D_Mesh *mesh, int frame, int precision, Evas_Vec2 tex_scale);
/* Filter functions */
Eina_Bool evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj, void *output, void *context, void *surface, int x, int y, Eina_Bool do_async, Eina_Bool alpha);
extern int _evas_alloc_error;
extern int _evas_event_counter;

View File

@ -306,7 +306,7 @@ START_TEST(evas_filter_text_padding_test)
// Don't test proxy cases here.
if (tc->source) continue;
eo_do(to, evas_obj_text_filter_program_set(tc->code));
eo_do(to, efl_gfx_filter_program_set(tc->code));
evas_object_text_style_pad_get(to, &l, &r, &t, &b);
evas_object_geometry_get(to, NULL, NULL, &W, &H);
//fprintf(stderr, "Case %d: %dx%d for padding %d,%d,%d,%d\n", k, W, H, l, r, t, b);
@ -394,14 +394,14 @@ START_TEST(evas_filter_text_render_test)
evas_object_show(o);
eo_do(to,
efl_gfx_color_set(255, 255, 255, 255),
evas_obj_text_filter_source_set(tc->source, o),
evas_obj_text_filter_program_set(tc->code));
efl_gfx_filter_source_set(tc->source, o),
efl_gfx_filter_program_set(tc->code));
}
else
{
eo_do(to,
efl_gfx_color_set(255, 255, 255, 255),
evas_obj_text_filter_program_set(tc->code));
efl_gfx_filter_program_set(tc->code));
}
evas_object_geometry_get(to, NULL, NULL, &w, &h);