// import efl_gfx_types -> need to add Efl.Gfx.Color
+import eina_types;
/* Everything in this file is internal to Evas. It is not meant to be used
from outside EFL itself! */
return evas_filter_program_state_set(pgm, &state);
}
+static inline Eina_Bool
+_evas_filter_obscured_region_changed(Evas_Filter_Data *pd)
+{
+ Eina_Rectangle inter;
+
+ inter = pd->data->prev_obscured;
+ if (eina_rectangle_is_empty(&pd->data->obscured) &&
+ eina_rectangle_is_empty(&inter))
+ return EINA_FALSE;
+ if (!eina_rectangle_intersection(&inter, &pd->data->obscured))
+ return EINA_TRUE;
+ if ((inter.w != pd->data->prev_obscured.w) ||
+ (inter.h != pd->data->prev_obscured.h))
+ return EINA_TRUE;
+
+ return EINA_FALSE;
+}
+
Eina_Bool
evas_filter_object_render(Eo *eo_obj, Evas_Object_Protected_Data *obj,
void *output, void *context, void *surface,
if (!pd->data->invalid && (pd->data->chain || pd->data->code))
{
- int X, Y, W, H, l = 0, r = 0, t = 0, b = 0;
+ int X, Y, W, H;
Evas_Filter_Context *filter;
void *drawctx;
Eina_Bool ok;
void *previous = pd->data->output;
Evas_Object_Filter_Data *fcow;
+ Evas_Filter_Padding pad;
/* NOTE: Filter rendering is now done ENTIRELY on CPU.
* So we rely on cache/cache2 to allocate a real image buffer,
}
else if (previous && !pd->data->changed)
{
- Eina_Bool redraw;
+ Eina_Bool redraw = EINA_TRUE;
- redraw = _evas_filter_state_set_internal(pd->data->chain, pd);
- if (redraw)
+ if (_evas_filter_state_set_internal(pd->data->chain, pd))
DBG("Filter redraw by state change!");
else if (obj->changed)
- {
- // FIXME: Check that something else than X,Y changed!
- redraw = EINA_TRUE;
- DBG("Filter redraw by object content change!");
- }
+ DBG("Filter redraw by object content change!");
+ else if (_evas_filter_obscured_region_changed(pd))
+ DBG("Filter redraw by obscure regions change!");
+ else redraw = EINA_FALSE;
// Scan proxies to find if any changed
if (!redraw && pd->data->sources)
drawctx = ENFN->context_new(ENDT);
ENFN->context_color_set(ENDT, drawctx, 255, 255, 255, 255);
+ // Set obscured region
+ evas_filter_context_obscured_region_set(filter, pd->data->obscured);
+
// Allocate all buffers now
evas_filter_context_buffers_allocate_all(filter);
evas_filter_target_set(filter, context, surface, X + x, Y + y);
// Request rendering from the object itself (child class)
- evas_filter_program_padding_get(pd->data->chain, &l, &r, &t, &b);
- ok = evas_filter_input_render(eo_obj, filter, drawctx, NULL, l, r, t, b, 0, 0, do_async);
+ evas_filter_program_padding_get(pd->data->chain, &pad, NULL);
+ ok = evas_filter_input_render(eo_obj, filter, drawctx, NULL, pad.l, pad.r, pad.t, pad.b, 0, 0, do_async);
if (!ok) ERR("Filter input render failed.");
ENFN->context_free(ENDT, drawctx);
fcow = FCOW_BEGIN(pd);
fcow->changed = EINA_FALSE;
fcow->async = do_async;
- if (!ok) fcow->invalid = EINA_TRUE;
+ fcow->prev_obscured = fcow->obscured;
+ fcow->invalid = !ok;
FCOW_END(fcow, pd);
if (ok)
_efl_canvas_filter_internal_efl_gfx_filter_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);
+ Evas_Filter_Padding pad = { 0, 0, 0, 0 };
+
+ if (pd->data->chain)
+ evas_filter_program_padding_get(pd->data->chain, &pad, NULL);
+
+ if (l) *l = pad.l;
+ if (r) *r = pad.r;
+ if (t) *t = pad.t;
+ if (b) *b = pad.b;
}
EOLIAN static void
return pd->data->output;
}
+void
+_evas_filter_obscured_region_set(Evas_Object_Protected_Data *obj,
+ const Eina_Rectangle rect)
+{
+ Evas_Filter_Data *pd;
+ Evas_Object_Filter_Data *fcow;
+
+ pd = efl_data_scope_get(obj->object, MY_CLASS);
+ if (!pd->data) return;
+
+ fcow = FCOW_BEGIN(pd);
+ if ((rect.w <= 0) || (rect.h <= 0))
+ memset(&fcow->obscured, 0, sizeof(fcow->obscured));
+ else
+ {
+ fcow->obscured.x = rect.x - obj->cur->geometry.x;
+ fcow->obscured.y = rect.y - obj->cur->geometry.y;
+ fcow->obscured.w = rect.w;
+ fcow->obscured.h = rect.h;
+ }
+ FCOW_END(fcow, pd);
+}
+
#include "canvas/efl_canvas_filter_internal.eo.c"
1.0, 0, EVAS_RENDER_BLEND, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE, EINA_FALSE
};
static const Evas_Object_Filter_Data default_filter = {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, { { NULL, 0.0 }, { NULL, 0.0 }, 0.0 }, EINA_FALSE, EINA_FALSE, EINA_TRUE
+ NULL, NULL, NULL, NULL, NULL, NULL, {}, {}, NULL, {}, EINA_FALSE, EINA_FALSE, EINA_TRUE
};
const void * const evas_object_filter_cow_default = &default_filter;
static const Evas_Object_Mask_Data default_mask = {
Evas_Object *eo_obj;
Evas_Public_Data *evas;
void *dc; /* draw context - no clip, white, no colmul... */
- struct {
- int l, r, t, b;
- } pad;
+ Evas_Filter_Padding pad;
Eina_Bool invalid;
Eina_Bool redraw;
};
if (EINA_UNLIKELY(ti->parent.format->gfx_filter != NULL))
{
- int l = 0, r = 0, t = 0, b = 0;
+ Evas_Filter_Padding pad = { 0, 0, 0, 0 };
Evas_Filter_Program *pgm;
pgm = _format_filter_program_get(c->o, ti->parent.format);
if (pgm)
{
- evas_filter_program_padding_get(pgm, &l, &r, &t, &b);
+ evas_filter_program_padding_get(pgm, &pad, NULL);
- ti->x_adjustment = r + l;
+ ti->x_adjustment = pad.r + pad.l;
ti->parent.w = tw + ti->x_adjustment; // FIXME: why add l+r here,
ti->parent.h = th; // but not t+b here?
ti->parent.adv = advw;
}
{
- Evas_Coord pad_l = 0, pad_r = 0, pad_t = 0, pad_b = 0;
+ Evas_Filter_Padding pad = { 0, 0, 0, 0 };
Evas_Filter_Program *pgm = NULL;
if (EINA_UNLIKELY(fmt->gfx_filter != NULL))
pgm = _format_filter_program_get(efl_data_scope_get(obj, MY_CLASS), fmt);
if (EINA_UNLIKELY(pgm != NULL))
- evas_filter_program_padding_get(pgm, &pad_l, &pad_r, &pad_t, &pad_b);
+ evas_filter_program_padding_get(pgm, &pad, NULL);
else
- evas_text_style_pad_get(fmt->style, &pad_l, &pad_r, &pad_t, &pad_b);
+ evas_text_style_pad_get(fmt->style, &pad.l, &pad.r, &pad.t, &pad.b);
- if (pad_l > *style_pad_l) *style_pad_l = pad_l;
- if (pad_r > *style_pad_r) *style_pad_r = pad_r;
- if (pad_t > *style_pad_t) *style_pad_t = pad_t;
- if (pad_b > *style_pad_b) *style_pad_b = pad_b;
+ if (pad.l > *style_pad_l) *style_pad_l = pad.l;
+ if (pad.r > *style_pad_r) *style_pad_r = pad.r;
+ if (pad.t > *style_pad_t) *style_pad_t = pad.t;
+ if (pad.b > *style_pad_b) *style_pad_b = pad.b;
}
if (fmt->underline2)
}
// target position
- evas_filter_program_padding_get(pgm,
- &filter->pad.l, &filter->pad.r,
- &filter->pad.t, &filter->pad.b);
+ evas_filter_program_padding_get(pgm, &filter->pad, NULL);
target = _filter_target_position_calc(obj, ti, x, y);
ENFN->context_color_set(ENDT, context, 255, 255, 255, 255);
ENFN->context_multiplier_set(ENDT, context,
Efl_Canvas_Text_Data *o = efl_data_scope_get(eo_obj, EFL_CANVAS_TEXT_CLASS);
Evas_Object_Textblock_Text_Item *ti = data;
Efl_Canvas_Text_Filter_Program *program;
- int l = 0, r = 0, t = 0, b = 0;
+ Evas_Filter_Padding pad = {};
#define STATE_COLOR(dst, src) dst.r = src.r; dst.g = src.g; dst.b = src.b; dst.a = src.a
STATE_COLOR(state->color, ti->parent.format->color.normal);
#undef STATE_COLOR
program = _filter_program_find(o, ti->parent.format->gfx_filter->name);
- if (program) evas_filter_program_padding_get(program->pgm, &l, &r, &t, &b);
+ if (program) evas_filter_program_padding_get(program->pgm, &pad, NULL);
state->w = ti->parent.w; // + l + r; (already included)
- state->h = ti->parent.h + t + b;
+ state->h = ti->parent.h + pad.t + pad.b;
state->scale = obj->cur->scale;
}
#include "evas_render2.h"
+// FIXME: Ugly!
+#define EFL_CANVAS_FILTER_INTERNAL_PROTECTED
+#include "efl_canvas_filter_internal.eo.h"
+
/* Enable this for extra verbose rendering debug logs */
//#define REND_DBG 1
#define STDOUT_DBG
}
#endif
+static inline Eina_Bool
+_rectangle_inside(Eina_Rectangle *big, Eina_Rectangle *small)
+{
+ Eina_Rectangle inter = *big;
+
+ if (!eina_rectangle_intersection(&inter, small))
+ return EINA_FALSE;
+ if ((inter.w == small->w) && (inter.h == small->h))
+ return EINA_TRUE;
+ return EINA_FALSE;
+}
+
static Eina_Bool
-_snapshot_needs_redraw(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap)
+_snapshot_needs_redraw(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap,
+ Eina_Rectangle *opaque)
{
+ Eina_Bool above = EINA_FALSE, ret = EINA_FALSE;
const int x = snap->cur->geometry.x;
const int y = snap->cur->geometry.y;
const int w = snap->cur->geometry.w;
const int h = snap->cur->geometry.h;
Evas_Object_Protected_Data *obj;
Evas_Active_Entry *ent;
+ Eina_Rectangle snap_rect = { x, y, w, h };
void *surface;
surface = _evas_object_image_surface_get(snap, EINA_FALSE);
- if (!surface) return EINA_TRUE;
+ if (!surface) ret = EINA_TRUE;
+ memset(opaque, 0, sizeof(*opaque));
EINA_INARRAY_FOREACH(&evas->active_objects, ent)
{
obj = ent->obj;
- if (obj == snap) break;
- if (!obj->is_smart && obj->changed &&
- evas_object_is_in_output_rect(obj->object, obj, x, y, w, h))
- return EINA_TRUE;
+ if (obj == snap)
+ {
+ above = EINA_TRUE;
+ continue;
+ }
+
+ if (!above)
+ {
+ if (ret) continue;
+ if (!obj->is_smart && obj->changed &&
+ evas_object_is_in_output_rect(obj->object, obj, x, y, w, h))
+ ret = EINA_TRUE;
+ }
+ else
+ {
+ if (!obj->is_smart && !obj->clip.clipees &&
+ evas_object_is_opaque(obj->object, obj))
+ {
+ Eina_Rectangle cur = {
+ obj->cur->geometry.x, obj->cur->geometry.y,
+ obj->cur->geometry.w, obj->cur->geometry.h
+ };
+
+ if (!eina_rectangles_intersect(&snap_rect, &cur))
+ continue;
+
+ if (!opaque->w || !opaque->h)
+ *opaque = cur;
+ else if (_rectangle_inside(&cur, opaque))
+ *opaque = cur;
+ else if (!_rectangle_inside(opaque, &cur))
+ {
+ *opaque = (Eina_Rectangle) { 0, 0, 0, 0 };
+ break;
+ }
+ }
+ }
}
- return EINA_FALSE;
+ return ret;
}
static Eina_Bool
eina_evlog("+render_snapshots", eo_e, 0.0, NULL);
for (j = e->snapshot_objects.count - 1; j >= 0; j--)
{
- Eina_Rectangle output, cr, ur;
+ Eina_Rectangle output, cr, ur, opaque;
obj = eina_array_data_get(&e->snapshot_objects, j);
EINA_RECTANGLE_SET(&ur, ux, uy, uw, uh);
if (eina_rectangle_intersection(&ur, &output) &&
- _snapshot_needs_redraw(evas, obj))
+ _snapshot_needs_redraw(evas, obj, &opaque))
{
void *pseudo_canvas;
unsigned int restore_offset = offset;
pseudo_canvas = _evas_object_image_surface_get(obj, EINA_TRUE);
+ // TODO: List of canvas regions that need redraw
+ // Add obscure region (make it a list?)
+ _evas_filter_obscured_region_set(obj, opaque);
+
RD(0, " SNAPSHOT %s [sfc:%p ur:%d,%d %dx%d]\n", RDNAME(obj), pseudo_canvas, ur.x, ur.y, ur.w, ur.h);
ctx = ENFN->context_new(ENDT);
clean_them |= evas_render_updates_internal_loop(eo_e, e, pseudo_canvas, ctx,
return cmd;
}
+void
+evas_filter_context_obscured_region_set(Evas_Filter_Context *ctx, Eina_Rectangle rect)
+{
+ ctx->obscured.real = rect;
+}
+
/* Final target */
Eina_Bool
evas_filter_target_set(Evas_Filter_Context *ctx, void *draw_context,
ctx->post_run.cb(ctx, ctx->post_run.data, success);
}
+static void
+_filter_obscured_region_calc(Evas_Filter_Context *ctx)
+{
+ Eina_Rectangle rect = ctx->obscured.real;
+
+ // left
+ if (rect.x > 0)
+ {
+ rect.x += ctx->pad.calculated.l;
+ rect.w -= ctx->pad.calculated.l;
+ }
+ else
+ {
+ rect.w -= (-rect.x);
+ rect.x = 0;
+ }
+ if (rect.w < 0) rect.w = 0;
+
+ // right
+ if ((rect.x + rect.w) <= ctx->w)
+ rect.w -= ctx->pad.calculated.r;
+ else
+ rect.w = ctx->w - rect.x;
+
+ // top
+ if (rect.y > 0)
+ {
+ rect.y += ctx->pad.calculated.t;
+ rect.h -= ctx->pad.calculated.t;
+ }
+ else
+ {
+ rect.h -= (-rect.y);
+ rect.y = 0;
+ }
+ if (rect.h < 0) rect.h = 0;
+
+ // bottom
+ if ((rect.y + rect.h) <= ctx->h)
+ rect.h -= ctx->pad.calculated.b;
+ else
+ rect.h = ctx->h - rect.y;
+
+ if ((rect.w <= 0) || (rect.h <= 0))
+ memset(&rect, 0, sizeof(rect));
+
+ ctx->obscured.effective = rect;
+}
+
Eina_Bool
evas_filter_run(Evas_Filter_Context *ctx)
{
if (!ctx->commands)
return EINA_TRUE;
+ _filter_obscured_region_calc(ctx);
+
if (ctx->async)
{
evas_thread_queue_flush(_filter_thread_run_cb, ctx);
Eina_Inlist /* Buffer */ *buffers;
struct {
// Note: padding can't be in the state as it's calculated after running Lua
- int l, r, t, b;
+ Evas_Filter_Padding calculated, final;
} pad;
Efl_Canvas_Filter_State state;
Eina_Inlist *data; // Evas_Filter_Data_Binding
EAPI Eina_Bool
evas_filter_program_padding_get(Evas_Filter_Program *pgm,
- int *l, int *r, int *t, int *b)
+ Evas_Filter_Padding *out_final,
+ Evas_Filter_Padding *out_calculated)
{
Evas_Filter_Instruction *instr;
int pl = 0, pr = 0, pt = 0, pb = 0;
int maxl = 0, maxr = 0, maxt = 0, maxb = 0;
+ int setl = 0, setr = 0, sett = 0, setb = 0;
+ Eina_Bool was_set = EINA_FALSE;
Buffer *buf;
EINA_SAFETY_ON_NULL_RETURN_VAL(pgm, EINA_FALSE);
- if (pgm->padding_calc || pgm->padding_set)
+ if (pgm->padding_calc)
{
- if (l) *l = pgm->pad.l;
- if (r) *r = pgm->pad.r;
- if (t) *t = pgm->pad.t;
- if (b) *b = pgm->pad.b;
+ if (out_final) *out_final = pgm->pad.final;
+ if (out_calculated) *out_calculated = pgm->pad.calculated;
return EINA_TRUE;
}
{
if (instr->type == EVAS_FILTER_MODE_PADDING_SET)
{
- instr->pad.update(pgm, instr, &maxl, &maxr, &maxt, &maxb);
- break;
+ instr->pad.update(pgm, instr, &setl, &setr, &sett, &setb);
+ was_set = EINA_TRUE;
}
else if (instr->pad.update)
{
}
}
- pgm->pad.l = maxl;
- pgm->pad.r = maxr;
- pgm->pad.t = maxt;
- pgm->pad.b = maxb;
+ pgm->pad.calculated.l = maxl;
+ pgm->pad.calculated.r = maxr;
+ pgm->pad.calculated.t = maxt;
+ pgm->pad.calculated.b = maxb;
+ if (!was_set)
+ pgm->pad.final = pgm->pad.calculated;
+ else
+ {
+ pgm->pad.final.l = setl;
+ pgm->pad.final.r = setr;
+ pgm->pad.final.t = sett;
+ pgm->pad.final.b = setb;
+ }
pgm->padding_calc = EINA_TRUE;
- if (l) *l = maxl;
- if (r) *r = maxr;
- if (t) *t = maxt;
- if (b) *b = maxb;
+ if (out_final) *out_final = pgm->pad.final;
+ if (out_calculated) *out_calculated = pgm->pad.calculated;
return EINA_TRUE;
}
_buffers_update(ctx, pgm);
// Compute and save padding info
- evas_filter_program_padding_get(pgm, &ctx->padl, &ctx->padr, &ctx->padt, &ctx->padb);
+ evas_filter_program_padding_get(pgm, &ctx->pad.final, &ctx->pad.calculated);
dc = ENFN->context_new(ENDT);
ENFN->context_color_set(ENDT, dc, 255, 255, 255, 255);
typedef Evas_Filter_Buffer * (*evas_filter_buffer_scaled_get_func)(Evas_Filter_Context *ctx, Evas_Filter_Buffer *src, unsigned w, unsigned h);
+
struct _Evas_Filter_Context
{
Evas_Public_Data *evas;
// Variables changing at each run
int w, h; // Dimensions of the input/output buffers
- int padl, padt, padr, padb; // Padding in the current input/output buffers
+
+ struct {
+ // Padding in the current input/output buffers
+ Evas_Filter_Padding calculated, final;
+ } pad;
+
+ struct {
+ // Useless region: obscured by other objects
+ Eina_Rectangle real, effective;
+ } obscured;
struct
{
typedef struct _Evas_Filter_Instruction Evas_Filter_Instruction;
typedef struct _Evas_Filter_Buffer Evas_Filter_Buffer;
typedef struct _Evas_Filter_Proxy_Binding Evas_Filter_Proxy_Binding;
+typedef struct _Evas_Filter_Padding Evas_Filter_Padding;
typedef enum _Evas_Filter_Mode Evas_Filter_Mode;
typedef enum _Evas_Filter_Blur_Type Evas_Filter_Blur_Type;
typedef enum _Evas_Filter_Channel Evas_Filter_Channel;
EVAS_FILTER_TRANSFORM_VFLIP = 1
};
+/** @internal */
+struct _Evas_Filter_Padding
+{
+ int l, r, t, b;
+};
+
#define EFL_CANVAS_FILTER_STATE_DEFAULT { {}, { 255, 255, 255, 255 }, { "default", 0.0 }, {}, 0, 0, 1.0, 0.0 }
/* Parser stuff (high level API) */
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);
-EAPI Eina_Bool evas_filter_program_padding_get(Evas_Filter_Program *pgm, int *l, int *r, int *t, int *b);
+EAPI Eina_Bool evas_filter_program_padding_get(Evas_Filter_Program *pgm, Evas_Filter_Padding *final, Evas_Filter_Padding *calc);
EAPI void evas_filter_program_source_set_all(Evas_Filter_Program *pgm, Eina_Hash *sources);
void evas_filter_program_data_set_all(Evas_Filter_Program *pgm, Eina_Inlist *data);
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);
+void evas_filter_context_obscured_region_set(Evas_Filter_Context *ctx, Eina_Rectangle rect);
int evas_filter_buffer_empty_new(Evas_Filter_Context *ctx, Eina_Bool alpha_only);
void *evas_filter_buffer_backing_steal(Evas_Filter_Context *ctx, int bufid);
Evas_Filter_Program *chain;
Eina_Hash *sources; // Evas_Filter_Proxy_Binding
Eina_Inlist *data; // Evas_Filter_Data_Binding
+ Eina_Rectangle prev_obscured, obscured;
void *output;
struct {
struct {
Eina_Bool evas_vg_loader_svg(Evas_Object *vg, const Eina_File *f, const char *key EINA_UNUSED);
void *_evas_object_image_surface_get(Evas_Object_Protected_Data *obj, Eina_Bool create);
+void _evas_filter_obscured_region_set(Evas_Object_Protected_Data *obj, const Eina_Rectangle rect);
Eina_Bool _evas_image_proxy_source_clip_get(const Eo *eo_obj);
void _evas_focus_dispatch_event(Evas_Object_Protected_Data *obj,