forked from enlightenment/efl
evas: "fix" masks of masks inside a proxy
Here's the situation: 1. A container (genlist) has a mask, M0. 2. An item I0 inside this container uses a proxy P0 as render object rather than the item directly (eg. for zooming in/out). 3. An element E0 inside this item has another mask, M1. Theory: 1. The proxy surface for P0 is rendered, and M1 is applied to the element E0. 2. The proxy P0 is rendered on the canvas, with M0 applied. Practice: 1. The element E0 is prepared for rendering, this triggers a mask subrender for M1. 2. M1 is rendered with M0 as a prev mask, then kept in cache and not redrawn (no geometry change, etc...) 3. When P0's surface is rendered, M1's surface is the result of M1+M0. 4. When P0 is drawn on screen, we can see the effect of M1+M0 as P0's geometry might be different from the item's I0. Solution: Discard prev masks and force a mask redraw when we're inside a proxy. Ideally we should detect if the prev mask belongs to the insides of the proxy or not. Problems: _mask_apply_inside_proxy() is definitely not correct, but it's not easy to test it. Anyway I believe that in order to properly implement all of this, we need to rethink evas_render and the draw context. Non-primary render surfaces (maps, proxies, masks, filters, ...) should be rendered with a clean context and clipping, masking, etc should be computed appropriately.
This commit is contained in:
parent
1c21cdfdbb
commit
2bed30b398
|
@ -1608,6 +1608,22 @@ _proxy_context_clip(Evas_Public_Data *evas, void *ctx, Evas_Proxy_Render_Data *p
|
||||||
-proxy_render_data->src_obj->cur->geometry.y);
|
-proxy_render_data->src_obj->cur->geometry.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_mask_apply_inside_proxy(Evas_Proxy_Render_Data *proxy_render_data,
|
||||||
|
Evas_Object_Protected_Data *mask)
|
||||||
|
{
|
||||||
|
// Trying to find out if the mask should be applied inside the proxy or not.
|
||||||
|
if (!proxy_render_data || proxy_render_data->source_clip) return EINA_TRUE;
|
||||||
|
if (!proxy_render_data->src_obj->cur->clipper) return EINA_FALSE;
|
||||||
|
if (!mask) return EINA_FALSE;
|
||||||
|
|
||||||
|
// FIXME: Need to implement a logic similar to _proxy_context_clip
|
||||||
|
return EINA_FALSE;
|
||||||
|
|
||||||
|
//if (mask == proxy_render_data->src_obj->cur->clipper) return EINA_TRUE;
|
||||||
|
//return _mask_apply_inside_proxy(proxy_render_data, mask->cur->clipper);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_evas_render_mapped_context_clip_set(Evas_Public_Data *evas, Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, void *ctx, Evas_Proxy_Render_Data *proxy_render_data, int off_x, int off_y)
|
_evas_render_mapped_context_clip_set(Evas_Public_Data *evas, Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, void *ctx, Evas_Proxy_Render_Data *proxy_render_data, int off_x, int off_y)
|
||||||
{
|
{
|
||||||
|
@ -1952,6 +1968,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* duplicate context and reset clip */
|
/* duplicate context and reset clip */
|
||||||
|
// FIXME: Shouldn't we use a new, clean context?
|
||||||
ctx = ENFN->context_dup(ENDT, context);
|
ctx = ENFN->context_dup(ENDT, context);
|
||||||
ENFN->context_clip_unset(ENDT, ctx);
|
ENFN->context_clip_unset(ENDT, ctx);
|
||||||
//ENFN->context_multiplier_unset(ENDT, ctx); // this probably should be here, too
|
//ENFN->context_multiplier_unset(ENDT, ctx); // this probably should be here, too
|
||||||
|
@ -1980,11 +1997,20 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
if (mask)
|
if (mask)
|
||||||
{
|
{
|
||||||
// This path can be hit when we're multiplying masks on top of each other...
|
// This path can be hit when we're multiplying masks on top of each other...
|
||||||
RD(level, " has mask: [%p%s%s] redraw:%d sfc:%p\n",
|
Evas_Object_Protected_Data *prev_mask = obj->clip.prev_mask;
|
||||||
mask, mask->name?":":"", mask->name?mask->name:"",
|
Eina_Bool redraw = mask->mask->redraw || !mask->mask->surface;
|
||||||
mask->mask->redraw, mask->mask->surface);
|
|
||||||
if (mask->mask->redraw || !mask->mask->surface)
|
RD(level, " has mask: [%p%s%s] redraw:%d sfc:%p prev_mask:%p\n",
|
||||||
evas_render_mask_subrender(evas, mask, obj->clip.prev_mask, level + 1, do_async);
|
mask->object, mask->name?":":"", mask->name?mask->name:"",
|
||||||
|
mask->mask->redraw, mask->mask->surface, prev_mask);
|
||||||
|
if (prev_mask && !_mask_apply_inside_proxy(proxy_render_data, prev_mask))
|
||||||
|
{
|
||||||
|
RD(level, " discard prev mask and redraw (guessed outside proxy)\n");
|
||||||
|
prev_mask = NULL;
|
||||||
|
redraw = EINA_TRUE;
|
||||||
|
}
|
||||||
|
if (redraw)
|
||||||
|
evas_render_mask_subrender(evas, mask, prev_mask, level + 1, do_async);
|
||||||
|
|
||||||
if (mask->mask->surface)
|
if (mask->mask->surface)
|
||||||
{
|
{
|
||||||
|
@ -2023,11 +2049,11 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
}
|
}
|
||||||
else // not "has map"
|
else // not "has map"
|
||||||
{
|
{
|
||||||
|
ctx = ENFN->context_dup(ENDT, context);
|
||||||
if (mapped)
|
if (mapped)
|
||||||
{
|
{
|
||||||
RD(level, " child of mapped obj\n");
|
RD(level, " child of mapped obj\n");
|
||||||
|
|
||||||
ctx = ENFN->context_dup(ENDT, context);
|
|
||||||
if (obj->is_smart)
|
if (obj->is_smart)
|
||||||
{
|
{
|
||||||
/* Clipper masks */
|
/* Clipper masks */
|
||||||
|
@ -2036,14 +2062,20 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
{
|
{
|
||||||
// This path can be hit when we're multiplying masks on top of each other...
|
// This path can be hit when we're multiplying masks on top of each other...
|
||||||
Evas_Object_Protected_Data *mask = obj->cur->clipper;
|
Evas_Object_Protected_Data *mask = obj->cur->clipper;
|
||||||
|
Evas_Object_Protected_Data *prev_mask = obj->clip.prev_mask;
|
||||||
|
Eina_Bool redraw = mask->mask->redraw || !mask->mask->surface;
|
||||||
|
|
||||||
evas_object_clip_recalc(obj);
|
RD(level, " has mask: [%p%s%s] redraw:%d sfc:%p prev_mask:%p\n",
|
||||||
|
mask->object, mask->name?":":"", mask->name?mask->name:"",
|
||||||
RD(level, " has mask: [%p%s%s] redraw:%d sfc:%p\n",
|
mask->mask->redraw, mask->mask->surface, prev_mask);
|
||||||
mask, mask->name?":":"", mask->name?mask->name:"",
|
if (prev_mask && !_mask_apply_inside_proxy(proxy_render_data, prev_mask))
|
||||||
mask->mask->redraw, mask->mask->surface);
|
{
|
||||||
if (mask->mask->redraw || !mask->mask->surface)
|
RD(level, " discard prev mask and redraw (guessed outside proxy)\n");
|
||||||
evas_render_mask_subrender(evas, mask, obj->clip.prev_mask, level + 1, do_async);
|
prev_mask = NULL;
|
||||||
|
redraw = EINA_TRUE;
|
||||||
|
}
|
||||||
|
if (redraw)
|
||||||
|
evas_render_mask_subrender(evas, mask, prev_mask, level + 1, do_async);
|
||||||
|
|
||||||
if (mask->mask->surface)
|
if (mask->mask->surface)
|
||||||
{
|
{
|
||||||
|
@ -2057,10 +2089,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
else if (!proxy_src_clip)
|
else if (!proxy_src_clip)
|
||||||
{
|
{
|
||||||
if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
|
if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
|
||||||
{
|
goto on_empty_clip;
|
||||||
eina_evlog("-render_object", eo_obj, 0.0, NULL);
|
|
||||||
return clean_them;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef REND_DBG
|
#ifdef REND_DBG
|
||||||
|
@ -2111,10 +2140,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
|
if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
|
||||||
{
|
goto on_empty_clip;
|
||||||
eina_evlog("-render_object", eo_obj, 0.0, NULL);
|
|
||||||
return clean_them;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2129,11 +2155,20 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
if (mask)
|
if (mask)
|
||||||
{
|
{
|
||||||
// This path can be hit when we're multiplying masks on top of each other...
|
// This path can be hit when we're multiplying masks on top of each other...
|
||||||
RD(level, " has mask: [%p%s%s] redraw:%d sfc:%p\n",
|
Evas_Object_Protected_Data *prev_mask = obj->clip.prev_mask;
|
||||||
mask, mask->name?":":"", mask->name?mask->name:"",
|
Eina_Bool redraw = mask->mask->redraw || !mask->mask->surface;
|
||||||
mask->mask->redraw, mask->mask->surface);
|
|
||||||
if (mask->mask->redraw || !mask->mask->surface)
|
RD(level, " has mask: [%p%s%s] redraw:%d sfc:%p prev_mask:%p\n",
|
||||||
evas_render_mask_subrender(evas, mask, obj->clip.prev_mask, level + 1, do_async);
|
mask->object, mask->name?":":"", mask->name?mask->name:"",
|
||||||
|
mask->mask->redraw, mask->mask->surface, prev_mask);
|
||||||
|
if (prev_mask && !_mask_apply_inside_proxy(proxy_render_data, prev_mask))
|
||||||
|
{
|
||||||
|
RD(level, " discard prev mask and redraw (guessed outside proxy)\n");
|
||||||
|
prev_mask = NULL;
|
||||||
|
redraw = EINA_TRUE;
|
||||||
|
}
|
||||||
|
if (redraw)
|
||||||
|
evas_render_mask_subrender(evas, mask, prev_mask, level + 1, do_async);
|
||||||
|
|
||||||
if (mask->mask->surface)
|
if (mask->mask->surface)
|
||||||
{
|
{
|
||||||
|
@ -2155,12 +2190,9 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
obj->func->render(eo_obj, obj, obj->private_data,
|
obj->func->render(eo_obj, obj, obj->private_data,
|
||||||
ENDT, ctx, surface, off_x, off_y, EINA_FALSE);
|
ENDT, ctx, surface, off_x, off_y, EINA_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ENFN->context_free(ENDT, ctx);
|
|
||||||
}
|
}
|
||||||
else if (!obj->is_smart)
|
else if (!obj->is_smart)
|
||||||
{
|
{
|
||||||
ctx = ENFN->context_dup(ENDT, context);
|
|
||||||
if (obj->cur->clipper)
|
if (obj->cur->clipper)
|
||||||
{
|
{
|
||||||
Evas_Object_Protected_Data *clipper = obj->cur->clipper;
|
Evas_Object_Protected_Data *clipper = obj->cur->clipper;
|
||||||
|
@ -2192,10 +2224,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
|
if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
|
||||||
{
|
goto on_empty_clip;
|
||||||
eina_evlog("-render_object", eo_obj, 0.0, NULL);
|
|
||||||
return clean_them;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!_is_obj_in_framespace(obj, evas))
|
else if (!_is_obj_in_framespace(obj, evas))
|
||||||
|
@ -2213,9 +2242,11 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
obj->func->render(eo_obj, obj, obj->private_data,
|
obj->func->render(eo_obj, obj, obj->private_data,
|
||||||
ENDT, ctx, surface,
|
ENDT, ctx, surface,
|
||||||
off_x, off_y, do_async);
|
off_x, off_y, do_async);
|
||||||
ENFN->context_free(ENDT, ctx);
|
|
||||||
}
|
}
|
||||||
if (obj->changed_map) clean_them = EINA_TRUE;
|
if (obj->changed_map) clean_them = EINA_TRUE;
|
||||||
|
|
||||||
|
on_empty_clip:
|
||||||
|
ENFN->context_free(ENDT, ctx);
|
||||||
}
|
}
|
||||||
RD(level, "}\n");
|
RD(level, "}\n");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue