evas: Fix unsafe code in previous patches (tb filters)

This also reduces the overhead required per text item when there
is no filter.
This commit is contained in:
Jean-Philippe Andre 2017-01-09 20:24:40 +09:00
parent 13c62c10e1
commit 59bda411b9
1 changed files with 84 additions and 68 deletions

View File

@ -237,6 +237,12 @@ typedef struct _Efl_Canvas_Text_Filter_Post_Render Efl_Canvas_Text_Filter_Post_R
* Filter name - code database * Filter name - code database
*/ */
typedef struct _Efl_Canvas_Text_Filter_Program Efl_Canvas_Text_Filter_Program; typedef struct _Efl_Canvas_Text_Filter_Program Efl_Canvas_Text_Filter_Program;
/**
* @internal
* @typedef Text_Item_Filter
* Text item filter properties (run context, output buffer, ...)
*/
typedef struct _Text_Item_Filter Text_Item_Filter;
/** /**
* @internal * @internal
* @def IS_AT_END(ti, ind) * @def IS_AT_END(ti, ind)
@ -437,8 +443,7 @@ struct _Evas_Object_Textblock_Text_Item
Evas_Object_Textblock_Item parent; /**< Textblock item. */ Evas_Object_Textblock_Item parent; /**< Textblock item. */
Evas_Text_Props text_props; /**< Props for this item. */ Evas_Text_Props text_props; /**< Props for this item. */
Evas_Coord x_adjustment; /**< Used to indicate by how much we adjusted sizes */ Evas_Coord x_adjustment; /**< Used to indicate by how much we adjusted sizes */
Evas_Filter_Context *gfx_filter_ctx; /* temp variable FIXME */ Text_Item_Filter *gfx_filter;
void *gfx_buffer; /* FIXME */
}; };
struct _Evas_Object_Textblock_Format_Item struct _Evas_Object_Textblock_Format_Item
@ -452,6 +457,15 @@ struct _Evas_Object_Textblock_Format_Item
Eina_Bool formatme : 1; /**< EINA_TRUE if format required, else EINA_FALSE */ Eina_Bool formatme : 1; /**< EINA_TRUE if format required, else EINA_FALSE */
}; };
struct _Text_Item_Filter
{
Evas_Object_Textblock_Text_Item *ti; /**< associated text item. if null, it was deleted */
Evas_Filter_Context *ctx; /**< running context for the filter */
Evas_Public_Data *evas; /**< evas instance */
void *output; /**< output rgba buffer for this text item (engine image) */
Eina_Bool do_async; /**< do_async flag when running the filter */
};
struct _Efl_Canvas_Text_Filter struct _Efl_Canvas_Text_Filter
{ {
Eina_Stringshare *name; Eina_Stringshare *name;
@ -948,31 +962,14 @@ _format_unref_free(const Evas_Object *eo_obj, Evas_Object_Textblock_Format *fmt)
free(fmt); free(fmt);
} }
typedef struct _Post_Render_Image_Unref_Job
{
Evas_Public_Data *evas;
void *image;
} Post_Render_Image_Unref_Job;
static void
_image_post_render_unref_cb(void *data)
{
Post_Render_Image_Unref_Job *job = data;
job->evas->engine.func->image_free(job->evas->engine.data.output, job->image);
free(job);
}
static inline void static inline void
_image_safe_unref(Evas_Public_Data *e, void *image) _image_safe_unref(Evas_Public_Data *e, void *image, Eina_Bool async)
{ {
Post_Render_Image_Unref_Job *job;
if (!image) return; if (!image) return;
job = calloc(1, sizeof(*job)); if (async)
job->evas = e; evas_unref_queue_image_put(e, image);
job->image = image; else
evas_post_render_job_add(e, _image_post_render_unref_cb, job); e->engine.func->image_free(e->engine.data.output, image);
} }
/** /**
@ -990,15 +987,21 @@ _item_free(const Evas_Object *eo_obj, Evas_Object_Textblock_Line *ln, Evas_Objec
Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it); Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it);
evas_common_text_props_content_unref(&ti->text_props); evas_common_text_props_content_unref(&ti->text_props);
if (ti->gfx_filter_ctx) if (EINA_UNLIKELY(ti->gfx_filter != NULL))
{ {
WRN("filter context still alive? (ignored)"); if (ti->gfx_filter->output)
} {
if (ti->gfx_buffer) Evas *eo_evas = evas_object_evas_get(eo_obj);
{ Evas_Public_Data *evas = efl_data_scope_get(eo_evas, EVAS_CANVAS_CLASS);
Evas_Public_Data *e = efl_data_scope_get(evas_object_evas_get(eo_obj), EVAS_CANVAS_CLASS); Eina_Bool async = ti->gfx_filter->do_async;
_image_safe_unref(e, ti->gfx_buffer);
ti->gfx_buffer = NULL; _image_safe_unref(evas, ti->gfx_filter->output, async);
ti->gfx_filter->output = NULL;
}
if (!ti->gfx_filter->ctx)
free(ti->gfx_filter);
else
ti->gfx_filter->ti = NULL;
} }
} }
else else
@ -12943,42 +12946,46 @@ evas_object_textblock_free(Evas_Object *eo_obj)
free(o->utf8); free(o->utf8);
} }
static Evas_Filter_Context * static inline Evas_Filter_Context *
_filter_context_get(Evas_Object_Textblock_Text_Item *ti) _filter_context_get(Evas_Object_Textblock_Text_Item *ti)
{ {
// FIXME: optimize this (memory usage) if (!ti || !ti->gfx_filter) return NULL;
if (!ti) return NULL; return ti->gfx_filter->ctx;
return ti->gfx_filter_ctx;
} }
static void static inline void *
_filter_context_set(Evas_Object_Textblock_Text_Item *ti, Evas_Filter_Context *ctx) _filter_output_get(Evas_Object_Textblock_Text_Item *ti)
{ {
if (!ti) return; if (!ti || !ti->gfx_filter) return NULL;
ti->gfx_filter_ctx = ctx; return ti->gfx_filter->output;
} }
static void static void
_filter_sync_end(Evas_Filter_Context *ctx, Eina_Bool success) _filter_sync_end(Evas_Filter_Context *ctx, Eina_Bool success)
{ {
Evas_Object_Textblock_Text_Item *ti; Text_Item_Filter *filter;
Efl_Canvas_Text_Filter *filter; Eina_Bool async;
void *buffer;
ti = evas_filter_context_data_get(ctx); filter = evas_filter_context_data_get(ctx);
filter = ti->parent.format->gfx_filter; EINA_SAFETY_ON_NULL_RETURN(filter);
buffer = evas_filter_buffer_backing_steal(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID); async = evas_filter_context_async_get(ctx);
if (buffer) _image_safe_unref(filter->evas, filter->output, async);
if (filter->ti)
{ {
if (ti->gfx_buffer) filter->output = evas_filter_buffer_backing_steal(ctx, EVAS_FILTER_BUFFER_OUTPUT_ID);
_image_safe_unref(filter->evas, ti->gfx_buffer); if (filter->ti->parent.format->gfx_filter)
ti->gfx_buffer = buffer; filter->ti->parent.format->gfx_filter->invalid = !success;
// else just avoid sigsegv
filter->ti = NULL;
filter->ctx = NULL;
}
else
{
free(filter);
} }
evas_filter_context_destroy(ctx); evas_filter_context_destroy(ctx);
_filter_context_set(ti, NULL);
filter->invalid = !success;
} }
static void static void
@ -12994,7 +13001,7 @@ static void
_filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success) _filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
{ {
Efl_Canvas_Text_Filter_Post_Render *post_data; Efl_Canvas_Text_Filter_Post_Render *post_data;
Efl_Canvas_Text_Filter *filter = data; Evas_Public_Data *evas = data;
if (!evas_filter_context_async_get(ctx)) if (!evas_filter_context_async_get(ctx))
{ {
@ -13005,7 +13012,7 @@ _filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
post_data = calloc(1, sizeof(*post_data)); post_data = calloc(1, sizeof(*post_data));
post_data->success = success; post_data->success = success;
post_data->ctx = ctx; post_data->ctx = ctx;
evas_post_render_job_add(filter->evas, _filter_post_render_cb, post_data); evas_post_render_job_add(evas, _filter_post_render_cb, post_data);
} }
static void static void
@ -13169,9 +13176,9 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
#define DRAW_TEXT(ox, oy) do { \ #define DRAW_TEXT(ox, oy) do { \
if (ti->parent.format->font.font) \ if (ti->parent.format->font.font) \
{ \ { \
if (EINA_LIKELY(!ti->gfx_filter_ctx)) \ if (EINA_LIKELY(!_filter_context_get(ti))) \
DRAW_TEXT_NOFILTER(ox, oy); \ DRAW_TEXT_NOFILTER(ox, oy); \
else if (!ti->gfx_buffer) \ else if (!_filter_output_get(ti)) \
DRAW_TEXT_FILTER(ti->parent.format->gfx_filter, ox, oy); \ DRAW_TEXT_FILTER(ti->parent.format->gfx_filter, ox, oy); \
} } while(0) } } while(0)
@ -13314,6 +13321,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
Efl_Canvas_Text_Filter *filter; Efl_Canvas_Text_Filter *filter;
Evas_Filter_Program *pgm; Evas_Filter_Program *pgm;
Evas_Filter_Context *ctx; Evas_Filter_Context *ctx;
void *previous_output;
Eina_Bool ok; Eina_Bool ok;
int X, Y; int X, Y;
@ -13327,16 +13335,23 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
} }
// previous run // previous run
if (ti->gfx_buffer) previous_output = _filter_output_get(ti);
if (previous_output)
{ {
if (!filter->redraw) continue; if (!filter->redraw) continue;
_image_safe_unref(obj->layer->evas, ti->gfx_buffer); _image_safe_unref(obj->layer->evas, previous_output, do_async);
ti->gfx_buffer = NULL; previous_output = NULL;
} }
// prepare filter context // prepare filter context
ctx = evas_filter_context_new(obj->layer->evas, do_async, ti); if (!ti->gfx_filter)
{
ti->gfx_filter = calloc(1, sizeof(*ti->gfx_filter));
ti->gfx_filter->evas = obj->layer->evas;
ti->gfx_filter->ti = ti;
}
ctx = evas_filter_context_new(obj->layer->evas, do_async, ti->gfx_filter);
evas_filter_state_prepare(eo_obj, &state, ti); evas_filter_state_prepare(eo_obj, &state, ti);
evas_filter_program_state_set(pgm, &state); evas_filter_program_state_set(pgm, &state);
ok = evas_filter_context_program_use(ctx, pgm); ok = evas_filter_context_program_use(ctx, pgm);
@ -13361,7 +13376,8 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
evas_filter_context_proxy_render_all(ctx, eo_obj, EINA_FALSE); evas_filter_context_proxy_render_all(ctx, eo_obj, EINA_FALSE);
evas_filter_context_buffers_allocate_all(ctx); evas_filter_context_buffers_allocate_all(ctx);
evas_filter_target_set(ctx, context, surface, X, Y); evas_filter_target_set(ctx, context, surface, X, Y);
_filter_context_set(ti, ctx); ti->gfx_filter->ctx = ctx;
ti->gfx_filter->do_async = do_async;
// common data for all items (FIXME: should be common to object) // common data for all items (FIXME: should be common to object)
if (!filter->dc) if (!filter->dc)
@ -13388,7 +13404,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
yoff = itr->yoff; yoff = itr->yoff;
ln = itr->ln; ln = itr->ln;
if (EINA_UNLIKELY(ti->gfx_filter_ctx != NULL)) if (EINA_UNLIKELY(_filter_context_get(ti) != NULL))
context = ti->parent.format->gfx_filter->dc; context = ti->parent.format->gfx_filter->dc;
shad_dst = shad_sz = dx = dy = haveshad = 0; shad_dst = shad_sz = dx = dy = haveshad = 0;
@ -13503,7 +13519,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
yoff = itr->yoff; yoff = itr->yoff;
ln = itr->ln; ln = itr->ln;
if (EINA_UNLIKELY(ti->gfx_filter_ctx != NULL)) if (EINA_UNLIKELY(_filter_context_get(ti) != NULL))
context = ti->parent.format->gfx_filter->dc; context = ti->parent.format->gfx_filter->dc;
if ((ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_GLOW) if ((ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_GLOW)
@ -13541,7 +13557,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
yoff = itr->yoff; yoff = itr->yoff;
ln = itr->ln; ln = itr->ln;
if (EINA_UNLIKELY(ti->gfx_filter_ctx != NULL)) if (EINA_UNLIKELY(_filter_context_get(ti) != NULL))
context = ti->parent.format->gfx_filter->dc; context = ti->parent.format->gfx_filter->dc;
if (((ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_OUTLINE) || if (((ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_OUTLINE) ||
@ -13626,7 +13642,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
{ {
void *fi = _ITEM_TEXT(itr)->text_props.font_instance; void *fi = _ITEM_TEXT(itr)->text_props.font_instance;
if (EINA_UNLIKELY(ti->gfx_filter_ctx != NULL)) if (EINA_UNLIKELY(_filter_context_get(ti) != NULL))
context = ti->parent.format->gfx_filter->dc; context = ti->parent.format->gfx_filter->dc;
COLOR_SET(normal); COLOR_SET(normal);
@ -13640,7 +13656,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
{ {
Evas_Filter_Context *ctx = _filter_context_get(ti); Evas_Filter_Context *ctx = _filter_context_get(ti);
Efl_Canvas_Text_Filter *filter = ti->parent.format->gfx_filter; Efl_Canvas_Text_Filter *filter = ti->parent.format->gfx_filter;
void *buffer = ti->gfx_buffer; void *buffer = _filter_output_get(ti);
if (buffer) if (buffer)
{ {
@ -13657,7 +13673,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
} }
else if (ctx) else if (ctx)
{ {
evas_filter_context_post_run_callback_set(ctx, _filter_cb, filter); evas_filter_context_post_run_callback_set(ctx, _filter_cb, obj->layer->evas);
evas_filter_run(ctx); evas_filter_run(ctx);
} }
} }