diff --git a/doc/previews/preview_text_filter.c b/doc/previews/preview_text_filter.c index 864342b080..24c51cdaca 100644 --- a/doc/previews/preview_text_filter.c +++ b/doc/previews/preview_text_filter.c @@ -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); diff --git a/src/Makefile_Efl.am b/src/Makefile_Efl.am index 5d45ae03ae..ad49f47bb6 100644 --- a/src/Makefile_Efl.am +++ b/src/Makefile_Efl.am @@ -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) diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index ef59a2f185..cfba9b61e3 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -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 \ diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c index 30478a6ac8..a1cd9c1aff 100644 --- a/src/lib/edje/edje_calc.c +++ b/src/lib/edje/edje_calc.c @@ -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: diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index 6f209f8dfd..d8c0411507 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -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, diff --git a/src/lib/edje/edje_text.c b/src/lib/edje/edje_text.c index 0f65671b93..a49b661c9e 100644 --- a/src/lib/edje/edje_text.c +++ b/src/lib/edje/edje_text.c @@ -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; diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h index f8eb8eb1f9..7a2ea8fa70 100644 --- a/src/lib/efl/Efl.h +++ b/src/lib/efl/Efl.h @@ -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 diff --git a/src/lib/efl/interfaces/efl_gfx_filter.eo b/src/lib/efl/interfaces/efl_gfx_filter.eo new file mode 100644 index 0000000000..baa604696b --- /dev/null +++ b/src/lib/efl/interfaces/efl_gfx_filter.eo @@ -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]] + } + } + } +} diff --git a/src/lib/efl/interfaces/efl_interfaces_main.c b/src/lib/efl/interfaces/efl_interfaces_main.c index 31a3aae616..5b044ff87e 100644 --- a/src/lib/efl/interfaces/efl_interfaces_main.c +++ b/src/lib/efl/interfaces/efl_interfaces_main.c @@ -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"); diff --git a/src/lib/evas/canvas/evas_filter.eo b/src/lib/evas/canvas/evas_filter.eo new file mode 100644 index 0000000000..7f6bdcb096 --- /dev/null +++ b/src/lib/evas/canvas/evas_filter.eo @@ -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; + } +} diff --git a/src/lib/evas/canvas/evas_filter_mixin.c b/src/lib/evas/canvas/evas_filter_mixin.c new file mode 100644 index 0000000000..20aa8cc72d --- /dev/null +++ b/src/lib/evas/canvas/evas_filter_mixin.c @@ -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" diff --git a/src/lib/evas/canvas/evas_object_main.c b/src/lib/evas/canvas/evas_object_main.c index d047d96668..9552a44de4 100644 --- a/src/lib/evas/canvas/evas_object_main.c +++ b/src/lib/evas/canvas/evas_object_main.c @@ -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 diff --git a/src/lib/evas/canvas/evas_object_text.c b/src/lib/evas/canvas/evas_object_text.c index 80a7e75f46..65350462d2 100644 --- a/src/lib/evas/canvas/evas_object_text.c +++ b/src/lib/evas/canvas/evas_object_text.c @@ -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" diff --git a/src/lib/evas/canvas/evas_text.eo b/src/lib/evas/canvas/evas_text.eo index 25e02dd750..5991c0a56f 100644 --- a/src/lib/evas/canvas/evas_text.eo +++ b/src/lib/evas/canvas/evas_text.eo @@ -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; } } diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 215e996581..33bfcd4285 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -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; diff --git a/src/tests/evas/evas_test_filters.c b/src/tests/evas/evas_test_filters.c index d211114e06..0b72d7c77d 100644 --- a/src/tests/evas/evas_test_filters.c +++ b/src/tests/evas/evas_test_filters.c @@ -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);