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