jpeg pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=2bed30b3984b4e73d64b99fe05d6574001173497

commit 2bed30b3984b4e73d64b99fe05d6574001173497
Author: Jean-Philippe Andre <jp.an...@samsung.com>
Date:   Fri Dec 16 11:19:17 2016 +0900

    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.
---
 src/lib/evas/canvas/evas_render.c | 99 +++++++++++++++++++++++++--------------
 1 file changed, 65 insertions(+), 34 deletions(-)

diff --git a/src/lib/evas/canvas/evas_render.c 
b/src/lib/evas/canvas/evas_render.c
index d7766f7..85acd3f 100644
--- a/src/lib/evas/canvas/evas_render.c
+++ b/src/lib/evas/canvas/evas_render.c
@@ -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);
 }
 
+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
 _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 */
+        // FIXME: Shouldn't we use a new, clean context?
         ctx = ENFN->context_dup(ENDT, context);
         ENFN->context_clip_unset(ENDT, ctx);
         //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)
                     {
                        // 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",
-                          mask, mask->name?":":"", mask->name?mask->name:"",
-                          mask->mask->redraw, mask->mask->surface);
-                       if (mask->mask->redraw || !mask->mask->surface)
-                         evas_render_mask_subrender(evas, mask, 
obj->clip.prev_mask, level + 1, do_async);
+                       Evas_Object_Protected_Data *prev_mask = 
obj->clip.prev_mask;
+                       Eina_Bool redraw = mask->mask->redraw || 
!mask->mask->surface;
+
+                       RD(level, "  has mask: [%p%s%s] redraw:%d sfc:%p 
prev_mask:%p\n",
+                          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)
                          {
@@ -2023,11 +2049,11 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object 
*eo_obj,
      }
    else // not "has map"
      {
+        ctx = ENFN->context_dup(ENDT, context);
         if (mapped)
           {
              RD(level, "  child of mapped obj\n");
 
-             ctx = ENFN->context_dup(ENDT, context);
              if (obj->is_smart)
                {
                   /* 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...
                        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\n",
-                          mask, mask->name?":":"", mask->name?mask->name:"",
-                          mask->mask->redraw, mask->mask->surface);
-                       if (mask->mask->redraw || !mask->mask->surface)
-                         evas_render_mask_subrender(evas, mask, 
obj->clip.prev_mask, level + 1, do_async);
+                       RD(level, "  has mask: [%p%s%s] redraw:%d sfc:%p 
prev_mask:%p\n",
+                          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)
                          {
@@ -2057,10 +2089,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object 
*eo_obj,
                   else if (!proxy_src_clip)
                     {
                        if (!_proxy_context_clip(evas, ctx, proxy_render_data, 
obj, off_x, off_y))
-                         {
-                            eina_evlog("-render_object", eo_obj, 0.0, NULL);
-                            return clean_them;
-                         }
+                         goto on_empty_clip;
                     }
 
 #ifdef REND_DBG
@@ -2111,10 +2140,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object 
*eo_obj,
                             else
                               {
                                  if (!_proxy_context_clip(evas, ctx, 
proxy_render_data, obj, off_x, off_y))
-                                   {
-                                      eina_evlog("-render_object", eo_obj, 
0.0, NULL);
-                                      return clean_them;
-                                   }
+                                   goto on_empty_clip;
                               }
                          }
                        else
@@ -2129,11 +2155,20 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object 
*eo_obj,
                        if (mask)
                          {
                             // 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",
-                               mask, mask->name?":":"", 
mask->name?mask->name:"",
-                               mask->mask->redraw, mask->mask->surface);
-                            if (mask->mask->redraw || !mask->mask->surface)
-                              evas_render_mask_subrender(evas, mask, 
obj->clip.prev_mask, level + 1, do_async);
+                            Evas_Object_Protected_Data *prev_mask = 
obj->clip.prev_mask;
+                            Eina_Bool redraw = mask->mask->redraw || 
!mask->mask->surface;
+
+                            RD(level, "  has mask: [%p%s%s] redraw:%d sfc:%p 
prev_mask:%p\n",
+                               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)
                               {
@@ -2155,12 +2190,9 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object 
*eo_obj,
                   obj->func->render(eo_obj, obj, obj->private_data,
                                     ENDT, ctx, surface, off_x, off_y, 
EINA_FALSE);
                }
-
-             ENFN->context_free(ENDT, ctx);
           }
         else if (!obj->is_smart)
           {
-             ctx = ENFN->context_dup(ENDT, context);
              if (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
                     {
                        if (!_proxy_context_clip(evas, ctx, proxy_render_data, 
obj, off_x, off_y))
-                         {
-                            eina_evlog("-render_object", eo_obj, 0.0, NULL);
-                            return clean_them;
-                         }
+                         goto on_empty_clip;
                     }
                }
              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,
                                ENDT, ctx, surface,
                                off_x, off_y, do_async);
-             ENFN->context_free(ENDT, ctx);
           }
         if (obj->changed_map) clean_them = EINA_TRUE;
+
+on_empty_clip:
+        ENFN->context_free(ENDT, ctx);
      }
    RD(level, "}\n");
 

-- 


Reply via email to