1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 #include <Ecore.h>
4 #include <math.h>
5 #include <assert.h>
6 
7 #ifdef EVAS_RENDER_DEBUG_TIMING
8 #include <sys/time.h>
9 #endif
10 
11 // FIXME: Ugly!
12 #define EFL_CANVAS_FILTER_INTERNAL_PROTECTED
13 #include "efl_canvas_filter_internal.eo.h"
14 
15 /* Enable this for extra verbose rendering debug logs */
16 //#define REND_DBG 1
17 #define STDOUT_DBG
18 
19 #ifdef REND_DBG
20 static FILE *dbf = NULL;
21 static int __RD_level = 0;
22 static int __RD_enable = REND_DBG;
23 
24 static inline Eina_Slstr *
_efl_object_name(const Evas_Object_Protected_Data * obj)25 _efl_object_name(const Evas_Object_Protected_Data *obj)
26 {
27    const Eo *eo_obj;
28    const char *name;
29    const char *klass;
30 
31    if (!obj) return "(nil)";
32    eo_obj = obj->object;
33    name = obj->name ?: efl_name_get(eo_obj);
34    klass = obj->type; //efl_class_name_get(eo_obj);
35    if (name)
36      return eina_slstr_printf("[%p@%p: %s '%s']", eo_obj, obj, klass, name);
37    else
38      return eina_slstr_printf("[%p@%p: %s]", eo_obj, obj, klass);
39 }
40 
41 #define RDNAME(_obj) _efl_object_name(_obj)
42 
43 static void
rend_dbg(const char * txt)44 rend_dbg(const char *txt)
45 {
46    if (!dbf)
47      {
48 #ifdef STDOUT_DBG
49         dbf = stdout;
50 #else
51         dbf = fopen("EVAS-RENDER-DEBUG.log", "wb");
52 #endif
53         if (!dbf) return;
54      }
55    fputs(txt, dbf);
56    fflush(dbf);
57 }
58 #define RD(xxxx, args...) \
59    do { if (__RD_enable) { \
60       char __tmpbuf[4096]; int __tmpi; \
61       __RD_level = xxxx; \
62       if (xxxx) { \
63         for (__tmpi = 0; __tmpi < xxxx * 2; __tmpi++) \
64           __tmpbuf[__tmpi] = ' '; \
65         __tmpbuf[__tmpi] = 0; \
66         rend_dbg(__tmpbuf); \
67       } \
68       snprintf(__tmpbuf, sizeof(__tmpbuf), ##args); \
69       rend_dbg(__tmpbuf); \
70    } } while (0)
71 #define IFRD(ifcase, xxxx, args...) \
72    if (__RD_enable && (ifcase)) { \
73       char __tmpbuf[4096]; int __tmpi; \
74       __RD_level = xxxx; \
75       if (xxxx) { \
76         for (__tmpi = 0; __tmpi < xxxx * 2; __tmpi++) \
77           __tmpbuf[__tmpi] = ' '; \
78         __tmpbuf[__tmpi] = 0; \
79         rend_dbg(__tmpbuf); \
80       } \
81       snprintf(__tmpbuf, sizeof(__tmpbuf), ##args); \
82       rend_dbg(__tmpbuf); \
83    }
84 #else
85 #define RD(xxx, args...)
86 #define IFRD(ifcase, xxx, args...)
87 #define RDNAME(xxx) ""
88 #endif
89 
90 #define OBJ_ARRAY_PUSH(array, obj) eina_array_push(array, obj)
91 #define OBJS_ARRAY_CLEAN(array) eina_array_clean(array)
92 #define OBJS_ARRAY_FLUSH(array) eina_array_flush(array)
93 
94 /* save typing */
95 #undef ENFN
96 #undef ENC
97 #define ENFN evas->engine.func
98 #define ENC _evas_engine_context(evas)
99 
100 typedef struct _Render_Updates Render_Updates;
101 typedef struct _Cutout_Margin  Cutout_Margin;
102 
103 struct _Render_Updates
104 {
105    void *surface;
106    Eina_Rectangle *area;
107 };
108 
109 struct _Cutout_Margin
110 {
111    int l, r, t, b;
112 };
113 
114 static void
115 evas_render_pipe_wakeup(void *data);
116 static Eina_Bool
117 evas_render_updates_internal(Evas *eo_e, unsigned char make_updates, unsigned char do_draw, Eina_Bool do_async);
118 static void
119 evas_render_mask_subrender(Evas_Public_Data *evas,
120                            void *output,
121                            Evas_Object_Protected_Data *mask,
122                            Evas_Object_Protected_Data *prev_mask,
123                            int level, Eina_Bool do_async);
124 
125 static Eina_List *_rendering_evases = NULL;
126 
127 #ifdef EVAS_RENDER_DEBUG_TIMING
128 static double
_time_get()129 _time_get()
130 {
131    struct timeval tv;
132 
133    gettimeofday(&tv, NULL);
134 
135    return (tv.tv_sec + tv.tv_usec / 1000000.0) * 1000.0;
136 }
137 
138 struct accumulator {
139    double total, min, max, draw_start_time;
140    int samples;
141    const char *what;
142 };
143 
144 static struct accumulator async_accumulator = {
145    .total = 0,
146    .min = 1000000,
147    .max = 0,
148    .samples = 0,
149    .what = "async render"
150 };
151 static struct accumulator sync_accumulator = {
152    .total = 0,
153    .min = 1000000,
154    .max = 0,
155    .samples = 0,
156    .what = "sync render"
157 };
158 
159 static void
_accumulate_time(double before,Eina_Bool async)160 _accumulate_time(double before, Eina_Bool async)
161 {
162    static Eina_Bool async_start = EINA_TRUE;
163    static double cache_before;
164    struct accumulator *acc = &sync_accumulator;
165    if (async)
166      {
167         acc = &async_accumulator;
168         if (async_start)
169           {
170              async_start = EINA_FALSE;
171              cache_before = before;
172              return;
173           }
174         else
175           {
176              async_start = EINA_TRUE;
177              before = cache_before;
178           }
179      }
180 
181    double diff = _time_get() - before;
182 
183    acc->total += diff;
184    if (diff > acc->max) acc->max = diff;
185    if (diff < acc->min) acc->min = diff;
186 
187    acc->samples++;
188    if (acc->samples % 100 == 0)
189      {
190         fprintf(stderr, "*** %s: avg %fms min %fms max %fms\n",
191                 acc->what, acc->total / 100.0, acc->min, acc->max);
192         acc->total = 0.0;
193         acc->max = 0.0;
194         acc->min = 1000000;
195      }
196 }
197 #endif
198 
199 static int _render_busy = 0;
200 
201 static inline Eina_Bool
_is_obj_in_framespace(Evas_Object_Protected_Data * obj,Evas_Public_Data * evas EINA_UNUSED)202 _is_obj_in_framespace(Evas_Object_Protected_Data *obj, Evas_Public_Data *evas EINA_UNUSED)
203 {
204    return obj->is_frame;
205 }
206 
207 static inline void
_evas_render_framespace_context_clip_clip(Evas_Public_Data * evas,void * ctx,int ox,int oy)208 _evas_render_framespace_context_clip_clip(Evas_Public_Data *evas, void *ctx,
209                                           int ox, int oy)
210 {
211    int fx, fy, fw, fh;
212 
213    fx = evas->framespace.x;
214    fy = evas->framespace.y;
215    fw = evas->viewport.w - evas->framespace.w;
216    fh = evas->viewport.h - evas->framespace.h;
217 
218    ENFN->context_clip_clip(ENC, ctx, fx + ox, fy + oy, fw, fh);
219 }
220 
221 static void
_evas_render_cleanup(void)222 _evas_render_cleanup(void)
223 {
224    if (_render_busy != 0) return;
225    evas_common_rgba_pending_unloads_cleanup();
226 }
227 
228 static void
_evas_render_busy_begin(void)229 _evas_render_busy_begin(void)
230 {
231    _render_busy++;
232 }
233 
234 static void
_evas_render_busy_end(void)235 _evas_render_busy_end(void)
236 {
237    _render_busy--;
238    _evas_render_cleanup();
239 }
240 
241 EOLIAN void
_evas_canvas_damage_rectangle_add(Eo * eo_e EINA_UNUSED,Evas_Public_Data * e,int x,int y,int w,int h)242 _evas_canvas_damage_rectangle_add(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e, int x, int y, int w, int h)
243 {
244    Eina_Rectangle *r;
245 
246    evas_canvas_async_block(e);
247    NEW_RECT(r, x, y, w, h);
248    if (!r) return;
249    e->damages = eina_list_append(e->damages, r);
250    e->changed = EINA_TRUE;
251 }
252 
253 EOLIAN void
_evas_canvas_obscured_rectangle_add(Eo * eo_e EINA_UNUSED,Evas_Public_Data * e,int x,int y,int w,int h)254 _evas_canvas_obscured_rectangle_add(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e, int x, int y, int w, int h)
255 {
256    Eina_Rectangle *r;
257 
258    evas_canvas_async_block(e);
259    NEW_RECT(r, x, y, w, h);
260    if (!r) return;
261    e->obscures = eina_list_append(e->obscures, r);
262 }
263 
264 EOLIAN void
_evas_canvas_obscured_clear(Eo * eo_e EINA_UNUSED,Evas_Public_Data * e)265 _evas_canvas_obscured_clear(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
266 {
267    Eina_Rectangle *r;
268 
269    evas_canvas_async_block(e);
270    EINA_LIST_FREE(e->obscures, r)
271      {
272         eina_rectangle_free(r);
273      }
274 }
275 
276 static Eina_Bool
_evas_clip_changes_free(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)277 _evas_clip_changes_free(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
278 {
279    eina_rectangle_free(data);
280    return EINA_TRUE;
281 }
282 
283 static inline Eina_Rectangle
_evas_render_smallest_static_clipped_geometry_get(const Evas_Object_Protected_State * state)284 _evas_render_smallest_static_clipped_geometry_get(const Evas_Object_Protected_State *state)
285 {
286    int cx, cy, cw, ch;
287 
288    cx = state->geometry.x;
289    cy = state->geometry.y;
290    cw = state->geometry.w;
291    ch = state->geometry.h;
292    while (state->clipper && state->has_fixed_size)
293      {
294         /* walk up the clipper tree as long as the clippers are static */
295         RECTS_CLIP_TO_RECT(cx, cy, cw, ch,
296                            state->clipper->cur->geometry.x,
297                            state->clipper->cur->geometry.y,
298                            state->clipper->cur->geometry.w,
299                            state->clipper->cur->geometry.h);
300         if (!state->clipper) break;
301         state = state->clipper->cur;
302      }
303    return (Eina_Rectangle){cx, cy, cw, ch};
304 }
305 
306 static Eina_Bool
_evas_render_had_map(Evas_Object_Protected_Data * obj)307 _evas_render_had_map(Evas_Object_Protected_Data *obj)
308 {
309    return ((obj->map->prev.map) && (obj->map->prev.usemap));
310 }
311 
312 static Eina_Bool
_evas_render_is_relevant(Evas_Object_Protected_Data * obj)313 _evas_render_is_relevant(Evas_Object_Protected_Data *obj)
314 {
315    return ((evas_object_is_visible(obj) && (!obj->cur->have_clipees)) ||
316            (evas_object_was_visible(obj) && (!obj->prev->have_clipees)));
317 }
318 
319 static Eina_Bool
_evas_render_can_render(Evas_Object_Protected_Data * obj)320 _evas_render_can_render(Evas_Object_Protected_Data *obj)
321 {
322    return (evas_object_is_visible(obj) && (!obj->cur->have_clipees) &&
323            !obj->no_render);
324 }
325 
326 static void
_evas_render_prev_cur_clip_cache_add(Evas_Public_Data * evas,Evas_Object_Protected_Data * obj)327 _evas_render_prev_cur_clip_cache_add(Evas_Public_Data *evas, Evas_Object_Protected_Data *obj)
328 {
329    // FIXME: Iterate over each output
330    ENFN->output_redraws_rect_add(ENC,
331                                  obj->prev->cache.clip.x + evas->framespace.x,
332                                  obj->prev->cache.clip.y + evas->framespace.y,
333                                  obj->prev->cache.clip.w,
334                                  obj->prev->cache.clip.h);
335    ENFN->output_redraws_rect_add(ENC,
336                                  obj->cur->cache.clip.x + evas->framespace.x,
337                                  obj->cur->cache.clip.y + evas->framespace.y,
338                                  obj->cur->cache.clip.w,
339                                  obj->cur->cache.clip.h);
340 }
341 
342 static void
_evas_render_cur_clip_cache_del(Evas_Public_Data * e,Evas_Object_Protected_Data * obj)343 _evas_render_cur_clip_cache_del(Evas_Public_Data *e, Evas_Object_Protected_Data *obj)
344 {
345    Evas_Coord x, y, w, h;
346 
347    x = obj->cur->cache.clip.x;
348    y = obj->cur->cache.clip.y;
349    w = obj->cur->cache.clip.w;
350    h = obj->cur->cache.clip.h;
351    if (obj->cur->clipper)
352      {
353         RECTS_CLIP_TO_RECT(x, y, w, h,
354                            obj->cur->clipper->cur->cache.clip.x,
355                            obj->cur->clipper->cur->cache.clip.y,
356                            obj->cur->clipper->cur->cache.clip.w,
357                            obj->cur->clipper->cur->cache.clip.h);
358      }
359    evas_render_update_del(e, x + e->framespace.x, y + e->framespace.y, w, h);
360 }
361 
362 /* sets the redraw flag for all the proxies depending on this obj as a source */
363 static void
_evas_proxy_redraw_set(Evas_Public_Data * e,Evas_Object_Protected_Data * obj,Eina_Bool render)364 _evas_proxy_redraw_set(Evas_Public_Data *e, Evas_Object_Protected_Data *obj,
365                        Eina_Bool render)
366 {
367    Evas_Object *eo_proxy;
368    Evas_Object_Protected_Data *proxy;
369    Eina_List *l;
370 
371    EINA_LIST_FOREACH(obj->proxy->proxies, l, eo_proxy)
372      {
373         proxy = efl_data_scope_get(eo_proxy, EFL_CANVAS_OBJECT_CLASS);
374 
375         /* Flag need redraw on proxy too */
376         EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, proxy->proxy,
377                              Evas_Object_Proxy_Data, proxy_write)
378            proxy_write->redraw = EINA_TRUE;
379         EINA_COW_WRITE_END(evas_object_proxy_cow, proxy->proxy, proxy_write);
380 
381         if (render)
382           {
383              /* Not good... but make it sure if the proxies have missed at update
384                 if its sources are remained changed as pending objects in the prev frame. */
385              evas_object_change(eo_proxy, proxy);
386              proxy->func->render_pre(eo_proxy, proxy, proxy->private_data);
387              _evas_render_prev_cur_clip_cache_add(e, proxy);
388           }
389 
390         //Update the proxies recursively.
391         _evas_proxy_redraw_set(e, proxy, render);
392      }
393 }
394 
395 /* sets the mask redraw flag for all the objects clipped by this mask */
396 static void
_evas_mask_redraw_set(Evas_Public_Data * e EINA_UNUSED,Evas_Object_Protected_Data * obj)397 _evas_mask_redraw_set(Evas_Public_Data *e EINA_UNUSED,
398                       Evas_Object_Protected_Data *obj)
399 {
400    Evas_Object_Protected_Data *clippee;
401    Eina_List *l;
402 
403    if (!(obj->mask->redraw))
404      {
405         EINA_COW_WRITE_BEGIN(evas_object_mask_cow, obj->mask,
406                              Evas_Object_Mask_Data, mask)
407           mask->redraw = EINA_TRUE;
408         EINA_COW_WRITE_END(evas_object_mask_cow, obj->mask, mask);
409      }
410 
411    if (!obj->cur->cache.clip.dirty)
412      {
413         EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
414           state_write->cache.clip.dirty = EINA_TRUE;
415         EINA_COW_STATE_WRITE_END(obj, state_write, cur);
416      }
417 
418    EINA_LIST_FOREACH(obj->clip.clipees, l, clippee)
419      {
420         evas_object_clip_recalc(clippee);
421      }
422 }
423 
424 static inline Eina_Bool
_evas_render_object_changed_get(Evas_Object_Protected_Data * obj)425 _evas_render_object_changed_get(Evas_Object_Protected_Data *obj)
426 {
427    if (obj->smart.smart)
428      return evas_object_smart_changed_get(obj);
429    else
430      return obj->changed;
431 }
432 
433 static inline Eina_Bool
_evas_render_object_is_mask(Evas_Object_Protected_Data * obj)434 _evas_render_object_is_mask(Evas_Object_Protected_Data *obj)
435 {
436    if (!obj) return EINA_FALSE;
437    if (obj->mask->is_mask && obj->clip.clipees)
438      return EINA_TRUE;
439    return EINA_FALSE;
440 }
441 
442 static void
_evas_render_phase1_direct(Evas_Public_Data * e,Eina_Inarray * active_objects,Eina_Array * restack_objects EINA_UNUSED,Eina_Array * delete_objects EINA_UNUSED,Eina_Array * render_objects)443 _evas_render_phase1_direct(Evas_Public_Data *e,
444                            Eina_Inarray *active_objects,
445                            Eina_Array *restack_objects EINA_UNUSED,
446                            Eina_Array *delete_objects EINA_UNUSED,
447                            Eina_Array *render_objects)
448 {
449    unsigned int i;
450    Evas_Object *eo_obj;
451 
452    RD(0, "  [--- PHASE 1 DIRECT\n");
453    for (i = 0; i < active_objects->len; i++)
454      {
455         Evas_Active_Entry *ent = eina_inarray_nth(active_objects, i);
456         Evas_Object_Protected_Data *obj = ent->obj;
457 
458         EINA_PREFETCH(&(obj->cur->clipper));
459         if (obj->changed) evas_object_clip_recalc(obj);
460 
461         if (obj->proxy->proxies)
462           {
463              /* is proxy source */
464              if (_evas_render_object_changed_get(obj))
465                _evas_proxy_redraw_set(e, obj, EINA_FALSE);
466           }
467         if (_evas_render_object_is_mask(obj))
468           {
469              /* is image clipper */
470              if (_evas_render_object_changed_get(obj))
471                _evas_mask_redraw_set(e, obj);
472           }
473      }
474    for (i = 0; i < render_objects->count; i++)
475      {
476         Evas_Object_Protected_Data *obj =
477           eina_array_data_get(render_objects, i);
478         eo_obj = obj->object;
479 
480         RD(0, "    OBJ %s changed %i\n", RDNAME(obj), obj->changed);
481 
482         if (obj->changed)
483           {
484              evas_object_clip_recalc(obj);
485              obj->func->render_pre(eo_obj, obj, obj->private_data);
486 
487              if (obj->proxy->redraw || obj->mask->redraw)
488                _evas_render_prev_cur_clip_cache_add(e, obj);
489 
490              if (!obj->smart.smart || evas_object_smart_changed_get(obj))
491                {
492                   /* proxy sources */
493                   if (obj->proxy->proxies)
494                     {
495                        EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy,
496                                             Evas_Object_Proxy_Data, proxy_write)
497                           proxy_write->redraw = EINA_TRUE;
498                        EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy,
499                                           proxy_write);
500                        _evas_proxy_redraw_set(e, obj, EINA_TRUE);
501                     }
502 
503                   /* clipper objects (image masks) */
504                   if (_evas_render_object_is_mask(obj))
505                     _evas_mask_redraw_set(e, obj);
506                }
507 
508              _evas_object_gfx_mapping_update(obj);
509 
510              Eina_Bool has_map = _evas_render_has_map(obj);
511 
512              RD(0, "      pre-render-done smart:%p|%p  [%p, %i] | [%p, %i] has_map:%i had_map:%i\n",
513                 obj->smart.smart,
514                 obj->is_smart ? evas_object_smart_members_get_direct(eo_obj) : NULL,
515                 obj->map->cur.map, obj->map->cur.usemap,
516                 obj->map->prev.map, obj->map->prev.usemap,
517                 has_map, _evas_render_had_map(obj));
518 
519              if ((obj->is_smart) &&
520                  ((has_map && !_evas_render_can_map(obj)) ||
521                   obj->changed_src_visible))
522                {
523                   RD(0, "      has map + smart\n");
524                   _evas_render_prev_cur_clip_cache_add(e, obj);
525                }
526              /* This is the only case that map was just turned off,
527                 Need to redraw the previous obj region as well. */
528              else if (!has_map && obj->changed_map &&
529                       _evas_render_object_changed_get(obj))
530                {
531                   _evas_render_prev_cur_clip_cache_add(e, obj);
532                   obj->changed_map = EINA_FALSE;
533                }
534           }
535         else
536           {
537              if (obj->is_smart)
538                {
539                }
540              else if (evas_object_is_visible(obj) &&
541                       ((obj->rect_del) ||
542                       (evas_object_is_opaque(obj))) &&
543                       (!evas_object_is_source_invisible(eo_obj, obj)))
544                {
545                   RD(0, "    rect del\n");
546                   _evas_render_cur_clip_cache_del(e, obj);
547                }
548           }
549      }
550    RD(0, "  ---]\n");
551 }
552 
553 static void
_evas_render_object_map_change_update(Evas_Public_Data * evas,Evas_Object_Protected_Data * obj,Eina_Bool map,Eina_Bool hmap,int * redraw_all)554 _evas_render_object_map_change_update(Evas_Public_Data *evas,
555                                       Evas_Object_Protected_Data *obj,
556                                       Eina_Bool map, Eina_Bool hmap,
557                                       int *redraw_all)
558 {
559    // FIXME: handle multiple output
560    Evas_Coord x = 0, y = 0, w = 0, h = 0;
561    const int fx = evas->framespace.x;
562    const int fy = evas->framespace.y;
563 
564    if (map == hmap) return;
565 
566    if (!obj->map)
567      {
568         *redraw_all = 1;
569         return;
570      }
571 
572    if (map)
573      {
574         x = obj->prev->cache.clip.x;
575         y = obj->prev->cache.clip.y;
576         w = obj->prev->cache.clip.w;
577         h = obj->prev->cache.clip.h;
578         if (obj->prev->clipper)
579           {
580              RECTS_CLIP_TO_RECT(x, y, w, h,
581                                 obj->prev->clipper->prev->cache.clip.x,
582                                 obj->prev->clipper->prev->cache.clip.y,
583                                 obj->prev->clipper->prev->cache.clip.w,
584                                 obj->prev->clipper->prev->cache.clip.h);
585           }
586         ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
587         x = obj->map->cur.map->normal_geometry.x;
588         y = obj->map->cur.map->normal_geometry.y;
589         w = obj->map->cur.map->normal_geometry.w;
590         h = obj->map->cur.map->normal_geometry.h;
591         if (obj->cur->clipper)
592           {
593              RECTS_CLIP_TO_RECT(x, y, w, h,
594                                 obj->cur->clipper->cur->cache.clip.x,
595                                 obj->cur->clipper->cur->cache.clip.y,
596                                 obj->cur->clipper->cur->cache.clip.w,
597                                 obj->cur->clipper->cur->cache.clip.h);
598           }
599         ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
600      }
601    else if (hmap)
602      {
603         x = obj->map->prev.map->normal_geometry.x;
604         y = obj->map->prev.map->normal_geometry.y;
605         w = obj->map->prev.map->normal_geometry.w;
606         h = obj->map->prev.map->normal_geometry.h;
607         if (obj->prev->clipper)
608           {
609              RECTS_CLIP_TO_RECT(x, y, w, h,
610                                 obj->prev->clipper->prev->cache.clip.x,
611                                 obj->prev->clipper->prev->cache.clip.y,
612                                 obj->prev->clipper->prev->cache.clip.w,
613                                 obj->prev->clipper->prev->cache.clip.h);
614           }
615         ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
616         x = obj->cur->cache.clip.x;
617         y = obj->cur->cache.clip.y;
618         w = obj->cur->cache.clip.w;
619         h = obj->cur->cache.clip.h;
620         if (obj->cur->clipper)
621           {
622              RECTS_CLIP_TO_RECT(x, y, w, h,
623                                 obj->cur->clipper->cur->cache.clip.x,
624                                 obj->cur->clipper->cur->cache.clip.y,
625                                 obj->cur->clipper->cur->cache.clip.w,
626                                 obj->cur->clipper->cur->cache.clip.h);
627           }
628         ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
629      }
630 }
631 
632 
633 
634 
635 ////////////////////////////////////////////////////////////////////////////
636 //
637 // object render update phase 1 code -> figure out updates and built object
638 // render/active/delete etc. lists/arrays.
639 //
640 
641 typedef struct
642 {
643    Eina_Inarray *active_objects;
644    Eina_Array   *render_objects;
645    Eina_Array   *snapshot_objects;
646 
647    Eina_Inarray *update_del;
648 } Render_Cache;
649 
650 void
evas_render_update_del(Evas_Public_Data * evas,int x,int y,int w,int h)651 evas_render_update_del(Evas_Public_Data *evas, int x, int y, int w, int h)
652 {
653    // FIXME: handle multiple output
654    if (EINA_LIKELY((evas->update_del_redirect_array == NULL)))
655      {
656         ENFN->output_redraws_rect_del(ENC, x, y, w, h);
657      }
658    else
659      {
660         Eina_Rectangle r;
661 
662         r.x = x; r.y = y; r.w = w; r.h = h;
663         eina_inarray_push(evas->update_del_redirect_array, &r);
664      }
665 }
666 
667 void
evas_render_object_render_cache_free(Evas_Object * eo_obj EINA_UNUSED,void * data)668 evas_render_object_render_cache_free(Evas_Object *eo_obj EINA_UNUSED,
669                                      void *data)
670 {
671    Render_Cache *rc;
672 
673    if (!data) return;
674    rc = data;
675    eina_inarray_free(rc->active_objects);
676    eina_array_free(rc->render_objects);
677    eina_array_free(rc->snapshot_objects);
678    eina_inarray_free(rc->update_del);
679    free(rc);
680 }
681 
682 typedef struct
683 {
684    Evas_Public_Data *e;
685    Eina_Inarray     *active_objects;
686    Eina_Array       *render_objects;
687    Eina_Array       *snapshot_objects;
688    Eina_Array       *restack_objects;
689    Eina_Array       *delete_objects;
690    int               redraw_all;
691 } Phase1_Context;
692 
693 #define RENDCACHE 1
694 
695 #ifdef RENDCACHE
696 static Render_Cache *
_evas_render_phase1_object_render_cache_new(void)697 _evas_render_phase1_object_render_cache_new(void)
698 {
699    Render_Cache *rc;
700 
701    rc = malloc(sizeof(Render_Cache));
702    rc->active_objects   = eina_inarray_new(sizeof(Evas_Active_Entry), 32);
703    rc->render_objects   = eina_array_new(32);
704    rc->snapshot_objects = eina_array_new(32);
705    rc->update_del       = eina_inarray_new(sizeof(Eina_Rectangle), 16);
706    return rc;
707 }
708 
709 static void
_evas_render_phase1_object_ctx_render_cache_fill(Phase1_Context * ctx,Render_Cache * rc)710 _evas_render_phase1_object_ctx_render_cache_fill(Phase1_Context *ctx,
711                                                  Render_Cache *rc)
712 {
713    ctx->active_objects   = rc->active_objects;
714    ctx->render_objects   = rc->render_objects;
715    ctx->snapshot_objects = rc->snapshot_objects;
716 }
717 
718 static void
_evas_render_phase1_object_ctx_render_cache_append(Phase1_Context * ctx,Render_Cache * rc)719 _evas_render_phase1_object_ctx_render_cache_append(Phase1_Context *ctx,
720                                                    Render_Cache *rc)
721 {
722    void *obj;
723    unsigned int i, c;
724    Eina_Rectangle *r;
725    Evas_Active_Entry *ent;
726 
727 #define ARR_APPEND(x) \
728    if (rc->x != ctx->x) { \
729       do { \
730          c = eina_array_count_get(rc->x); \
731          for (i = 0; i < c; i++) { \
732             obj = eina_array_data_get(rc->x, i); \
733             eina_array_push(ctx->x, obj); \
734          } \
735       } while (0); \
736    }
737    ARR_APPEND(render_objects);
738    ARR_APPEND(snapshot_objects);
739 
740    c = eina_inarray_count(rc->active_objects);
741    for (i = 0; i < c; i++)
742      {
743         ent = eina_inarray_nth(rc->active_objects, i);
744         eina_inarray_push(ctx->active_objects, ent);
745      }
746 
747    c = eina_inarray_count(rc->update_del);
748    for (i = 0; i < c; i++)
749      {
750         r = eina_inarray_nth(rc->update_del, i);
751         evas_render_update_del(ctx->e, r->x, r->y, r->w, r->h);
752      }
753 }
754 #endif
755 
756 static Eina_Bool
757 _evas_render_phase1_object_process(Phase1_Context *p1ctx,
758                                    Evas_Object_Protected_Data *obj,
759                                    Eina_Bool restack,
760                                    Eina_Bool mapped_parent,
761                                    Eina_Bool src_changed,
762                                    int level);
763 
764 static void
_evas_render_phase1_object_restack_handle(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool obj_changed)765 _evas_render_phase1_object_restack_handle(Phase1_Context *p1ctx,
766                                           Evas_Object_Protected_Data *obj,
767                                           Eina_Bool obj_changed)
768 {
769    if (!obj_changed)
770      {
771         OBJ_ARRAY_PUSH(&(p1ctx->e->pending_objects), obj);
772         obj->changed = EINA_TRUE;
773         obj->in_pending_objects = EINA_TRUE;
774      }
775    obj->restack = EINA_TRUE;
776 }
777 
778 static void
_evas_render_phase1_object_map_clipper_fix(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj)779 _evas_render_phase1_object_map_clipper_fix(Evas_Object *eo_obj,
780                                            Evas_Object_Protected_Data *obj)
781 {
782    evas_object_change(obj->cur->clipper->object, obj->cur->clipper);
783    evas_object_clip_dirty(obj->cur->clipper->object, obj->cur->clipper);
784    evas_object_clip_recalc(obj->cur->clipper);
785    evas_object_update_bounding_box(eo_obj, obj, NULL);
786 }
787 
788 static void
_evas_render_phase1_object_mapped(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool src_changed,Eina_Bool hmap,Eina_Bool is_active,Eina_Bool obj_changed,int level)789 _evas_render_phase1_object_mapped(Phase1_Context *p1ctx,
790                                   Evas_Object_Protected_Data *obj,
791                                   Eina_Bool src_changed,
792                                   Eina_Bool hmap,
793                                   Eina_Bool is_active,
794                                   Eina_Bool obj_changed,
795                                   int level)
796 {
797    Evas_Object_Protected_Data *obj2;
798    Evas_Object *eo_obj = obj->object;
799 
800    RD(level, "  obj mapped\n");
801    if (!obj_changed) return;
802 
803    if (!hmap && obj->cur->clipper)
804      // Fix some bad clipping issues before an evas map animation starts
805      _evas_render_phase1_object_map_clipper_fix(eo_obj, obj);
806 
807    _evas_render_object_map_change_update(p1ctx->e, obj, EINA_TRUE, hmap, &(p1ctx->redraw_all));
808    if (!((is_active) &&
809          (!obj->clip.clipees) &&
810          ((evas_object_is_visible(obj) &&
811            (!obj->cur->have_clipees)) ||
812           (evas_object_was_visible(obj) &&
813            (!obj->prev->have_clipees)))))
814      return;
815    OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
816    _evas_render_prev_cur_clip_cache_add(p1ctx->e, obj);
817    obj->render_pre = EINA_TRUE;
818    if (!obj->is_smart) return;
819    if (obj_changed) evas_object_smart_render_cache_clear(eo_obj);
820    EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2)
821      {
822         _evas_render_phase1_object_process(p1ctx, obj2, obj->restack,
823                                            EINA_TRUE, src_changed, level + 1);
824      }
825 
826    /* Restacked mapped object should be used as a redraw rect.
827       The "phase 2. force updates for restack" will use restack_objects. */
828    if (EINA_UNLIKELY(obj->restack))
829      OBJ_ARRAY_PUSH(p1ctx->restack_objects, obj);
830 }
831 
832 static void
_evas_render_phase1_object_mapped_had_restack(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool map,Eina_Bool obj_changed,int level)833 _evas_render_phase1_object_mapped_had_restack(Phase1_Context *p1ctx,
834                                               Evas_Object_Protected_Data *obj,
835                                               Eina_Bool map,
836                                               Eina_Bool obj_changed,
837                                               int level)
838 {
839    Evas_Object *eo_obj = obj->object;
840    (void) level;
841 
842    RD(level, "  had map - restack objs\n");
843    _evas_render_prev_cur_clip_cache_add(p1ctx->e, obj);
844    if (obj_changed)
845      {
846         if (!map)
847           {
848              if ((obj->map->cur.map) && (obj->map->cur.usemap))
849                map = EINA_TRUE;
850           }
851         _evas_render_object_map_change_update(p1ctx->e, obj, map, EINA_TRUE, &(p1ctx->redraw_all));
852      }
853    if (!(!map && obj->cur->clipper)) return;
854    // Fix some bad clipping issues after an evas_map animation finishes
855    evas_object_change(obj->cur->clipper->object, obj->cur->clipper);
856    evas_object_clip_dirty(obj->cur->clipper->object, obj->cur->clipper);
857    evas_object_clip_recalc(obj->cur->clipper);
858    evas_object_update_bounding_box(eo_obj, obj, NULL);
859 }
860 
861 static Eina_Bool
_evas_render_phase1_object_changed_smart(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool mapped_parent,Eina_Bool obj_changed,Eina_Bool src_changed,Eina_Bool is_active,int level)862 _evas_render_phase1_object_changed_smart(Phase1_Context *p1ctx,
863                                          Evas_Object_Protected_Data *obj,
864                                          Eina_Bool mapped_parent,
865                                          Eina_Bool obj_changed,
866                                          Eina_Bool src_changed,
867                                          Eina_Bool is_active,
868                                          int level)
869 {
870    Evas_Object_Protected_Data *obj2;
871    Evas_Object *eo_obj = obj->object;
872 
873    RD(level, "  changed + smart - render ok\n");
874    OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
875 
876    if (!is_active && obj->proxy->proxies) src_changed = EINA_TRUE;
877 
878    obj->render_pre = EINA_TRUE;
879    if (obj_changed)
880      {
881         evas_object_smart_render_cache_clear(eo_obj);
882         EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2)
883           {
884              _evas_render_phase1_object_process(p1ctx, obj2, obj->restack,
885                                                 mapped_parent, src_changed,
886                                                 level + 1);
887           }
888      }
889    else
890      {
891         Phase1_Context *ctx = p1ctx;
892 
893 #ifdef RENDCACHE
894         Render_Cache *rc = NULL;
895         void *p_del_redir;
896         Phase1_Context tmpctx;
897 
898         if (obj->no_change_render > 3)
899           {
900              rc = evas_object_smart_render_cache_get(eo_obj);
901              if (!rc)
902                {
903                   rc = _evas_render_phase1_object_render_cache_new();
904                   evas_object_smart_render_cache_set(eo_obj, rc);
905                   ctx = &tmpctx;
906                   *ctx = *p1ctx;
907                   p_del_redir = p1ctx->e->update_del_redirect_array;
908                   p1ctx->e->update_del_redirect_array = rc->update_del;
909                   _evas_render_phase1_object_ctx_render_cache_fill(ctx, rc);
910                   EINA_INLIST_FOREACH
911                     (evas_object_smart_members_get_direct(eo_obj), obj2)
912                     {
913                        _evas_render_phase1_object_process(ctx, obj2,
914                                                           obj->restack,
915                                                           mapped_parent,
916                                                           src_changed,
917                                                           level + 1);
918                     }
919                   p1ctx->redraw_all = ctx->redraw_all;
920                   p1ctx->e->update_del_redirect_array = p_del_redir;
921                }
922              _evas_render_phase1_object_ctx_render_cache_append(p1ctx, rc);
923           }
924         else
925 #endif
926           {
927              EINA_INLIST_FOREACH
928                (evas_object_smart_members_get_direct(eo_obj), obj2)
929                {
930                   _evas_render_phase1_object_process(ctx, obj2, obj->restack,
931                                                      mapped_parent,
932                                                      src_changed, level + 1);
933                }
934           }
935      }
936    return src_changed;
937 }
938 
939 static void
_evas_render_phase1_object_changed_normal(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool is_active,int level EINA_UNUSED)940 _evas_render_phase1_object_changed_normal(Phase1_Context *p1ctx,
941                                           Evas_Object_Protected_Data *obj,
942                                           Eina_Bool is_active,
943                                           int level
944 #ifndef REND_DBG
945                                              EINA_UNUSED
946 #endif
947                                          )
948 {
949    if ((!obj->clip.clipees) && _evas_render_is_relevant(obj))
950      {
951         if (EINA_LIKELY(is_active))
952           {
953              RD(level, "  relevant + active\n");
954              if (EINA_UNLIKELY(obj->restack))
955                OBJ_ARRAY_PUSH(p1ctx->restack_objects, obj);
956              else
957                {
958                   OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
959                   obj->render_pre = EINA_TRUE;
960                }
961           }
962         else
963           {
964              /* It goes to be hidden. Prev caching should be replaced
965               by the current (hidden) state. */
966              if (evas_object_is_visible(obj) !=
967                  evas_object_was_visible(obj))
968                evas_object_cur_prev(obj);
969              RD(level, "  skip - not smart, not active or clippees or not relevant\n");
970           }
971      }
972    else if (is_active && _evas_render_object_is_mask(obj) &&
973             (obj->cur->visible || obj->prev->visible))
974      {
975         if (EINA_UNLIKELY(obj->restack))
976           OBJ_ARRAY_PUSH(p1ctx->restack_objects, obj);
977         else
978           {
979              OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
980              obj->render_pre = EINA_TRUE;
981           }
982         RD(level, "  relevant + active: clipper image\n");
983      }
984    else
985      {
986         RD(level, "  skip - not smart, not active or clippees or not relevant\n");
987      }
988 }
989 
990 static void
_evas_render_phase1_object_no_changed_smart(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool restack,Eina_Bool mapped_parent,Eina_Bool src_changed,int level)991 _evas_render_phase1_object_no_changed_smart(Phase1_Context *p1ctx,
992                                             Evas_Object_Protected_Data *obj,
993                                             Eina_Bool restack,
994                                             Eina_Bool mapped_parent,
995                                             Eina_Bool src_changed,
996                                             int level)
997 {
998    Evas_Object_Protected_Data *obj2;
999    Phase1_Context *ctx = p1ctx;
1000    Evas_Object *eo_obj = obj->object;
1001 
1002    RD(level, "  smart + visible/was visible + not clip\n");
1003    OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1004    obj->render_pre = EINA_TRUE;
1005 #ifdef RENDCACHE
1006    void *p_del_redir;
1007    Render_Cache *rc = NULL;
1008    Phase1_Context tmpctx;
1009 
1010    if (obj->no_change_render > 3)
1011      {
1012         rc = evas_object_smart_render_cache_get(eo_obj);
1013         if (!rc)
1014           {
1015              rc = _evas_render_phase1_object_render_cache_new();
1016              evas_object_smart_render_cache_set(eo_obj, rc);
1017              ctx = &tmpctx;
1018              *ctx = *p1ctx;
1019              p_del_redir = p1ctx->e->update_del_redirect_array;
1020              p1ctx->e->update_del_redirect_array = rc->update_del;
1021              _evas_render_phase1_object_ctx_render_cache_fill(ctx, rc);
1022              EINA_INLIST_FOREACH
1023                (evas_object_smart_members_get_direct(eo_obj), obj2)
1024                {
1025                   _evas_render_phase1_object_process(ctx, obj2, restack,
1026                                                      mapped_parent,
1027                                                      src_changed, level + 1);
1028                }
1029              p1ctx->redraw_all = ctx->redraw_all;
1030              p1ctx->e->update_del_redirect_array = p_del_redir;
1031           }
1032         _evas_render_phase1_object_ctx_render_cache_append(p1ctx, rc);
1033      }
1034    else
1035 #endif
1036      {
1037         EINA_INLIST_FOREACH
1038           (evas_object_smart_members_get_direct(eo_obj), obj2)
1039           {
1040              _evas_render_phase1_object_process(ctx, obj2, restack,
1041                                                 mapped_parent,
1042                                                 src_changed, level + 1);
1043           }
1044      }
1045 }
1046 
1047 static void
_evas_render_phase1_object_no_changed_normal(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,int level EINA_UNUSED)1048 _evas_render_phase1_object_no_changed_normal(Phase1_Context *p1ctx,
1049                                              Evas_Object_Protected_Data *obj,
1050                                              int level
1051 #ifndef REND_DBG
1052                                              EINA_UNUSED
1053 #endif
1054                                             )
1055 {
1056    if (evas_object_is_opaque(obj) &&
1057        evas_object_is_visible(obj))
1058      {
1059         RD(level, "  opaque + visible\n");
1060         OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1061         obj->rect_del = EINA_TRUE;
1062      }
1063    else if (evas_object_is_visible(obj))
1064      {
1065         RD(level, "  visible\n");
1066         OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1067         obj->render_pre = EINA_TRUE;
1068      }
1069    else
1070      {
1071         RD(level, "  skip\n");
1072      }
1073 }
1074 
1075 static Eina_Bool
_evas_render_phase1_object_process(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool restack,Eina_Bool mapped_parent,Eina_Bool src_changed,int level)1076 _evas_render_phase1_object_process(Phase1_Context *p1ctx,
1077                                    Evas_Object_Protected_Data *obj,
1078                                    Eina_Bool restack,
1079                                    Eina_Bool mapped_parent,
1080                                    Eina_Bool src_changed,
1081                                    int level)
1082 {
1083    Eina_Bool clean_them = EINA_FALSE;
1084    Eina_Bool map, hmap, can_map, map_not_can_map, obj_changed, is_active;
1085    Evas_Object *eo_obj = obj->object;
1086 
1087    EINA_PREFETCH(&(obj->cur->clipper));
1088 
1089    obj->rect_del = EINA_FALSE;
1090    obj->render_pre = EINA_FALSE;
1091 
1092    if (obj->delete_me == 2) OBJ_ARRAY_PUSH(p1ctx->delete_objects, obj);
1093    else if (obj->delete_me != 0) obj->delete_me++;
1094 
1095    /* If the object will be removed, we should not cache anything during this run. */
1096    if (obj->delete_me != 0) clean_them = EINA_TRUE;
1097 
1098    obj_changed = obj->changed;
1099 
1100    if (obj->is_static_clip) goto done;
1101 
1102    //Need pre render for the children of mapped object.
1103    //But only when they have changed.
1104    if (mapped_parent && (!obj->changed)) goto done;
1105 
1106    /* build active object list */
1107    evas_object_clip_recalc(obj);
1108 
1109    if (src_changed) is_active = EINA_TRUE;
1110    else
1111      {
1112        is_active = evas_object_is_active(eo_obj, obj);
1113        if (is_active && obj->proxy->proxies) src_changed = is_active;
1114      }
1115    obj->is_active = is_active;
1116 
1117 #ifdef REND_DBG
1118    RD(level, "[--- PROCESS %s active = %i, del = %i | %i,%i %ix%i\n",
1119       RDNAME(obj), is_active, obj->delete_me, obj->cur->geometry.x,
1120       obj->cur->geometry.y, obj->cur->geometry.w, obj->cur->geometry.h);
1121 #endif
1122 
1123    if ((!mapped_parent) &&
1124        ((is_active) || (obj->delete_me != 0)) &&
1125        (!obj->no_render))
1126      {
1127         Evas_Active_Entry ent;
1128 
1129 #ifdef INLINE_ACTIVE_GEOM
1130         if (obj->is_smart)
1131           evas_object_smart_bounding_box_get(obj, &(ent.rect), NULL);
1132         else
1133           {
1134              ent.rect.x = obj->cur->cache.clip.x;
1135              ent.rect.y = obj->cur->cache.clip.y;
1136              ent.rect.w = obj->cur->cache.clip.w;
1137              ent.rect.h = obj->cur->cache.clip.h;
1138           }
1139 #endif
1140         ent.obj = obj;
1141         eina_inarray_push(p1ctx->active_objects, &ent);
1142      }
1143    if (is_active && obj->cur->snapshot && !obj->delete_me &&
1144        evas_object_is_visible(obj))
1145      {
1146         // FIXME: Array should be clean (no need to check if already in there)
1147         int found = 0;
1148         for (unsigned i = 0; !found && (i < p1ctx->snapshot_objects->count); i++)
1149           if (obj == eina_array_data_get(p1ctx->snapshot_objects, i))
1150             found = 1;
1151         if (!found) OBJ_ARRAY_PUSH(p1ctx->snapshot_objects, obj);
1152      }
1153 
1154 #ifdef REND_DBG
1155    if (!is_active)
1156      {
1157         RD(level, "%s vis: %i, cache.clip.vis: %i cache.clip.a: %i [func: %p]\n",
1158            RDNAME(obj), obj->cur->visible, obj->cur->cache.clip.visible,
1159            obj->cur->cache.clip.a, obj->func->is_visible);
1160      }
1161 #endif
1162 
1163    _evas_object_gfx_mapping_update(obj);
1164    map = _evas_render_has_map(obj);
1165    hmap = _evas_render_had_map(obj);
1166    can_map = _evas_render_can_map(obj);
1167    map_not_can_map = map & !can_map;
1168 
1169    if (EINA_UNLIKELY((restack && !map_not_can_map)))
1170      {
1171         _evas_render_phase1_object_restack_handle(p1ctx, obj, obj_changed);
1172         obj_changed = EINA_TRUE;
1173         clean_them = EINA_TRUE;
1174      }
1175 
1176    if (EINA_UNLIKELY(map_not_can_map))
1177      {
1178         _evas_render_phase1_object_mapped(p1ctx, obj, src_changed, hmap,
1179                                           is_active, obj_changed, level);
1180         goto done;
1181      }
1182    else if (EINA_UNLIKELY(hmap && !can_map))
1183      _evas_render_phase1_object_mapped_had_restack(p1ctx, obj, map,
1184                                                    obj_changed, level);
1185 
1186    /* handle normal rendering. this object knows how to handle maps */
1187    if (obj_changed)
1188      {
1189         if (obj->is_smart)
1190           src_changed =
1191             _evas_render_phase1_object_changed_smart(p1ctx, obj, mapped_parent,
1192                                                      obj_changed, src_changed,
1193                                                      is_active, level);
1194         else /* non smart object */
1195           _evas_render_phase1_object_changed_normal(p1ctx, obj, is_active,
1196                                                     level);
1197      }
1198    else
1199      {
1200         /* not changed */
1201         RD(level, "  not changed... [%i] -> (%i %i %p %i) [%i]\n",
1202            evas_object_is_visible(obj),
1203            obj->cur->visible, obj->cur->cache.clip.visible, obj->smart.smart,
1204            obj->cur->cache.clip.a, evas_object_was_visible(obj));
1205         if ((!obj->clip.clipees) &&
1206             (EINA_LIKELY(obj->delete_me == 0)) &&
1207             (_evas_render_can_render(obj) ||
1208              (evas_object_was_visible(obj) &&
1209               (!obj->prev->have_clipees))))
1210           {
1211              if (obj->is_smart)
1212                _evas_render_phase1_object_no_changed_smart(p1ctx, obj, restack,
1213                                                            mapped_parent,
1214                                                            src_changed, level);
1215              else /* not smart */
1216                _evas_render_phase1_object_no_changed_normal(p1ctx, obj, level);
1217           }
1218         else if (EINA_UNLIKELY(is_active &&
1219                                _evas_render_object_is_mask(obj) &&
1220                                obj->cur->visible))
1221           {
1222              RD(level, "  visible clipper image\n");
1223              OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1224              obj->render_pre = EINA_TRUE;
1225           }
1226      }
1227    if (!is_active) obj->restack = EINA_FALSE;
1228    RD(level, "---]\n");
1229 done:
1230    if (obj_changed) obj->no_change_render = 0;
1231    else
1232      {
1233         if (obj->no_change_render < 255) obj->no_change_render++;
1234      }
1235    return clean_them;
1236 }
1237 
1238 //
1239 //
1240 //
1241 ////////////////////////////////////////////////////////////////////////////
1242 
1243 
1244 
1245 
1246 
1247 
1248 
1249 static Eina_Bool
_evas_render_phase1_process(Phase1_Context * p1ctx)1250 _evas_render_phase1_process(Phase1_Context *p1ctx)
1251 {
1252    Evas_Layer *lay;
1253    Eina_Bool clean_them = EINA_FALSE;
1254 
1255    RD(0, "  [--- PHASE 1\n");
1256    EINA_INLIST_FOREACH(p1ctx->e->layers, lay)
1257      {
1258         Evas_Object_Protected_Data *obj;
1259 
1260         EINA_INLIST_FOREACH(lay->objects, obj)
1261           {
1262              if (evas_object_is_on_plane(obj)) continue;
1263              clean_them |= _evas_render_phase1_object_process
1264                 (p1ctx, obj, EINA_FALSE, EINA_FALSE, EINA_FALSE, 2);
1265           }
1266      }
1267    RD(0, "  ---]\n");
1268    return clean_them;
1269 }
1270 
1271 static void
_evas_render_check_pending_objects(Eina_Array * pending_objects,Evas * eo_e EINA_UNUSED,Evas_Public_Data * e)1272 _evas_render_check_pending_objects(Eina_Array *pending_objects, Evas *eo_e EINA_UNUSED, Evas_Public_Data *e)
1273 {
1274    unsigned int i;
1275 
1276    for (i = 0; i < pending_objects->count; ++i)
1277      {
1278         Evas_Object *eo_obj;
1279         int is_active;
1280         Eina_Bool ok = EINA_FALSE;
1281 
1282         Evas_Object_Protected_Data *obj = eina_array_data_get(pending_objects, i);
1283         eo_obj = obj->object;
1284 
1285         if (!obj->layer) goto clean_stuff;
1286 
1287         _evas_object_gfx_mapping_update(obj);
1288         EINA_PREFETCH(&(obj->cur->clipper));
1289         EINA_PREFETCH(&(obj->cur->cache.clip));
1290         //If the children are in active objects, They should be cleaned up.
1291         if (EINA_UNLIKELY((obj->changed_map) &&
1292                           (_evas_render_has_map(obj)) &&
1293                           (!_evas_render_can_map(obj))))
1294           goto clean_stuff;
1295 
1296         evas_object_clip_recalc(obj);
1297         is_active = evas_object_is_active(eo_obj, obj);
1298 
1299         if ((!is_active) && (!obj->is_active) && (!obj->render_pre) &&
1300             (!obj->rect_del))
1301           {
1302              ok = EINA_TRUE;
1303              goto clean_stuff;
1304           }
1305 
1306         if (obj->is_active == is_active)
1307           {
1308              if (obj->changed)
1309                {
1310                   if (obj->is_smart)
1311                     {
1312                        if (obj->render_pre || obj->rect_del) ok = EINA_TRUE;
1313                     }
1314                   else
1315                     if ((is_active) && (obj->restack) && (!obj->clip.clipees) &&
1316                         (_evas_render_can_render(obj) ||
1317                          (evas_object_was_visible(obj) && (!obj->prev->have_clipees))))
1318                       {
1319                          if (!obj->render_pre && !obj->rect_del && !obj->delete_me)
1320                            ok = EINA_TRUE;
1321                       }
1322                     else
1323                       if (is_active && (!obj->clip.clipees) &&
1324                           (_evas_render_can_render(obj) ||
1325                            (evas_object_was_visible(obj) && (!obj->prev->have_clipees))))
1326                         {
1327                            if (obj->render_pre || obj->rect_del) ok = EINA_TRUE;
1328                         }
1329                }
1330              else
1331                {
1332                   if ((!obj->clip.clipees) && (obj->delete_me == 0) &&
1333                       (!obj->cur->have_clipees || (evas_object_was_visible(obj) && (!obj->prev->have_clipees)))
1334                       && evas_object_is_opaque(obj) && evas_object_is_visible(obj))
1335                     {
1336                        if (obj->rect_del || obj->is_smart) ok = EINA_TRUE;
1337                     }
1338                }
1339           }
1340 
1341 clean_stuff:
1342         if (!ok)
1343           {
1344              eina_inarray_flush(&e->active_objects);
1345              OBJS_ARRAY_CLEAN(&e->render_objects);
1346              OBJS_ARRAY_CLEAN(&e->restack_objects);
1347              OBJS_ARRAY_CLEAN(&e->delete_objects);
1348              OBJS_ARRAY_CLEAN(&e->snapshot_objects);
1349              e->invalidate = EINA_TRUE;
1350              return;
1351           }
1352      }
1353 }
1354 
1355 Eina_Bool
pending_change(void * data,void * gdata EINA_UNUSED)1356 pending_change(void *data, void *gdata EINA_UNUSED)
1357 {
1358    Evas_Object *eo_obj;
1359 
1360    Evas_Object_Protected_Data *obj = data;
1361    eo_obj = obj->object;
1362    if (obj->delete_me) return EINA_FALSE;
1363    if (obj->pre_render_done)
1364      {
1365         RD(0, "  OBJ %s pending change %i -> 0, pre %i\n", RDNAME(obj), obj->changed, obj->pre_render_done);
1366         evas_object_change_reset(obj);
1367         obj->func->render_post(eo_obj, obj, obj->private_data);
1368         obj->pre_render_done = EINA_FALSE;
1369      }
1370    else if (!_evas_render_can_render(obj) &&
1371             (!obj->is_active) && (!obj->render_pre) &&
1372             (!obj->rect_del))
1373      {
1374         evas_object_change_reset(obj);
1375      }
1376 
1377    //FIXME: after evas_object_change_reset(), obj->changed is always false...
1378    Eina_Bool val = obj->changed ? EINA_TRUE : EINA_FALSE;
1379    obj->in_pending_objects = val;
1380    return val;
1381 }
1382 
1383 static Eina_Bool
_evas_render_can_use_overlay(Evas_Public_Data * e,Evas_Object * eo_obj,Efl_Canvas_Output * output)1384 _evas_render_can_use_overlay(Evas_Public_Data *e, Evas_Object *eo_obj, Efl_Canvas_Output *output)
1385 {
1386    Eina_Rectangle *r;
1387    Evas_Object *eo_tmp;
1388    Eina_List *alphas = NULL;
1389    Eina_List *opaques = NULL;
1390    Evas_Object *video_parent = NULL;
1391    Eina_Rectangle zone;
1392    Evas_Coord xc1, yc1, xc2, yc2;
1393    int i;
1394    Eina_Bool nooverlay;
1395    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1396    Evas_Object_Protected_Data *tmp = NULL;
1397    Evas_Coord imgw, imgh;
1398    unsigned int caps;
1399    Eina_Bool surface_below, stacking_check, object_above = EINA_FALSE;
1400    Eina_Bool ignore_window;
1401 
1402    if (!_evas_object_image_can_use_plane(obj, output))
1403      return EINA_FALSE;
1404 
1405    video_parent = _evas_object_image_video_parent_get(eo_obj);
1406 
1407    /* Check if any one is the stack make this object mapped */
1408    eo_tmp = eo_obj;
1409    tmp = efl_data_scope_get(eo_tmp, EFL_CANVAS_OBJECT_CLASS);
1410    _evas_object_gfx_mapping_update(tmp);
1411    while (tmp && !(_evas_render_has_map(tmp) && !_evas_render_can_map(tmp)))
1412      {
1413         eo_tmp = tmp->smart.parent;
1414         tmp = efl_data_scope_get(eo_tmp, EFL_CANVAS_OBJECT_CLASS);
1415         if (tmp) _evas_object_gfx_mapping_update(tmp);
1416      }
1417 
1418    if (tmp && _evas_render_has_map(tmp) && !_evas_render_can_map(tmp))
1419      return EINA_FALSE; /* we are mapped, we can't be an overlay */
1420 
1421    if (!evas_object_is_visible(obj))
1422      return EINA_FALSE; /* no need to update the overlay if it's not visible */
1423 
1424    /* If any recoloring of the surface is needed, n overlay to */
1425    if ((obj->cur->cache.clip.r != 255) ||
1426        (obj->cur->cache.clip.g != 255) ||
1427        (obj->cur->cache.clip.b != 255) ||
1428        (obj->cur->cache.clip.a != 255))
1429      return EINA_FALSE;
1430 
1431    caps = evas_object_image_video_surface_caps_get(eo_obj);
1432 
1433    /* check if surface is above the canvas */
1434    surface_below = !!(caps & EVAS_VIDEO_SURFACE_BELOW);
1435    if (!surface_below)
1436      {
1437         /* above canvas, must support resize and clipping */
1438 
1439         /* check if video surface supports resize */
1440         evas_object_image_size_get(eo_obj, &imgw, &imgh);
1441         if ((obj->cur->geometry.w != imgw) ||
1442             (obj->cur->geometry.h != imgh))
1443           {
1444              if (!(caps & EVAS_VIDEO_SURFACE_RESIZE))
1445                 return EINA_FALSE;
1446           }
1447         /* check if video surface supports clipping */
1448         evas_object_image_size_get(eo_obj, &imgw, &imgh);
1449         if ((obj->cur->cache.clip.x != obj->cur->geometry.x) ||
1450             (obj->cur->cache.clip.y != obj->cur->geometry.y) ||
1451             (obj->cur->cache.clip.w != obj->cur->geometry.w) ||
1452             (obj->cur->cache.clip.h != obj->cur->geometry.h))
1453           {
1454              if (!(caps & EVAS_VIDEO_SURFACE_CLIP))
1455                 return EINA_FALSE;
1456           }
1457      }
1458 
1459    /* check for window/surface/canvas limits */
1460    ignore_window = !!(caps & EVAS_VIDEO_SURFACE_IGNORE_WINDOW);
1461    if (!ignore_window)
1462      {
1463         Evas_Coord x1, x2, y1, y2;
1464         Evas_Coord fx, fy, fw, fh;
1465 
1466         fx = e->framespace.x;
1467         fy = e->framespace.y;
1468         fw = e->framespace.w;
1469         fh = e->framespace.h;
1470 
1471         x1 = obj->cur->geometry.x + fx;
1472         y1 = obj->cur->geometry.y + fy;
1473         x2 = obj->cur->geometry.x + obj->cur->geometry.w + fx;
1474         y2 = obj->cur->geometry.y + obj->cur->geometry.h + fy;
1475 
1476         if ((x1 < fx) || (y1 < fy) ||
1477             (x2 > e->output.w - (fw - fx)) ||
1478             (y2 > e->output.h - (fh - fy)))
1479           return EINA_FALSE;
1480      }
1481 
1482    /* check if there are other objects above the video object? */
1483    stacking_check = !!(caps & EVAS_VIDEO_SURFACE_STACKING_CHECK);
1484    if (!stacking_check)
1485      return EINA_TRUE;
1486 
1487    /* Check presence of transparent object on top of the video object */
1488    EINA_RECTANGLE_SET(&zone,
1489                       obj->cur->cache.clip.x,
1490                       obj->cur->cache.clip.y,
1491                       obj->cur->cache.clip.w,
1492                       obj->cur->cache.clip.h);
1493 
1494    for (i = e->active_objects.len - 1; i > 0; i--)
1495      {
1496         Eina_Rectangle self;
1497         Eina_Rectangle *match;
1498         Evas_Object *eo_current;
1499         Eina_List *l;
1500         int xm1, ym1, xm2, ym2;
1501         Evas_Active_Entry *ent = eina_inarray_nth(&e->active_objects, i);
1502         Evas_Object_Protected_Data *current = ent->obj;
1503 
1504         eo_current = current->object;
1505         /* Did we find the video object in the stack ? */
1506         if (eo_current == video_parent || eo_current == eo_obj)
1507           break;
1508 
1509         EINA_RECTANGLE_SET(&self,
1510                            current->cur->cache.clip.x,
1511                            current->cur->cache.clip.y,
1512                            current->cur->cache.clip.w,
1513                            current->cur->cache.clip.h);
1514 
1515         /* This doesn't cover the area of the video object, so don't bother with that object */
1516         if (!eina_rectangles_intersect(&zone, &self))
1517           continue;
1518 
1519         xc1 = current->cur->cache.clip.x;
1520         yc1 = current->cur->cache.clip.y;
1521         xc2 = current->cur->cache.clip.x + current->cur->cache.clip.w;
1522         yc2 = current->cur->cache.clip.y + current->cur->cache.clip.h;
1523 
1524         if (evas_object_is_visible(current) &&
1525             (!current->clip.clipees) &&
1526             (current->cur->visible) &&
1527             (!current->delete_me) &&
1528             (current->cur->cache.clip.visible) &&
1529             (!efl_isa(eo_current, EFL_CANVAS_GROUP_CLASS)))
1530           {
1531              Eina_Bool included = EINA_FALSE;
1532 
1533              if (!surface_below)
1534                {
1535                   object_above = EINA_TRUE;
1536                   break;
1537                }
1538 
1539              if (evas_object_is_opaque(current) ||
1540                  ((current->func->has_opaque_rect) &&
1541                   (current->func->has_opaque_rect(eo_current, current, current->private_data))))
1542                {
1543                   /* The object is opaque */
1544 
1545                   /* Check if the opaque object is inside another opaque object */
1546                   EINA_LIST_FOREACH(opaques, l, match)
1547                     {
1548                        xm1 = match->x;
1549                        ym1 = match->y;
1550                        xm2 = match->x + match->w;
1551                        ym2 = match->y + match->h;
1552 
1553                        /* Both object are included */
1554                        if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
1555                          {
1556                             included = EINA_TRUE;
1557                             break;
1558                          }
1559                     }
1560 
1561                   /* Not included yet */
1562                   if (!included)
1563                     {
1564                        Eina_List *ln;
1565                        Evas_Coord xn2, yn2;
1566 
1567                        r = eina_rectangle_new(current->cur->cache.clip.x, current->cur->cache.clip.y,
1568                                               current->cur->cache.clip.w, current->cur->cache.clip.h);
1569 
1570                        opaques = eina_list_append(opaques, r);
1571 
1572                        xn2 = r->x + r->w;
1573                        yn2 = r->y + r->h;
1574 
1575                        /* Remove all the transparent object that are covered by the new opaque object */
1576                        EINA_LIST_FOREACH_SAFE(alphas, l, ln, match)
1577                          {
1578                             xm1 = match->x;
1579                             ym1 = match->y;
1580                             xm2 = match->x + match->w;
1581                             ym2 = match->y + match->h;
1582 
1583                             if (xm1 >= r->x && ym1 >= r->y && xm2 <= xn2 && ym2 <= yn2)
1584                               {
1585                                  /* The new rectangle is over some transparent object,
1586                                     so remove the transparent object */
1587                                  alphas = eina_list_remove_list(alphas, l);
1588                               }
1589                          }
1590                     }
1591                }
1592              else
1593                {
1594                   /* The object has some transparency */
1595 
1596                   /* Check if the transparent object is inside any other transparent object */
1597                   EINA_LIST_FOREACH(alphas, l, match)
1598                     {
1599                        xm1 = match->x;
1600                        ym1 = match->y;
1601                        xm2 = match->x + match->w;
1602                        ym2 = match->y + match->h;
1603 
1604                        /* Both object are included */
1605                        if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
1606                          {
1607                             included = EINA_TRUE;
1608                             break;
1609                          }
1610                     }
1611 
1612                   /* If not check if it is inside any opaque one */
1613                   if (!included)
1614                     {
1615                        EINA_LIST_FOREACH(opaques, l, match)
1616                          {
1617                             xm1 = match->x;
1618                             ym1 = match->y;
1619                             xm2 = match->x + match->w;
1620                             ym2 = match->y + match->h;
1621 
1622                             /* Both object are included */
1623                             if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
1624                               {
1625                                  included = EINA_TRUE;
1626                                  break;
1627                               }
1628                          }
1629                     }
1630 
1631                   /* No inclusion at all, so add it */
1632                   if (!included)
1633                     {
1634                        r = eina_rectangle_new(current->cur->cache.clip.x, current->cur->cache.clip.y,
1635                                               current->cur->cache.clip.w, current->cur->cache.clip.h);
1636 
1637                        alphas = eina_list_append(alphas, r);
1638                     }
1639                }
1640           }
1641      }
1642 
1643    /* If there is any pending transparent object, then no overlay */
1644    nooverlay = !!eina_list_count(alphas);
1645 
1646    EINA_LIST_FREE(alphas, r)
1647      eina_rectangle_free(r);
1648    EINA_LIST_FREE(opaques, r)
1649      eina_rectangle_free(r);
1650 
1651    if (nooverlay || object_above)
1652      return EINA_FALSE;
1653 
1654    return EINA_TRUE;
1655 }
1656 
1657 static Eina_Bool
_proxy_context_clip(Evas_Public_Data * evas,void * ctx,Evas_Proxy_Render_Data * proxy_render_data,Evas_Object_Protected_Data * obj,int off_x,int off_y)1658 _proxy_context_clip(Evas_Public_Data *evas, void *ctx, Evas_Proxy_Render_Data *proxy_render_data, Evas_Object_Protected_Data *obj, int off_x, int off_y)
1659 {
1660    const Eina_Rectangle *clip;
1661    Evas_Object_Protected_Data *clipper;
1662    int cw, ch;
1663 
1664    /* cache.clip can not be relied on, since the evas is frozen, but we need
1665     * to set the clip. so we recurse from clipper to clipper until we reach
1666     * the source object's clipper */
1667 
1668    if (!proxy_render_data) return EINA_TRUE;
1669    if (proxy_render_data->source_clip)
1670      {
1671         Evas_Object_Protected_Data *src_obj = proxy_render_data->src_obj;
1672         /* trust cache.clip since we clip like the source */
1673         ENFN->context_clip_clip(ENC, ctx,
1674                                 src_obj->cur->cache.clip.x + off_x,
1675                                 src_obj->cur->cache.clip.y + off_y,
1676                                 src_obj->cur->cache.clip.w, src_obj->cur->cache.clip.h);
1677         ENFN->context_clip_get(ENC, ctx, NULL, NULL, &cw, &ch);
1678         return ((cw > 0) && (ch > 0));
1679      }
1680 
1681    if (!obj->cur->clipper) return EINA_TRUE;
1682 
1683    clipper = obj->cur->clipper;
1684    if (!clipper->cur->visible) return EINA_FALSE;
1685    clip = &clipper->cur->geometry;
1686    ENFN->context_clip_clip(ENC, ctx, clip->x + off_x, clip->y + off_y, clip->w, clip->h);
1687    ENFN->context_clip_get(ENC, ctx, NULL, NULL, &cw, &ch);
1688    if ((cw <= 0) || (ch <= 0)) return EINA_FALSE;
1689 
1690    /* stop if we found the source object's clipper */
1691    if (clipper == proxy_render_data->src_obj->cur->clipper) return EINA_TRUE;
1692 
1693    /* recurse to the clipper itself.
1694     * origin of clipper's clipper won't be transformed to derivative space. */
1695    return _proxy_context_clip(evas, ctx, proxy_render_data, clipper,
1696                               -proxy_render_data->src_obj->cur->geometry.x,
1697                               -proxy_render_data->src_obj->cur->geometry.y);
1698 }
1699 
1700 static Eina_Bool
_mask_apply_inside_proxy(Evas_Proxy_Render_Data * proxy_render_data,Evas_Object_Protected_Data * mask)1701 _mask_apply_inside_proxy(Evas_Proxy_Render_Data *proxy_render_data,
1702                          Evas_Object_Protected_Data *mask)
1703 {
1704    // Trying to find out if the mask should be applied inside the proxy or not.
1705    if (!proxy_render_data || proxy_render_data->source_clip) return EINA_TRUE;
1706    if (!proxy_render_data->src_obj->cur->clipper) return EINA_FALSE;
1707    if (!mask) return EINA_FALSE;
1708 
1709    // FIXME: Need to implement a logic similar to _proxy_context_clip
1710    return EINA_FALSE;
1711 }
1712 
1713 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)1714 _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)
1715 {
1716    int x, y, w, h;
1717    Eina_Bool proxy_src_clip = EINA_TRUE;
1718 
1719    if (proxy_render_data) proxy_src_clip = proxy_render_data->source_clip;
1720 
1721    if (proxy_src_clip)
1722      {
1723         x = obj->cur->cache.clip.x;
1724         y = obj->cur->cache.clip.y;
1725         w = obj->cur->cache.clip.w;
1726         h = obj->cur->cache.clip.h;
1727 
1728         RECTS_CLIP_TO_RECT(x, y, w, h,
1729                            obj->cur->clipper->cur->cache.clip.x,
1730                            obj->cur->clipper->cur->cache.clip.y,
1731                            obj->cur->clipper->cur->cache.clip.w,
1732                            obj->cur->clipper->cur->cache.clip.h);
1733 
1734         ENFN->context_clip_set(ENC, ctx, x + off_x, y + off_y, w, h);
1735      }
1736    else if (evas->is_frozen)
1737      {
1738         /* can't trust cache.clip here - clip should be in ctx already */
1739      }
1740    else
1741      {
1742         //FIXME: Consider to clip by the proxy clipper.
1743         if (proxy_render_data->eo_src != eo_obj)
1744           {
1745              x = obj->cur->clipper->cur->geometry.x + off_x;
1746              y = obj->cur->clipper->cur->geometry.y + off_y;
1747              w = obj->cur->clipper->cur->geometry.w;
1748              h = obj->cur->clipper->cur->geometry.h;
1749              ENFN->context_clip_clip(ENC, ctx, x, y, w, h);
1750           }
1751      }
1752 }
1753 
1754 static void
_evas_render_mapped_mask(Evas_Public_Data * evas,Evas_Object_Protected_Data * obj,Evas_Object_Protected_Data * mask,Evas_Proxy_Render_Data * proxy_render_data,void * output,void * ctx,int off_x,int off_y,int level,Eina_Bool do_async)1755 _evas_render_mapped_mask(Evas_Public_Data *evas, Evas_Object_Protected_Data *obj, Evas_Object_Protected_Data *mask,
1756                          Evas_Proxy_Render_Data *proxy_render_data, void *output, void *ctx, int off_x, int off_y, int level, Eina_Bool do_async)
1757 {
1758    if (!mask) return;
1759    if (proxy_render_data &&
1760        !proxy_render_data->source_clip &&
1761        proxy_render_data->src_obj->clip.mask == mask) return;
1762 
1763    // This path can be hit when we're multiplying masks on top of each other...
1764    Evas_Object_Protected_Data *prev_mask = obj->clip.prev_mask;
1765    Eina_Bool redraw = mask->mask->redraw || !mask->mask->surface;
1766 
1767    RD(level, "  has mask: %s redraw:%d sfc:%p prev_mask:%p\n",
1768       RDNAME(mask), mask->mask->redraw, mask->mask->surface, prev_mask);
1769    if (prev_mask && !_mask_apply_inside_proxy(proxy_render_data, prev_mask))
1770      {
1771         RD(level, "  discard prev mask and redraw (guessed outside proxy)\n");
1772         prev_mask = NULL;
1773         redraw = EINA_TRUE;
1774      }
1775    if (redraw)
1776      evas_render_mask_subrender(evas, output, mask, prev_mask, level + 1, do_async);
1777 
1778    if (mask->mask->surface)
1779      {
1780         Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(mask->cur);
1781         ENFN->context_clip_image_set(ENC, ctx, mask->mask->surface,
1782                                      clip.x + off_x,
1783                                      clip.y + off_y,
1784                                      evas, do_async);
1785      }
1786 }
1787 
1788 Eina_Bool
evas_render_mapped(Evas_Public_Data * evas,Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * context,void * output,void * surface,int off_x,int off_y,int mapped,int ecx,int ecy,int ecw,int ech,Evas_Proxy_Render_Data * proxy_render_data,int level,Eina_Bool do_async)1789 evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
1790                    Evas_Object_Protected_Data *obj, void *context,
1791                    void *output, void *surface,
1792                    int off_x, int off_y, int mapped, int ecx,
1793                    int ecy, int ecw, int ech,
1794                    Evas_Proxy_Render_Data *proxy_render_data, int level,
1795                    Eina_Bool do_async)
1796 {
1797    Evas_Object_Protected_Data *obj2;
1798    Eina_Bool clean_them = EINA_FALSE;
1799    Eina_Bool proxy_src_clip = EINA_TRUE;
1800    Eina_Bool was_pre_render_done = obj->pre_render_done;
1801    void *ctx;
1802 
1803    if (!proxy_render_data)
1804      {
1805         /* don't render if the source is invisible */
1806         if ((evas_object_is_source_invisible(eo_obj, obj)))
1807           return EINA_FALSE;
1808      }
1809    else
1810      proxy_src_clip = proxy_render_data->source_clip;
1811 
1812    evas_object_clip_recalc(obj);
1813    _evas_object_gfx_mapping_update(obj);
1814 
1815    /* leave early if clipper is not visible */
1816    if ((obj->cur->clipper) && (!obj->cur->clipper->cur->visible))
1817      return EINA_FALSE;
1818 
1819    eina_evlog("+render_object", eo_obj, 0.0, NULL);
1820 #ifdef REND_DBG
1821    RD(level, "{\n");
1822    RD(level, "  evas_render_mapped(evas:%p, obj:%s, ctx:%p, sfc:%p, offset:%i,%i, %s, %s)\n",
1823       evas->evas, RDNAME(obj), context, surface, off_x, off_y,
1824       mapped ? "mapped" : "normal", do_async ? "async" : "sync");
1825    IFRD(obj->is_smart, level, "  is_smart");
1826    IFRD(obj->is_frame, level, "  in framespace%s", obj->is_frame_top ? " (top object)" : "");
1827    if (obj->cur->clipper)
1828      {
1829         RD(level, "  clipper: %s (mask: %s) %d,%d %dx%d ; color: {%d,%d,%d,%d} ; cached: {%d,%d,%d,%d}\n",
1830            RDNAME(obj->cur->clipper), RDNAME(obj->clip.mask),
1831            obj->cur->clipper->cur->geometry.x, obj->cur->clipper->cur->geometry.y,
1832            obj->cur->clipper->cur->geometry.w, obj->cur->clipper->cur->geometry.h,
1833            obj->cur->clipper->cur->color.r, obj->cur->clipper->cur->color.g,
1834            obj->cur->clipper->cur->color.b, obj->cur->clipper->cur->color.a,
1835            obj->cur->clipper->cur->cache.clip.r, obj->cur->clipper->cur->cache.clip.g,
1836            obj->cur->clipper->cur->cache.clip.b, obj->cur->clipper->cur->cache.clip.a);
1837      }
1838 
1839    RD(level, "  geom: %d,%d %dx%d, cache.clip: (vis: %d) %d,%d %dx%d ; color: {%d,%d,%d,%d} ; cached: {%d,%d,%d,%d}\n",
1840       obj->cur->geometry.x, obj->cur->geometry.y, obj->cur->geometry.w, obj->cur->geometry.h, obj->cur->cache.clip.visible,
1841       obj->cur->cache.clip.x, obj->cur->cache.clip.y, obj->cur->cache.clip.w, obj->cur->cache.clip.h,
1842       obj->cur->color.r, obj->cur->color.g, obj->cur->color.b, obj->cur->color.a,
1843       obj->cur->cache.clip.r, obj->cur->cache.clip.g, obj->cur->cache.clip.b, obj->cur->cache.clip.a);
1844    {
1845       int _cu, _cc, _cm, _cx, _cy, _cw, _ch, _cr, _cg, _cb, _ca, _cmr, _cmg, _cmb, _cma;
1846       _cu = ENFN->context_clip_get(ENC, context, &_cx, &_cy, &_cw, &_ch);
1847       _cc = ENFN->context_color_get(ENC, context, &_cr, &_cg, &_cb, &_ca);
1848       _cm = ENFN->context_multiplier_get(ENC, context, &_cmr, &_cmg, &_cmb, &_cma);
1849       RD(level, "  context clip: [%d] %d,%d %dx%d ; color: [%d] {%d,%d,%d,%d} ; mult: [%d] {%d,%d,%d,%d}\n",
1850          _cu, _cx, _cy, _cw, _ch, _cc, _cr, _cg, _cb, _ca, _cm, _cmr, _cmg, _cmb, _cma);
1851    }
1852 #endif
1853 
1854    if (mapped)
1855      {
1856         if (_evas_render_object_is_mask(obj))
1857           {
1858              RD(level, "  is mask: redraw:%d sfc:%p\n", obj->mask->redraw, obj->mask->surface);
1859              if (surface != obj->mask->surface)
1860                {
1861                   RD(level, "  not rendering mask surface\n");
1862                   RD(level, "}\n");
1863                   eina_evlog("-render_object", eo_obj, 0.0, NULL);
1864                   return EINA_FALSE;
1865                }
1866              // else don't return: draw mask in its surface
1867           }
1868         else if (proxy_src_clip)
1869           {
1870              if (!evas->is_frozen) /* same as "if (proxy_render_data)" */
1871                {
1872                   if ((!evas_object_is_visible(obj)) || (obj->clip.clipees)
1873                       || (obj->cur->have_clipees) || (obj->no_render))
1874                     {
1875                        IFRD(obj->no_render, level, "  no_render\n");
1876                        IFRD(obj->clip.clipees || obj->cur->have_clipees, level, "  has clippees\n");
1877                        IFRD(!evas_object_is_visible(obj), level, "  not visible\n");
1878                        RD(level, "}\n");
1879                        eina_evlog("-render_object", eo_obj, 0.0, NULL);
1880                        return EINA_FALSE;
1881                     }
1882                }
1883              else
1884                {
1885                   /* can not trust cache.clip - evas is frozen */
1886                   if (!obj->cur->visible || obj->clip.clipees || (obj->no_render && !proxy_render_data) ||
1887                       (!obj->cur->color.a && (obj->cur->render_op == EVAS_RENDER_BLEND)))
1888                     {
1889                        IFRD(obj->no_render, level, "  proxy_src_clip + no_render\n");
1890                        IFRD(obj->clip.clipees || obj->cur->have_clipees, level, "  proxy_src_clip + has clippees\n");
1891                        IFRD(!obj->cur->visible, level, "  proxy_src_clip + not visible\n");
1892                        IFRD(!obj->cur->color.a && (obj->cur->render_op == EVAS_RENDER_BLEND), level, "  proxy_src_clip + 0 alpha\n");
1893                        RD(level, "}\n");
1894                        eina_evlog("-render_object", eo_obj, 0.0, NULL);
1895                        return EINA_FALSE;
1896                     }
1897                   else if (proxy_render_data && (surface != obj->proxy->surface) &&
1898                            obj->proxy->src_invisible)
1899                     {
1900                        RD(level, "  src_invisible + not proxy surface (recursive proxies)\n");
1901                        RD(level, "}\n");
1902                        eina_evlog("-render_object", eo_obj, 0.0, NULL);
1903                        return EINA_FALSE;
1904                     }
1905                }
1906           }
1907         else if (!evas_object_is_proxy_visible(obj) ||
1908                  (obj->clip.clipees) || (obj->cur->have_clipees))
1909           {
1910              IFRD(!evas_object_is_proxy_visible(obj), level, "  proxy not visible\n");
1911              IFRD(obj->clip.clipees || obj->cur->have_clipees, level, "  has clippees\n");
1912              RD(level, "}\n");
1913              eina_evlog("-render_object", eo_obj, 0.0, NULL);
1914              return EINA_FALSE;
1915           }
1916         else if (obj->no_render && (surface != obj->proxy->surface))
1917           {
1918              RD(level, "  no_render\n");
1919              RD(level, "}\n");
1920              eina_evlog("-render_object", eo_obj, 0.0, NULL);
1921              return EINA_FALSE;
1922           }
1923      }
1924    else if (!(((evas_object_is_active(eo_obj, obj) && (!obj->clip.clipees) &&
1925                 (_evas_render_can_render(obj))))
1926              ))
1927      {
1928         IFRD(!evas_object_is_active(eo_obj, obj), level, "  not active\n");
1929         IFRD(!_evas_render_can_render(obj), level, "  can't render\n");
1930         IFRD(obj->clip.clipees, level, "  has clippees\n");
1931         RD(level, "}\n");
1932         eina_evlog("-render_object", eo_obj, 0.0, NULL);
1933         return EINA_FALSE;
1934      }
1935 
1936    // set render_pre - for child objs that may not have gotten it.
1937    obj->pre_render_done = EINA_TRUE;
1938    RD(level, "  hasmap: %s [can_map: %d] cur.map:%p cur.usemap:%d\n",
1939       _evas_render_has_map(obj) ? "yes" : "no",
1940       obj->func->can_map ? obj->func->can_map(eo_obj): -1,
1941       obj->map->cur.map, obj->map->cur.usemap);
1942    if (_evas_render_has_map(obj) && !_evas_render_can_map(obj))
1943      {
1944         int sw, sh;
1945         Eina_Bool changed = EINA_FALSE, rendered = EINA_FALSE, pchanged = EINA_FALSE;
1946 
1947         clean_them = EINA_TRUE;
1948 
1949         sw = obj->cur->geometry.w;
1950         sh = obj->cur->geometry.h;
1951         RD(level, "  surf size: %ix%i\n", sw, sh);
1952         if ((sw <= 0) || (sh <= 0)) goto end;
1953 
1954         pchanged = evas_object_map_update(eo_obj, off_x, off_y, sw, sh, sw, sh);
1955 
1956         if (obj->map->surface)
1957           {
1958              if ((obj->map->surface_w != sw) ||
1959                  (obj->map->surface_h != sh))
1960                {
1961                   RD(level, "  new surf: %ix%i\n", sw, sh);
1962                   EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
1963                     {
1964                        ENFN->image_free(ENC, map_write->surface);
1965                        map_write->surface = NULL;
1966                     }
1967                   EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
1968                }
1969           }
1970         if (!obj->map->surface)
1971           {
1972              EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
1973                {
1974                   map_write->surface_w = sw;
1975                   map_write->surface_h = sh;
1976 
1977                   map_write->surface = ENFN->image_map_surface_new
1978                         (ENC, map_write->surface_w,
1979                          map_write->surface_h,
1980                          map_write->cur.map->alpha);
1981                }
1982              EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
1983 
1984              RD(level, "  first surf: %ix%i\n", sw, sh);
1985              changed = EINA_TRUE;
1986           }
1987 
1988         if (!changed) changed = evas_object_smart_changed_get(obj);
1989 
1990         /* mark the old map as invalid, so later we don't reuse it as a
1991          * cache. */
1992         if (pchanged && obj->map->prev.map)
1993           {
1994              EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
1995                map_write->prev.valid_map = EINA_FALSE;
1996              EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
1997           }
1998 
1999         // clear surface before re-render
2000         if ((changed) && (obj->map->surface))
2001           {
2002              int off_x2, off_y2;
2003 
2004              RD(level, "  children redraw\n");
2005              // FIXME: calculate "changes" within map surface and only clear
2006              // and re-render those
2007              if (obj->map->cur.map->alpha)
2008                {
2009                   ctx = ENFN->context_new(ENC);
2010                   ENFN->context_color_set(ENC, ctx, 0, 0, 0, 0);
2011                   ENFN->context_render_op_set(ENC, ctx, EVAS_RENDER_COPY);
2012                   ENFN->rectangle_draw(ENC, output, ctx, obj->map->surface,
2013                                        0, 0, obj->map->surface_w, obj->map->surface_h,
2014                                        EINA_FALSE);
2015                   ENFN->context_free(ENC, ctx);
2016                }
2017              ctx = ENFN->context_new(ENC);
2018              off_x2 = -obj->cur->geometry.x;
2019              off_y2 = -obj->cur->geometry.y;
2020              if (obj->is_smart)
2021                {
2022                   EINA_INLIST_FOREACH
2023                      (evas_object_smart_members_get_direct(eo_obj), obj2)
2024                        {
2025                           clean_them |= evas_render_mapped(evas, obj2->object,
2026                                                            obj2, ctx,
2027                                                            output, obj->map->surface,
2028                                                            off_x2, off_y2, 1,
2029                                                            ecx, ecy, ecw, ech,
2030                                                            proxy_render_data,
2031                                                            level + 1, do_async);
2032                           /* We aren't sure this object will be rendered by
2033                              normal(not proxy) drawing after, we reset this
2034                              only in case of normal drawing. For optmizing,
2035                              push this object in an array then reset them
2036                              in the end of the rendering.*/
2037                           if (!proxy_render_data)
2038                             evas_object_change_reset(obj2);
2039                        }
2040                }
2041              else
2042                {
2043                   int x = 0, y = 0, w = 0, h = 0;
2044 
2045                   w = obj->map->surface_w;
2046                   h = obj->map->surface_h;
2047                   RECTS_CLIP_TO_RECT(x, y, w, h,
2048                                      obj->cur->geometry.x + off_x2,
2049                                      obj->cur->geometry.y + off_y2,
2050                                      obj->cur->geometry.w,
2051                                      obj->cur->geometry.h);
2052 
2053                   ENFN->context_clip_set(ENC, ctx, x, y, w, h);
2054 #ifdef REND_DBG
2055                   int _c, _cx, _cy, _cw, _ch;
2056                   _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2057                   RD(level, "  draw mapped obj: render(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2058 #endif
2059                   // FIXME: Should this really be sync render?
2060                   obj->func->render(eo_obj, obj, obj->private_data,
2061                                     ENC, output, ctx,
2062                                     obj->map->surface, off_x2, off_y2,
2063                                     EINA_FALSE);
2064                }
2065              ENFN->context_free(ENC, ctx);
2066              rendered = EINA_TRUE;
2067           }
2068 
2069         if (rendered)
2070           {
2071              EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
2072                {
2073                   map_write->surface = ENFN->image_dirty_region
2074                     (ENC, map_write->surface,
2075                      0, 0, map_write->surface_w, map_write->surface_h);
2076 
2077                   map_write->cur.valid_map = EINA_TRUE;
2078                }
2079              EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
2080           }
2081 
2082         /* duplicate context and reset clip */
2083         // FIXME: Shouldn't we use a new, clean context?
2084         ctx = ENFN->context_dup(ENC, context);
2085         ENFN->context_clip_unset(ENC, ctx);
2086         //ENFN->context_multiplier_unset(ENC, ctx); // this probably should be here, too
2087 
2088         if (obj->map->surface)
2089           {
2090              Evas_Object_Protected_Data *mask = obj->clip.mask;
2091 
2092              if (obj->cur->clipper)
2093                {
2094                   evas_object_clip_recalc(obj);
2095 
2096                   if (obj->is_smart)
2097                     {
2098                        EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
2099                          {
2100                             state_write->cache.clip.dirty = EINA_TRUE;
2101                          }
2102                        EINA_COW_STATE_WRITE_END(obj, state_write, cur);
2103                     }
2104                   _evas_render_mapped_context_clip_set(evas, eo_obj, obj, ctx,
2105                                                        proxy_render_data, off_x,
2106                                                        off_y);
2107 
2108                   /* Clipper masks */
2109                   _evas_render_mapped_mask(evas, obj, mask, proxy_render_data, output, ctx, off_x, off_y, level, do_async);
2110                }
2111 
2112              if (obj->cur->cache.clip.visible || !proxy_src_clip)
2113                {
2114                   if (!mapped)
2115                     {
2116                        ENFN->context_clip_clip(ENC, ctx, ecx, ecy, ecw, ech);
2117                        if (!_is_obj_in_framespace(obj, evas))
2118                          {
2119                             _evas_render_framespace_context_clip_clip
2120                                   (evas, ctx, off_x - evas->framespace.x, off_y - evas->framespace.y);
2121                          }
2122                     }
2123                   ENFN->context_multiplier_unset(ENC, ctx);
2124                   ENFN->context_render_op_set(ENC, ctx, obj->cur->render_op);
2125 #ifdef REND_DBG
2126                   int _c, _cx, _cy, _cw, _ch;
2127                   _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2128                   RD(level, "  draw image map(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2129 #endif
2130                   evas_draw_image_map_async_check
2131                     (obj, ENC, output, ctx, surface,
2132                      obj->map->surface, obj->map->spans,
2133                      obj->map->cur.map->smooth, 0, do_async);
2134                }
2135           }
2136 
2137         ENFN->context_free(ENC, ctx);
2138 
2139         // FIXME: needs to cache these maps and
2140         // keep them only rendering updates
2141      }
2142    else // not "has map"
2143      {
2144         ctx = ENFN->context_dup(ENC, context);
2145         if (mapped)
2146           {
2147              RD(level, "  child of mapped obj\n");
2148 
2149              if (obj->is_smart)
2150                {
2151                   /* Clipper masks */
2152                   if (obj->cur->clipper && (mapped > 1) &&
2153                       _evas_render_object_is_mask(obj->cur->clipper))
2154                     _evas_render_mapped_mask(evas, obj, obj->cur->clipper, proxy_render_data, output, ctx, off_x, off_y, level, do_async);
2155                   else if (!proxy_src_clip && proxy_render_data)
2156                     {
2157                        if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
2158                          goto on_empty_clip;
2159                     }
2160 
2161 #ifdef REND_DBG
2162                   int _c, _cx, _cy, _cw, _ch;
2163                   _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2164                   RD(level, "  draw smart children(clip: [%d] %d,%d %dx%d)\n",
2165                      _c, _cx, _cy, _cw, _ch);
2166 #endif
2167 
2168                   EINA_INLIST_FOREACH
2169                      (evas_object_smart_members_get_direct(eo_obj), obj2)
2170                        {
2171                           /* skip proxy object if its source is its smart parent.
2172                              who makes this relation? a proxy object working for
2173                              a smart object to set a filter program. the proxy
2174                              object should be a member of smart object to sync
2175                              stacking changes. */
2176                           if (obj2->is_filter_object) continue;
2177 
2178                           clean_them |= evas_render_mapped(evas, obj2->object,
2179                                                            obj2, ctx,
2180                                                            output, surface,
2181                                                            off_x, off_y, mapped + 1,
2182                                                            ecx, ecy, ecw, ech,
2183                                                            proxy_render_data,
2184                                                            level + 1, do_async);
2185                           /* We aren't sure this object will be rendered by
2186                              normal(not proxy) drawing after, we reset this
2187                              only in case of normal drawing. For optmizing,
2188                              push this object in an array then reset them
2189                              in the end of the rendering.*/
2190                           if (!proxy_render_data)
2191                             evas_object_change_reset(obj2);
2192                        }
2193                }
2194              else
2195                {
2196                   const Eina_Rectangle *clip = &obj->cur->geometry;
2197                   ENFN->context_clip_clip(ENC, ctx, clip->x + off_x, clip->y + off_y, clip->w, clip->h);
2198 
2199                   if (obj->cur->clipper && (mapped > 1))
2200                     {
2201                        Evas_Object_Protected_Data *mask = obj->clip.mask;
2202 
2203                        if (obj->mask->surface != surface)
2204                          {
2205                             if (proxy_src_clip)
2206                               {
2207                                  if ((_evas_render_has_map(obj) && !_evas_render_can_map(obj)) ||
2208                                      _evas_render_object_is_mask(obj->cur->clipper))
2209                                    evas_object_clip_recalc(obj);
2210                                  _evas_render_mapped_context_clip_set(evas, eo_obj, obj, ctx,
2211                                                                       proxy_render_data,
2212                                                                       off_x, off_y);
2213                               }
2214                             else if (proxy_render_data)
2215                               {
2216                                  if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
2217                                    goto on_empty_clip;
2218                               }
2219                          }
2220                        else
2221                          {
2222                             // rendering a mask in its own surface:
2223                             // we want to render it fully and clip only at
2224                             // clippee (maskee) render time
2225                             RD(level, "  draw mask\n");
2226                          }
2227 
2228                        /* Clipper masks */
2229                        _evas_render_mapped_mask(evas, obj, mask, proxy_render_data, output, ctx, off_x, off_y, level, do_async);
2230                     }
2231 
2232 #ifdef REND_DBG
2233                   int _c, _cx, _cy, _cw, _ch;
2234                   _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2235                   RD(level, "  render(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2236 #endif
2237 
2238                   obj->func->render(eo_obj, obj, obj->private_data,
2239                                     ENC, output, ctx, surface, off_x, off_y, do_async);
2240                }
2241           }
2242         else if (!obj->is_smart)
2243           {
2244              if (obj->cur->clipper)
2245                {
2246                   Evas_Object_Protected_Data *clipper = obj->cur->clipper;
2247                   int x, y, w, h;
2248 
2249                   if (proxy_src_clip)
2250                     {
2251                        if ((_evas_render_has_map(obj) && !_evas_render_can_map(obj)) ||
2252                            _evas_render_object_is_mask(obj->cur->clipper))
2253                          evas_object_clip_recalc(obj);
2254                        x = obj->cur->cache.clip.x;
2255                        y = obj->cur->cache.clip.y;
2256                        w = obj->cur->cache.clip.w;
2257                        h = obj->cur->cache.clip.h;
2258                        RECTS_CLIP_TO_RECT(x, y, w, h,
2259                                           clipper->cur->cache.clip.x,
2260                                           clipper->cur->cache.clip.y,
2261                                           clipper->cur->cache.clip.w,
2262                                           clipper->cur->cache.clip.h);
2263                        ENFN->context_clip_set(ENC, ctx, x + off_x, y + off_y, w, h);
2264                        if (!_is_obj_in_framespace(obj, evas))
2265                          {
2266                             _evas_render_framespace_context_clip_clip
2267                                   (evas, ctx, off_x - evas->framespace.x, off_y - evas->framespace.y);
2268                          }
2269 
2270                        ENFN->context_clip_clip(ENC, ctx, ecx, ecy, ecw, ech);
2271                     }
2272                   else if (proxy_render_data)
2273                     {
2274                        if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
2275                          goto on_empty_clip;
2276                     }
2277                }
2278              else if (!_is_obj_in_framespace(obj, evas))
2279                {
2280                   _evas_render_framespace_context_clip_clip
2281                         (evas, ctx, off_x - evas->framespace.x, off_y - evas->framespace.y);
2282                }
2283 
2284 #ifdef REND_DBG
2285              int _c, _cx, _cy, _cw, _ch;
2286              _c = ENFN->context_clip_get(ENC, context, &_cx, &_cy, &_cw, &_ch);
2287              RD(level, "  draw normal obj: render(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2288 #endif
2289 
2290              obj->func->render(eo_obj, obj, obj->private_data,
2291                                ENC, output, ctx, surface,
2292                                off_x, off_y, do_async);
2293           }
2294         if (obj->changed_map) clean_them = EINA_TRUE;
2295 
2296 on_empty_clip:
2297         ENFN->context_free(ENC, ctx);
2298      }
2299 
2300 end:
2301    RD(level, "}\n");
2302    obj->pre_render_done = was_pre_render_done;
2303    eina_evlog("-render_object", eo_obj, 0.0, NULL);
2304    return clean_them;
2305 }
2306 
2307 /*
2308  * Render the source object when a proxy is set.
2309  * Used to force a draw if necessary, else just makes sure it's available.
2310  * Called from: image objects and text with filters.
2311  */
2312 void
evas_render_proxy_subrender(Evas * eo_e,void * output,Evas_Object * eo_source,Evas_Object * eo_proxy,Evas_Object_Protected_Data * proxy_obj,Eina_Bool source_clip,Eina_Bool do_async)2313 evas_render_proxy_subrender(Evas *eo_e, void *output, Evas_Object *eo_source, Evas_Object *eo_proxy,
2314                             Evas_Object_Protected_Data *proxy_obj,
2315                             Eina_Bool source_clip, Eina_Bool do_async)
2316 {
2317    Evas_Public_Data *evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
2318    Evas_Object_Protected_Data *source, *proxy;
2319    int level = 1;
2320    void *ctx;
2321    int w, h, off_x = 0, off_y = 0;
2322    Eina_Rectangle lr = {0, 0, 0, 0};
2323 
2324 #ifdef REND_DBG
2325    level = __RD_level;
2326 #endif
2327 
2328    if (!eo_source) return;
2329    eina_evlog("+proxy_subrender", eo_proxy, 0.0, NULL);
2330    source = efl_data_scope_get(eo_source, EFL_CANVAS_OBJECT_CLASS);
2331    proxy = efl_data_scope_get(eo_proxy, EFL_CANVAS_OBJECT_CLASS);
2332 
2333    evas_object_image_load_region_get(eo_proxy, &lr.x, &lr.y, &lr.w, &lr.h);
2334 
2335    if (lr.w > 0 && lr.h > 0)
2336      {
2337         w = lr.w;
2338         h = lr.h;
2339         off_x = -lr.x;
2340         off_y = -lr.y;
2341      }
2342    else if (proxy->proxy->proxies || (!proxy->cur->clipper) || (!proxy->cur->has_fixed_size))
2343      {
2344         /* make full surface available if this proxy is being sampled from */
2345         w = source->cur->geometry.w;
2346         h = source->cur->geometry.h;
2347      }
2348    else
2349      {
2350         Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(proxy->cur);
2351         /* nothing is using this proxy, so the proxy render surface can be sized
2352          * to fit exactly the proxy object's render size, and the proxy render will
2353          * naturally be clipped to this geometry
2354          */
2355         w = clip.w;
2356         h = clip.h;
2357         /* set the render offset for the proxy offset based on the geometry which will
2358          * be visible on the proxy surface after clipping
2359          */
2360         off_x = proxy->cur->geometry.x - clip.x;
2361         off_y = proxy->cur->geometry.y - clip.y;
2362      }
2363 
2364    RD(level, "  proxy_subrender(source: %s, proxy: %s, %dx%d)\n",
2365       RDNAME(source), RDNAME(proxy_obj), w, h);
2366 
2367    EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
2368                         Evas_Object_Proxy_Data, proxy_write)
2369      {
2370         proxy_write->redraw = EINA_FALSE;
2371 
2372         /* We need to redraw surface then */
2373         if ((proxy_write->surface) &&
2374             ((proxy_write->w != w) || (proxy_write->h != h)))
2375           {
2376              RD(level, "  free surface: %p\n", proxy_write->surface);
2377              ENFN->image_free(ENC, proxy_write->surface);
2378              proxy_write->surface = NULL;
2379           }
2380 
2381         /* FIXME: Hardcoded alpha 'on' */
2382         /* FIXME (cont): Should see if the object has alpha */
2383         if (!proxy_write->surface)
2384           {
2385              if ((w < 1) || (h < 1)) goto end;
2386              proxy_write->surface = ENFN->image_map_surface_new(ENC, w, h, 1);
2387              RD(level, "  created surface: %p %dx%d\n", proxy_write->surface, w, h);
2388              if (!proxy_write->surface) goto end;
2389              proxy_write->w = w;
2390              proxy_write->h = h;
2391           }
2392 
2393         eina_evlog("+proxy_fill", eo_proxy, 0.0, NULL);
2394         ctx = ENFN->context_new(ENC);
2395         ENFN->context_color_set(ENC, ctx, 0, 0,0, 0);
2396         ENFN->context_render_op_set(ENC, ctx, EVAS_RENDER_COPY);
2397         ENFN->rectangle_draw(ENC, output, ctx, proxy_write->surface, 0, 0, w, h, do_async);
2398         ENFN->context_free(ENC, ctx);
2399         eina_evlog("-proxy_fill", eo_proxy, 0.0, NULL);
2400 
2401         Evas_Proxy_Render_Data proxy_render_data = {
2402              .eo_proxy = eo_proxy,
2403              .proxy_obj = proxy_obj,
2404              .eo_src = eo_source,
2405              .src_obj = source,
2406              .source_clip = source_clip
2407         };
2408 
2409         /* protect changes to the objects' cache.clip */
2410         evas_event_freeze(evas->evas);
2411 
2412         ctx = ENFN->context_new(ENC);
2413         evas_render_mapped(evas, eo_source, source, ctx,
2414                            output, proxy_write->surface,
2415                            -source->cur->geometry.x + off_x,
2416                            -source->cur->geometry.y + off_y,
2417                            level + 1, 0, 0, evas->output.w, evas->output.h,
2418                            &proxy_render_data, level + 1, do_async);
2419         ENFN->context_free(ENC, ctx);
2420 
2421         proxy_write->surface = ENFN->image_dirty_region(ENC, proxy_write->surface, 0, 0, w, h);
2422 
2423         /* restore previous state */
2424         evas_event_thaw(evas->evas);
2425      }
2426  end:
2427    EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write);
2428    eina_evlog("-proxy_subrender", eo_proxy, 0.0, NULL);
2429 }
2430 
2431 /* @internal
2432  * Synchronously render a mask image (or smart object) into a surface.
2433  * In SW the target surface will be ALPHA only (GRY8), after conversion.
2434  * In GL the target surface will be RGBA for now. TODO: Find out how to
2435  *   render GL to alpha, if that's possible.
2436  */
2437 static void
evas_render_mask_subrender(Evas_Public_Data * evas,void * output,Evas_Object_Protected_Data * mask,Evas_Object_Protected_Data * prev_mask,int level,Eina_Bool do_async)2438 evas_render_mask_subrender(Evas_Public_Data *evas,
2439                            void *output,
2440                            Evas_Object_Protected_Data *mask,
2441                            Evas_Object_Protected_Data *prev_mask,
2442                            int level, Eina_Bool do_async)
2443 {
2444    int x, y, w, h, r, g, b, a, cr, cg, cb, ca;
2445    Eina_Bool is_image, done = EINA_FALSE, restore_state = EINA_FALSE;
2446    void *ctx;
2447 
2448    if (!mask) return;
2449 
2450    eina_evlog("+mask_subrender", mask->object, 0.0, NULL);
2451    RD(level, "evas_render_mask_subrender(mask: %s, prev: %s, %s)\n",
2452       RDNAME(mask), RDNAME(prev_mask), do_async ? "async" : "sync");
2453 
2454    is_image = efl_isa(mask->object, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
2455 
2456    x = mask->cur->geometry.x;
2457    y = mask->cur->geometry.y;
2458    w = mask->cur->geometry.w;
2459    h = mask->cur->geometry.h;
2460    if (mask->cur->clipper && mask->cur->has_fixed_size)
2461      {
2462         Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(mask->cur);
2463         x = clip.x;
2464         y = clip.y;
2465         w = clip.w;
2466         h = clip.h;
2467      }
2468 
2469    r = mask->cur->color.r;
2470    g = mask->cur->color.g;
2471    b = mask->cur->color.b;
2472    a = mask->cur->color.a;
2473    cr = mask->cur->cache.clip.r;
2474    cg = mask->cur->cache.clip.g;
2475    cb = mask->cur->cache.clip.b;
2476    ca = mask->cur->cache.clip.a;
2477    if ((r != 255) || (g != 255) || (b != 255) || (a != 255) ||
2478        (cr != 255) || (cg != 255) || (cb != 255) || (ca != 255))
2479      {
2480         restore_state = EINA_TRUE;
2481         EINA_COW_STATE_WRITE_BEGIN(mask, state_write, cur)
2482           {
2483              state_write->color.r = 255;
2484              state_write->color.g = 255;
2485              state_write->color.b = 255;
2486              state_write->color.a = 255;
2487              state_write->cache.clip.r = 255;
2488              state_write->cache.clip.g = 255;
2489              state_write->cache.clip.b = 255;
2490              state_write->cache.clip.a = 255;
2491         }
2492         EINA_COW_STATE_WRITE_END(mask, state_write, cur);
2493      }
2494 
2495    // For SW engine, we want sync render of masks to be able to convert the
2496    // surface from RGBA to Alpha. See below. (this logic could be improved)
2497    if (!ENFN->gl_surface_read_pixels)
2498      do_async = EINA_FALSE;
2499 
2500    if (prev_mask == mask)
2501      prev_mask = NULL;
2502 
2503    if (prev_mask)
2504      {
2505         if (!prev_mask->mask->is_mask)
2506           {
2507              ERR("Passed invalid mask that is not a mask");
2508              prev_mask = NULL;
2509           }
2510         else if (!prev_mask->mask->surface)
2511           {
2512              // Note: This is preventive code. Never seen it happen.
2513              WRN("Mask render order may be invalid");
2514              evas_render_mask_subrender(evas, output, prev_mask, prev_mask->clip.prev_mask, level + 1, do_async);
2515           }
2516      }
2517 
2518    EINA_COW_WRITE_BEGIN(evas_object_mask_cow, mask->mask, Evas_Object_Mask_Data, mdata)
2519      mdata->redraw = EINA_FALSE;
2520 
2521      if (is_image && ENFN->image_scaled_update)
2522        {
2523           Eina_Bool filled = EINA_FALSE, border = EINA_FALSE;
2524           int bl = 0, br = 0, bt = 0, bb = 0;
2525 
2526           if (evas_object_image_filled_get(mask->object))
2527             filled = EINA_TRUE;
2528           else
2529             {
2530                int fx, fy, fw, fh;
2531                evas_object_image_fill_get(mask->object, &fx, &fy, &fw, &fh);
2532                if ((fx == 0) && (fy == 0) && (fw == mask->cur->geometry.w) && (fh == mask->cur->geometry.h))
2533                  filled = EINA_TRUE;
2534             }
2535 
2536           evas_object_image_border_get(mask->object, &bl, &br, &bt, &bb);
2537           if (bl || br || bt || bb)
2538             border = EINA_TRUE;
2539 
2540           if (!border && filled && !prev_mask && mask->func->engine_data_get)
2541             {
2542                eina_evlog("+mask_scaled_update", mask->object, 0.0, NULL);
2543                /* Fast path (for GL) that avoids creating a map surface, render the
2544                 * scaled image in it, when the shaders can just scale on the fly. */
2545                Eina_Bool smooth = evas_object_image_smooth_scale_get(mask->object);
2546                void *original = mask->func->engine_data_get(mask->object);
2547                void *scaled = ENFN->image_scaled_update
2548                  (ENC, mdata->surface, original, w, h, smooth, EVAS_COLORSPACE_GRY8);
2549                if (scaled)
2550                  {
2551                     done = EINA_TRUE;
2552                     mdata->surface = scaled;
2553                     mdata->w = w;
2554                     mdata->h = h;
2555                     mdata->is_alpha = (ENFN->image_colorspace_get(ENC, scaled) == EVAS_COLORSPACE_GRY8);
2556                     mdata->is_scaled = EINA_TRUE;
2557                  }
2558                eina_evlog("-mask_scaled_update", mask->object, 0.0, NULL);
2559             }
2560        }
2561 
2562      if (!done)
2563        {
2564           /* delete render surface if changed or if already alpha
2565            * (we don't know how to render objects to alpha) */
2566           if (mdata->surface && ((w != mdata->w) || (h != mdata->h) || mdata->is_alpha || mdata->is_scaled))
2567             {
2568                ENFN->image_free(ENC, mdata->surface);
2569                mdata->surface = NULL;
2570             }
2571 
2572           /* create new RGBA render surface if needed */
2573           if (!mdata->surface)
2574             {
2575                eina_evlog("+mask_surface_new", mask->object, 0.0, NULL);
2576                mdata->surface = ENFN->image_map_surface_new(ENC, w, h, EINA_TRUE);
2577                eina_evlog("-mask_surface_new", mask->object, 0.0, NULL);
2578                if (!mdata->surface) goto end;
2579                mdata->is_alpha = EINA_FALSE;
2580                mdata->is_scaled = EINA_FALSE;
2581                mdata->w = w;
2582                mdata->h = h;
2583             }
2584 
2585           /* Clear surface with transparency */
2586           eina_evlog("+mask_rect_clear", mask->object, 0.0, NULL);
2587           ctx = ENFN->context_new(ENC);
2588           ENFN->context_color_set(ENC, ctx, 0, 0, 0, 0);
2589           ENFN->context_render_op_set(ENC, ctx, EVAS_RENDER_COPY);
2590           ENFN->rectangle_draw(ENC, output, ctx, mdata->surface, 0, 0, w, h, do_async);
2591           ENFN->context_free(ENC, ctx);
2592           eina_evlog("-mask_rect_clear", mask->object, 0.0, NULL);
2593 
2594           /* Render mask to RGBA surface */
2595           ctx = ENFN->context_new(ENC);
2596           if (prev_mask)
2597             {
2598                Eina_Rectangle pclip = _evas_render_smallest_static_clipped_geometry_get(prev_mask->cur);
2599                ENFN->context_clip_image_set(ENC, ctx,
2600                                             prev_mask->mask->surface,
2601                                             pclip.x - x,
2602                                             pclip.y - y,
2603                                             evas, do_async);
2604                ENFN->context_clip_set(ENC, ctx,
2605                                       pclip.x - x,
2606                                       pclip.y - y,
2607                                       pclip.w,
2608                                       pclip.h);
2609             }
2610 
2611           if (EINA_LIKELY(!mask->is_smart))
2612             {
2613                mask->func->render(mask->object, mask, mask->private_data,
2614                                   ENC, output, ctx, mdata->surface, -x, -y, do_async);
2615             }
2616           else
2617             {
2618                // Unreachable code until we implement support for smart masks
2619                evas_render_mapped(evas, mask->object, mask, ctx,
2620                                   output, mdata->surface,
2621                                   -x, -y, 2, 0, 0, evas->output.w, evas->output.h,
2622                                   NULL, level, do_async);
2623             }
2624           ENFN->context_free(ENC, ctx);
2625 
2626           /* BEGIN HACK */
2627 
2628           /* Now we want to convert this RGBA surface to Alpha.
2629            * NOTE: So, this is not going to work with the GL engine but only with
2630            *       the SW engine. Here's the detection hack:
2631            * FIXME: If you know of a way to support rendering to GL_ALPHA in GL,
2632            *        then we should render directly to an ALPHA surface. A priori,
2633            *        GLES FBO does not support this.
2634            */
2635           if (!ENFN->gl_surface_read_pixels)
2636             {
2637                RGBA_Image *alpha_surface;
2638                DATA32 *rgba;
2639                DATA8* alpha;
2640 
2641                eina_evlog("+mask_new_cpy_data", mask->object, 0.0, NULL);
2642                alpha_surface = ENFN->image_new_from_copied_data
2643                      (ENC, w, h, NULL, EINA_TRUE, EVAS_COLORSPACE_GRY8);
2644                eina_evlog("-mask_new_cpy_data", mask->object, 0.0, NULL);
2645                if (!alpha_surface) goto end;
2646 
2647                eina_evlog("+mask_cpy_data", mask->object, 0.0, NULL);
2648                /* Copy alpha channel */
2649                rgba = ((RGBA_Image *) mdata->surface)->image.data;
2650                alpha = alpha_surface->image.data8;
2651                for (y = h; y; --y)
2652                  for (x = w; x; --x, alpha++, rgba++)
2653                    *alpha = (DATA8) A_VAL(rgba);
2654                eina_evlog("-mask_cpy_data", mask->object, 0.0, NULL);
2655 
2656                /* Now we can drop the original surface */
2657                ENFN->image_free(ENC, mdata->surface);
2658                mdata->surface = alpha_surface;
2659                mdata->is_alpha = EINA_TRUE;
2660             }
2661           /* END OF HACK */
2662        }
2663 
2664      mdata->surface = ENFN->image_dirty_region(ENC, mdata->surface, 0, 0, w, h);
2665 
2666 end:
2667    EINA_COW_WRITE_END(evas_object_mask_cow, mask->mask, mdata);
2668 
2669    if (restore_state)
2670      {
2671         EINA_COW_STATE_WRITE_BEGIN(mask, state_write, cur)
2672           {
2673              state_write->color.r = r;
2674              state_write->color.g = g;
2675              state_write->color.b = b;
2676              state_write->color.a = a;
2677              state_write->cache.clip.r = cr;
2678              state_write->cache.clip.g = cg;
2679              state_write->cache.clip.b = cb;
2680              state_write->cache.clip.a = ca;
2681           }
2682         EINA_COW_STATE_WRITE_END(mask, state_write, cur);
2683      }
2684    eina_evlog("-mask_subrender", mask->object, 0.0, NULL);
2685 }
2686 
2687 static void
_evas_render_cutout_add(Evas_Public_Data * evas,void * context,Evas_Object_Protected_Data * obj,int off_x,int off_y,Cutout_Margin * cutout_margin)2688 _evas_render_cutout_add(Evas_Public_Data *evas, void *context,
2689                         Evas_Object_Protected_Data *obj, int off_x, int off_y,
2690                         Cutout_Margin *cutout_margin)
2691 {
2692    Evas_Coord cox = 0, coy = 0, cow = 0, coh = 0;
2693 
2694    if (evas_object_is_source_invisible(obj->object, obj)) return;
2695    if (evas_object_is_opaque(obj))
2696      {
2697         cox = obj->cur->cache.clip.x;
2698         coy = obj->cur->cache.clip.y;
2699         cow = obj->cur->cache.clip.w;
2700         coh = obj->cur->cache.clip.h;
2701         if ((obj->map->cur.map) && (obj->map->cur.usemap))
2702           {
2703              Evas_Object_Protected_Data *oo;
2704 
2705              for (oo = obj; oo->cur->clipper; oo = oo->cur->clipper)
2706                {
2707                   if ((oo->cur->clipper->map->cur.map_parent
2708                        != oo->map->cur.map_parent) &&
2709                       (!((oo->map->cur.map) && (oo->map->cur.usemap))))
2710                     break;
2711                   RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
2712                                      oo->cur->geometry.x,
2713                                      oo->cur->geometry.y,
2714                                      oo->cur->geometry.w,
2715                                      oo->cur->geometry.h);
2716                   if ((cow <= 0) || (coh <= 0)) return;
2717                }
2718           }
2719      }
2720    else if (obj->func->get_opaque_rect)
2721      {
2722         obj->func->get_opaque_rect(obj->object, obj, obj->private_data, &cox, &coy, &cow, &coh);
2723         if ((cow <= 0) || (coh <= 0)) return;
2724         RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
2725                            obj->cur->cache.clip.x, obj->cur->cache.clip.y,
2726                            obj->cur->cache.clip.w, obj->cur->cache.clip.h);
2727      }
2728    else return;
2729    if (!_is_obj_in_framespace(obj, evas))
2730      {
2731         int fw, fh;
2732 
2733         fw = evas->viewport.w - evas->framespace.w;
2734         fh = evas->viewport.h - evas->framespace.h;
2735         RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
2736                            0, 0, fw, fh);
2737      }
2738    if (cutout_margin)
2739      {
2740         cox += cutout_margin->l;
2741         coy += cutout_margin->t;
2742         cow -= cutout_margin->l + cutout_margin->r;
2743         coh -= cutout_margin->t + cutout_margin->b;
2744      }
2745    if ((cow <= 0) || (coh <= 0)) return;
2746    ENFN->context_cutout_add(ENC, context, cox + off_x, coy + off_y, cow, coh);
2747 }
2748 
2749 void
evas_render_rendering_wait(Evas_Public_Data * evas)2750 evas_render_rendering_wait(Evas_Public_Data *evas)
2751 {
2752    double t0 = ecore_time_get();
2753    while (evas->rendering)
2754      {
2755         evas_async_events_process_blocking();
2756         if ((ecore_time_get() - t0) > 0.2)
2757           {
2758              ERR("timeout waiting for async rendering");
2759              break;
2760           }
2761      }
2762 }
2763 
2764 /*
2765  * Syncs ALL async rendering canvases. Must be called in the main thread.
2766  */
2767 void
evas_all_sync(void)2768 evas_all_sync(void)
2769 {
2770    Evas_Public_Data *evas;
2771 
2772    if (!_rendering_evases) return;
2773 
2774    evas = eina_list_data_get(eina_list_last(_rendering_evases));
2775    evas_render_rendering_wait(evas);
2776 
2777    assert(_rendering_evases == NULL);
2778 }
2779 
2780 static Eina_Bool
_drop_scie_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)2781 _drop_scie_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
2782 {
2783    evas_common_rgba_image_scalecache_item_unref(data);
2784    return EINA_TRUE;
2785 }
2786 
2787 static Eina_Bool
_drop_image_cache_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)2788 _drop_image_cache_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
2789 {
2790    evas_cache_image_drop((Image_Entry *)data);
2791 
2792    return EINA_TRUE;
2793 }
2794 
2795 static void
_cb_always_call(Evas * eo_e,Evas_Public_Data * e,Evas_Callback_Type type,void * event_info)2796 _cb_always_call(Evas *eo_e, Evas_Public_Data *e, Evas_Callback_Type type, void *event_info)
2797 {
2798    int freeze_num = 0, i;
2799 
2800    switch (type)
2801      {
2802       case EVAS_CALLBACK_RENDER_PRE:
2803         if (!e->cb_render_pre) return;
2804         break;
2805       case EVAS_CALLBACK_RENDER_POST:
2806         if (!e->cb_render_post) return;
2807         break;
2808       case EVAS_CALLBACK_RENDER_FLUSH_PRE:
2809         if (!e->cb_render_flush_pre) return;
2810         break;
2811       case EVAS_CALLBACK_RENDER_FLUSH_POST:
2812         if (!e->cb_render_flush_post) return;
2813         break;
2814       default: break;
2815      }
2816    freeze_num = efl_event_freeze_count_get(eo_e);
2817    for (i = 0; i < freeze_num; i++) efl_event_thaw(eo_e);
2818    evas_event_callback_call(eo_e, type, event_info);
2819    for (i = 0; i < freeze_num; i++) efl_event_freeze(eo_e);
2820 }
2821 
2822 #ifndef INLINE_ACTIVE_GEOM
2823 static inline Eina_Bool
_is_obj_in_rect(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,int x,int y,int w,int h)2824 _is_obj_in_rect(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj,
2825                 int x, int y, int w, int h)
2826 {
2827    if (obj->is_smart && !_evas_render_has_map(obj))
2828      {
2829         Eina_Rectangle rect;
2830 
2831         evas_object_smart_bounding_box_get(obj, &rect, NULL);
2832         if (RECTS_INTERSECT(x, y, w, h, rect.x, rect.y, rect.w, rect.h))
2833           return EINA_TRUE;
2834      }
2835    else
2836      {
2837         // FIXME: handle multiple output
2838         if (evas_object_is_in_output_rect(eo_obj, obj, x, y, w, h))
2839           return EINA_TRUE;
2840      }
2841    return EINA_FALSE;
2842 }
2843 #endif
2844 
2845 static void
_snapshot_redraw_update(Evas_Public_Data * evas,Evas_Object_Protected_Data * snap)2846 _snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap)
2847 {
2848    Eina_Bool above = EINA_FALSE, add_rect = EINA_FALSE, need_redraw = EINA_FALSE;
2849    const int x = snap->cur->geometry.x;
2850    const int y = snap->cur->geometry.y;
2851    const int w = snap->cur->geometry.w;
2852    const int h = snap->cur->geometry.h;
2853    Evas_Object_Protected_Data *obj;
2854    Evas_Active_Entry *ent;
2855    Eina_Rectangle snap_clip;
2856    Eina_Tiler *tiler = NULL;
2857    void *surface;
2858 
2859    // FIXME: Tiler should be inside snapshot data
2860    // TODO: Also list redraw regions (partial updates)
2861 
2862    if (!evas_object_is_visible(snap)) return;
2863 
2864    evas_object_clip_recalc(snap);
2865    snap_clip.x = snap->cur->cache.clip.x - x;
2866    snap_clip.y = snap->cur->cache.clip.y - y;
2867    snap_clip.w = snap->cur->cache.clip.w;
2868    snap_clip.h = snap->cur->cache.clip.h;
2869 
2870    surface = _evas_object_image_surface_get(snap, EINA_FALSE);
2871    if (!surface) need_redraw = EINA_TRUE;
2872    if (snap->changed) add_rect = EINA_TRUE;
2873 
2874    if (!add_rect && !need_redraw)
2875      {
2876         // Objects below snapshot
2877         EINA_INARRAY_FOREACH(&evas->active_objects, ent)
2878           {
2879              obj = ent->obj;
2880              if (obj == snap) break;
2881 
2882              if (!obj->is_smart && obj->changed &&
2883                  evas_object_is_in_output_rect(obj->object, obj, x, y, w, h))
2884                need_redraw = EINA_TRUE;
2885           }
2886      }
2887 
2888    if (snap->snapshot_no_obscure || _evas_render_has_map(snap))
2889      goto skip_obscures;
2890 
2891    tiler = eina_tiler_new(w, h);
2892    eina_tiler_tile_size_set(tiler, 1, 1);
2893    eina_tiler_strict_set(tiler, EINA_TRUE);
2894 
2895    // Opaque objects above snapshot
2896    for (unsigned i = 0; i < evas->obscuring_objects.count; i++)
2897      {
2898         obj = eina_array_data_get(&evas->obscuring_objects, i);
2899         if (!above)
2900           {
2901              if (obj == snap) above = EINA_TRUE;
2902              continue;
2903           }
2904         if (!obj->cur->snapshot || evas_object_is_opaque(obj))
2905           {
2906              const Eina_Rectangle cur = {
2907                 obj->cur->cache.clip.x - x, obj->cur->cache.clip.y - y,
2908                 obj->cur->cache.clip.w, obj->cur->cache.clip.h
2909              };
2910 
2911              if (_evas_eina_rectangle_inside(&cur, &snap_clip))
2912                goto end; // Totally hidden
2913 
2914              eina_tiler_rect_add(tiler, &cur);
2915           }
2916      }
2917 
2918 skip_obscures:
2919    need_redraw |= _evas_filter_obscured_regions_set(snap, tiler);
2920    if (memcmp(&snap->cur->geometry, &snap->prev->geometry, sizeof(snap->cur->geometry)))
2921      need_redraw = EINA_TRUE;
2922    snap->snapshot_needs_redraw |= need_redraw;
2923 
2924    if (add_rect || need_redraw)
2925      {
2926         // FIXME: Only add necessary rects (if object itself hasn't changed)
2927         // FIXME: handle multiple output
2928         ENFN->output_redraws_rect_add(ENC, x, y, w, h);
2929      }
2930 
2931 end:
2932    eina_tiler_free(tiler);
2933 }
2934 
2935 static void
evas_render_pre(Evas * eo_e,Evas_Public_Data * evas)2936 evas_render_pre(Evas *eo_e, Evas_Public_Data *evas)
2937 {
2938    Eo *eo_obj;
2939 
2940    if (!evas->finalize_objects) return; // avoid evlog
2941 
2942    // Finalize EO objects now
2943    eina_evlog("+render_pre_objects_finalize", eo_e, 0.0, NULL);
2944 
2945    EINA_LIST_FREE(evas->finalize_objects, eo_obj)
2946      {
2947         Evas_Object_Protected_Data *obj;
2948 
2949         obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2950         if (!EVAS_OBJECT_DATA_ALIVE(obj)) continue;
2951         obj->legacy.finalized = EINA_TRUE;
2952 
2953         if (!obj->legacy.visible_set)
2954           efl_gfx_entity_visible_set(eo_obj, EINA_TRUE);
2955 
2956         // weight should be set during finalize()
2957         if (EINA_UNLIKELY(!obj->legacy.weight_set))
2958           efl_gfx_hint_weight_set(eo_obj, 1.0, 1.0);
2959      }
2960 
2961    eina_evlog("-render_pre_objects_finalize", eo_e, 0.0, NULL);
2962 }
2963 
2964 EAPI void
evas_render_pending_objects_flush(Evas * eo_e)2965 evas_render_pending_objects_flush(Evas *eo_e)
2966 {
2967    Evas_Public_Data *evas = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
2968    EINA_SAFETY_ON_NULL_RETURN(evas);
2969    evas_render_pre(eo_e, evas);
2970 }
2971 
2972 static Eina_Bool
evas_render_updates_internal_loop(Evas * eo_e,Evas_Public_Data * evas,void * output,void * surface,void * context,Evas_Object_Protected_Data * top,int ux,int uy,int uw,int uh,int cx,int cy,int cw,int ch,int fx,int fy,Eina_Bool skip_cutouts,Cutout_Margin * cutout_margin,Eina_Bool alpha,Eina_Bool do_async,unsigned int * offset,int level)2973 evas_render_updates_internal_loop(Evas *eo_e, Evas_Public_Data *evas,
2974                                   void *output, void *surface, void *context,
2975                                   Evas_Object_Protected_Data *top,
2976                                   int ux, int uy, int uw, int uh,
2977                                   int cx, int cy, int cw, int ch,
2978                                   int fx, int fy,
2979                                   Eina_Bool skip_cutouts, Cutout_Margin *cutout_margin,
2980                                   Eina_Bool alpha, Eina_Bool do_async,
2981                                   unsigned int *offset, int level)
2982 {
2983    Evas_Object *eo_obj;
2984    Evas_Object_Protected_Data *obj;
2985    int off_x, off_y;
2986    unsigned int i, j;
2987    Eina_Bool clean_them = EINA_FALSE;
2988    Eina_Bool above_top = EINA_FALSE;
2989 
2990    eina_evlog("+render_setup", eo_e, 0.0, NULL);
2991    RD(level, "  [--- UPDATE %i %i %ix%i\n", ux, uy, uw, uh);
2992 
2993    off_x = cx - ux;
2994    off_y = cy - uy;
2995    /* build obscuring objects list (in order from bottom to top) */
2996    if (alpha)
2997      {
2998         ENFN->context_clip_set(ENC, context, ux + off_x, uy + off_y, uw, uh);
2999      }
3000    for (i = 0; i < evas->obscuring_objects.count; ++i)
3001      {
3002         obj = eina_array_data_get(&evas->obscuring_objects, i);
3003         if (obj == top) above_top = EINA_TRUE;
3004 
3005         if (evas_object_is_in_output_rect(obj->object, obj, ux - fx, uy - fy, uw, uh))
3006           {
3007              OBJ_ARRAY_PUSH(&evas->temporary_objects, obj);
3008 
3009              if (above_top) continue;
3010              if (obj->cur->snapshot && !evas_object_is_opaque(obj))
3011                continue;
3012 
3013              /* reset the background of the area if needed (using cutout and engine alpha flag to help) */
3014              if (alpha && !skip_cutouts)
3015                _evas_render_cutout_add(evas, context, obj, off_x + fx, off_y + fy, cutout_margin);
3016           }
3017      }
3018    if (alpha)
3019      {
3020         ENFN->context_color_set(ENC, context, 0, 0, 0, 0);
3021         ENFN->context_multiplier_unset(ENC, context);
3022         ENFN->context_render_op_set(ENC, context, EVAS_RENDER_COPY);
3023         ENFN->rectangle_draw(ENC, output, context, surface, cx, cy, cw, ch, do_async);
3024         ENFN->context_cutout_clear(ENC, context);
3025         ENFN->context_clip_unset(ENC, context);
3026      }
3027    eina_evlog("-render_setup", eo_e, 0.0, NULL);
3028 
3029    eina_evlog("+render_objects", eo_e, 0.0, NULL);
3030    /* render all object that intersect with rect */
3031    for (i = 0; i < evas->active_objects.len; i++)
3032      {
3033         Evas_Active_Entry *ent = eina_inarray_nth(&evas->active_objects, i);
3034 
3035         obj = ent->obj;
3036         eo_obj = obj->object;
3037 
3038         if (obj == top) break;
3039 
3040         /* if it's in our outpout rect and it doesn't clip anything */
3041         RD(level, "    OBJ: %s %i %i %ix%i\n", RDNAME(obj), obj->cur->geometry.x, obj->cur->geometry.y, obj->cur->geometry.w, obj->cur->geometry.h);
3042         if (
3043             (!obj->clip.clipees) &&
3044             (obj->cur->visible) &&
3045             (obj->cur->cache.clip.visible) &&
3046 #ifdef INLINE_ACTIVE_GEOM
3047             RECTS_INTERSECT(ux - fx, uy - fy, uw, uh,
3048                             ent->rect.x, ent->rect.y,
3049                             ent->rect.w, ent->rect.h) &&
3050 #else
3051             (_is_obj_in_rect(eo_obj, obj, ux - fx, uy - fy, uw, uh)) &&
3052 #endif
3053             (!obj->delete_me) &&
3054             ((obj->cur->color.a > 0 || obj->cur->render_op != EVAS_RENDER_BLEND)))
3055           {
3056              int x, y, w, h;
3057 
3058              RD(level, "      DRAW (vis: %i, a: %i, clipees: %p)\n", obj->cur->visible, obj->cur->color.a, obj->clip.clipees);
3059              if ((evas->temporary_objects.count > *offset) &&
3060                  (eina_array_data_get(&evas->temporary_objects, *offset) == obj))
3061                (*offset)++;
3062              x = cx; y = cy; w = cw; h = ch;
3063              if (((w > 0) && (h > 0)) || (obj->is_smart))
3064                {
3065                   Evas_Object_Protected_Data *mask;
3066 
3067                   if (!obj->is_smart)
3068                     {
3069                        int cfx, cfy;
3070                        if (!obj->is_frame)
3071                          {
3072                             cfx = obj->cur->cache.clip.x + off_x + fx;
3073                             cfy = obj->cur->cache.clip.y + off_y + fy;
3074                          }
3075                        else
3076                          {
3077                             cfx = obj->cur->cache.clip.x + off_x;
3078                             cfy = obj->cur->cache.clip.y + off_y;
3079                          }
3080                        RECTS_CLIP_TO_RECT(x, y, w, h, cfx, cfy,
3081                                           obj->cur->cache.clip.w,
3082                                           obj->cur->cache.clip.h);
3083                     }
3084 
3085                   ENFN->context_clip_set(ENC, context, x, y, w, h);
3086 
3087                   mask = obj->clip.mask;
3088                   if (mask)
3089                     {
3090                        Evas_Object_Protected_Data *prev_mask = obj->clip.prev_mask;
3091 
3092                        if (mask->mask->redraw || !mask->mask->surface)
3093                          evas_render_mask_subrender(obj->layer->evas, output, mask, prev_mask, 4, do_async);
3094 
3095                        if (mask->mask->surface)
3096                          {
3097                             Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(mask->cur);
3098                             ENFN->context_clip_image_set(ENC, context,
3099                                                          mask->mask->surface,
3100                                                          clip.x + off_x,
3101                                                          clip.y + off_y,
3102                                                          evas, do_async);
3103                          }
3104                     }
3105 
3106                   eina_evlog("+cutouts_add", obj->object, 0.0, NULL);
3107                   above_top = EINA_FALSE;
3108 #if 1 /* FIXME: this can slow things down... figure out optimum... coverage */
3109                   if (!skip_cutouts)
3110                     {
3111                        for (j = *offset; j < evas->temporary_objects.count; ++j)
3112                          {
3113                             Evas_Object_Protected_Data *obj2;
3114 
3115                             obj2 = eina_array_data_get(&evas->temporary_objects, j);
3116                             if (obj2 == top) above_top = EINA_TRUE;
3117                             if (obj2->cur->snapshot)
3118                               {
3119                                  if (above_top) continue;
3120                                  if (!evas_object_is_opaque(obj2)) continue;
3121                               }
3122 #if 1
3123                             if (
3124                                 RECTS_INTERSECT
3125                                 (obj->cur->cache.clip.x, obj->cur->cache.clip.y,
3126                                  obj->cur->cache.clip.w, obj->cur->cache.clip.h,
3127                                  obj2->cur->cache.clip.x, obj2->cur->cache.clip.y,
3128                                  obj2->cur->cache.clip.w, obj2->cur->cache.clip.h) &&
3129                                 RECTS_INTERSECT
3130                                 (obj2->cur->cache.clip.x, obj2->cur->cache.clip.y,
3131                                  obj2->cur->cache.clip.w, obj2->cur->cache.clip.h,
3132                                  ux, uy, uw, uh)
3133                                 )
3134 #endif
3135                               _evas_render_cutout_add(evas, context, obj2, off_x + fx, off_y + fy, cutout_margin);
3136                          }
3137                     }
3138 #endif
3139                   ENFN->context_cutout_target(ENC, context,
3140                                               off_x + obj->cur->cache.clip.x,
3141                                               off_y + obj->cur->cache.clip.y,
3142                                               obj->cur->cache.clip.w,
3143                                               obj->cur->cache.clip.h);
3144                   eina_evlog("-cutouts_add", obj->object, 0.0, NULL);
3145                   clean_them |= evas_render_mapped(evas, eo_obj, obj, context,
3146                                                    output, surface,
3147                                                    off_x + fx, off_y + fy, 0,
3148                                                    cx, cy, cw, ch,
3149                                                    NULL, level + 3, do_async);
3150                   ENFN->context_cutout_clear(ENC, context);
3151 
3152                   if (mask) ENFN->context_clip_image_unset(ENC, context);
3153                }
3154           }
3155      }
3156 
3157    eina_evlog("-render_objects", eo_e, 0.0, NULL);
3158    /* free obscuring objects list */
3159    OBJS_ARRAY_CLEAN(&evas->temporary_objects);
3160 
3161 #ifdef REND_DBG
3162    if (top) RD(level, "   ---] SNAPSHOT [obj:%s sfc:%p]\n", RDNAME(top), surface);
3163    else RD(level, "  ---]\n");
3164 #endif
3165 
3166    return clean_them;
3167 }
3168 
3169 typedef enum _Evas_3State
3170 {
3171   EVAS_3STATE_OUTSIDE,
3172   EVAS_3STATE_INSIDE,
3173   EVAS_3STATE_OVER
3174 } Evas_3State;
3175 
3176 static Evas_3State
_evas_overlay_output_find(Efl_Canvas_Output * output,Evas_Object_Protected_Data * obj)3177 _evas_overlay_output_find(Efl_Canvas_Output *output,
3178                           Evas_Object_Protected_Data *obj)
3179 {
3180    const Eina_Rectangle geometry = {
3181      obj->cur->geometry.x,
3182      obj->cur->geometry.y,
3183      obj->cur->geometry.w,
3184      obj->cur->geometry.h
3185    };
3186    Eina_Rectangle copy = geometry;
3187 
3188    /* A video object can only be in one output at a time, check that first */
3189    if (!eina_rectangle_intersection(&copy, &output->geometry))
3190      return EVAS_3STATE_OUTSIDE;
3191 
3192    if (memcmp(&copy, &geometry, sizeof (Eina_Rectangle)) != 0)
3193      /* This means that it does intersect this output and another */
3194      return EVAS_3STATE_OVER;
3195 
3196    return EVAS_3STATE_INSIDE;
3197 }
3198 
3199 static void
_evas_planes(Evas_Public_Data * evas)3200 _evas_planes(Evas_Public_Data *evas)
3201 {
3202    Evas_Active_Entry *ao;
3203 
3204    /* check if individual image objects can be dropped into hardware planes */
3205    if (ENFN->image_plane_assign)
3206      EINA_INARRAY_FOREACH(&evas->active_objects, ao)
3207        {
3208           Evas_Object_Protected_Data *obj2;
3209           Evas_Object *eo_obj2;
3210           Efl_Canvas_Output *output;
3211           Evas_3State state;
3212           Eina_List *lo;
3213 
3214           obj2 = ao->obj;
3215           eo_obj2 = obj2->object;
3216 
3217           if (!efl_isa(eo_obj2, EFL_CANVAS_IMAGE_INTERNAL_CLASS)) continue;
3218 
3219           /* Find the output the object was in */
3220           EINA_LIST_FOREACH(evas->outputs, lo, output)
3221             {
3222                if (!output->output) continue ;
3223                if (!eina_list_data_find(output->planes, obj2)) continue;
3224                _evas_object_image_plane_release(eo_obj2, obj2, output);
3225                break;
3226             }
3227 
3228          if (evas_object_is_visible(obj2))
3229            EINA_LIST_FOREACH(evas->outputs, lo, output)
3230             {
3231                /* A video object can only be in one output at a time, check that first */
3232                state = _evas_overlay_output_find(output, obj2);
3233                if (state == EVAS_3STATE_OUTSIDE) continue;
3234 
3235                if (!_evas_render_can_use_overlay(evas, eo_obj2, output))
3236                  {
3237                     /* This may free up things temporarily allocated by
3238                      * _can_use_overlay() testing in the engine */
3239                     _evas_object_image_plane_release(eo_obj2, obj2, output);
3240                  } else break;
3241             }
3242           if (evas_object_plane_changed(obj2))
3243             {
3244                /* Since we're lifting this object out of the scene graph
3245                 * (or putting it back), we need to force redraw of the space
3246                 * under it.
3247                 */
3248                _evas_canvas_damage_rectangle_add(NULL, evas,
3249                                                  obj2->cur->geometry.x,
3250                                                  obj2->cur->geometry.y,
3251                                                  obj2->cur->geometry.w,
3252                                                  obj2->cur->geometry.h);
3253 
3254                /* We also need to clean its previously drawn position
3255                 * but only if we're removing it */
3256                if (evas_object_is_on_plane(obj2))
3257                  _evas_canvas_damage_rectangle_add(NULL, evas,
3258                                                    obj2->prev->geometry.x,
3259                                                    obj2->prev->geometry.y,
3260                                                    obj2->prev->geometry.w,
3261                                                    obj2->prev->geometry.h);
3262 
3263             }
3264        }
3265 }
3266 
3267 static Eina_Bool
evas_render_updates_internal(Evas * eo_e,unsigned char make_updates,unsigned char do_draw,Eina_Bool do_async)3268 evas_render_updates_internal(Evas *eo_e,
3269                              unsigned char make_updates,
3270                              unsigned char do_draw,
3271                              Eina_Bool do_async)
3272 {
3273    // FIXME: handle multiple output
3274    Evas_Object *eo_obj;
3275    Evas_Object_Protected_Data *obj;
3276    Evas_Public_Data *evas, *e;
3277    Efl_Canvas_Output *out;
3278    Eina_List *ll, *l;
3279    Eina_Bool clean_them = EINA_FALSE;
3280    Eina_Bool rendering = EINA_FALSE;
3281    Eina_Bool alpha;
3282    Eina_Rectangle *r;
3283    unsigned int i;
3284    Phase1_Context p1ctx;
3285    int redraw_all = 0;
3286    Evas_Render_Mode render_mode = !do_async ?
3287      EVAS_RENDER_MODE_SYNC :
3288      EVAS_RENDER_MODE_ASYNC_INIT;
3289    Eina_Bool haveup = EINA_FALSE;
3290    static int show_update_boxes = -1;
3291 
3292    MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS);
3293    return EINA_FALSE;
3294    MAGIC_CHECK_END();
3295 
3296    e = evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
3297    if (e->inside_post_render) return EINA_FALSE;
3298    if (!e->changed) return EINA_FALSE;
3299 
3300    if (e->rendering)
3301      {
3302         if (do_async)
3303           return EINA_FALSE;
3304         else
3305           {
3306               WRN("Mixing render sync as already doing async "
3307                   "render! Syncing! e=%p [%s]", e,
3308                   e->engine.module->definition->name);
3309              eina_evlog("+render_wait", eo_e, 0.0, NULL);
3310              evas_render_rendering_wait(e);
3311              eina_evlog("-render_wait", eo_e, 0.0, NULL);
3312           }
3313      }
3314 #ifdef EVAS_RENDER_DEBUG_TIMING
3315    double start_time = _time_get();
3316 #endif
3317 
3318    if (show_update_boxes == -1)
3319      {
3320         if (getenv("EVAS_RENDER_DEBUG_UPDATE_BOXES")) show_update_boxes = 1;
3321         else show_update_boxes = 0;
3322      }
3323    evas_render_pre(eo_e, evas);
3324 
3325    _evas_planes(e);
3326 
3327    eina_evlog("+render_calc", eo_e, 0.0, NULL);
3328    evas_call_smarts_calculate(eo_e);
3329    eina_evlog("-render_calc", eo_e, 0.0, NULL);
3330 
3331    RD(0, "[--- RENDER EVAS (size: %ix%i): %p (eo %p)\n", e->viewport.w, e->viewport.h, e, eo_e);
3332 
3333    _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_PRE, NULL);
3334 
3335    /* Check if the modified object mean recalculating every thing */
3336    if (!e->invalidate)
3337      {
3338         eina_evlog("+render_pending", eo_e, 0.0, NULL);
3339         _evas_render_check_pending_objects(&e->pending_objects, eo_e, e);
3340         eina_evlog("-render_pending", eo_e, 0.0, NULL);
3341      }
3342 
3343    /* phase 1. add extra updates for changed objects */
3344    if (e->invalidate || e->render_objects.count <= 0)
3345      {
3346         eina_evlog("+render_phase1", eo_e, 0.0, NULL);
3347 
3348         p1ctx.e                = e;
3349         p1ctx.active_objects   = &e->active_objects;
3350         p1ctx.restack_objects  = &e->restack_objects;
3351         p1ctx.delete_objects   = &e->delete_objects;
3352         p1ctx.render_objects   = &e->render_objects;
3353         p1ctx.snapshot_objects = &e->snapshot_objects;
3354         p1ctx.redraw_all       = redraw_all;
3355         clean_them = _evas_render_phase1_process(&p1ctx);
3356         redraw_all = p1ctx.redraw_all;
3357         eina_evlog("-render_phase1", eo_e, 0.0, NULL);
3358      }
3359 
3360    eina_evlog("+render_phase1_direct", eo_e, 0.0, NULL);
3361    /* phase 1.8. pre render for proxy */
3362    _evas_render_phase1_direct(e, &e->active_objects, &e->restack_objects,
3363                               &e->delete_objects, &e->render_objects);
3364    eina_evlog("-render_phase1_direct", eo_e, 0.0, NULL);
3365 
3366    /* phase 2. force updates for restacks */
3367    eina_evlog("+render_phase2", eo_e, 0.0, NULL);
3368    for (i = 0; i < e->restack_objects.count; ++i)
3369      {
3370         obj = eina_array_data_get(&e->restack_objects, i);
3371         if (!obj->private_data) continue;
3372         if (_evas_render_object_is_mask(obj))
3373           _evas_mask_redraw_set(e, obj);
3374         obj->func->render_pre(obj->object, obj, obj->private_data);
3375         _evas_render_prev_cur_clip_cache_add(e, obj);
3376      }
3377    OBJS_ARRAY_CLEAN(&e->restack_objects);
3378    eina_evlog("-render_phase2", eo_e, 0.0, NULL);
3379 
3380    /* phase 3. add exposes */
3381    eina_evlog("+render_phase3", eo_e, 0.0, NULL);
3382    EINA_LIST_FREE(e->damages, r)
3383      {
3384         ENFN->output_redraws_rect_add(ENC, r->x, r->y, r->w, r->h);
3385         eina_rectangle_free(r);
3386      }
3387    eina_evlog("-render_phase3", eo_e, 0.0, NULL);
3388 
3389    /* phase 4. framespace, output & viewport changes */
3390    eina_evlog("+render_phase4", eo_e, 0.0, NULL);
3391    if (e->viewport.changed)
3392      {
3393         ENFN->output_redraws_rect_add(ENC, 0, 0, e->output.w, e->output.h);
3394      }
3395    if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
3396      {
3397         ERR("viewport size != output size!");
3398      }
3399 
3400    if (e->framespace.changed)
3401      {
3402         /* NB: If the framespace changes, we need to add a redraw rectangle
3403          * which covers the Whole viewport. This is because 'framespace' is
3404          * defined as "the space IN the viewport which is Occupied by the
3405          * window frame" */
3406         ENFN->output_redraws_rect_add(ENC,
3407                                       e->viewport.x, e->viewport.y,
3408                                       e->viewport.w, e->viewport.h);
3409      }
3410 
3411    if (redraw_all)
3412      {
3413         ENFN->output_redraws_rect_add(ENC, 0, 0, e->output.w, e->output.h);
3414      }
3415    eina_evlog("-render_phase4", eo_e, 0.0, NULL);
3416 
3417    /* phase 5. add obscures */
3418    eina_evlog("+render_phase5", eo_e, 0.0, NULL);
3419    EINA_LIST_FOREACH(e->obscures, ll, r)
3420      evas_render_update_del(e, r->x, r->y, r->w, r->h);
3421 
3422    static int prepare = -1;
3423    if (prepare == -1)
3424      {
3425         if (getenv("EVAS_PREPARE")) prepare = !!atoi(getenv("EVAS_PREPARE"));
3426         else prepare = 1;
3427      }
3428    /* build obscure objects list of active objects that obscure as well
3429     * as objects that may need data (image data loads, texture updates,
3430     * pre-render buffers/fbo's etc.) that are not up to date yet */
3431    for (i = 0; i < e->active_objects.len; i++)
3432      {
3433         Evas_Active_Entry *ent = eina_inarray_nth(&e->active_objects, i);
3434 
3435         obj = ent->obj;
3436         eo_obj = obj->object;
3437         if (!obj->private_data) continue;
3438         if (UNLIKELY(
3439                      (!obj->is_smart) &&
3440                      (!obj->clip.clipees) &&
3441                      (evas_object_is_opaque(obj) || obj->cur->snapshot ||
3442                       ((obj->func->has_opaque_rect) &&
3443                        (obj->func->has_opaque_rect(eo_obj, obj, obj->private_data)))) &&
3444                      evas_object_is_visible(obj) &&
3445                      (!obj->mask->is_mask) && (!obj->clip.mask) &&
3446                      (!obj->delete_me)))
3447           OBJ_ARRAY_PUSH(&e->obscuring_objects, obj);
3448         if (prepare)
3449           {
3450              if (obj->func->render_prepare)
3451                obj->func->render_prepare(eo_obj, obj, do_async);
3452           }
3453      }
3454    if (!redraw_all)
3455      {
3456         for (i = 0; i < e->snapshot_objects.count; i++)
3457           {
3458              obj = eina_array_data_get(&e->snapshot_objects, i);
3459              _snapshot_redraw_update(evas, obj);
3460           }
3461      }
3462    eina_evlog("-render_phase5", eo_e, 0.0, NULL);
3463 
3464    EINA_LIST_FOREACH(e->outputs, l, out)
3465      {
3466         // Avoid processing not ready output until they are
3467         if (!out->output) continue;
3468         // Locked output are output that should not yet be rendered
3469         // because the tick/vsync for it doesn't allow it yet.
3470         if (out->lock > 0) continue;
3471 
3472         /* phase 6. Initialize output */
3473         if (out->changed)
3474           {
3475              ENFN->output_resize(ENC, out->output,
3476                                  out->geometry.w, out->geometry.h);
3477              ENFN->output_redraws_rect_add(ENC,
3478                                            out->geometry.x, out->geometry.y,
3479                                            out->geometry.w, out->geometry.h);
3480              out->changed = EINA_FALSE;
3481           }
3482 
3483         /* Define the output for Evas_GL operation */
3484         if (ENFN->gl_output_set)
3485           ENFN->gl_output_set(ENC, out->output);
3486 
3487         /* phase 7. check if video surface should be inlined or stay in their hardware plane */
3488         eina_evlog("+render_phase7", eo_e, 0.0, NULL);
3489         alpha = ENFN->canvas_alpha_get(out->output);
3490 
3491         EINA_LIST_FOREACH(e->video_objects, ll, eo_obj)
3492           {
3493              Evas_Object_Protected_Data *obj2;
3494              Evas_3State state;
3495 
3496              obj2 = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
3497              state = _evas_overlay_output_find(out, obj2);
3498              if (state == EVAS_3STATE_OUTSIDE) continue;
3499 
3500              /* we need the surface to be transparent to display the underlying overlay */
3501              if (state == EVAS_3STATE_INSIDE &&
3502                  alpha &&
3503                  _evas_render_can_use_overlay(e, eo_obj, out))
3504                _evas_object_image_video_overlay_show(eo_obj);
3505              else
3506                _evas_object_image_video_overlay_hide(eo_obj);
3507           }
3508         eina_evlog("-render_phase7", eo_e, 0.0, NULL);
3509 
3510         /* phase 8. go thru each update rect and render objects in it*/
3511         eina_evlog("+render_phase8", eo_e, 0.0, NULL);
3512         if (do_draw)
3513           {
3514              Render_Updates *ru;
3515              void *surface;
3516              int ux, uy, uw, uh;
3517              int cx, cy, cw, ch;
3518              unsigned int offset = 0;
3519              int fx = e->framespace.x;
3520              int fy = e->framespace.y;
3521              int j;
3522 
3523              DBG("Rendering output %p [%i, %i, %i, %i]\n", out,
3524                  out->geometry.x, out->geometry.y,
3525                  out->geometry.w, out->geometry.h);
3526 
3527              if (do_async) _evas_render_busy_begin();
3528              eina_evlog("+render_surface", eo_e, 0.0, NULL);
3529              while ((surface =
3530                      ENFN->output_redraws_next_update_get
3531                      (ENC, out->output,
3532                       &ux, &uy, &uw, &uh,
3533                       &cx, &cy, &cw, &ch)))
3534                {
3535                   void *ctx;
3536 
3537                   haveup = EINA_TRUE;
3538 
3539                   /* adjust the rendering rectangle to the output offset */
3540                   ux += out->geometry.x;
3541                   uy += out->geometry.y;
3542 
3543                   DBG("Surface %p offset: [%i, %i, %i, %i]\n", surface,
3544                       ux, uy, uw, uh);
3545 
3546                   /* phase 7.1 render every snapshot that needs to be updated
3547                      for this part of the screen */
3548                   eina_evlog("+render_snapshots", eo_e, 0.0, NULL);
3549                   for (j = e->snapshot_objects.count - 1; j >= 0; j--)
3550                     {
3551                        Evas_Object_Protected_Data *snap;
3552                        Eina_Rectangle output, cr, ur;
3553 
3554                        snap = eina_array_data_get(&e->snapshot_objects, j);
3555 
3556                        EINA_RECTANGLE_SET(&output,
3557                                           snap->cur->geometry.x,
3558                                           snap->cur->geometry.y,
3559                                           snap->cur->geometry.w,
3560                                           snap->cur->geometry.h);
3561                        EINA_RECTANGLE_SET(&ur, ux, uy, uw, uh);
3562 
3563                        // FIXME: We should render snapshots only once per frame,
3564                        // not once per update region per output !
3565                        if (snap->snapshot_needs_redraw &&
3566                            eina_rectangle_intersection(&ur, &output))
3567                          {
3568                             Cutout_Margin cm = {};
3569                             unsigned int restore_offset = offset;
3570                             Eina_Bool skip_cutouts = EINA_FALSE;
3571                             void *pseudo_canvas;
3572 
3573                             EINA_RECTANGLE_SET(&cr,
3574                                                ur.x - output.x, ur.y - output.y,
3575                                                ur.w, ur.h);
3576 
3577                             pseudo_canvas = _evas_object_image_surface_get(snap, EINA_TRUE);
3578 
3579                             // Get required margin for filters (eg. blur radius)
3580                             _evas_filter_radius_get(snap, &cm.l, &cm.r, &cm.t, &cm.b);
3581 
3582                             if (snap->map->cur.usemap || snap->proxy->proxies ||
3583                                 snap->snapshot_no_obscure ||
3584                                 ((cm.l + cm.r) >= output.w) ||
3585                                 ((cm.t + cm.b) >= output.h))
3586                               skip_cutouts = EINA_TRUE;
3587 
3588                             RD(0, "  SNAPSHOT %s [sfc:%p ur:%d,%d %dx%d]\n", RDNAME(snap), pseudo_canvas, ur.x, ur.y, ur.w, ur.h);
3589                             ctx = ENFN->context_new(ENC);
3590                             clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, pseudo_canvas, ctx,
3591                                                                             snap,
3592                                                                             ur.x, ur.y, ur.w, ur.h,
3593                                                                             cr.x, cr.y, cr.w, cr.h,
3594                                                                             fx, fy, skip_cutouts, &cm,
3595                                                                             alpha, do_async,
3596                                                                             &offset, 1);
3597                             ENFN->context_free(ENC, ctx);
3598 
3599                             offset = restore_offset;
3600                          }
3601                     }
3602                   eina_evlog("-render_snapshots", eo_e, 0.0, NULL);
3603 
3604                   eina_evlog("+render_update", eo_e, 0.0, NULL);
3605                   /* phase 7.2 render all the object on the target surface */
3606                   if ((do_async) || (make_updates))
3607                     {
3608                        ru = malloc(sizeof(*ru));
3609                        ru->surface = surface;
3610                        //XXX: need a way of reffing output surfaces
3611                        NEW_RECT(ru->area, ux, uy, uw, uh);
3612                        eina_spinlock_take(&(e->render.lock));
3613                        out->updates = eina_list_append(out->updates, ru);
3614                        eina_spinlock_release(&(e->render.lock));
3615                     }
3616 
3617                   ctx = ENFN->context_new(ENC);
3618                   clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, surface,
3619                                                                   ctx, NULL,
3620                                                                   ux, uy, uw, uh,
3621                                                                   cx, cy, cw, ch,
3622                                                                   fx, fy,
3623                                                                   EINA_FALSE, NULL,
3624                                                                   alpha, do_async,
3625                                                                   &offset, 0);
3626                   ENFN->context_free(ENC, ctx);
3627 
3628                   eina_evlog("-render_update", eo_e, 0.0, NULL);
3629                   if (!do_async)
3630                     {
3631                        if (show_update_boxes == 1)
3632                          {
3633                             static int fn = 0;
3634                             void *ctx;
3635 
3636                             fn++;
3637                             ctx = ENFN->context_new(ENC);
3638                             ENFN->context_color_set
3639                               (ENC, ctx, fn & 0xff, 0x40, 0x20, 0xff);
3640                             ENFN->rectangle_draw(ENC, out->output,
3641                                                  ctx, surface,
3642                                                  ux - out->geometry.x, uy - out->geometry.y, uw, 1, do_async);
3643                             ENFN->rectangle_draw(ENC, out->output,
3644                                                  ctx, surface,
3645                                                  ux - out->geometry.x, uy - out->geometry.y + uh - 1, uw, 1, do_async);
3646                             ENFN->rectangle_draw(ENC, out->output,
3647                                                  ctx, surface,
3648                                                  ux - out->geometry.x, uy - out->geometry.y, 1, uh, do_async);
3649                             ENFN->rectangle_draw(ENC, out->output,
3650                                                  ctx, surface,
3651                                                  ux - out->geometry.x + uw - 1, uy - out->geometry.y, 1, uh, do_async);
3652                             ENFN->context_free(ENC, ctx);
3653                          }
3654                        eina_evlog("+render_push", eo_e, 0.0, NULL);
3655                        ENFN->output_redraws_next_update_push(ENC, out->output, surface,
3656                                                              ux - out->geometry.x, uy - out->geometry.y, uw, uh,
3657                                                              render_mode);
3658                        eina_evlog("-render_push", eo_e, 0.0, NULL);
3659                     }
3660                }
3661 
3662              eina_evlog("-render_surface", eo_e, 0.0, NULL);
3663           }
3664         else if (make_updates)
3665           {
3666              Render_Updates *ru;
3667              void *surface;
3668              int ux, uy, uw, uh;
3669              int cx, cy, cw, ch;
3670              while ((surface =
3671                      ENFN->output_redraws_next_update_get
3672                      (ENC, out->output,
3673                       &ux, &uy, &uw, &uh,
3674                       &cx, &cy, &cw, &ch)))
3675                {
3676                   haveup = EINA_TRUE;
3677 
3678                   /* adjust the rendering rectangle to the output offset */
3679                   ux += out->geometry.x;
3680                   uy += out->geometry.y;
3681                   ru = malloc(sizeof(*ru));
3682                   ru->surface = surface;
3683                   //XXX: need a way of reffing output surfaces
3684                   NEW_RECT(ru->area, ux, uy, uw, uh);
3685                   eina_spinlock_take(&(e->render.lock));
3686                   out->updates = eina_list_append(out->updates, ru);
3687                   eina_spinlock_release(&(e->render.lock));
3688                }
3689 
3690           }
3691      }
3692 
3693    /* First process all output, then flush */
3694    if (do_draw)
3695      {
3696         if (haveup)
3697           {
3698              if (do_async)
3699                {
3700                   eina_evlog("+render_output_async_flush", eo_e, 0.0, NULL);
3701                   efl_ref(eo_e);
3702                   _rendering_evases = eina_list_prepend(_rendering_evases, e);
3703                   e->rendering = _rendering_evases;
3704                   _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
3705                   evas_thread_queue_flush((Evas_Thread_Command_Cb)evas_render_pipe_wakeup, e);
3706                   eina_evlog("-render_output_async_flush", eo_e, 0.0, NULL);
3707                }
3708              else
3709                {
3710                   eina_evlog("+render_output_flush", eo_e, 0.0, NULL);
3711                   EINA_LIST_FOREACH(e->video_objects, ll, eo_obj)
3712                     {
3713                        _evas_object_image_video_overlay_do(eo_obj);
3714                     }
3715                   _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
3716                   EINA_LIST_FOREACH(e->outputs, l, out)
3717                     if (out->output)
3718                       ENFN->output_flush(ENC, out->output, EVAS_RENDER_MODE_SYNC);
3719                   _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
3720                   _deferred_callbacks_process(eo_e, evas);
3721                   eina_evlog("-render_output_flush", eo_e, 0.0, NULL);
3722                }
3723           }
3724         rendering = haveup;
3725      }
3726    eina_evlog("-render_phase8", eo_e, 0.0, NULL);
3727 
3728    if (evas_font_data_cache_get(EVAS_FONT_DATA_CACHE_TEXTURE) == 0)
3729       ENFN->font_glyphs_gc_collect(ENC, 1.0f, NULL, NULL, EINA_TRUE);
3730    else
3731       ENFN->font_glyphs_gc_collect(ENC, 0.33f, NULL, NULL, EINA_TRUE);
3732 
3733    eina_evlog("+render_clear", eo_e, 0.0, NULL);
3734    if (!do_async && rendering)
3735      {
3736         /* clear redraws */
3737         EINA_LIST_FOREACH(e->outputs, l, out)
3738           if (out->output)
3739             ENFN->output_redraws_clear(ENC, out->output);
3740      }
3741    eina_evlog("-render_clear", eo_e, 0.0, NULL);
3742 
3743    /* and do a post render pass */
3744    eina_evlog("+render_post", eo_e, 0.0, NULL);
3745    IFRD(e->active_objects.len, 0, "  [--- POST RENDER\n");
3746    for (i = 0; i < e->active_objects.len; i++)
3747      {
3748         Evas_Active_Entry *ent = eina_inarray_nth(&e->active_objects, i);
3749 
3750         obj = ent->obj;
3751         eo_obj = obj->object;
3752         if (!obj->private_data) continue;
3753         obj->pre_render_done = EINA_FALSE;
3754         RD(0, "    OBJ %s changed:%i do_draw:%i\n", RDNAME(obj), obj->changed, do_draw);
3755         if ((clean_them) || (obj->changed && do_draw))
3756           {
3757              RD(0, "    OBJ %s render_post()\n", RDNAME(obj));
3758              obj->restack = EINA_FALSE;
3759              evas_object_change_reset(obj);
3760              obj->func->render_post(eo_obj, obj, obj->private_data);
3761           }
3762      }
3763 
3764    for (i = 0; i < e->snapshot_objects.count; i++)
3765      {
3766         Evas_Object_Protected_Data *snap;
3767 
3768         snap = eina_array_data_get(&e->snapshot_objects, i);
3769         snap->snapshot_needs_redraw = EINA_FALSE;
3770         snap->snapshot_no_obscure = EINA_FALSE;
3771      }
3772    eina_evlog("-render_post", eo_e, 0.0, NULL);
3773    IFRD(e->active_objects.len, 0, "  ---]\n");
3774 
3775    /* Set back Evas_GL output to NULL */
3776    /* if (ENFN->gl_output_set) */
3777    /*   ENFN->gl_output_set(ENC, NULL); */
3778 
3779    /* free our obscuring object list */
3780    OBJS_ARRAY_CLEAN(&e->obscuring_objects);
3781 
3782    /* If some object are still marked as changed, do not remove
3783       them from the pending list. */
3784    eina_array_remove(&e->pending_objects, pending_change, NULL);
3785 
3786    /* Reinsert parent of changed object in the pending changed state */
3787    eina_evlog("+render_post_change", eo_e, 0.0, NULL);
3788    for (i = 0; i < e->pending_objects.count; ++i)
3789      {
3790         obj = eina_array_data_get(&e->pending_objects, i);
3791         if (obj->smart.parent)
3792           {
3793              /* these are all objects which could not be rendered because they were
3794               * added to their smart parent in this cycle and the parent was not changed
3795               */
3796              Evas_Object_Protected_Data *smart_parent;
3797 
3798              smart_parent = efl_data_scope_get(obj->smart.parent,
3799                                               EFL_CANVAS_OBJECT_CLASS);
3800              evas_object_change(obj->smart.parent, smart_parent);
3801              /* render cache must be invalidated to correctly render subobj on next pass */
3802              evas_object_smart_render_cache_clear(obj->smart.parent);
3803           }
3804         obj->changed = EINA_TRUE;
3805      }
3806    eina_evlog("-render_post_change", eo_e, 0.0, NULL);
3807 
3808    eina_evlog("+render_post_reset", eo_e, 0.0, NULL);
3809    for (i = 0; i < e->render_objects.count; ++i)
3810      {
3811         obj = eina_array_data_get(&e->render_objects, i);
3812         eo_obj = obj->object;
3813         if (!obj->private_data) continue;
3814         obj->pre_render_done = EINA_FALSE;
3815         if ((obj->changed) && (do_draw))
3816           {
3817              obj->restack = EINA_FALSE;
3818              evas_object_change_reset(obj);
3819              obj->func->render_post(eo_obj, obj, obj->private_data);
3820           }
3821      }
3822    eina_evlog("-render_post_reset", eo_e, 0.0, NULL);
3823 
3824    for (i = 0; i < e->render_post_change_objects.count; ++i)
3825      {
3826         obj = eina_array_data_get(&e->render_post_change_objects, i);
3827         eo_obj = obj->object;
3828         evas_object_change(eo_obj, obj);
3829      }
3830    OBJS_ARRAY_CLEAN(&e->render_post_change_objects);
3831 
3832    eina_evlog("+render_end", eo_e, 0.0, NULL);
3833    e->changed = EINA_FALSE;
3834    e->viewport.changed = EINA_FALSE;
3835    e->framespace.changed = EINA_FALSE;
3836    e->invalidate = EINA_FALSE;
3837 
3838    // always clean... lots of mem waste!
3839    /* If their are some object to restack or some object to delete,
3840     * it's useless to keep the render object list around. */
3841    if (clean_them)
3842      {
3843         eina_inarray_flush(&e->active_objects);
3844         OBJS_ARRAY_CLEAN(&e->render_objects);
3845         OBJS_ARRAY_CLEAN(&e->restack_objects);
3846         OBJS_ARRAY_CLEAN(&e->temporary_objects);
3847         OBJS_ARRAY_CLEAN(&e->snapshot_objects);
3848         eina_array_foreach(&e->clip_changes, _evas_clip_changes_free, NULL);
3849         eina_array_clean(&e->clip_changes);
3850         e->invalidate = EINA_TRUE;
3851      }
3852 
3853    /* delete all objects flagged for deletion now */
3854    for (i = 0; i < e->delete_objects.count; ++i)
3855      {
3856         obj = eina_array_data_get(&e->delete_objects, i);
3857         evas_object_free(obj, EINA_TRUE);
3858      }
3859    eina_array_clean(&e->delete_objects);
3860    /* if we deleted no objects this frame or we deleted a lot (> 1024) then
3861     * try and reset the deleted objects array to empty (no mem used) for
3862     * efficiency */
3863    if ((e->delete_objects.count == 0) || (e->delete_objects.count > 1024))
3864      eina_array_flush(&e->delete_objects);
3865 
3866    evas_module_clean();
3867 
3868    /* Send a RENDER_POST when we are rendering synchronously or,
3869       when do_async but no drawing. This gurantees pre-post pair. */
3870    if (!do_async || !rendering)
3871      {
3872         Evas_Event_Render_Post post;
3873         Eina_List *l1, *l2;
3874         Render_Updates *ru;
3875 
3876         post.updated_area = NULL;
3877         if (haveup)
3878           {
3879              EINA_LIST_FOREACH(e->outputs, l1, out)
3880                {
3881                   if (!out->output) continue ;
3882                   EINA_LIST_FOREACH(out->updates, l2, ru)
3883                     {
3884                        post.updated_area = eina_list_append(post.updated_area, ru->area);
3885                        //XXX: need a way of unreffing output surfaces
3886                        ru->surface = NULL;
3887                     }
3888                }
3889           }
3890         eina_spinlock_take(&(e->render.lock));
3891         e->inside_post_render = EINA_TRUE;
3892         _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_POST, &post);
3893         e->inside_post_render = EINA_FALSE;
3894         eina_spinlock_release(&(e->render.lock));
3895         if (post.updated_area) eina_list_free(post.updated_area);
3896      }
3897 
3898    RD(0, "---]\n");
3899 
3900 #ifdef EVAS_RENDER_DEBUG_TIMING
3901    _accumulate_time(start_time, do_async);
3902 #endif
3903 
3904    if (!do_async) _evas_render_cleanup();
3905    eina_evlog("-render_end", eo_e, 0.0, NULL);
3906    return rendering;
3907 }
3908 
3909 static Eina_Bool
_drop_glyph_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)3910 _drop_glyph_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
3911 {
3912    evas_common_font_glyphs_unref(data);
3913    return EINA_TRUE;
3914 }
3915 
3916 static Eina_Bool
_drop_texts_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)3917 _drop_texts_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
3918 {
3919    evas_common_font_fonts_unref(data);
3920 
3921    return EINA_TRUE;
3922 }
3923 
3924 static void
evas_render_wakeup(Evas * eo_e)3925 evas_render_wakeup(Evas *eo_e)
3926 {
3927    Evas_Event_Render_Post post;
3928    Render_Updates *ru;
3929    Eina_Bool haveup = EINA_FALSE;
3930    Eina_List *ret_updates = NULL, *l;
3931    Evas_Post_Render_Job *job;
3932    Evas_Public_Data *evas;
3933    Efl_Canvas_Output *out;
3934    Eina_Inlist *jobs_il;
3935 
3936    evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
3937 
3938    eina_evlog("+render_wakeup", eo_e, 0.0, NULL);
3939    eina_spinlock_take(&(evas->render.lock));
3940    EINA_LIST_FOREACH(evas->outputs, l, out)
3941      {
3942         if (!out->output) continue ;
3943         EINA_LIST_FREE(out->updates, ru)
3944           {
3945              ret_updates = eina_list_append(ret_updates, ru->area);
3946              free(ru);
3947              haveup = EINA_TRUE;
3948           }
3949      }
3950    eina_spinlock_release(&(evas->render.lock));
3951 
3952    /* post rendering */
3953    _rendering_evases = eina_list_remove_list(_rendering_evases, evas->rendering);
3954    evas->rendering = NULL;
3955 
3956    /* flush redraws */
3957    if (haveup)
3958      {
3959         Eina_List *ll;
3960         Evas_Object *eo_obj;
3961         EINA_LIST_FOREACH(evas->video_objects, ll, eo_obj)
3962           {
3963              _evas_object_image_video_overlay_do(eo_obj);
3964           }
3965         _cb_always_call(eo_e, evas, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
3966      }
3967 
3968    /* clear redraws */
3969    EINA_LIST_FOREACH(evas->outputs, l, out)
3970      {
3971         if (!out->output) continue ;
3972         ENFN->output_redraws_clear(ENC, out->output);
3973      }
3974 
3975    /* unref queues */
3976    eina_array_foreach(&evas->scie_unref_queue, _drop_scie_ref, NULL);
3977    eina_array_flush(&evas->scie_unref_queue);
3978    evas_common_rgba_image_scalecache_prune();
3979 
3980    eina_array_foreach(&evas->image_unref_queue, _drop_image_cache_ref, NULL);
3981    eina_array_flush(&evas->image_unref_queue);
3982 
3983    eina_array_foreach(&evas->glyph_unref_queue, _drop_glyph_ref, NULL);
3984    eina_array_flush(&evas->glyph_unref_queue);
3985 
3986    eina_array_foreach(&evas->texts_unref_queue, _drop_texts_ref, NULL);
3987    eina_array_flush(&evas->texts_unref_queue);
3988 
3989    SLKL(evas->post_render.lock);
3990    jobs_il = EINA_INLIST_GET(evas->post_render.jobs);
3991    evas->post_render.jobs = NULL;
3992    SLKU(evas->post_render.lock);
3993 
3994    evas->inside_post_render = EINA_TRUE;
3995    EINA_INLIST_FREE(jobs_il, job)
3996      {
3997         jobs_il = eina_inlist_remove(jobs_il, EINA_INLIST_GET(job));
3998         if (job->func)
3999           job->func(job->data);
4000         free(job);
4001      }
4002 
4003    post.updated_area = ret_updates;
4004    _cb_always_call(eo_e, evas, EVAS_CALLBACK_RENDER_POST, &post);
4005    evas->inside_post_render = EINA_FALSE;
4006    _deferred_callbacks_process(eo_e, evas);
4007 
4008    evas_render_updates_free(ret_updates);
4009 
4010    eina_evlog("-render_wakeup", eo_e, 0.0, NULL);
4011    efl_unref(eo_e);
4012 
4013 #ifdef EVAS_RENDER_DEBUG_TIMING
4014    _accumulate_time(0, EINA_TRUE);
4015 #endif
4016 }
4017 
4018 static void
evas_render_async_wakeup(void * target,Evas_Callback_Type type EINA_UNUSED,void * event_info EINA_UNUSED)4019 evas_render_async_wakeup(void *target, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
4020 {
4021    Evas_Public_Data *e = target;
4022    evas_render_wakeup(e->evas);
4023    _evas_render_busy_end();
4024 }
4025 
4026 // FIXME: This event should be per output... maybe ? maybe not ?
4027 static void
evas_render_pipe_wakeup(void * data)4028 evas_render_pipe_wakeup(void *data)
4029 {
4030    Eina_List *l, *ll;
4031    Render_Updates *ru;
4032    Evas_Public_Data *evas = data;
4033    Efl_Canvas_Output *out;
4034    Evas *e;
4035 
4036    eina_evlog("+render_pipe_wakeup", evas->evas, 0.0, NULL);
4037    eina_spinlock_take(&(evas->render.lock));
4038    e = evas->evas;
4039    EINA_LIST_FOREACH(evas->outputs, ll, out)
4040      {
4041         if (!out->output) continue ;
4042         EINA_LIST_FOREACH(out->updates, l, ru)
4043           {
4044              eina_evlog("+render_push", evas->evas, 0.0, NULL);
4045              ENFN->output_redraws_next_update_push
4046                (ENC, out->output, ru->surface,
4047                 ru->area->x - out->geometry.x, ru->area->y - out->geometry.y,
4048                 ru->area->w, ru->area->h,
4049                 EVAS_RENDER_MODE_ASYNC_END);
4050              eina_evlog("-render_push", evas->evas, 0.0, NULL);
4051              //XXX: need a way to unref render output surfaces
4052              ru->surface = NULL;
4053           }
4054         eina_evlog("+render_output_flush", evas->evas, 0.0, NULL);
4055         ENFN->output_flush(ENC, out->output, EVAS_RENDER_MODE_ASYNC_END);
4056         eina_evlog("-render_output_flush", evas->evas, 0.0, NULL);
4057      }
4058    eina_spinlock_release(&(evas->render.lock));
4059    evas_async_events_put(data, 0, NULL, evas_render_async_wakeup);
4060    /* use local pointer to avoid data race with 'evas' deref after releasing lock */
4061    eina_evlog("-render_pipe_wakeup", e, 0.0, NULL);
4062 }
4063 
4064 EAPI void
evas_render_updates_free(Eina_List * updates)4065 evas_render_updates_free(Eina_List *updates)
4066 {
4067    Eina_Rectangle *r;
4068 
4069    EINA_LIST_FREE(updates, r)
4070       eina_rectangle_free(r);
4071 }
4072 
4073 EOLIAN Eina_Bool
_evas_canvas_render_async(Eo * eo_e,Evas_Public_Data * e)4074 _evas_canvas_render_async(Eo *eo_e, Evas_Public_Data *e)
4075 {
4076    Eina_Bool ret;
4077    eina_evlog("+render_block", eo_e, 0.0, NULL);
4078    evas_canvas_async_block(e);
4079    eina_evlog("-render_block", eo_e, 0.0, NULL);
4080    eina_evlog("+render", eo_e, 0.0, NULL);
4081    ret = evas_render_updates_internal(eo_e, 1, 1, EINA_TRUE);
4082    eina_evlog("-render", eo_e, 0.0, NULL);
4083    return ret;
4084 }
4085 
4086 static Eina_List *
evas_render_updates_internal_wait(Evas * eo_e,unsigned char make_updates,unsigned char do_draw)4087 evas_render_updates_internal_wait(Evas *eo_e,
4088                                   unsigned char make_updates,
4089                                   unsigned char do_draw)
4090 {
4091    Eina_List *ret = NULL, *l;
4092    Efl_Canvas_Output *out;
4093    Evas_Public_Data *e;
4094 
4095    e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
4096    if (!evas_render_updates_internal(eo_e, make_updates, do_draw, EINA_FALSE))
4097      return NULL;
4098 
4099    eina_spinlock_take(&(e->render.lock));
4100    EINA_LIST_FOREACH(e->outputs, l, out)
4101      {
4102         if (!out->output) continue ;
4103         ret = eina_list_merge(ret, out->updates);
4104         out->updates = NULL;
4105      }
4106    eina_spinlock_release(&(e->render.lock));
4107 
4108    return ret;
4109 }
4110 
4111 EOLIAN Eina_List*
_evas_canvas_render_updates(Eo * eo_e,Evas_Public_Data * e)4112 _evas_canvas_render_updates(Eo *eo_e, Evas_Public_Data *e)
4113 {
4114    Eina_List *ret, *updates = NULL;
4115    Render_Updates *ru;
4116    eina_evlog("+render_block", eo_e, 0.0, NULL);
4117    evas_canvas_async_block(e);
4118    eina_evlog("-render_block", eo_e, 0.0, NULL);
4119    eina_evlog("+render", eo_e, 0.0, NULL);
4120    ret = evas_render_updates_internal_wait(eo_e, 1, 1);
4121    eina_evlog("-render", eo_e, 0.0, NULL);
4122    EINA_LIST_FREE(ret, ru)
4123      {
4124         updates = eina_list_append(updates, ru->area);
4125         free(ru);
4126      }
4127    return updates;
4128 }
4129 
4130 EOLIAN void
_evas_canvas_render(Eo * eo_e,Evas_Public_Data * e)4131 _evas_canvas_render(Eo *eo_e, Evas_Public_Data *e)
4132 {
4133    Eina_List *ret;
4134    Render_Updates *ru;
4135    if (!e->changed) return;
4136    eina_evlog("+render_block", eo_e, 0.0, NULL);
4137    evas_canvas_async_block(e);
4138    eina_evlog("-render_block", eo_e, 0.0, NULL);
4139    eina_evlog("+render", eo_e, 0.0, NULL);
4140    ret = evas_render_updates_internal_wait(eo_e, 0, 1);
4141    eina_evlog("-render", eo_e, 0.0, NULL);
4142    EINA_LIST_FREE(ret, ru)
4143      {
4144         eina_rectangle_free(ru->area);
4145         free(ru);
4146      }
4147 }
4148 
4149 EOLIAN void
_evas_canvas_norender(Eo * eo_e,Evas_Public_Data * e)4150 _evas_canvas_norender(Eo *eo_e, Evas_Public_Data *e)
4151 {
4152    evas_canvas_async_block(e);
4153    evas_render_updates_internal_wait(eo_e, 0, 0);
4154 }
4155 
4156 EAPI void
evas_norender_with_updates(Eo * eo_e)4157 evas_norender_with_updates(Eo *eo_e)
4158 {
4159    Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
4160    Eina_List *ret;
4161    Render_Updates *ru;
4162 
4163    evas_canvas_async_block(e);
4164    ret = evas_render_updates_internal_wait(eo_e, 1, 0);
4165    EINA_LIST_FREE(ret, ru)
4166      {
4167         eina_rectangle_free(ru->area);
4168         free(ru);
4169      }
4170 }
4171 
4172 EOLIAN void
_evas_canvas_render_idle_flush(Eo * eo_e,Evas_Public_Data * evas)4173 _evas_canvas_render_idle_flush(Eo *eo_e, Evas_Public_Data *evas)
4174 {
4175    eina_evlog("+idle_flush", eo_e, 0.0, NULL);
4176    evas_canvas_async_block(evas);
4177 
4178    evas_render_rendering_wait(evas);
4179 
4180    evas_fonts_zero_pressure();
4181 
4182    if (ENFN && ENFN->output_idle_flush)
4183      {
4184         Efl_Canvas_Output *output;
4185         Eina_List *l;
4186 
4187         EINA_LIST_FOREACH(evas->outputs, l, output)
4188           if (output->output)
4189             ENFN->output_idle_flush(ENC, output->output);
4190      }
4191 
4192    eina_inarray_flush(&evas->active_objects);
4193    OBJS_ARRAY_FLUSH(&evas->render_objects);
4194    OBJS_ARRAY_FLUSH(&evas->restack_objects);
4195    OBJS_ARRAY_FLUSH(&evas->delete_objects);
4196    OBJS_ARRAY_FLUSH(&evas->obscuring_objects);
4197    OBJS_ARRAY_FLUSH(&evas->temporary_objects);
4198    OBJS_ARRAY_FLUSH(&evas->map_clip_objects);
4199    eina_array_foreach(&evas->clip_changes, _evas_clip_changes_free, NULL);
4200    eina_array_clean(&evas->clip_changes);
4201 
4202    evas->invalidate = EINA_TRUE;
4203    eina_evlog("-idle_flush", eo_e, 0.0, NULL);
4204 }
4205 
4206 EOLIAN void
_evas_canvas_sync(Eo * eo_e,Evas_Public_Data * e)4207 _evas_canvas_sync(Eo *eo_e, Evas_Public_Data *e)
4208 {
4209    eina_evlog("+render_sync", eo_e, 0.0, NULL);
4210    evas_canvas_async_block(e);
4211    evas_render_rendering_wait(e);
4212    eina_evlog("-render_sync", eo_e, 0.0, NULL);
4213 }
4214 
4215 void
_evas_render_dump_map_surfaces(Evas_Object * eo_obj)4216 _evas_render_dump_map_surfaces(Evas_Object *eo_obj)
4217 {
4218    Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
4219    if ((obj->map->cur.map) && obj->map->surface)
4220      {
4221         Evas_Public_Data *evas = obj->layer->evas;
4222         ENFN->image_free(ENC, obj->map->surface);
4223         EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
4224           map_write->surface = NULL;
4225         EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
4226      }
4227 
4228    if (obj->is_smart)
4229      {
4230         Evas_Object_Protected_Data *obj2;
4231 
4232         EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2)
4233            _evas_render_dump_map_surfaces(obj2->object);
4234      }
4235 }
4236 
4237 EOLIAN void
_evas_canvas_render_dump(Eo * eo_e EINA_UNUSED,Evas_Public_Data * evas)4238 _evas_canvas_render_dump(Eo *eo_e EINA_UNUSED, Evas_Public_Data *evas)
4239 {
4240    Evas_Layer *lay;
4241 
4242    evas_canvas_async_block(evas);
4243 
4244    evas_all_sync();
4245    evas_cache_async_freeze();
4246 
4247    EINA_INLIST_FOREACH(evas->layers, lay)
4248      {
4249         Evas_Object_Protected_Data *obj;
4250 
4251         lay->walking_objects++;
4252         EINA_INLIST_FOREACH(lay->objects, obj)
4253           {
4254              if (obj->proxy->surface)
4255                {
4256                   EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy, Evas_Object_Proxy_Data, proxy_write)
4257                     {
4258                        ENFN->image_free(ENC, proxy_write->surface);
4259                        proxy_write->surface = NULL;
4260                     }
4261                   EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_write);
4262                }
4263              if (obj->mask->surface)
4264                {
4265                   EINA_COW_WRITE_BEGIN(evas_object_mask_cow, obj->mask, Evas_Object_Mask_Data, mdata)
4266                     {
4267                        ENFN->image_free(ENC, mdata->surface);
4268                        mdata->surface = NULL;
4269                     }
4270                   EINA_COW_WRITE_END(evas_object_mask_cow, obj->mask, mdata);
4271                }
4272              if ((obj->type) && (!strcmp(obj->type, "image")))
4273                evas_object_inform_call_image_unloaded(obj->object);
4274              _evas_render_dump_map_surfaces(obj->object);
4275           }
4276         lay->walking_objects--;
4277         _evas_layer_flush_removes(lay);
4278      }
4279    if (ENFN && ENFN->output_dump)
4280      {
4281         Efl_Canvas_Output *output;
4282         Eina_List *l;
4283 
4284         EINA_LIST_FOREACH(evas->outputs, l, output)
4285           if (output->output)
4286             ENFN->output_dump(ENC, output->output);
4287      }
4288 
4289 #define GC_ALL(Cow) \
4290 if (Cow) while (eina_cow_gc(Cow))
4291    GC_ALL(evas_object_proxy_cow);
4292    GC_ALL(evas_object_map_cow);
4293    GC_ALL(evas_object_image_pixels_cow);
4294    GC_ALL(evas_object_image_load_opts_cow);
4295    GC_ALL(evas_object_image_state_cow);
4296 
4297    evas_fonts_zero_pressure();
4298 
4299    if (ENFN && ENFN->output_idle_flush)
4300      {
4301         Efl_Canvas_Output *output;
4302         Eina_List *l;
4303 
4304         EINA_LIST_FOREACH(evas->outputs, l, output)
4305           if (output->output)
4306             ENFN->output_idle_flush(ENC, output->output);
4307      }
4308 
4309    eina_inarray_flush(&evas->active_objects);
4310    OBJS_ARRAY_FLUSH(&evas->render_objects);
4311    OBJS_ARRAY_FLUSH(&evas->restack_objects);
4312    OBJS_ARRAY_FLUSH(&evas->delete_objects);
4313    OBJS_ARRAY_FLUSH(&evas->obscuring_objects);
4314    OBJS_ARRAY_FLUSH(&evas->temporary_objects);
4315    OBJS_ARRAY_FLUSH(&evas->map_clip_objects);
4316    eina_array_foreach(&evas->clip_changes, _evas_clip_changes_free, NULL);
4317    eina_array_clean(&evas->clip_changes);
4318 
4319    evas->invalidate = EINA_TRUE;
4320 
4321    evas_cache_async_thaw();
4322 }
4323 
4324 void
evas_render_invalidate(Evas * eo_e)4325 evas_render_invalidate(Evas *eo_e)
4326 {
4327    Evas_Public_Data *e;
4328 
4329    MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS);
4330    return;
4331    MAGIC_CHECK_END();
4332    e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
4333 
4334    eina_inarray_flush(&e->active_objects);
4335    OBJS_ARRAY_CLEAN(&e->render_objects);
4336 
4337    OBJS_ARRAY_FLUSH(&e->restack_objects);
4338    OBJS_ARRAY_FLUSH(&e->delete_objects);
4339 
4340    OBJS_ARRAY_FLUSH(&e->snapshot_objects);
4341    OBJS_ARRAY_FLUSH(&e->map_clip_objects);
4342 
4343    e->invalidate = EINA_TRUE;
4344 }
4345 
4346 void
evas_render_object_recalc(Evas_Object_Protected_Data * obj)4347 evas_render_object_recalc(Evas_Object_Protected_Data *obj)
4348 {
4349    if ((!obj->changed) && (obj->delete_me < 2))
4350      {
4351        Evas_Public_Data *e;
4352 
4353        e = obj->layer->evas;
4354        if ((!e) || (e->cleanup)) return;
4355        if (!obj->in_pending_objects)
4356          OBJ_ARRAY_PUSH(&e->pending_objects, obj);
4357        obj->in_pending_objects = obj->changed = EINA_TRUE;
4358      }
4359 }
4360 
4361 void
evas_unref_queue_image_put(Evas_Public_Data * pd,void * image)4362 evas_unref_queue_image_put(Evas_Public_Data *pd, void *image)
4363 {
4364    eina_array_push(&pd->image_unref_queue, image);
4365    evas_common_rgba_image_scalecache_items_ref(image, &pd->scie_unref_queue);
4366 }
4367 
4368 void
evas_unref_queue_glyph_put(Evas_Public_Data * pd,void * glyph)4369 evas_unref_queue_glyph_put(Evas_Public_Data *pd, void *glyph)
4370 {
4371    eina_array_push(&pd->glyph_unref_queue, glyph);
4372 }
4373 
4374 void
evas_unref_queue_texts_put(Evas_Public_Data * pd,void * texts)4375 evas_unref_queue_texts_put(Evas_Public_Data *pd, void *texts)
4376 {
4377    eina_array_push(&pd->texts_unref_queue, texts);
4378 }
4379 
4380 void
evas_post_render_job_add(Evas_Public_Data * pd,void (* func)(void *),void * data)4381 evas_post_render_job_add(Evas_Public_Data *pd, void (*func)(void *), void *data)
4382 {
4383    Evas_Post_Render_Job *job;
4384 
4385    if (!pd || pd->delete_me) return;
4386    if (!func) return;
4387 
4388    job = malloc(sizeof(*job));
4389    job->func = func;
4390    job->data = data;
4391 
4392    SLKL(pd->post_render.lock);
4393    pd->post_render.jobs = (Evas_Post_Render_Job *)
4394          eina_inlist_append(EINA_INLIST_GET(pd->post_render.jobs), EINA_INLIST_GET(job));
4395    SLKU(pd->post_render.lock);
4396 }
4397 
4398 void
evas_render_post_change_object_push(Evas_Object_Protected_Data * obj)4399 evas_render_post_change_object_push(Evas_Object_Protected_Data *obj)
4400 {
4401    Evas_Public_Data *e;
4402 
4403    if (!obj || !obj->layer || !obj->layer->evas) return;
4404 
4405    e = obj->layer->evas;
4406    OBJ_ARRAY_PUSH(&e->render_post_change_objects, obj);
4407 }
4408 
4409 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
4410 
4411