evas: Fix tb filters spanning over multiple items

If a gfx filter was applied to a block of text spanning over
multiple text items, then it would improperly render as the
filter context was stored in the format, rather than the text
item. This is fixed by using a list of contexts in the format
node rather than a single context.
This commit is contained in:
Jean-Philippe Andre 2017-01-04 16:50:09 +09:00
parent 5f1c993d17
commit de47187dde
5 changed files with 69 additions and 38 deletions

View File

@ -278,7 +278,7 @@ evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
_evas_filter_state_set_internal(pd->data->chain, pd);
}
filter = evas_filter_context_new(obj->layer->evas, do_async);
filter = evas_filter_context_new(obj->layer->evas, do_async, 0);
// Run script
ok = evas_filter_context_program_use(filter, pd->data->chain);

View File

@ -430,7 +430,6 @@ struct _Evas_Object_Textblock_Item
Evas_Coord yoff; /**< y offset. */
Eina_Bool merge : 1; /**< Indicates whether this item should merge to the previous item or not */
Eina_Bool visually_deleted : 1; /**< Indicates whether this item is used in the visual layout or not. */
Eina_Bool has_gfx_filter : 1; /**< True if this item should be rendered with a gfx filter */
};
struct _Evas_Object_Textblock_Text_Item
@ -439,6 +438,7 @@ struct _Evas_Object_Textblock_Text_Item
Evas_Text_Props text_props; /**< Props for this item. */
Evas_Coord inset; /**< Inset of text item. */
Evas_Coord x_adjustment; /**< Used to indicate by how much we adjusted sizes */
int gfx_filter_id; /**< Index for the filter context in parent.format->gfx_filter */
};
struct _Evas_Object_Textblock_Format_Item
@ -456,15 +456,15 @@ struct _Efl_Canvas_Text_Filter
{
// FIXME: sources not handled! --> global to the textblock
// FIXME: data not handled! --> global to the textblock
// FIXME: filters need names! --> global to the textblock
Eina_Stringshare *name;
Evas_Filter_Context *ctx;
Eina_Array *contexts; /* contains Evas_Filter_Context items for each sub text item */
Evas_Object *eo_obj;
Evas_Public_Data *evas;
void *dc; /* draw context */
void *dc; /* draw context - no clip, white, no colmul... */
struct {
int l, r, t, b;
} pad;
int pending_ctx;
Eina_Bool invalid;
Eina_Bool async;
};
@ -472,7 +472,8 @@ struct _Efl_Canvas_Text_Filter
struct _Efl_Canvas_Text_Filter_Post_Render
{
Efl_Canvas_Text_Filter *filter;
Eina_Bool success;
int ctx_id;
Eina_Bool success;
};
struct _Efl_Canvas_Text_Filter_Program
@ -504,7 +505,7 @@ struct _Evas_Object_Textblock_Format
struct {
int l, r;
} margin; /**< Left and right margin width. */
Efl_Canvas_Text_Filter *gfx_filter; /**< Gfx Filter to apply to this node */
Efl_Canvas_Text_Filter *gfx_filter; /**< Gfx Filter to apply to the children text items */
int ref; /**< Value of the ref. */
int tabstops; /**< Value of the size of the tab character. */
int linesize; /**< Value of the size of the line of the text. */
@ -12813,11 +12814,21 @@ evas_object_textblock_free(Evas_Object *eo_obj)
}
static void
_filter_sync_end(Efl_Canvas_Text_Filter *filter, Eina_Bool success)
_filter_sync_end(Efl_Canvas_Text_Filter *filter, int id, Eina_Bool success)
{
evas_filter_context_destroy(filter->ctx);
Evas_Filter_Context *ctx;
EINA_SAFETY_ON_NULL_RETURN(filter->contexts);
ctx = eina_array_data_get(filter->contexts, id);
eina_array_data_set(filter->contexts, id, NULL);
evas_filter_context_destroy(ctx);
filter->invalid = !success;
filter->ctx = NULL;
if ((--filter->pending_ctx) == 0)
{
eina_array_free(filter->contexts);
filter->contexts = NULL;
}
}
static void
@ -12825,7 +12836,7 @@ _filter_post_render_cb(void *data)
{
Efl_Canvas_Text_Filter_Post_Render *post_data = data;
_filter_sync_end(post_data->filter, post_data->success);
_filter_sync_end(post_data->filter, post_data->ctx_id, post_data->success);
free(post_data);
}
@ -12834,18 +12845,20 @@ _filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
{
Efl_Canvas_Text_Filter_Post_Render *post_data;
Efl_Canvas_Text_Filter *filter = data;
int ctx_id;
EINA_SAFETY_ON_FALSE_RETURN(filter->ctx == ctx);
ctx_id = evas_filter_context_id_get(ctx);
if (!filter->async)
{
_filter_sync_end(filter, success);
_filter_sync_end(filter, ctx_id, success);
return;
}
post_data = calloc(1, sizeof(*post_data));
post_data->success = success;
post_data->filter = filter;
post_data->ctx_id = ctx_id;
evas_post_render_job_add(filter->evas, _filter_post_render_cb, post_data);
}
@ -13002,10 +13015,11 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
cr = nr; cg = ng; cb = nb; ca = na; \
}
#define DRAW_TEXT_FILTER(gfx_f, ox, oy) do { \
evas_filter_input_render(eo_obj, gfx_f->ctx, gfx_f->dc, ti, \
gfx_f->pad.l, gfx_f->pad.r, \
gfx_f->pad.t, gfx_f->pad.b, do_async); \
#define DRAW_TEXT_FILTER(gf, gf_id, ox, oy) do { \
Evas_Filter_Context *ctx = eina_array_data_get(gf->contexts, gf_id); \
evas_filter_input_render(eo_obj, ctx, gf->dc, ti, \
gf->pad.l, gf->pad.r, \
gf->pad.t, gf->pad.b, do_async); \
} while (0)
#define DRAW_TEXT_NOFILTER(ox, oy) do { \
@ -13024,10 +13038,10 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
#define DRAW_TEXT(ox, oy) do { \
if (ti->parent.format->font.font) \
{ \
if (EINA_LIKELY(!itr->has_gfx_filter)) \
if (EINA_LIKELY(!ti->gfx_filter_id)) \
DRAW_TEXT_NOFILTER(ox, oy); \
else \
DRAW_TEXT_FILTER(ti->parent.format->gfx_filter, ox, oy); \
DRAW_TEXT_FILTER(ti->parent.format->gfx_filter, ti->gfx_filter_id - 1, ox, oy); \
} } while(0)
/* backing */
@ -13172,12 +13186,13 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
Efl_Canvas_Text_Filter *filter;
Evas_Filter_Program *pgm;
Evas_Filter_Context *ctx;
int filter_id;
Eina_Bool ok;
filter = ti->parent.format->gfx_filter;
if (!filter->name || filter->invalid)
{
itr->has_gfx_filter = EINA_FALSE;
ti->gfx_filter_id = 0;
continue;
}
@ -13185,7 +13200,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
if (!program)
{
WRN("Filter '%s' not found on this object", filter->name);
itr->has_gfx_filter = EINA_FALSE;
ti->gfx_filter_id = 0;
continue;
}
@ -13199,18 +13214,22 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
{
evas_filter_program_del(pgm);
filter->invalid = EINA_TRUE;
itr->has_gfx_filter = EINA_FALSE;
ti->gfx_filter_id = 0;
continue;
}
program->pgm = pgm;
}
#ifdef DEBUG
if (filter->ctx) WRN("Previous filter context was not deleted");
if (filter->contexts) WRN("Previous filter context was not deleted");
#endif
if (!filter->contexts)
filter->contexts = eina_array_new(8);
filter_id = eina_array_count(filter->contexts);
// TODO: sources set
ctx = evas_filter_context_new(obj->layer->evas, do_async);
ctx = evas_filter_context_new(obj->layer->evas, do_async, filter_id);
evas_filter_state_prepare(eo_obj, &state, ti);
evas_filter_program_state_set(pgm, &state);
ok = evas_filter_context_program_use(ctx, pgm);
@ -13218,10 +13237,12 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
{
evas_filter_context_destroy(ctx);
filter->invalid = EINA_TRUE;
itr->has_gfx_filter = EINA_FALSE;
ti->gfx_filter_id = 0;
continue;
}
filter->ctx = ctx;
eina_array_push(filter->contexts, ctx);
ti->gfx_filter_id = filter_id + 1;
ln = ti->parent.ln;
ENFN->context_color_set(ENDT, context, 255, 255, 255, 255);
@ -13243,8 +13264,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
filter->eo_obj = eo_obj;
filter->evas = obj->layer->evas;
filter->async = do_async;
itr->has_gfx_filter = EINA_TRUE;
filter->pending_ctx++;
ENFN->context_multiplier_unset(ENDT, context);
}
@ -13262,7 +13282,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
yoff = itr->yoff;
ln = itr->ln;
if (EINA_UNLIKELY(itr->has_gfx_filter))
if (EINA_UNLIKELY(ti->gfx_filter_id))
context = ti->parent.format->gfx_filter->dc;
shad_dst = shad_sz = dx = dy = haveshad = 0;
@ -13377,7 +13397,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
yoff = itr->yoff;
ln = itr->ln;
if (EINA_UNLIKELY(itr->has_gfx_filter))
if (EINA_UNLIKELY(ti->gfx_filter_id))
context = ti->parent.format->gfx_filter->dc;
if ((ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_GLOW)
@ -13415,7 +13435,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
yoff = itr->yoff;
ln = itr->ln;
if (EINA_UNLIKELY(itr->has_gfx_filter))
if (EINA_UNLIKELY(ti->gfx_filter_id))
context = ti->parent.format->gfx_filter->dc;
if (((ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) == EVAS_TEXT_STYLE_OUTLINE) ||
@ -13500,7 +13520,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
{
void *fi = _ITEM_TEXT(itr)->text_props.font_instance;
if (EINA_UNLIKELY(itr->has_gfx_filter))
if (EINA_UNLIKELY(ti->gfx_filter_id))
context = ti->parent.format->gfx_filter->dc;
COLOR_SET(normal);
@ -13510,10 +13530,10 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
context = context_save;
if (EINA_UNLIKELY(itr->has_gfx_filter))
if (EINA_UNLIKELY(ti->gfx_filter_id))
{
Efl_Canvas_Text_Filter *filter = ti->parent.format->gfx_filter;
Evas_Filter_Context *ctx = filter->ctx;
Evas_Filter_Context *ctx = eina_array_data_get(filter->contexts, ti->gfx_filter_id - 1);
evas_filter_context_post_run_callback_set(ctx, _filter_cb, filter);
evas_filter_run(ctx);

View File

@ -49,7 +49,7 @@ _evas_image_get(Ector_Buffer *buf)
/* Main functions */
Evas_Filter_Context *
evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async)
evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async, int id)
{
Evas_Filter_Context *ctx;
@ -60,10 +60,19 @@ evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async)
ctx->evas = evas;
ctx->async = async;
ctx->context_id = id;
return ctx;
}
int
evas_filter_context_id_get(Evas_Filter_Context *ctx)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, -1);
return ctx->context_id;
}
/* Private function to reset the filter context. Used from parser.c */
void
evas_filter_context_clear(Evas_Filter_Context *ctx)

