evas/render - Fixed proxy clipping if the source object is clipped by output area.
[framework/uifw/evas.git] / src / lib / canvas / evas_render.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3 #include <math.h>
4 #ifdef EVAS_CSERVE2
5 #include "evas_cs2_private.h"
6 #endif
7
8 /* debug rendering
9  * NOTE: Define REND_DBG 1 in evas_private.h to enable debugging. Don't define
10  * it here since the flag is used on other places too. */
11
12 /* #define STDOUT_DBG 1 */
13
14 #ifdef REND_DBG
15 static FILE *dbf = NULL;
16
17 static void
18 rend_dbg(const char *txt)
19 {
20    if (!dbf)
21      {
22 #ifdef STDOUT_DBG
23         dbf = stdout;
24 #else
25         dbf = fopen("EVAS-RENDER-DEBUG.log", "w");
26 #endif
27         if (!dbf) return;
28      }
29    fputs(txt, dbf);
30    fflush(dbf);
31 }
32 #define RD(args...) \
33    { \
34       char __tmpbuf[4096]; \
35       \
36       snprintf(__tmpbuf, sizeof(__tmpbuf), ##args); \
37       rend_dbg(__tmpbuf); \
38    }
39 #define RDI(xxxx) \
40    { \
41       char __tmpbuf[4096]; int __tmpi; \
42       for (__tmpi = 0; __tmpi < xxxx; __tmpi++) \
43         __tmpbuf[__tmpi] = ' '; \
44       __tmpbuf[__tmpi] = 0; \
45       rend_dbg(__tmpbuf); \
46    }
47 #else
48 #define RD(args...)
49 #define RDI(x)
50 #endif
51
52 static Eina_List *
53 evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char do_draw);
54
55 EAPI void
56 evas_damage_rectangle_add(Evas *e, int x, int y, int w, int h)
57 {
58    Eina_Rectangle *r;
59
60    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
61    return;
62    MAGIC_CHECK_END();
63    NEW_RECT(r, x, y, w, h);
64    if (!r) return;
65    e->damages = eina_list_append(e->damages, r);
66    e->changed = EINA_TRUE;
67 }
68
69 EAPI void
70 evas_obscured_rectangle_add(Evas *e, int x, int y, int w, int h)
71 {
72    Eina_Rectangle *r;
73
74    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
75    return;
76    MAGIC_CHECK_END();
77    NEW_RECT(r, x, y, w, h);
78    if (!r) return;
79    e->obscures = eina_list_append(e->obscures, r);
80 }
81
82 EAPI void
83 evas_obscured_clear(Evas *e)
84 {
85    Eina_Rectangle *r;
86
87    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
88    return;
89    MAGIC_CHECK_END();
90    EINA_LIST_FREE(e->obscures, r)
91      {
92         eina_rectangle_free(r);
93      }
94 }
95
96 static Eina_Bool
97 _evas_clip_changes_free(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
98 {
99    eina_rectangle_free(data);
100    return EINA_TRUE;
101 }
102
103 static Eina_Bool
104 _evas_render_had_map(Evas_Object *obj)
105 {
106    return ((obj->prev.map) && (obj->prev.usemap));
107    //   return ((!obj->cur.map) && (obj->prev.usemap));
108 }
109
110 static Eina_Bool
111 _evas_render_is_relevant(Evas_Object *obj)
112 {
113    return ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
114            (evas_object_was_visible(obj) && (!obj->prev.have_clipees)));
115 }
116
117 static Eina_Bool
118 _evas_render_can_render(Evas_Object *obj)
119 {
120    return (evas_object_is_visible(obj) && (!obj->cur.have_clipees));
121 }
122
123 static void
124 _evas_render_prev_cur_clip_cache_add(Evas *e, Evas_Object *obj)
125 {
126    e->engine.func->output_redraws_rect_add(e->engine.data.output,
127                                            obj->prev.cache.clip.x,
128                                            obj->prev.cache.clip.y,
129                                            obj->prev.cache.clip.w,
130                                            obj->prev.cache.clip.h);
131    e->engine.func->output_redraws_rect_add(e->engine.data.output,
132                                            obj->cur.cache.clip.x,
133                                            obj->cur.cache.clip.y,
134                                            obj->cur.cache.clip.w,
135                                            obj->cur.cache.clip.h);
136 }
137
138 static void
139 _evas_render_cur_clip_cache_del(Evas *e, Evas_Object *obj)
140 {
141    Evas_Coord x, y, w, h;
142
143    x = obj->cur.cache.clip.x;
144    y = obj->cur.cache.clip.y;
145    w = obj->cur.cache.clip.w;
146    h = obj->cur.cache.clip.h;
147    if (obj->cur.clipper)
148      {
149         RECTS_CLIP_TO_RECT(x, y, w, h,
150                            obj->cur.clipper->cur.cache.clip.x,
151                            obj->cur.clipper->cur.cache.clip.y,
152                            obj->cur.clipper->cur.cache.clip.w,
153                            obj->cur.clipper->cur.cache.clip.h);
154      }
155    e->engine.func->output_redraws_rect_del(e->engine.data.output,
156                                            x, y, w, h);
157 }
158
159 static void
160 _evas_render_phase1_direct(Evas *e,
161                            Eina_Array *active_objects,
162                            Eina_Array *restack_objects __UNUSED__,
163                            Eina_Array *delete_objects __UNUSED__,
164                            Eina_Array *render_objects)
165 {
166    unsigned int i;
167    Eina_List *l;
168    Evas_Object *proxy;
169
170    RD("  [--- PHASE 1 DIRECT\n");
171    for (i = 0; i < active_objects->count; i++)
172      {
173         Evas_Object *obj;
174
175         obj = eina_array_data_get(active_objects, i);
176         if (obj->changed)
177           {
178              /* Flag need redraw on proxy too */
179              evas_object_clip_recalc(obj);
180              EINA_LIST_FOREACH(obj->proxy.proxies, l, proxy)
181                proxy->proxy.redraw = EINA_TRUE;
182           }
183      }
184    for (i = 0; i < render_objects->count; i++)
185      {
186         Evas_Object *obj;
187
188         obj = eina_array_data_get(render_objects, i);
189         RD("    OBJ [%p] changed %i\n", obj, obj->changed);
190         if (obj->changed)
191           {
192              /* Flag need redraw on proxy too */
193              evas_object_clip_recalc(obj);
194              obj->func->render_pre(obj);
195              if (obj->proxy.redraw)
196                _evas_render_prev_cur_clip_cache_add(e, obj);
197              if (obj->proxy.proxies)
198                {
199                   obj->proxy.redraw = EINA_TRUE;
200                   EINA_LIST_FOREACH(obj->proxy.proxies, l, proxy)
201                     {
202                        proxy->func->render_pre(proxy);
203                        _evas_render_prev_cur_clip_cache_add(e, proxy);
204                     }
205                }
206
207              RD("      pre-render-done smart:%p|%p  [%p, %i] | [%p, %i] has_map:%i had_map:%i\n",
208                 obj->smart.smart,
209                 evas_object_smart_members_get_direct(obj),
210                 obj->cur.map, obj->cur.usemap,
211                 obj->prev.map, obj->prev.usemap,
212                 _evas_render_has_map(obj),
213                 _evas_render_had_map(obj));
214              if ((obj->smart.smart) &&
215                  (_evas_render_has_map(obj) || (obj->changed_src_visible)))
216                {
217                   RD("      has map + smart\n");
218                   _evas_render_prev_cur_clip_cache_add(e, obj);
219                }
220           }
221         else
222           {
223              if (obj->smart.smart)
224                {
225                   //                  obj->func->render_pre(obj);
226                }
227              else if ((obj->rect_del) ||
228                       (evas_object_is_opaque(obj) && evas_object_is_visible(obj)))
229                {
230                   RD("    rect del\n");
231                   _evas_render_cur_clip_cache_del(e, obj);
232                }
233           }
234      }
235    RD("  ---]\n");
236 }
237
238 static Eina_Bool
239 _evas_render_phase1_object_process(Evas *e, Evas_Object *obj,
240                                    Eina_Array *active_objects,
241                                    Eina_Array *restack_objects,
242                                    Eina_Array *delete_objects,
243                                    Eina_Array *render_objects,
244                                    int restack,
245                                    int *redraw_all,
246                                    Eina_Bool mapped_parent
247 #ifdef REND_DBG
248                                    , int level
249 #endif
250                                   )
251 {
252    Eina_Bool clean_them = EINA_FALSE;
253    Evas_Object *obj2;
254    int is_active;
255    Eina_Bool map, hmap;
256
257    //Need pre render for the children of mapped object.
258    //But only when they have changed.
259    if (mapped_parent && (!obj->changed)) return EINA_FALSE;
260
261    obj->rect_del = EINA_FALSE;
262    obj->render_pre = EINA_FALSE;
263
264    if (obj->delete_me == 2)
265      eina_array_push(delete_objects, obj);
266    else if (obj->delete_me != 0) obj->delete_me++;
267    /* If the object will be removed, we should not cache anything during this run. */
268    if (obj->delete_me != 0) clean_them = EINA_TRUE;
269
270    /* build active object list */
271    evas_object_clip_recalc(obj);
272    is_active = evas_object_is_active(obj);
273    obj->is_active = is_active;
274
275    RDI(level);
276    RD("    [--- PROCESS [%p] '%s' active = %i, del = %i | %i %i %ix%i\n", obj, obj->type, is_active, obj->delete_me, obj->cur.geometry.x, obj->cur.geometry.y, obj->cur.geometry.w, obj->cur.geometry.h);
277
278    if ((!mapped_parent) && ((is_active) || (obj->delete_me != 0)))
279      eina_array_push(active_objects, obj);
280
281 #ifdef REND_DBG
282    if (!is_active)
283      {
284         RDI(level);
285         RD("     [%p] vis: %i, cache.clip.vis: %i cache.clip.a: %i [%p]\n", obj, obj->cur.visible, obj->cur.cache.clip.visible, obj->cur.cache.clip.a, obj->func->is_visible);
286      }
287 #endif
288
289    map = _evas_render_has_map(obj);
290    hmap = _evas_render_had_map(obj);
291
292    if ((restack) && (!map))
293      {
294         if (!obj->changed)
295           {
296              eina_array_push(&e->pending_objects, obj);
297              obj->changed = EINA_TRUE;
298           }
299         obj->restack = EINA_TRUE;
300         clean_them = EINA_TRUE;
301      }
302
303    if (map)
304      {
305         RDI(level);
306         RD("      obj mapped\n");
307         if (obj->changed)
308           {
309              if (map != hmap) *redraw_all = 1;
310
311              if ((is_active) && (!obj->clip.clipees) &&
312                  ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
313                   (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
314                {
315                   eina_array_push(render_objects, obj);
316                   _evas_render_prev_cur_clip_cache_add(e, obj);
317                   obj->render_pre = EINA_TRUE;
318
319                   if (obj->smart.smart)
320                     {
321                        EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
322                          {
323                             _evas_render_phase1_object_process(e, obj2,
324                                                                active_objects,
325                                                                restack_objects,
326                                                                delete_objects,
327                                                                render_objects,
328                                                                obj->restack,
329                                                                redraw_all,
330                                                                EINA_TRUE
331 #ifdef REND_DBG
332                                                                , level + 1
333 #endif
334                                                               );
335                          }
336                     }
337                }
338           }
339         return clean_them;
340      }
341    else if (hmap)
342      {
343         RDI(level);
344         RD("      had map - restack objs\n");
345         //        eina_array_push(restack_objects, obj);
346         _evas_render_prev_cur_clip_cache_add(e, obj);
347         if (obj->changed)
348           {
349              if (!map)
350                {
351                   if ((obj->cur.map) && (obj->cur.usemap)) map = EINA_TRUE;
352                }
353              if (map != hmap)
354                {
355                   *redraw_all = 1;
356                }
357           }
358      }
359
360    /* handle normal rendering. this object knows how to handle maps */
361    if (obj->changed)
362      {
363         if (obj->smart.smart)
364           {
365              RDI(level);
366              RD("      changed + smart - render ok\n");
367              eina_array_push(render_objects, obj);
368              obj->render_pre = EINA_TRUE;
369              EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj),
370                                  obj2)
371                {
372                   _evas_render_phase1_object_process(e, obj2,
373                                                      active_objects,
374                                                      restack_objects,
375                                                      delete_objects,
376                                                      render_objects,
377                                                      obj->restack,
378                                                      redraw_all,
379                                                      mapped_parent
380 #ifdef REND_DBG
381                                                      , level + 1
382 #endif
383                                                     );
384                }
385           }
386         else
387           {
388              if ((!obj->clip.clipees) && _evas_render_is_relevant(obj))
389                {
390                   if (is_active)
391                     {
392                        RDI(level);
393                        RD("      relevant + active\n");
394                        if (obj->restack)
395                          eina_array_push(restack_objects, obj);
396                        else
397                          {
398                             eina_array_push(render_objects, obj);
399                             obj->render_pre = EINA_TRUE;
400                          }
401                     }
402                   else
403                     {
404                        /* It goes to be hidden. Prev caching should be replaced
405                           by the current (hidden) state. */
406                        if (evas_object_is_visible(obj) !=
407                            evas_object_was_visible(obj))
408                          evas_object_cur_prev(obj);
409
410                        RDI(level);
411                        RD("      skip - not smart, not active or clippees or not relevant\n");
412                     }
413                }
414              else
415                {
416                   RDI(level);
417                   RD("      skip - not smart, not active or clippees or not relevant\n");
418                }
419           }
420      }
421    else
422      {
423         RD("      not changed... [%i] -> (%i %i %p %i) [%i]\n",
424            evas_object_is_visible(obj),
425            obj->cur.visible, obj->cur.cache.clip.visible, obj->smart.smart,
426            obj->cur.cache.clip.a, evas_object_was_visible(obj));
427
428         if ((!obj->clip.clipees) && (obj->delete_me == 0) &&
429             (_evas_render_can_render(obj) ||
430              (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
431           {
432              if (obj->smart.smart)
433                {
434                   RDI(level);
435                   RD("      smart + visible/was visible + not clip\n");
436                   eina_array_push(render_objects, obj);
437                   obj->render_pre = EINA_TRUE;
438                   EINA_INLIST_FOREACH
439                      (evas_object_smart_members_get_direct(obj), obj2)
440                        {
441                           _evas_render_phase1_object_process(e, obj2,
442                                                              active_objects,
443                                                              restack_objects,
444                                                              delete_objects,
445                                                              render_objects,
446                                                              restack,
447                                                              redraw_all,
448                                                              mapped_parent
449 #ifdef REND_DBG
450                                                              , level + 1
451 #endif
452                                                             );
453                        }
454                }
455              else
456                {
457                   if (evas_object_is_opaque(obj) &&
458                       evas_object_is_visible(obj))
459                     {
460                        RDI(level);
461                        RD("      opaque + visible\n");
462                        eina_array_push(render_objects, obj);
463                        obj->rect_del = EINA_TRUE;
464                     }
465                   else if (evas_object_is_visible(obj))
466                     {
467                        RDI(level);
468                        RD("      visible\n");
469                        eina_array_push(render_objects, obj);
470                        obj->render_pre = EINA_TRUE;
471                     }
472                   else
473                     {
474                        RDI(level);
475                        RD("      skip\n");
476                     }
477                }
478           }
479  /*       else if (obj->smart.smart)
480           {
481              RDI(level);
482              RD("      smart + mot visible/was visible\n");
483              eina_array_push(render_objects, obj);
484              obj->render_pre = 1;
485              EINA_INLIST_FOREACH (evas_object_smart_members_get_direct(obj),
486                                   obj2)
487                {
488                   _evas_render_phase1_object_process(e, obj2,
489                                                      active_objects,
490                                                      restack_objects,
491                                                      delete_objects,
492                                                      render_objects,
493                                                      restack,
494                                                      redraw_all
495 #ifdef REND_DBG
496                                                      , level + 1
497 #endif
498                                                     );
499                }
500           }
501 */
502      }
503    if (!is_active) obj->restack = EINA_FALSE;
504    RDI(level);
505    RD("    ---]\n");
506    return clean_them;
507 }
508
509 static Eina_Bool
510 _evas_render_phase1_process(Evas *e,
511                             Eina_Array *active_objects,
512                             Eina_Array *restack_objects,
513                             Eina_Array *delete_objects,
514                             Eina_Array *render_objects,
515                             int *redraw_all)
516 {
517    Evas_Layer *lay;
518    Eina_Bool clean_them = EINA_FALSE;
519
520    RD("  [--- PHASE 1\n");
521    EINA_INLIST_FOREACH(e->layers, lay)
522      {
523         Evas_Object *obj;
524
525         EINA_INLIST_FOREACH(lay->objects, obj)
526           {
527              clean_them |= _evas_render_phase1_object_process
528                 (e, obj, active_objects, restack_objects, delete_objects,
529                  render_objects, 0, redraw_all, EINA_FALSE
530 #ifdef REND_DBG
531                  , 1
532 #endif
533                 );
534           }
535      }
536    RD("  ---]\n");
537    return clean_them;
538 }
539
540 static void
541 _evas_render_check_pending_objects(Eina_Array *pending_objects, Evas *e)
542 {
543    unsigned int i;
544
545    for (i = 0; i < pending_objects->count; ++i)
546      {
547         Evas_Object *obj;
548         int is_active;
549         Eina_Bool ok = EINA_FALSE;
550         obj = eina_array_data_get(pending_objects, i);
551         if (!obj->layer) goto clean_stuff;
552
553        //If the children are in active objects, They should be cleaned up.
554        if (obj->changed_map && _evas_render_has_map(obj))
555          goto clean_stuff;
556
557         evas_object_clip_recalc(obj);
558         is_active = evas_object_is_active(obj);
559
560         if ((!is_active) && (!obj->is_active) && (!obj->render_pre) &&
561             (!obj->rect_del))
562           {
563              ok = EINA_TRUE;
564              goto clean_stuff;
565           }
566
567         if (obj->is_active == is_active)
568           {
569              if (obj->changed)
570                {
571                   if (obj->smart.smart)
572                     {
573                        if (obj->render_pre || obj->rect_del) ok = EINA_TRUE;
574                     }
575                   else
576                     if ((is_active) && (obj->restack) && (!obj->clip.clipees) &&
577                         (_evas_render_can_render(obj) ||
578                          (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
579                       {
580                          if (!(obj->render_pre || obj->rect_del))
581                            ok = EINA_TRUE;
582                       }
583                     else
584                       if (is_active && (!obj->clip.clipees) &&
585                           (_evas_render_can_render(obj) ||
586                            (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
587                         {
588                            if (obj->render_pre || obj->rect_del) ok = EINA_TRUE;
589                         }
590                }
591              else
592                {
593                   if ((!obj->clip.clipees) && (obj->delete_me == 0) &&
594                       (!obj->cur.have_clipees || (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))
595                       && evas_object_is_opaque(obj) && evas_object_is_visible(obj))
596                     {
597                        if (obj->rect_del || obj->smart.smart) ok = EINA_TRUE;
598                     }
599                }
600           }
601
602 clean_stuff:
603         if (!ok)
604           {
605              eina_array_clean(&e->active_objects);
606              eina_array_clean(&e->render_objects);
607              eina_array_clean(&e->restack_objects);
608              eina_array_clean(&e->delete_objects);
609              e->invalidate = EINA_TRUE;
610              return ;
611           }
612      }
613 }
614
615 Eina_Bool
616 pending_change(void *data, void *gdata __UNUSED__)
617 {
618    Evas_Object *obj;
619
620    obj = data;
621    if (obj->delete_me) return EINA_FALSE;
622    if (obj->pre_render_done)
623      {
624         RD("  OBJ [%p] pending change %i -> 0, pre %i\n", obj, obj->changed, obj->pre_render_done);
625         obj->func->render_post(obj);
626         obj->pre_render_done = EINA_FALSE;
627         evas_object_change_reset(obj);
628      }
629    return obj->changed ? EINA_TRUE : EINA_FALSE;
630 }
631
632 static Eina_Bool
633 _evas_render_can_use_overlay(Evas *e, Evas_Object *obj)
634 {
635    Eina_Rectangle *r;
636    Evas_Object *tmp;
637    Eina_List *alphas = NULL;
638    Eina_List *opaques = NULL;
639    Evas_Object *video_parent = NULL;
640    Eina_Rectangle zone;
641    Evas_Coord xc1, yc1, xc2, yc2;
642    unsigned int i;
643    Eina_Bool nooverlay;
644
645    video_parent = _evas_object_image_video_parent_get(obj);
646
647    /* Check if any one is the stack make this object mapped */
648    tmp = obj;
649    while (tmp && !_evas_render_has_map(tmp))
650      tmp = tmp->smart.parent;
651
652    if (tmp && _evas_render_has_map(tmp)) return EINA_FALSE; /* we are mapped, we can't be an overlay */
653
654    if (!evas_object_is_visible(obj)) return EINA_FALSE; /* no need to update the overlay if it's not visible */
655
656    /* If any recoloring of the surface is needed, n overlay to */
657    if ((obj->cur.cache.clip.r != 255) ||
658        (obj->cur.cache.clip.g != 255) ||
659        (obj->cur.cache.clip.b != 255) ||
660        (obj->cur.cache.clip.a != 255))
661      return EINA_FALSE;
662
663    /* Check presence of transparent object on top of the video object */
664    EINA_RECTANGLE_SET(&zone,
665                       obj->cur.cache.clip.x,
666                       obj->cur.cache.clip.y,
667                       obj->cur.cache.clip.w,
668                       obj->cur.cache.clip.h);
669
670    for (i = e->active_objects.count - 1; i > 0; i--)
671      {
672         Eina_Rectangle self;
673         Eina_Rectangle *match;
674         Evas_Object *current;
675         Eina_List *l;
676         int xm1, ym1, xm2, ym2;
677
678         current = eina_array_data_get(&e->active_objects, i);
679
680         /* Did we find the video object in the stack ? */
681         if (current == video_parent || current == obj)
682           break;
683
684         EINA_RECTANGLE_SET(&self,
685                            current->cur.cache.clip.x,
686                            current->cur.cache.clip.y,
687                            current->cur.cache.clip.w,
688                            current->cur.cache.clip.h);
689
690         /* This doesn't cover the area of the video object, so don't bother with that object */
691         if (!eina_rectangles_intersect(&zone, &self))
692           continue;
693
694         xc1 = current->cur.cache.clip.x;
695         yc1 = current->cur.cache.clip.y;
696         xc2 = current->cur.cache.clip.x + current->cur.cache.clip.w;
697         yc2 = current->cur.cache.clip.y + current->cur.cache.clip.h;
698
699         if (evas_object_is_visible(current) &&
700             (!current->clip.clipees) &&
701             (current->cur.visible) &&
702             (!current->delete_me) &&
703             (current->cur.cache.clip.visible) &&
704             (!current->smart.smart))
705           {
706              Eina_Bool included = EINA_FALSE;
707
708              if (evas_object_is_opaque(current) ||
709                  ((current->func->has_opaque_rect) &&
710                   (current->func->has_opaque_rect(current))))
711                {
712                   /* The object is opaque */
713
714                   /* Check if the opaque object is inside another opaque object */
715                   EINA_LIST_FOREACH(opaques, l, match)
716                     {
717                        xm1 = match->x;
718                        ym1 = match->y;
719                        xm2 = match->x + match->w;
720                        ym2 = match->y + match->h;
721
722                        /* Both object are included */
723                        if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
724                          {
725                             included = EINA_TRUE;
726                             break;
727                          }
728                     }
729
730                   /* Not included yet */
731                   if (!included)
732                     {
733                        Eina_List *ln;
734                        Evas_Coord xn2, yn2;
735
736                        r = eina_rectangle_new(current->cur.cache.clip.x, current->cur.cache.clip.y,
737                                               current->cur.cache.clip.w, current->cur.cache.clip.h);
738
739                        opaques = eina_list_append(opaques, r);
740
741                        xn2 = r->x + r->w;
742                        yn2 = r->y + r->h;
743
744                        /* Remove all the transparent object that are covered by the new opaque object */
745                        EINA_LIST_FOREACH_SAFE(alphas, l, ln, match)
746                          {
747                             xm1 = match->x;
748                             ym1 = match->y;
749                             xm2 = match->x + match->w;
750                             ym2 = match->y + match->h;
751
752                             if (xm1 >= r->x && ym1 >= r->y && xm2 <= xn2 && ym2 <= yn2)
753                               {
754                                  /* The new rectangle is over some transparent object,
755                                     so remove the transparent object */
756                                  alphas = eina_list_remove_list(alphas, l);
757                               }
758                          }
759                     }
760                }
761              else
762                {
763                   /* The object has some transparency */
764
765                   /* Check if the transparent object is inside any other transparent object */
766                   EINA_LIST_FOREACH(alphas, l, match)
767                     {
768                        xm1 = match->x;
769                        ym1 = match->y;
770                        xm2 = match->x + match->w;
771                        ym2 = match->y + match->h;
772
773                        /* Both object are included */
774                        if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
775                          {
776                             included = EINA_TRUE;
777                             break;
778                          }
779                     }
780
781                   /* If not check if it is inside any opaque one */
782                   if (!included)
783                     {
784                        EINA_LIST_FOREACH(opaques, l, match)
785                          {
786                             xm1 = match->x;
787                             ym1 = match->y;
788                             xm2 = match->x + match->w;
789                             ym2 = match->y + match->h;
790
791                             /* Both object are included */
792                             if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
793                               {
794                                  included = EINA_TRUE;
795                                  break;
796                               }
797                          }
798                     }
799
800                   /* No inclusion at all, so add it */
801                   if (!included)
802                     {
803                        r = eina_rectangle_new(current->cur.cache.clip.x, current->cur.cache.clip.y,
804                                               current->cur.cache.clip.w, current->cur.cache.clip.h);
805
806                        alphas = eina_list_append(alphas, r);
807                     }
808                }
809           }
810      }
811
812    /* If there is any pending transparent object, then no overlay */
813    nooverlay = !!eina_list_count(alphas);
814
815    EINA_LIST_FREE(alphas, r)
816      eina_rectangle_free(r);
817    EINA_LIST_FREE(opaques, r)
818      eina_rectangle_free(r);
819
820    if (nooverlay)
821      return EINA_FALSE;
822
823    return EINA_TRUE;
824 }
825
826 Eina_Bool
827 _smart_members_changed_check(Evas_Object *obj)
828 {
829    Evas_Object *o2;
830
831    if (!evas_object_is_visible(obj) &&
832        !evas_object_was_visible(obj))
833      return EINA_FALSE;
834
835    if (!obj->smart.smart) return EINA_TRUE;
836    if (obj->changed_color) return EINA_TRUE;
837    if ((obj->changed_pchange) && (obj->changed_map)) return EINA_TRUE;
838
839    EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), o2)
840      {
841         if (!o2->changed) continue;
842         if (_smart_members_changed_check(o2)) return EINA_TRUE;
843      }
844
845    return EINA_FALSE;
846 }
847
848 Eina_Bool
849 evas_render_mapped(Evas *e, Evas_Object *obj, void *context, void *surface,
850                    int off_x, int off_y, int mapped,
851                    int ecx, int ecy, int ecw, int ech, Evas_Object *proxy_obj
852 #ifdef REND_DBG
853                    , int level
854 #endif
855                   )
856 {
857    void *ctx;
858    Evas_Object *obj2;
859    Eina_Bool clean_them = EINA_FALSE;
860    Eina_Bool proxy_src_clip = EINA_TRUE;
861
862    if (!proxy_obj)
863      {
864         if (evas_object_is_source_invisible(obj))
865           return clean_them;
866      }
867    else
868      proxy_src_clip = evas_object_image_source_clip_get(proxy_obj);
869
870    evas_object_clip_recalc(obj);
871
872    RDI(level);
873    RD("      { evas_render_mapped(%p, %p,   %p, %p,   %i, %i,   %i,   %i)\n", e, obj, context, surface, off_x, off_y, mapped, level);
874
875    if (mapped)
876      {
877         if (proxy_src_clip)
878           {
879              if ((!evas_object_is_visible(obj)) || (obj->clip.clipees)
880                  || (obj->cur.have_clipees))
881                {
882                   RDI(level);
883                   RD("      }\n");
884                   return clean_them;
885                }
886           }
887         else
888           {
889              RDI(level);
890              RD("      }\n");
891              return clean_them;
892           }
893      }
894    else if (!(((evas_object_is_active(obj) && (!obj->clip.clipees) &&
895                 (_evas_render_can_render(obj))))
896              ))
897      {
898         RDI(level);
899         RD("      }\n");
900         return clean_them;
901      }
902
903    // set render_pre - for child objs that may not have gotten it.
904    obj->pre_render_done = EINA_TRUE;
905    RD("          Hasmap: %p (%d) %p %d -> %d\n",obj->func->can_map,
906       obj->func->can_map ? obj->func->can_map(obj): -1,
907       obj->cur.map, obj->cur.usemap,
908       _evas_render_has_map(obj));
909    if (_evas_render_has_map(obj))
910      {
911         int sw, sh;
912         Eina_Bool changed = EINA_FALSE, rendered = EINA_FALSE;
913
914         clean_them = EINA_TRUE;
915
916         sw = obj->cur.geometry.w;
917         sh = obj->cur.geometry.h;
918         RDI(level);
919         RD("        mapped obj: %ix%i\n", sw, sh);
920         if ((sw <= 0) || (sh <= 0))
921           {
922              RDI(level);
923              RD("      }\n");
924              return clean_them;
925           }
926         evas_object_map_update(obj, off_x, off_y, sw, sh, sw, sh);
927
928         if (obj->map.surface)
929           {
930              if ((obj->map.surface_w != sw) ||
931                  (obj->map.surface_h != sh))
932                {
933                   RDI(level);
934                   RD("        new surf: %ix%i\n", sw, sh);
935                   obj->layer->evas->engine.func->image_map_surface_free
936                      (e->engine.data.output, obj->map.surface);
937                   obj->map.surface = NULL;
938                }
939           }
940         if (!obj->map.surface)
941           {
942              obj->map.surface_w = sw;
943              obj->map.surface_h = sh;
944
945              obj->map.surface =
946                 obj->layer->evas->engine.func->image_map_surface_new
947                 (e->engine.data.output, obj->map.surface_w,
948                  obj->map.surface_h,
949                  obj->cur.map->alpha);
950              RDI(level);
951              RD("        fisrt surf: %ix%i\n", sw, sh);
952              changed = EINA_TRUE;
953           }
954         if (!changed)
955           {
956              if (obj->smart.smart)
957                {
958                   Evas_Object *o2;
959
960                   EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj),
961                                       o2)
962                     {
963                        if (!o2->changed) continue;
964                        changed = _smart_members_changed_check(o2);
965                        if (changed) break;
966                     }
967                   if (obj->changed_color) changed = EINA_TRUE;
968                }
969              else if (obj->changed)
970                {
971                   if (((obj->changed_pchange) && (obj->changed_map)) ||
972                       (obj->changed_color))
973                     changed = EINA_TRUE;
974                }
975           }
976
977         /* mark the old map as invalid, so later we don't reuse it as a
978          * cache. */
979         if (changed && obj->prev.map)
980            obj->prev.valid_map = EINA_FALSE;
981
982         // clear surface before re-render
983         if ((changed) && (obj->map.surface))
984           {
985              int off_x2, off_y2;
986
987              RDI(level);
988              RD("        children redraw\n");
989              // FIXME: calculate "changes" within map surface and only clear
990              // and re-render those
991              if (obj->cur.map->alpha)
992                {
993                   ctx = e->engine.func->context_new(e->engine.data.output);
994                   e->engine.func->context_color_set
995                      (e->engine.data.output, ctx, 0, 0, 0, 0);
996                   e->engine.func->context_render_op_set
997                      (e->engine.data.output, ctx, EVAS_RENDER_COPY);
998                   e->engine.func->rectangle_draw(e->engine.data.output,
999                                                  ctx,
1000                                                  obj->map.surface,
1001                                                  0, 0,
1002                                                  obj->map.surface_w,
1003                                                  obj->map.surface_h);
1004                   e->engine.func->context_free(e->engine.data.output, ctx);
1005                }
1006              ctx = e->engine.func->context_new(e->engine.data.output);
1007              off_x2 = -obj->cur.geometry.x;
1008              off_y2 = -obj->cur.geometry.y;
1009              if (obj->smart.smart)
1010                {
1011                   EINA_INLIST_FOREACH
1012                      (evas_object_smart_members_get_direct(obj), obj2)
1013                        {
1014                           clean_them |= evas_render_mapped(e, obj2, ctx,
1015                                                            obj->map.surface,
1016                                                            off_x2, off_y2, 1,
1017                                                            ecx, ecy, ecw, ech,
1018                                                            proxy_obj
1019 #ifdef REND_DBG
1020                                                            , level + 1
1021 #endif
1022                                                           );
1023                           evas_object_change_reset(obj2);
1024                        }
1025                }
1026              else
1027                {
1028                   int x = 0, y = 0, w = 0, h = 0;
1029
1030                   w = obj->map.surface_w;
1031                   h = obj->map.surface_h;
1032                   RECTS_CLIP_TO_RECT(x, y, w, h,
1033                                      obj->cur.geometry.x + off_x2,
1034                                      obj->cur.geometry.y + off_y2,
1035                                      obj->cur.geometry.w,
1036                                      obj->cur.geometry.h);
1037
1038                   e->engine.func->context_clip_set(e->engine.data.output,
1039                                                    ctx, x, y, w, h);
1040                   obj->func->render(obj, e->engine.data.output, ctx,
1041                                     obj->map.surface, off_x2, off_y2);
1042                }
1043              e->engine.func->context_free(e->engine.data.output, ctx);
1044              rendered = EINA_TRUE;
1045           }
1046
1047         RDI(level);
1048         RD("        draw map\n");
1049
1050         if (rendered)
1051           {
1052              obj->map.surface = e->engine.func->image_dirty_region
1053                 (e->engine.data.output, obj->map.surface,
1054                  0, 0, obj->map.surface_w, obj->map.surface_h);
1055              obj->cur.valid_map = EINA_TRUE;
1056           }
1057         e->engine.func->context_clip_unset(e->engine.data.output,
1058                                            context);
1059         if (obj->map.surface)
1060           {
1061              if (obj->cur.clipper)
1062                {
1063                   int x, y, w, h;
1064                   evas_object_clip_recalc(obj);
1065                   x = obj->cur.cache.clip.x;
1066                   y = obj->cur.cache.clip.y;
1067                   w = obj->cur.cache.clip.w;
1068                   h = obj->cur.cache.clip.h;
1069
1070                   if (obj->smart.smart)
1071                     {
1072                        Evas_Object *tobj;
1073
1074                        obj->cur.cache.clip.dirty = EINA_TRUE;
1075                        tobj = obj->cur.map_parent;
1076                        obj->cur.map_parent = obj->cur.clipper->cur.map_parent;
1077                        obj->cur.map_parent = tobj;
1078                     }
1079
1080                   RECTS_CLIP_TO_RECT(x, y, w, h,
1081                                      obj->cur.clipper->cur.cache.clip.x,
1082                                      obj->cur.clipper->cur.cache.clip.y,
1083                                      obj->cur.clipper->cur.cache.clip.w,
1084                                      obj->cur.clipper->cur.cache.clip.h);
1085
1086                   e->engine.func->context_clip_set(e->engine.data.output,
1087                                                    context,
1088                                                    x + off_x, y + off_y, w, h);
1089
1090                }
1091           }
1092 //        if (surface == e->engine.data.output)
1093           e->engine.func->context_clip_clip(e->engine.data.output,
1094                                             context,
1095                                             ecx, ecy, ecw, ech);
1096         if (obj->cur.cache.clip.visible)
1097           {
1098              obj->layer->evas->engine.func->context_multiplier_unset
1099                (e->engine.data.output, context);
1100              obj->layer->evas->engine.func->image_map_draw
1101                (e->engine.data.output, context, surface,
1102                    obj->map.surface, obj->spans,
1103                    obj->cur.map->smooth, 0);
1104           }
1105         // FIXME: needs to cache these maps and
1106         // keep them only rendering updates
1107         //        obj->layer->evas->engine.func->image_map_surface_free
1108         //          (e->engine.data.output, obj->map.surface);
1109         //        obj->map.surface = NULL;
1110      }
1111    else
1112      {
1113         if (0 && obj->cur.cached_surface)
1114           fprintf(stderr, "We should cache '%s' [%i, %i, %i, %i]\n",
1115                   evas_object_type_get(obj),
1116                   obj->cur.bounding_box.x, obj->cur.bounding_box.x,
1117                   obj->cur.bounding_box.w, obj->cur.bounding_box.h);
1118         if (mapped)
1119           {
1120              RDI(level);
1121              RD("        draw child of mapped obj\n");
1122              ctx = e->engine.func->context_new(e->engine.data.output);
1123              if (obj->smart.smart)
1124                {
1125                   EINA_INLIST_FOREACH
1126                      (evas_object_smart_members_get_direct(obj), obj2)
1127                        {
1128                           clean_them |= evas_render_mapped(e, obj2, ctx,
1129                                                            surface,
1130                                                            off_x, off_y, 1,
1131                                                            ecx, ecy, ecw, ech,
1132                                                            proxy_obj
1133 #ifdef REND_DBG
1134                                                            , level + 1
1135 #endif
1136                                                           );
1137                        }
1138                }
1139              else
1140                {
1141                   RDI(level);
1142
1143                   if (obj->cur.clipper)
1144                     {
1145                        int x, y, w, h;
1146
1147                        if (proxy_src_clip)
1148                          {
1149                             if (_evas_render_has_map(obj))
1150                               evas_object_clip_recalc(obj);
1151
1152                             x = obj->cur.cache.clip.x + off_x;
1153                             y = obj->cur.cache.clip.y + off_y;
1154                             w = obj->cur.cache.clip.w;
1155                             h = obj->cur.cache.clip.h;
1156
1157                             RECTS_CLIP_TO_RECT(x, y, w, h,
1158                                                obj->cur.clipper->cur.cache.clip.x + off_x,
1159                                                obj->cur.clipper->cur.cache.clip.y + off_y,
1160                                                obj->cur.clipper->cur.cache.clip.w,
1161                                                obj->cur.clipper->cur.cache.clip.h);
1162
1163                             e->engine.func->context_clip_set(e->engine.data.output,
1164                                                              ctx, x, y, w, h);
1165
1166                          }
1167                        else
1168                          {
1169                             //FIXME: Consider to clip by the proxy clipper.
1170                             if (proxy_obj && (proxy_obj != obj))
1171                               {
1172                                  if (_evas_render_has_map(obj))
1173                                    evas_object_clip_recalc(obj);
1174
1175                                  x = obj->cur.clipper->cur.geometry.x + off_x;
1176                                  y = obj->cur.clipper->cur.geometry.y + off_y;
1177                                  w = obj->cur.clipper->cur.geometry.w;
1178                                  h = obj->cur.clipper->cur.geometry.h;
1179
1180                                  e->engine.func->context_clip_set(e->engine.data.output,
1181                                                                   ctx, x, y, w, h);
1182                               }
1183                          }
1184                     }
1185                   obj->func->render(obj, e->engine.data.output, ctx,
1186                                     surface, off_x, off_y);
1187                }
1188              e->engine.func->context_free(e->engine.data.output, ctx);
1189           }
1190         else
1191           {
1192              if (obj->cur.clipper)
1193                {
1194                   int x, y, w, h;
1195
1196                   if (_evas_render_has_map(obj))
1197                     evas_object_clip_recalc(obj);
1198                   x = obj->cur.cache.clip.x;
1199                   y = obj->cur.cache.clip.y;
1200                   w = obj->cur.cache.clip.w;
1201                   h = obj->cur.cache.clip.h;
1202                   RECTS_CLIP_TO_RECT(x, y, w, h,
1203                                      obj->cur.clipper->cur.cache.clip.x,
1204                                      obj->cur.clipper->cur.cache.clip.y,
1205                                      obj->cur.clipper->cur.cache.clip.w,
1206                                      obj->cur.clipper->cur.cache.clip.h);
1207                   e->engine.func->context_clip_set(e->engine.data.output,
1208                                                    context,
1209                                                    x + off_x, y + off_y, w, h);
1210                   e->engine.func->context_clip_clip(e->engine.data.output,
1211                                                     context,
1212                                                     ecx, ecy, ecw, ech);
1213                }
1214
1215              RDI(level);
1216              RD("        draw normal obj\n");
1217              obj->func->render(obj, e->engine.data.output, context, surface,
1218                                off_x, off_y);
1219           }
1220         if (obj->changed_map) clean_them = EINA_TRUE;
1221      }
1222    RDI(level);
1223    RD("      }\n");
1224
1225    return clean_them;
1226 }
1227
1228 static void
1229 _evas_render_cutout_add(Evas *e, Evas_Object *obj, int off_x, int off_y)
1230 {
1231    if (evas_object_is_source_invisible(obj)) return;
1232    if (evas_object_is_opaque(obj))
1233      {
1234         Evas_Coord cox, coy, cow, coh;
1235
1236         cox = obj->cur.cache.clip.x;
1237         coy = obj->cur.cache.clip.y;
1238         cow = obj->cur.cache.clip.w;
1239         coh = obj->cur.cache.clip.h;
1240         if ((obj->cur.map) && (obj->cur.usemap))
1241           {
1242              Evas_Object *oo;
1243
1244              oo = obj;
1245              while (oo->cur.clipper)
1246                {
1247                   if ((oo->cur.clipper->cur.map_parent
1248                        != oo->cur.map_parent) &&
1249                       (!((oo->cur.map) && (oo->cur.usemap))))
1250                     break;
1251                   RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
1252                                      oo->cur.geometry.x,
1253                                      oo->cur.geometry.y,
1254                                      oo->cur.geometry.w,
1255                                      oo->cur.geometry.h);
1256                   oo = oo->cur.clipper;
1257                }
1258           }
1259         e->engine.func->context_cutout_add
1260           (e->engine.data.output, e->engine.data.context,
1261               cox + off_x, coy + off_y, cow, coh);
1262      }
1263    else
1264      {
1265         if (obj->func->get_opaque_rect)
1266           {
1267              Evas_Coord obx, oby, obw, obh;
1268
1269              obj->func->get_opaque_rect(obj, &obx, &oby, &obw, &obh);
1270              if ((obw > 0) && (obh > 0))
1271                {
1272                   obx += off_x;
1273                   oby += off_y;
1274                   RECTS_CLIP_TO_RECT(obx, oby, obw, obh,
1275                                      obj->cur.cache.clip.x + off_x,
1276                                      obj->cur.cache.clip.y + off_y,
1277                                      obj->cur.cache.clip.w,
1278                                      obj->cur.cache.clip.h);
1279                   e->engine.func->context_cutout_add
1280                     (e->engine.data.output, e->engine.data.context,
1281                         obx, oby, obw, obh);
1282                }
1283           }
1284      }
1285 }
1286
1287 static Eina_List *
1288 evas_render_updates_internal(Evas *e,
1289                              unsigned char make_updates,
1290                              unsigned char do_draw)
1291 {
1292    Evas_Object *obj;
1293    Eina_List *updates = NULL;
1294    Eina_List *ll;
1295    void *surface;
1296    Eina_Bool clean_them = EINA_FALSE;
1297    Eina_Bool alpha;
1298    Eina_Rectangle *r;
1299    int ux, uy, uw, uh;
1300    int cx, cy, cw, ch;
1301    unsigned int i, j;
1302    int redraw_all = 0;
1303    Eina_Bool haveup = 0;
1304
1305    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1306    return NULL;
1307    MAGIC_CHECK_END();
1308    if (!e->changed) return NULL;
1309
1310 #ifdef EVAS_CSERVE2
1311    if (evas_cserve2_use_get())
1312       evas_cserve2_dispatch();
1313 #endif
1314    evas_call_smarts_calculate(e);
1315
1316    RD("[--- RENDER EVAS (size: %ix%i)\n", e->viewport.w, e->viewport.h);
1317
1318    evas_event_callback_call(e, EVAS_CALLBACK_RENDER_PRE, NULL);
1319
1320    /* Check if the modified object mean recalculating every thing */
1321    if (!e->invalidate)
1322      _evas_render_check_pending_objects(&e->pending_objects, e);
1323
1324    /* phase 1. add extra updates for changed objects */
1325    if (e->invalidate || e->render_objects.count <= 0)
1326      clean_them = _evas_render_phase1_process(e,
1327                                               &e->active_objects,
1328                                               &e->restack_objects,
1329                                               &e->delete_objects,
1330                                               &e->render_objects,
1331                                               &redraw_all);
1332
1333    /* phase 1.5. check if the video should be inlined or stay in their overlay */
1334    alpha = e->engine.func->canvas_alpha_get(e->engine.data.output,
1335                                             e->engine.data.context);
1336
1337    EINA_LIST_FOREACH(e->video_objects, ll, obj)
1338      {
1339         /* we need the surface to be transparent to display the underlying overlay */
1340         if (alpha && _evas_render_can_use_overlay(e, obj))
1341           _evas_object_image_video_overlay_show(obj);
1342         else
1343           _evas_object_image_video_overlay_hide(obj);
1344      }
1345    /* phase 1.8. pre render for proxy */
1346    _evas_render_phase1_direct(e, &e->active_objects, &e->restack_objects,
1347                               &e->delete_objects, &e->render_objects);
1348
1349    /* phase 2. force updates for restacks */
1350    for (i = 0; i < e->restack_objects.count; ++i)
1351      {
1352         obj = eina_array_data_get(&e->restack_objects, i);
1353         obj->func->render_pre(obj);
1354         _evas_render_prev_cur_clip_cache_add(e, obj);
1355      }
1356    eina_array_clean(&e->restack_objects);
1357
1358    /* phase 3. add exposes */
1359    EINA_LIST_FREE(e->damages, r)
1360      {
1361         e->engine.func->output_redraws_rect_add(e->engine.data.output,
1362                                                 r->x, r->y, r->w, r->h);
1363         eina_rectangle_free(r);
1364      }
1365
1366    /* phase 4. framespace, output & viewport changes */
1367    if (e->viewport.changed)
1368      {
1369         e->engine.func->output_redraws_rect_add(e->engine.data.output,
1370                                                 0, 0,
1371                                                 e->output.w, e->output.h);
1372      }
1373    if (e->output.changed)
1374      {
1375         e->engine.func->output_resize(e->engine.data.output,
1376                                       e->output.w, e->output.h);
1377         e->engine.func->output_redraws_rect_add(e->engine.data.output,
1378                                                 0, 0,
1379                                                 e->output.w, e->output.h);
1380      }
1381    if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
1382      {
1383         ERR("viewport size != output size!");
1384      }
1385
1386    if (e->framespace.changed)
1387      {
1388         int fx, fy, fw, fh;
1389
1390         fx = e->viewport.x - e->framespace.x;
1391         fy = e->viewport.y - e->framespace.y;
1392         fw = e->viewport.w + e->framespace.w;
1393         fh = e->viewport.h + e->framespace.h;
1394         if (fx < 0) fx = 0;
1395         if (fy < 0) fy = 0;
1396         e->engine.func->output_redraws_rect_add(e->engine.data.output,
1397                                                 fx, fy, fw, fh);
1398      }
1399
1400    /* phase 4.5: check if object is not in framespace. if not, we need to clip 
1401     * it to the 'master' clip.
1402     * 
1403     * NB: This is for the wayland engine(s). If we do not do this, then 
1404     * objects will draw outside the viewport and potentially onto the frame 
1405     * itself */
1406    if (!strncmp(e->engine.module->definition->name, "wayland", 7))
1407      {
1408         Eina_Rectangle clip_rect;
1409
1410         /* see if the master clip has been added yet, if not, then create */
1411         if (!e->framespace.clip)
1412           {
1413              e->framespace.clip = evas_object_rectangle_add(e);
1414              evas_object_color_set(e->framespace.clip, 255, 255, 255, 255);
1415              evas_object_move(e->framespace.clip,
1416                               e->framespace.x, e->framespace.y);
1417              evas_object_resize(e->framespace.clip,
1418                                 e->viewport.w - e->framespace.w, 
1419                                 e->viewport.h - e->framespace.h);
1420              evas_object_show(e->framespace.clip);
1421           }
1422         else
1423           {
1424              /* master clip is already present. check for size changes in the 
1425               * viewport, and update master clip size if needed */
1426              if ((e->viewport.changed) || (e->output.changed) || 
1427                  (e->framespace.changed))
1428                {
1429                   evas_object_move(e->framespace.clip, 
1430                                    e->framespace.x, e->framespace.y);
1431                   evas_object_resize(e->framespace.clip,
1432                                      e->viewport.w - e->framespace.w,
1433                                      e->viewport.h - e->framespace.h);
1434                }
1435           }
1436
1437         EINA_RECTANGLE_SET(&clip_rect,
1438                            e->framespace.clip->cur.geometry.x,
1439                            e->framespace.clip->cur.geometry.y,
1440                            e->framespace.clip->cur.geometry.w,
1441                            e->framespace.clip->cur.geometry.h)
1442
1443         /* With the master clip all setup, we need to loop the objects on this 
1444          * canvas and determine if the object is in the viewport space. If it 
1445          * is in the viewport space (and not in framespace), then we need to 
1446          * clip the object to the master clip so that it does not draw on top 
1447          * of the frame (eg: elm 3d test) */
1448         for (i = 0; i < e->render_objects.count; ++i)
1449           {
1450              Eina_Rectangle obj_rect;
1451              Evas_Object *pclip;
1452
1453              obj = eina_array_data_get(&e->render_objects, i);
1454              if (obj->is_frame) continue;
1455
1456              if (obj->delete_me) continue;
1457
1458              EINA_RECTANGLE_SET(&obj_rect,
1459                                 obj->cur.geometry.x, obj->cur.geometry.y,
1460                                 obj->cur.geometry.w, obj->cur.geometry.h);
1461
1462              /* if the object does not intersect our clip rect, ignore it */
1463              if (!eina_rectangles_intersect(&clip_rect, &obj_rect))
1464                continue;
1465
1466              if (!(pclip = evas_object_clip_get(obj)))
1467                {
1468                   /* skip clipping if the object is itself the 
1469                    * framespace clip */
1470                   if (obj == e->framespace.clip) continue;
1471
1472                   /* clip this object so it does not draw on the window frame */
1473                   evas_object_clip_set(obj, e->framespace.clip);
1474                }
1475           }
1476      }
1477
1478    if (redraw_all)
1479      {
1480         e->engine.func->output_redraws_rect_add(e->engine.data.output, 0, 0,
1481                                                 e->output.w, e->output.h);
1482      }
1483
1484    /* phase 5. add obscures */
1485    EINA_LIST_FOREACH(e->obscures, ll, r)
1486      {
1487         e->engine.func->output_redraws_rect_del(e->engine.data.output,
1488                                                 r->x, r->y, r->w, r->h);
1489      }
1490    /* build obscure objects list of active objects that obscure */
1491    for (i = 0; i < e->active_objects.count; ++i)
1492      {
1493         obj = eina_array_data_get(&e->active_objects, i);
1494         if (UNLIKELY((evas_object_is_opaque(obj) ||
1495                       ((obj->func->has_opaque_rect) &&
1496                        (obj->func->has_opaque_rect(obj)))) &&
1497                      evas_object_is_visible(obj) &&
1498                      (!obj->clip.clipees) &&
1499                      (obj->cur.visible) &&
1500                      (!obj->delete_me) &&
1501                      (obj->cur.cache.clip.visible) &&
1502                      (!obj->smart.smart)))
1503           /*      obscuring_objects = eina_list_append(obscuring_objects, obj); */
1504           eina_array_push(&e->obscuring_objects, obj);
1505      }
1506
1507    /* save this list */
1508    /*    obscuring_objects_orig = obscuring_objects; */
1509    /*    obscuring_objects = NULL; */
1510    /* phase 6. go thru each update rect and render objects in it*/
1511    if (do_draw)
1512      {
1513         unsigned int offset = 0;
1514
1515         while ((surface =
1516                 e->engine.func->output_redraws_next_update_get
1517                 (e->engine.data.output,
1518                  &ux, &uy, &uw, &uh,
1519                  &cx, &cy, &cw, &ch)))
1520           {
1521              int off_x, off_y;
1522
1523              RD("  [--- UPDATE %i %i %ix%i\n", ux, uy, uw, uh);
1524              if (make_updates)
1525                {
1526                   Eina_Rectangle *rect;
1527
1528                   NEW_RECT(rect, ux, uy, uw, uh);
1529                   if (rect)
1530                     updates = eina_list_append(updates, rect);
1531                }
1532              haveup = EINA_TRUE;
1533              off_x = cx - ux;
1534              off_y = cy - uy;
1535              /* build obscuring objects list (in order from bottom to top) */
1536              if (alpha)
1537                {
1538                   e->engine.func->context_clip_set(e->engine.data.output,
1539                                                    e->engine.data.context,
1540                                                    ux + off_x, uy + off_y, uw, uh);
1541                }
1542              for (i = 0; i < e->obscuring_objects.count; ++i)
1543                {
1544                   obj = (Evas_Object *)eina_array_data_get
1545                      (&e->obscuring_objects, i);
1546                   if (evas_object_is_in_output_rect(obj, ux, uy, uw, uh))
1547                     {
1548                        eina_array_push(&e->temporary_objects, obj);
1549
1550                        /* reset the background of the area if needed (using cutout and engine alpha flag to help) */
1551                        if (alpha)
1552                          _evas_render_cutout_add(e, obj, off_x, off_y);
1553                     }
1554                }
1555              if (alpha)
1556                {
1557                   e->engine.func->context_color_set(e->engine.data.output,
1558                                                     e->engine.data.context,
1559                                                     0, 0, 0, 0);
1560                   e->engine.func->context_multiplier_unset
1561                      (e->engine.data.output, e->engine.data.context);
1562                   e->engine.func->context_render_op_set(e->engine.data.output,
1563                                                         e->engine.data.context,
1564                                                         EVAS_RENDER_COPY);
1565                   e->engine.func->rectangle_draw(e->engine.data.output,
1566                                                  e->engine.data.context,
1567                                                  surface,
1568                                                  cx, cy, cw, ch);
1569                   e->engine.func->context_cutout_clear(e->engine.data.output,
1570                                                        e->engine.data.context);
1571                   e->engine.func->context_clip_unset(e->engine.data.output,
1572                                                      e->engine.data.context);
1573                }
1574
1575              /* render all object that intersect with rect */
1576              for (i = 0; i < e->active_objects.count; ++i)
1577                {
1578                   obj = eina_array_data_get(&e->active_objects, i);
1579
1580                   /* if it's in our outpout rect and it doesn't clip anything */
1581                   RD("    OBJ: [%p] '%s' %i %i %ix%i\n", obj, obj->type, obj->cur.geometry.x, obj->cur.geometry.y, obj->cur.geometry.w, obj->cur.geometry.h);
1582                   if ((evas_object_is_in_output_rect(obj, ux, uy, uw, uh) ||
1583                        (obj->smart.smart)) &&
1584                       (!obj->clip.clipees) &&
1585                       (obj->cur.visible) &&
1586                       (!obj->delete_me) &&
1587                       (obj->cur.cache.clip.visible) &&
1588 //                    (!obj->smart.smart) &&
1589                       ((obj->cur.color.a > 0 || obj->cur.render_op != EVAS_RENDER_BLEND)))
1590                     {
1591                        int x, y, w, h;
1592
1593                        RD("      DRAW (vis: %i, a: %i, clipees: %p\n", obj->cur.visible, obj->cur.color.a, obj->clip.clipees);
1594                        if ((e->temporary_objects.count > offset) &&
1595                            (eina_array_data_get(&e->temporary_objects, offset) == obj))
1596                          offset++;
1597                        x = cx; y = cy; w = cw; h = ch;
1598                        if (((w > 0) && (h > 0)) || (obj->smart.smart))
1599                          {
1600                             if (!obj->smart.smart)
1601                               {
1602                                  RECTS_CLIP_TO_RECT(x, y, w, h,
1603                                                     obj->cur.cache.clip.x + off_x,
1604                                                     obj->cur.cache.clip.y + off_y,
1605                                                     obj->cur.cache.clip.w,
1606                                                     obj->cur.cache.clip.h);
1607                               }
1608                             if (obj->cur.mask)
1609                               e->engine.func->context_mask_set(e->engine.data.output,
1610                                                                e->engine.data.context,
1611                                                                obj->cur.mask->func->engine_data_get(obj->cur.mask),
1612                                                                obj->cur.mask->cur.geometry.x + off_x,
1613                                                                obj->cur.mask->cur.geometry.y + off_y,
1614                                                                obj->cur.mask->cur.geometry.w,
1615                                                                obj->cur.mask->cur.geometry.h);
1616                             else
1617                               e->engine.func->context_mask_unset(e->engine.data.output,
1618                                                                  e->engine.data.context);
1619                             e->engine.func->context_clip_set(e->engine.data.output,
1620                                                              e->engine.data.context,
1621                                                              x, y, w, h);
1622 #if 1 /* FIXME: this can slow things down... figure out optimum... coverage */
1623                             for (j = offset; j < e->temporary_objects.count; ++j)
1624                               {
1625                                  Evas_Object *obj2;
1626
1627                                  obj2 = (Evas_Object *)eina_array_data_get
1628                                    (&e->temporary_objects, j);
1629                                  _evas_render_cutout_add(e, obj2, off_x, off_y);
1630                               }
1631 #endif
1632                             clean_them |= evas_render_mapped(e, obj, e->engine.data.context,
1633                                                              surface, off_x, off_y, 0,
1634                                                              cx, cy, cw, ch,
1635                                                              NULL
1636 #ifdef REND_DBG
1637                                                              , 1
1638 #endif
1639                                                             );
1640
1641                             e->engine.func->context_cutout_clear(e->engine.data.output,
1642                                                                  e->engine.data.context);
1643                          }
1644                     }
1645                }
1646              /* punch rect out */
1647              e->engine.func->output_redraws_next_update_push(e->engine.data.output,
1648                                                              surface,
1649                                                              ux, uy, uw, uh);
1650              /* free obscuring objects list */
1651              eina_array_clean(&e->temporary_objects);
1652              RD("  ---]\n");
1653           }
1654         /* flush redraws */
1655         if (haveup)
1656           {
1657              evas_event_callback_call(e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
1658              e->engine.func->output_flush(e->engine.data.output);
1659              evas_event_callback_call(e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
1660           }
1661      }
1662    /* clear redraws */
1663    e->engine.func->output_redraws_clear(e->engine.data.output);
1664    /* and do a post render pass */
1665    for (i = 0; i < e->active_objects.count; ++i)
1666      {
1667         obj = eina_array_data_get(&e->active_objects, i);
1668         obj->pre_render_done = EINA_FALSE;
1669         RD("    OBJ [%p] post... %i %i\n", obj, obj->changed, do_draw);
1670         if ((obj->changed) && (do_draw))
1671           {
1672              RD("    OBJ [%p] post... func1\n", obj);
1673              obj->func->render_post(obj);
1674              obj->restack = EINA_FALSE;
1675              evas_object_change_reset(obj);
1676           }
1677         else if (clean_them)
1678           {
1679              RD("    OBJ [%p] post... func2\n", obj);
1680              obj->func->render_post(obj);
1681              obj->restack = EINA_FALSE;
1682              evas_object_change_reset(obj);
1683           }
1684         /* moved to other pre-process phase 1
1685            if (obj->delete_me == 2)
1686            {
1687            delete_objects = eina_list_append(delete_objects, obj);
1688            }
1689            else if (obj->delete_me != 0) obj->delete_me++;
1690          */
1691      }
1692    /* free our obscuring object list */
1693    eina_array_clean(&e->obscuring_objects);
1694
1695    /* If some object are still marked as changed, do not remove
1696       them from the pending list. */
1697    eina_array_remove(&e->pending_objects, pending_change, NULL);
1698
1699    for (i = 0; i < e->render_objects.count; ++i)
1700      {
1701         obj = eina_array_data_get(&e->render_objects, i);
1702         obj->pre_render_done = EINA_FALSE;
1703         if ((obj->changed) && (do_draw))
1704           {
1705              obj->func->render_post(obj);
1706              obj->restack = EINA_FALSE;
1707              evas_object_change_reset(obj);
1708           }
1709      }
1710
1711    /* delete all objects flagged for deletion now */
1712    for (i = 0; i < e->delete_objects.count; ++i)
1713      {
1714         obj = eina_array_data_get(&e->delete_objects, i);
1715         evas_object_free(obj, 1);
1716      }
1717    eina_array_clean(&e->delete_objects);
1718
1719    e->changed = EINA_FALSE;
1720    e->viewport.changed = EINA_FALSE;
1721    e->output.changed = EINA_FALSE;
1722    e->framespace.changed = EINA_FALSE;
1723    e->invalidate = EINA_FALSE;
1724
1725    // always clean... lots of mem waste!
1726    /* If their are some object to restack or some object to delete,
1727     * it's useless to keep the render object list around. */
1728    if (clean_them)
1729      {
1730         eina_array_clean(&e->active_objects);
1731         eina_array_clean(&e->render_objects);
1732         eina_array_clean(&e->restack_objects);
1733         eina_array_clean(&e->temporary_objects);
1734         eina_array_foreach(&e->clip_changes, _evas_clip_changes_free, NULL);
1735         eina_array_clean(&e->clip_changes);
1736 /* we should flush here and have a mempool system for this        
1737         eina_array_flush(&e->active_objects);
1738         eina_array_flush(&e->render_objects);
1739         eina_array_flush(&e->restack_objects);
1740         eina_array_flush(&e->delete_objects);
1741         eina_array_flush(&e->obscuring_objects);
1742         eina_array_flush(&e->temporary_objects);
1743         eina_array_flush(&e->clip_changes);
1744  */
1745         e->invalidate = EINA_TRUE;
1746      }
1747
1748    evas_module_clean();
1749
1750    evas_event_callback_call(e, EVAS_CALLBACK_RENDER_POST, NULL);
1751
1752    RD("---]\n");
1753
1754    return updates;
1755 }
1756
1757 EAPI void
1758 evas_render_updates_free(Eina_List *updates)
1759 {
1760    Eina_Rectangle *r;
1761
1762    EINA_LIST_FREE(updates, r)
1763       eina_rectangle_free(r);
1764 }
1765
1766 EAPI Eina_List *
1767 evas_render_updates(Evas *e)
1768 {
1769    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1770    return NULL;
1771    MAGIC_CHECK_END();
1772
1773    if (!e->changed) return NULL;
1774    return evas_render_updates_internal(e, 1, 1);
1775 }
1776
1777 EAPI void
1778 evas_render(Evas *e)
1779 {
1780    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1781    return;
1782    MAGIC_CHECK_END();
1783
1784    if (!e->changed) return;
1785    evas_render_updates_internal(e, 0, 1);
1786 }
1787
1788 EAPI void
1789 evas_norender(Evas *e)
1790 {
1791    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1792    return;
1793    MAGIC_CHECK_END();
1794
1795    //   if (!e->changed) return;
1796    evas_render_updates_internal(e, 0, 0);
1797 }
1798
1799 EAPI void
1800 evas_render_idle_flush(Evas *e)
1801 {
1802    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1803    return;
1804    MAGIC_CHECK_END();
1805
1806    evas_fonts_zero_presure(e);
1807
1808    if ((e->engine.func) && (e->engine.func->output_idle_flush) &&
1809        (e->engine.data.output))
1810      e->engine.func->output_idle_flush(e->engine.data.output);
1811
1812    eina_array_flush(&e->active_objects);
1813    eina_array_flush(&e->render_objects);
1814    eina_array_flush(&e->restack_objects);
1815    eina_array_flush(&e->delete_objects);
1816    eina_array_flush(&e->obscuring_objects);
1817    eina_array_flush(&e->temporary_objects);
1818    eina_array_foreach(&e->clip_changes, _evas_clip_changes_free, NULL);
1819    eina_array_flush(&e->clip_changes);
1820
1821    e->invalidate = EINA_TRUE;
1822 }
1823
1824 EAPI void
1825 evas_sync(Evas *e)
1826 {
1827   (void) e;
1828 }
1829
1830 static void
1831 _evas_render_dump_map_surfaces(Evas_Object *obj)
1832 {
1833    if ((obj->cur.map) && obj->map.surface)
1834      {
1835         obj->layer->evas->engine.func->image_map_surface_free
1836            (obj->layer->evas->engine.data.output, obj->map.surface);
1837         obj->map.surface = NULL;
1838      }
1839
1840    if (obj->smart.smart)
1841      {
1842         Evas_Object *obj2;
1843
1844         EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2)
1845            _evas_render_dump_map_surfaces(obj2);
1846      }
1847 }
1848
1849 EAPI void
1850 evas_render_dump(Evas *e)
1851 {
1852    Evas_Layer *lay;
1853
1854    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1855    return;
1856    MAGIC_CHECK_END();
1857
1858    EINA_INLIST_FOREACH(e->layers, lay)
1859      {
1860         Evas_Object *obj;
1861
1862         EINA_INLIST_FOREACH(lay->objects, obj)
1863           {
1864              if ((obj->type) && (!strcmp(obj->type, "image")))
1865                evas_object_inform_call_image_unloaded(obj);
1866              _evas_render_dump_map_surfaces(obj);
1867           }
1868      }
1869    if ((e->engine.func) && (e->engine.func->output_dump) &&
1870        (e->engine.data.output))
1871      e->engine.func->output_dump(e->engine.data.output);
1872 }
1873
1874 void
1875 evas_render_invalidate(Evas *e)
1876 {
1877    MAGIC_CHECK(e, Evas, MAGIC_EVAS);
1878    return;
1879    MAGIC_CHECK_END();
1880
1881    eina_array_clean(&e->active_objects);
1882    eina_array_clean(&e->render_objects);
1883
1884    eina_array_flush(&e->restack_objects);
1885    eina_array_flush(&e->delete_objects);
1886
1887    e->invalidate = EINA_TRUE;
1888 }
1889
1890 void
1891 evas_render_object_recalc(Evas_Object *obj)
1892 {
1893    MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
1894    return;
1895    MAGIC_CHECK_END();
1896
1897    if ((!obj->changed) && (obj->delete_me < 2))
1898      {
1899        Evas *e;
1900
1901        e = obj->layer->evas;
1902        if ((!e) || (e->cleanup)) return;
1903        eina_array_push(&e->pending_objects, obj);
1904        obj->changed = EINA_TRUE;
1905      }
1906 }
1907
1908 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/