evas: Drop unused buffer from textblock filters

This is a first step before implementing some form of caching of
those output buffers. At the moment, it very aggressively deletes
any buffer that falls outside the clip of the textblock object.
Note that this is better in terms of memory usage but way worse
in terms of render performance (eg. scrolling). If a textblock
is a proxy source then we keep all the buffers (the entire object
is to be rendered).

+ fix a crash
This commit is contained in:
Jean-Philippe Andre 2017-01-10 11:44:25 +09:00
parent 59bda411b9
commit 3a98d0ea88
1 changed files with 85 additions and 8 deletions

View File

@ -140,6 +140,10 @@ static const char o_type[] = "textblock";
} \
while(0)
// testing out some macros to maybe add to eina
#define EINA_INLIST_REMOVE(l,i) do { l = (__typeof__(l)) eina_inlist_remove(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
#define EINA_INLIST_APPEND(l,i) do { l = (__typeof__(l)) eina_inlist_append(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
/* private struct for textblock object internal data */
/**
* @internal
@ -459,6 +463,8 @@ struct _Evas_Object_Textblock_Format_Item
struct _Text_Item_Filter
{
EINA_INLIST; /**< list on the tb object */
Efl_Canvas_Text_Data *textblock;
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 */
@ -609,6 +615,7 @@ struct _Evas_Object_Textblock
Efl_Canvas_Text_Filter_Program *programs;
Evas_Filter_Data_Binding *data_bindings;
Eina_Hash *sources;
Text_Item_Filter *text_items; // inlist
} gfx_filter;
Eina_Bool redraw : 1;
Eina_Bool changed : 1;
@ -989,6 +996,8 @@ _item_free(const Evas_Object *eo_obj, Evas_Object_Textblock_Line *ln, Evas_Objec
evas_common_text_props_content_unref(&ti->text_props);
if (EINA_UNLIKELY(ti->gfx_filter != NULL))
{
Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, MY_CLASS);
if (ti->gfx_filter->output)
{
Evas *eo_evas = evas_object_evas_get(eo_obj);
@ -998,6 +1007,7 @@ _item_free(const Evas_Object *eo_obj, Evas_Object_Textblock_Line *ln, Evas_Objec
_image_safe_unref(evas, ti->gfx_filter->output, async);
ti->gfx_filter->output = NULL;
}
EINA_INLIST_REMOVE(o->gfx_filter.text_items, ti->gfx_filter);
if (!ti->gfx_filter->ctx)
free(ti->gfx_filter);
else
@ -2761,6 +2771,15 @@ _format_dup(Evas_Object *eo_obj, const Evas_Object_Textblock_Format *fmt)
/* FIXME: just ref the font here... */
fmt2->font.font = evas_font_load(obj->layer->evas->evas, fmt2->font.fdesc,
fmt2->font.source, (int)(((double) fmt2->font.size) * obj->cur->scale));
if (fmt->gfx_filter)
{
fmt2->gfx_filter = malloc(sizeof(*fmt2->gfx_filter));
memcpy(fmt2->gfx_filter, fmt->gfx_filter, sizeof(*fmt->gfx_filter));
fmt2->gfx_filter->name = eina_stringshare_ref(fmt->gfx_filter->name);
fmt2->gfx_filter->dc = ENFN->context_dup(ENDT, fmt->gfx_filter->dc);
}
return fmt2;
}
@ -12886,9 +12905,6 @@ _efl_canvas_text_efl_object_destructor(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_
efl_destructor(efl_super(eo_obj, MY_CLASS));
}
// testing this macro...
#define EINA_INLIST_REMOVE(l,i) do { l = (__typeof__(l)) eina_inlist_remove(EINA_INLIST_GET(l), EINA_INLIST_GET(i)); } while (0)
static void
evas_object_textblock_free(Evas_Object *eo_obj)
{
@ -12978,7 +12994,6 @@ _filter_sync_end(Evas_Filter_Context *ctx, Eina_Bool success)
if (filter->ti->parent.format->gfx_filter)
filter->ti->parent.format->gfx_filter->invalid = !success;
// else just avoid sigsegv
filter->ti = NULL;
filter->ctx = NULL;
}
else
@ -13015,6 +13030,66 @@ _filter_cb(Evas_Filter_Context *ctx, void *data, Eina_Bool success)
evas_post_render_job_add(evas, _filter_post_render_cb, post_data);
}
static Eina_Rectangle
_filter_relative_bounding_box_get(const Text_Item_Filter *tif)
{
int x_offset, y_offset, l, r, t, b;
Eina_Rectangle rect;
x_offset = tif->ti->parent.ln->x + tif->ti->parent.x;
y_offset = tif->ti->parent.ln->par->y + tif->ti->parent.ln->y;
l = tif->ti->parent.format->gfx_filter->pad.l;
r = tif->ti->parent.format->gfx_filter->pad.r;
t = tif->ti->parent.format->gfx_filter->pad.t;
b = tif->ti->parent.format->gfx_filter->pad.b;
rect.x = x_offset - l;
rect.y = y_offset - t;
rect.w = tif->ti->parent.w;
rect.h = tif->ti->parent.h + t + b;
return rect;
}
static void
_filter_output_cache_prune(Evas_Object_Protected_Data *obj, Efl_Canvas_Text_Data *o)
{
Text_Item_Filter *tif;
Eina_Inlist *il;
Eina_Rectangle obj_rect;
// proxy surfaces contain the entire object, nothing to prune
if (obj->proxy->proxies)
return;
obj_rect.x = obj->cur->cache.clip.x;
obj_rect.y = obj->cur->cache.clip.y;
obj_rect.w = obj->cur->cache.clip.w;
obj_rect.h = obj->cur->cache.clip.h;
EINA_INLIST_FOREACH_SAFE(o->gfx_filter.text_items, il, tif)
{
Eina_Rectangle it_rect;
if (!tif->ti)
{
if (tif->ctx) continue;
}
else
{
if (!tif->ti->parent.ln || !tif->ti->parent.ln->par) continue;
it_rect = _filter_relative_bounding_box_get(tif);
it_rect.x += obj->cur->geometry.x;
it_rect.y += obj->cur->geometry.y;
if (eina_rectangles_intersect(&obj_rect, &it_rect)) continue;
}
_image_safe_unref(obj->layer->evas, tif->output, tif->do_async);
tif->output = NULL;
}
}
static void
evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
@ -13176,9 +13251,9 @@ 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(!_filter_context_get(ti))) \
if (EINA_LIKELY(!ti->gfx_filter || (!ti->gfx_filter->ctx && !ti->gfx_filter->output))) \
DRAW_TEXT_NOFILTER(ox, oy); \
else if (!_filter_output_get(ti)) \
else if (ti->gfx_filter->ctx != NULL) \
DRAW_TEXT_FILTER(ti->parent.format->gfx_filter, ox, oy); \
} } while(0)
@ -13350,6 +13425,7 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
ti->gfx_filter = calloc(1, sizeof(*ti->gfx_filter));
ti->gfx_filter->evas = obj->layer->evas;
ti->gfx_filter->ti = ti;
EINA_INLIST_APPEND(o->gfx_filter.text_items, ti->gfx_filter);
}
ctx = evas_filter_context_new(obj->layer->evas, do_async, ti->gfx_filter);
evas_filter_state_prepare(eo_obj, &state, ti);
@ -13665,8 +13741,8 @@ evas_object_textblock_render(Evas_Object *eo_obj EINA_UNUSED,
X = obj->cur->geometry.x + ln->x + ti->parent.x + x - filter->pad.l;
Y = obj->cur->geometry.y + ln->par->y + ln->y + y - filter->pad.t;
ca = cr = cb = cg = 255;
ENFN->context_color_set(ENDT, context, 255, 255, 255, 255);
ENFN->context_multiplier_unset(ENDT, context);
ENFN->image_size_get(ENDT, buffer, &W, &H);
ENFN->image_draw(ENDT, context, surface, buffer,
0, 0, W, H, X, Y, W, H, 0, do_async);
@ -14089,7 +14165,7 @@ done:
static void
evas_object_textblock_render_post(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,
void *type_private_data EINA_UNUSED)
{
/* Efl_Canvas_Text_Data *o; */
@ -14103,6 +14179,7 @@ evas_object_textblock_render_post(Evas_Object *eo_obj,
/* move cur to prev safely for object data */
evas_object_cur_prev(eo_obj);
/* o->prev = o->cur; */
_filter_output_cache_prune(obj, type_private_data);
}
static unsigned int evas_object_textblock_id_get(Evas_Object *eo_obj)