View File

@ -116,6 +116,7 @@ struct _Evas_Filter_Context
Eina_List *buffers; // Evas_Filter_Buffer *
int last_buffer_id;
int last_command_id;
int context_id; // used by textblock
// Variables changing at each run
int w, h; // Dimensions of the input/output buffers

View File

@ -132,15 +132,16 @@ EAPI Evas_Filter_Program *evas_filter_program_new(const char *name, Eina_Bool in
EAPI Eina_Bool evas_filter_program_state_set(Evas_Filter_Program *pgm, const Efl_Canvas_Filter_State *state);
EAPI Eina_Bool evas_filter_program_parse(Evas_Filter_Program *pgm, const char *str);
EAPI void evas_filter_program_del(Evas_Filter_Program *pgm);
Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm);
EAPI Eina_Bool evas_filter_program_padding_get(Evas_Filter_Program *pgm, int *l, int *r, int *t, int *b);
EAPI void evas_filter_program_source_set_all(Evas_Filter_Program *pgm, Eina_Hash *sources);
void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async);
void evas_filter_program_data_set_all(Evas_Filter_Program *pgm, Eina_Inlist *data);
/* Filter context (low level) */
Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async);
Evas_Filter_Context *evas_filter_context_new(Evas_Public_Data *evas, Eina_Bool async, int id);
int evas_filter_context_id_get(Evas_Filter_Context *ctx);
void evas_filter_context_destroy(Evas_Filter_Context *ctx);
Eina_Bool evas_filter_context_program_use(Evas_Filter_Context *ctx, Evas_Filter_Program *pgm);
void evas_filter_context_proxy_render_all(Evas_Filter_Context *ctx, Eo *eo_obj, Eina_Bool do_async);
void evas_filter_context_post_run_callback_set(Evas_Filter_Context *ctx, Evas_Filter_Cb cb, void *data);
#define evas_filter_context_autodestroy(ctx) evas_filter_context_post_run_callback_set(ctx, ((Evas_Filter_Cb) evas_filter_context_destroy), ctx)
Eina_Bool evas_filter_context_buffers_allocate_all(Evas_Filter_Context *ctx);